blob: 568e6a7b8a672536248145588b3c487288141ac6 [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,
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000448 xmlNodePtr ctxt1,
449 void *comp1,
450 const xmlChar *value2,
451 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000452typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
453typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
454struct _xmlRelaxNGTypeLibrary {
455 const xmlChar *namespace; /* the datatypeLibrary value */
456 void *data; /* data needed for the library */
457 xmlRelaxNGTypeHave have; /* the export function */
458 xmlRelaxNGTypeCheck check; /* the checking function */
459 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000460 xmlRelaxNGFacetCheck facet; /* the facet check function */
461 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000462};
463
464/************************************************************************
465 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000466 * Allocation functions *
467 * *
468 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000469static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
470static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000471static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000472static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000473static int xmlRelaxNGEqualValidState(
474 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
475 xmlRelaxNGValidStatePtr state1,
476 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000477static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
478 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000479
480/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000481 * xmlRelaxNGFreeDocument:
482 * @docu: a document structure
483 *
484 * Deallocate a RelaxNG document structure.
485 */
486static void
487xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
488{
489 if (docu == NULL)
490 return;
491
492 if (docu->href != NULL)
493 xmlFree(docu->href);
494 if (docu->doc != NULL)
495 xmlFreeDoc(docu->doc);
496 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000497 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000498 xmlFree(docu);
499}
500
501/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000502 * xmlRelaxNGFreeDocumentList:
503 * @docu: a list of document structure
504 *
505 * Deallocate a RelaxNG document structures.
506 */
507static void
508xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
509{
510 xmlRelaxNGDocumentPtr next;
511 while (docu != NULL) {
512 next = docu->next;
513 xmlRelaxNGFreeDocument(docu);
514 docu = next;
515 }
516}
517
518/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000519 * xmlRelaxNGFreeInclude:
520 * @incl: a include structure
521 *
522 * Deallocate a RelaxNG include structure.
523 */
524static void
525xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
526{
527 if (incl == NULL)
528 return;
529
530 if (incl->href != NULL)
531 xmlFree(incl->href);
532 if (incl->doc != NULL)
533 xmlFreeDoc(incl->doc);
534 if (incl->schema != NULL)
535 xmlRelaxNGFree(incl->schema);
536 xmlFree(incl);
537}
538
539/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000540 * xmlRelaxNGFreeIncludeList:
541 * @incl: a include structure list
542 *
543 * Deallocate a RelaxNG include structure.
544 */
545static void
546xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
547{
548 xmlRelaxNGIncludePtr next;
549 while (incl != NULL) {
550 next = incl->next;
551 xmlRelaxNGFreeInclude(incl);
552 incl = next;
553 }
554}
555
556/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000557 * xmlRelaxNGNewRelaxNG:
558 * @ctxt: a Relax-NG validation context (optional)
559 *
560 * Allocate a new RelaxNG structure.
561 *
562 * Returns the newly allocated structure or NULL in case or error
563 */
564static xmlRelaxNGPtr
565xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
566{
567 xmlRelaxNGPtr ret;
568
569 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
570 if (ret == NULL) {
571 if ((ctxt != NULL) && (ctxt->error != NULL))
572 ctxt->error(ctxt->userData, "Out of memory\n");
573 ctxt->nbErrors++;
574 return (NULL);
575 }
576 memset(ret, 0, sizeof(xmlRelaxNG));
577
578 return (ret);
579}
580
581/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000582 * xmlRelaxNGFreeInnerSchema:
583 * @schema: a schema structure
584 *
585 * Deallocate a RelaxNG schema structure.
586 */
587static void
588xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
589{
590 if (schema == NULL)
591 return;
592
593 if (schema->doc != NULL)
594 xmlFreeDoc(schema->doc);
595 if (schema->defTab != NULL) {
596 int i;
597
598 for (i = 0;i < schema->defNr;i++)
599 xmlRelaxNGFreeDefine(schema->defTab[i]);
600 xmlFree(schema->defTab);
601 }
602
603 xmlFree(schema);
604}
605
606/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000607 * xmlRelaxNGFree:
608 * @schema: a schema structure
609 *
610 * Deallocate a RelaxNG structure.
611 */
612void
613xmlRelaxNGFree(xmlRelaxNGPtr schema)
614{
615 if (schema == NULL)
616 return;
617
Daniel Veillard6eadf632003-01-23 18:29:16 +0000618 if (schema->topgrammar != NULL)
619 xmlRelaxNGFreeGrammar(schema->topgrammar);
620 if (schema->doc != NULL)
621 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000622 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000623 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000624 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000625 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000626 if (schema->defTab != NULL) {
627 int i;
628
629 for (i = 0;i < schema->defNr;i++)
630 xmlRelaxNGFreeDefine(schema->defTab[i]);
631 xmlFree(schema->defTab);
632 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000633
634 xmlFree(schema);
635}
636
637/**
638 * xmlRelaxNGNewGrammar:
639 * @ctxt: a Relax-NG validation context (optional)
640 *
641 * Allocate a new RelaxNG grammar.
642 *
643 * Returns the newly allocated structure or NULL in case or error
644 */
645static xmlRelaxNGGrammarPtr
646xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
647{
648 xmlRelaxNGGrammarPtr ret;
649
650 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
651 if (ret == NULL) {
652 if ((ctxt != NULL) && (ctxt->error != NULL))
653 ctxt->error(ctxt->userData, "Out of memory\n");
654 ctxt->nbErrors++;
655 return (NULL);
656 }
657 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
658
659 return (ret);
660}
661
662/**
663 * xmlRelaxNGFreeGrammar:
664 * @grammar: a grammar structure
665 *
666 * Deallocate a RelaxNG grammar structure.
667 */
668static void
669xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
670{
671 if (grammar == NULL)
672 return;
673
Daniel Veillardc482e262003-02-26 14:48:48 +0000674 if (grammar->children != NULL) {
675 xmlRelaxNGFreeGrammar(grammar->children);
676 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000677 if (grammar->next != NULL) {
678 xmlRelaxNGFreeGrammar(grammar->next);
679 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000680 if (grammar->refs != NULL) {
681 xmlHashFree(grammar->refs, NULL);
682 }
683 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000684 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000685 }
686
687 xmlFree(grammar);
688}
689
690/**
691 * xmlRelaxNGNewDefine:
692 * @ctxt: a Relax-NG validation context
693 * @node: the node in the input document.
694 *
695 * Allocate a new RelaxNG define.
696 *
697 * Returns the newly allocated structure or NULL in case or error
698 */
699static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000700xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000701{
702 xmlRelaxNGDefinePtr ret;
703
Daniel Veillard419a7682003-02-03 23:22:49 +0000704 if (ctxt->defMax == 0) {
705 ctxt->defMax = 16;
706 ctxt->defNr = 0;
707 ctxt->defTab = (xmlRelaxNGDefinePtr *)
708 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
709 if (ctxt->defTab == NULL) {
710 if ((ctxt != NULL) && (ctxt->error != NULL))
711 ctxt->error(ctxt->userData, "Out of memory\n");
712 ctxt->nbErrors++;
713 return (NULL);
714 }
715 } else if (ctxt->defMax <= ctxt->defNr) {
716 xmlRelaxNGDefinePtr *tmp;
717 ctxt->defMax *= 2;
718 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
719 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
720 if (tmp == NULL) {
721 if ((ctxt != NULL) && (ctxt->error != NULL))
722 ctxt->error(ctxt->userData, "Out of memory\n");
723 ctxt->nbErrors++;
724 return (NULL);
725 }
726 ctxt->defTab = tmp;
727 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000728 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
729 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000730 if ((ctxt != NULL) && (ctxt->error != NULL))
731 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000732 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000733 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000734 }
735 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000736 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000737 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000738 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000739 return (ret);
740}
741
742/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000743 * xmlRelaxNGFreePartition:
744 * @partitions: a partition set structure
745 *
746 * Deallocate RelaxNG partition set structures.
747 */
748static void
749xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
750 xmlRelaxNGInterleaveGroupPtr group;
751 int j;
752
753 if (partitions != NULL) {
754 if (partitions->groups != NULL) {
755 for (j = 0;j < partitions->nbgroups;j++) {
756 group = partitions->groups[j];
757 if (group != NULL) {
758 if (group->defs != NULL)
759 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000760 if (group->attrs != NULL)
761 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000762 xmlFree(group);
763 }
764 }
765 xmlFree(partitions->groups);
766 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000767 if (partitions->triage != NULL) {
768 xmlHashFree(partitions->triage, NULL);
769 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000770 xmlFree(partitions);
771 }
772}
773/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000774 * xmlRelaxNGFreeDefine:
775 * @define: a define structure
776 *
777 * Deallocate a RelaxNG define structure.
778 */
779static void
780xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
781{
782 if (define == NULL)
783 return;
784
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000785 if ((define->type == XML_RELAXNG_VALUE) &&
786 (define->attrs != NULL)) {
787 xmlRelaxNGTypeLibraryPtr lib;
788
789 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
790 if ((lib != NULL) && (lib->freef != NULL))
791 lib->freef(lib->data, (void *) define->attrs);
792 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000793 if ((define->data != NULL) &&
794 (define->type == XML_RELAXNG_INTERLEAVE))
795 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillarde063f482003-03-21 16:53:17 +0000796 if ((define->data != NULL) &&
797 (define->type == XML_RELAXNG_CHOICE))
798 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000799 if (define->name != NULL)
800 xmlFree(define->name);
801 if (define->ns != NULL)
802 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000803 if (define->value != NULL)
804 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000805 xmlFree(define);
806}
807
808/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000809 * xmlRelaxNGNewStates:
810 * @ctxt: a Relax-NG validation context
811 * @size: the default size for the container
812 *
813 * Allocate a new RelaxNG validation state container
814 * TODO: keep a pool in the ctxt
815 *
816 * Returns the newly allocated structure or NULL in case or error
817 */
818static xmlRelaxNGStatesPtr
819xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
820{
821 xmlRelaxNGStatesPtr ret;
822
Daniel Veillard798024a2003-03-19 10:36:09 +0000823 if ((ctxt != NULL) &&
824 (ctxt->freeState != NULL) &&
825 (ctxt->freeStatesNr > 0)) {
826 ctxt->freeStatesNr--;
827 ret = ctxt->freeStates[ctxt->freeStatesNr];
828 ret->nbState = 0;
829 return(ret);
830 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000831 if (size < 16) size = 16;
832
833 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
834 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
835 if (ret == NULL) {
836 if ((ctxt != NULL) && (ctxt->error != NULL))
837 ctxt->error(ctxt->userData, "Out of memory\n");
838 return (NULL);
839 }
840 ret->nbState = 0;
841 ret->maxState = size;
842 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
843 (size) * sizeof(xmlRelaxNGValidStatePtr));
844 if (ret->tabState == NULL) {
845 if ((ctxt != NULL) && (ctxt->error != NULL))
846 ctxt->error(ctxt->userData, "Out of memory\n");
847 xmlFree(ret->tabState);
848 return (NULL);
849 }
850 return(ret);
851}
852
853/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000854 * xmlRelaxNGAddStateUniq:
855 * @ctxt: a Relax-NG validation context
856 * @states: the states container
857 * @state: the validation state
858 *
859 * Add a RelaxNG validation state to the container without checking
860 * for unicity.
861 *
862 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
863 */
864static int
865xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
866 xmlRelaxNGStatesPtr states,
867 xmlRelaxNGValidStatePtr state)
868{
869 if (state == NULL) {
870 return(-1);
871 }
872 if (states->nbState >= states->maxState) {
873 xmlRelaxNGValidStatePtr *tmp;
874 int size;
875
876 size = states->maxState * 2;
877 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
878 (size) * sizeof(xmlRelaxNGValidStatePtr));
879 if (tmp == NULL) {
880 if ((ctxt != NULL) && (ctxt->error != NULL))
881 ctxt->error(ctxt->userData, "Out of memory\n");
882 return(-1);
883 }
884 states->tabState = tmp;
885 states->maxState = size;
886 }
887 states->tabState[states->nbState++] = state;
888 return(1);
889}
890
891/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000892 * xmlRelaxNGAddState:
893 * @ctxt: a Relax-NG validation context
894 * @states: the states container
895 * @state: the validation state
896 *
897 * Add a RelaxNG validation state to the container
898 *
899 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
900 */
901static int
902xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
903 xmlRelaxNGValidStatePtr state)
904{
905 int i;
906
907 if (state == NULL) {
908 return(-1);
909 }
910 if (states->nbState >= states->maxState) {
911 xmlRelaxNGValidStatePtr *tmp;
912 int size;
913
914 size = states->maxState * 2;
915 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
916 (size) * sizeof(xmlRelaxNGValidStatePtr));
917 if (tmp == NULL) {
918 if ((ctxt != NULL) && (ctxt->error != NULL))
919 ctxt->error(ctxt->userData, "Out of memory\n");
920 return(-1);
921 }
922 states->tabState = tmp;
923 states->maxState = size;
924 }
925 for (i = 0;i < states->nbState;i++) {
926 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000927 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000928 return(0);
929 }
930 }
931 states->tabState[states->nbState++] = state;
932 return(1);
933}
934
935/**
936 * xmlRelaxNGFreeStates:
937 * @ctxt: a Relax-NG validation context
938 * @states: teh container
939 *
940 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000941 */
942static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000943xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000944 xmlRelaxNGStatesPtr states)
945{
Daniel Veillard798024a2003-03-19 10:36:09 +0000946 if (states == NULL)
947 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000948 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
949 ctxt->freeStatesMax = 40;
950 ctxt->freeStatesNr = 0;
951 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
952 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
953 if (ctxt->freeStates == NULL) {
954 if ((ctxt != NULL) && (ctxt->error != NULL))
955 ctxt->error(ctxt->userData, "Out of memory\n");
956 }
957 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
958 xmlRelaxNGStatesPtr *tmp;
959
960 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
961 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
962 if (tmp == NULL) {
963 if ((ctxt != NULL) && (ctxt->error != NULL))
964 ctxt->error(ctxt->userData, "Out of memory\n");
965 xmlFree(states->tabState);
966 xmlFree(states);
967 return;
968 }
969 ctxt->freeStates = tmp;
970 ctxt->freeStatesMax *= 2;
971 }
972 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000973 xmlFree(states->tabState);
974 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +0000975 } else {
976 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000977 }
978}
979
980/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000981 * xmlRelaxNGNewValidState:
982 * @ctxt: a Relax-NG validation context
983 * @node: the current node or NULL for the document
984 *
985 * Allocate a new RelaxNG validation state
986 *
987 * Returns the newly allocated structure or NULL in case or error
988 */
989static xmlRelaxNGValidStatePtr
990xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
991{
992 xmlRelaxNGValidStatePtr ret;
993 xmlAttrPtr attr;
994 xmlAttrPtr attrs[MAX_ATTR];
995 int nbAttrs = 0;
996 xmlNodePtr root = NULL;
997
998 if (node == NULL) {
999 root = xmlDocGetRootElement(ctxt->doc);
1000 if (root == NULL)
1001 return(NULL);
1002 } else {
1003 attr = node->properties;
1004 while (attr != NULL) {
1005 if (nbAttrs < MAX_ATTR)
1006 attrs[nbAttrs++] = attr;
1007 else
1008 nbAttrs++;
1009 attr = attr->next;
1010 }
1011 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001012 if ((ctxt->freeState != NULL) &&
1013 (ctxt->freeState->nbState > 0)) {
1014 ctxt->freeState->nbState--;
1015 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1016 } else {
1017 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1018 if (ret == NULL) {
1019 if ((ctxt != NULL) && (ctxt->error != NULL))
1020 ctxt->error(ctxt->userData, "Out of memory\n");
1021 return (NULL);
1022 }
1023 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001024 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001025 ret->value = NULL;
1026 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001027 if (node == NULL) {
1028 ret->node = (xmlNodePtr) ctxt->doc;
1029 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001030 } else {
1031 ret->node = node;
1032 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001033 }
1034 ret->nbAttrs = 0;
1035 if (nbAttrs > 0) {
1036 if (ret->attrs == NULL) {
1037 if (nbAttrs < 4) ret->maxAttrs = 4;
1038 else ret->maxAttrs = nbAttrs;
1039 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1040 sizeof(xmlAttrPtr));
1041 if (ret->attrs == NULL) {
1042 if ((ctxt != NULL) && (ctxt->error != NULL))
1043 ctxt->error(ctxt->userData, "Out of memory\n");
1044 return (ret);
1045 }
1046 } else if (ret->maxAttrs < nbAttrs) {
1047 xmlAttrPtr *tmp;
1048
1049 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1050 sizeof(xmlAttrPtr));
1051 if (tmp == NULL) {
1052 if ((ctxt != NULL) && (ctxt->error != NULL))
1053 ctxt->error(ctxt->userData, "Out of memory\n");
1054 return (ret);
1055 }
1056 ret->attrs = tmp;
1057 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001058 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001059 if (nbAttrs < MAX_ATTR) {
1060 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1061 } else {
1062 attr = node->properties;
1063 nbAttrs = 0;
1064 while (attr != NULL) {
1065 ret->attrs[nbAttrs++] = attr;
1066 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001067 }
1068 }
1069 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001070 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001071 return (ret);
1072}
1073
1074/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001075 * xmlRelaxNGCopyValidState:
1076 * @ctxt: a Relax-NG validation context
1077 * @state: a validation state
1078 *
1079 * Copy the validation state
1080 *
1081 * Returns the newly allocated structure or NULL in case or error
1082 */
1083static xmlRelaxNGValidStatePtr
1084xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1085 xmlRelaxNGValidStatePtr state)
1086{
1087 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001088 unsigned int maxAttrs;
1089 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001090
1091 if (state == NULL)
1092 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001093 if ((ctxt->freeState != NULL) &&
1094 (ctxt->freeState->nbState > 0)) {
1095 ctxt->freeState->nbState--;
1096 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1097 } else {
1098 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1099 if (ret == NULL) {
1100 if ((ctxt != NULL) && (ctxt->error != NULL))
1101 ctxt->error(ctxt->userData, "Out of memory\n");
1102 return (NULL);
1103 }
1104 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001105 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001106 attrs = ret->attrs;
1107 maxAttrs = ret->maxAttrs;
1108 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1109 ret->attrs = attrs;
1110 ret->maxAttrs = maxAttrs;
1111 if (state->nbAttrs > 0) {
1112 if (ret->attrs == NULL) {
1113 ret->maxAttrs = state->maxAttrs;
1114 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1115 sizeof(xmlAttrPtr));
1116 if (ret->attrs == 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 } else if (ret->maxAttrs < state->nbAttrs) {
1123 xmlAttrPtr *tmp;
1124
1125 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1126 sizeof(xmlAttrPtr));
1127 if (tmp == NULL) {
1128 if ((ctxt != NULL) && (ctxt->error != NULL))
1129 ctxt->error(ctxt->userData, "Out of memory\n");
1130 ret->nbAttrs = 0;
1131 return (ret);
1132 }
1133 ret->maxAttrs = state->maxAttrs;
1134 }
1135 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1136 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001137 return(ret);
1138}
1139
1140/**
1141 * xmlRelaxNGEqualValidState:
1142 * @ctxt: a Relax-NG validation context
1143 * @state1: a validation state
1144 * @state2: a validation state
1145 *
1146 * Compare the validation states for equality
1147 *
1148 * Returns 1 if equald, 0 otherwise
1149 */
1150static int
1151xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1152 xmlRelaxNGValidStatePtr state1,
1153 xmlRelaxNGValidStatePtr state2)
1154{
1155 int i;
1156
1157 if ((state1 == NULL) || (state2 == NULL))
1158 return(0);
1159 if (state1 == state2)
1160 return(1);
1161 if (state1->node != state2->node)
1162 return(0);
1163 if (state1->seq != state2->seq)
1164 return(0);
1165 if (state1->nbAttrLeft != state2->nbAttrLeft)
1166 return(0);
1167 if (state1->nbAttrs != state2->nbAttrs)
1168 return(0);
1169 if (state1->endvalue != state2->endvalue)
1170 return(0);
1171 if ((state1->value != state2->value) &&
1172 (!xmlStrEqual(state1->value, state2->value)))
1173 return(0);
1174 for (i = 0;i < state1->nbAttrs;i++) {
1175 if (state1->attrs[i] != state2->attrs[i])
1176 return(0);
1177 }
1178 return(1);
1179}
1180
1181/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001182 * xmlRelaxNGFreeValidState:
1183 * @state: a validation state structure
1184 *
1185 * Deallocate a RelaxNG validation state structure.
1186 */
1187static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001188xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1189 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001190{
1191 if (state == NULL)
1192 return;
1193
Daniel Veillard798024a2003-03-19 10:36:09 +00001194 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1195 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1196 }
1197 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1198 if (state->attrs != NULL)
1199 xmlFree(state->attrs);
1200 xmlFree(state);
1201 } else {
1202 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1203 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001204}
1205
1206/************************************************************************
1207 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001208 * Document functions *
1209 * *
1210 ************************************************************************/
1211static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1212 xmlDocPtr doc);
1213
1214/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001215 * xmlRelaxNGIncludePush:
1216 * @ctxt: the parser context
1217 * @value: the element doc
1218 *
1219 * Pushes a new include on top of the include stack
1220 *
1221 * Returns 0 in case of error, the index in the stack otherwise
1222 */
1223static int
1224xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1225 xmlRelaxNGIncludePtr value)
1226{
1227 if (ctxt->incTab == NULL) {
1228 ctxt->incMax = 4;
1229 ctxt->incNr = 0;
1230 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1231 ctxt->incMax * sizeof(ctxt->incTab[0]));
1232 if (ctxt->incTab == NULL) {
1233 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1234 return (0);
1235 }
1236 }
1237 if (ctxt->incNr >= ctxt->incMax) {
1238 ctxt->incMax *= 2;
1239 ctxt->incTab =
1240 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1241 ctxt->incMax *
1242 sizeof(ctxt->incTab[0]));
1243 if (ctxt->incTab == NULL) {
1244 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1245 return (0);
1246 }
1247 }
1248 ctxt->incTab[ctxt->incNr] = value;
1249 ctxt->inc = value;
1250 return (ctxt->incNr++);
1251}
1252
1253/**
1254 * xmlRelaxNGIncludePop:
1255 * @ctxt: the parser context
1256 *
1257 * Pops the top include from the include stack
1258 *
1259 * Returns the include just removed
1260 */
1261static xmlRelaxNGIncludePtr
1262xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1263{
1264 xmlRelaxNGIncludePtr ret;
1265
1266 if (ctxt->incNr <= 0)
1267 return (0);
1268 ctxt->incNr--;
1269 if (ctxt->incNr > 0)
1270 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1271 else
1272 ctxt->inc = NULL;
1273 ret = ctxt->incTab[ctxt->incNr];
1274 ctxt->incTab[ctxt->incNr] = 0;
1275 return (ret);
1276}
1277
1278/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001279 * xmlRelaxNGRemoveRedefine:
1280 * @ctxt: the parser context
1281 * @URL: the normalized URL
1282 * @target: the included target
1283 * @name: the define name to eliminate
1284 *
1285 * Applies the elimination algorithm of 4.7
1286 *
1287 * Returns 0 in case of error, 1 in case of success.
1288 */
1289static int
1290xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1291 const xmlChar *URL ATTRIBUTE_UNUSED,
1292 xmlNodePtr target, const xmlChar *name) {
1293 int found = 0;
1294 xmlNodePtr tmp, tmp2;
1295 xmlChar *name2;
1296
1297#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001298 if (name == NULL)
1299 xmlGenericError(xmlGenericErrorContext,
1300 "Elimination of <include> start from %s\n", URL);
1301 else
1302 xmlGenericError(xmlGenericErrorContext,
1303 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001304#endif
1305 tmp = target;
1306 while (tmp != NULL) {
1307 tmp2 = tmp->next;
1308 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1309 found = 1;
1310 xmlUnlinkNode(tmp);
1311 xmlFreeNode(tmp);
1312 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1313 name2 = xmlGetProp(tmp, BAD_CAST "name");
1314 xmlRelaxNGNormExtSpace(name2);
1315 if (name2 != NULL) {
1316 if (xmlStrEqual(name, name2)) {
1317 found = 1;
1318 xmlUnlinkNode(tmp);
1319 xmlFreeNode(tmp);
1320 }
1321 xmlFree(name2);
1322 }
1323 } else if (IS_RELAXNG(tmp, "include")) {
1324 xmlChar *href = NULL;
1325 xmlRelaxNGDocumentPtr inc = tmp->_private;
1326
1327 if ((inc != NULL) && (inc->doc != NULL) &&
1328 (inc->doc->children != NULL)) {
1329
1330 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1331#ifdef DEBUG_INCLUDE
1332 href = xmlGetProp(tmp, BAD_CAST "href");
1333#endif
1334 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1335 inc->doc->children->children, name) == 1) {
1336 found = 1;
1337 }
1338 if (href != NULL)
1339 xmlFree(href);
1340 }
1341 }
1342 }
1343 tmp = tmp2;
1344 }
1345 return(found);
1346}
1347
1348/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001349 * xmlRelaxNGLoadInclude:
1350 * @ctxt: the parser context
1351 * @URL: the normalized URL
1352 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001353 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001354 *
1355 * First lookup if the document is already loaded into the parser context,
1356 * check against recursion. If not found the resource is loaded and
1357 * the content is preprocessed before being returned back to the caller.
1358 *
1359 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1360 */
1361static xmlRelaxNGIncludePtr
1362xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001363 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001364 xmlRelaxNGIncludePtr ret = NULL;
1365 xmlDocPtr doc;
1366 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001367 xmlNodePtr root, cur;
1368
1369#ifdef DEBUG_INCLUDE
1370 xmlGenericError(xmlGenericErrorContext,
1371 "xmlRelaxNGLoadInclude(%s)\n", URL);
1372#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001373
1374 /*
1375 * check against recursion in the stack
1376 */
1377 for (i = 0;i < ctxt->incNr;i++) {
1378 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1379 if (ctxt->error != NULL)
1380 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001381 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001382 URL);
1383 ctxt->nbErrors++;
1384 return(NULL);
1385 }
1386 }
1387
1388 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001389 * load the document
1390 */
1391 doc = xmlParseFile((const char *) URL);
1392 if (doc == NULL) {
1393 if (ctxt->error != NULL)
1394 ctxt->error(ctxt->userData,
1395 "xmlRelaxNG: could not load %s\n", URL);
1396 ctxt->nbErrors++;
1397 return (NULL);
1398 }
1399
Daniel Veillard5add8682003-03-10 13:13:58 +00001400#ifdef DEBUG_INCLUDE
1401 xmlGenericError(xmlGenericErrorContext,
1402 "Parsed %s Okay\n", URL);
1403#endif
1404
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001405 /*
1406 * Allocate the document structures and register it first.
1407 */
1408 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1409 if (ret == NULL) {
1410 if (ctxt->error != NULL)
1411 ctxt->error(ctxt->userData,
1412 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1413 ctxt->nbErrors++;
1414 xmlFreeDoc(doc);
1415 return (NULL);
1416 }
1417 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1418 ret->doc = doc;
1419 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001420 ret->next = ctxt->includes;
1421 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001422
1423 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001424 * transmit the ns if needed
1425 */
1426 if (ns != NULL) {
1427 root = xmlDocGetRootElement(doc);
1428 if (root != NULL) {
1429 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1430 xmlSetProp(root, BAD_CAST"ns", ns);
1431 }
1432 }
1433 }
1434
1435 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001436 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001437 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001438 xmlRelaxNGIncludePush(ctxt, ret);
1439
1440 /*
1441 * Some preprocessing of the document content, this include recursing
1442 * in the include stack.
1443 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001444#ifdef DEBUG_INCLUDE
1445 xmlGenericError(xmlGenericErrorContext,
1446 "cleanup of %s\n", URL);
1447#endif
1448
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001449 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1450 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001451 ctxt->inc = NULL;
1452 return(NULL);
1453 }
1454
1455 /*
1456 * Pop up the include from the stack
1457 */
1458 xmlRelaxNGIncludePop(ctxt);
1459
Daniel Veillard5add8682003-03-10 13:13:58 +00001460#ifdef DEBUG_INCLUDE
1461 xmlGenericError(xmlGenericErrorContext,
1462 "Checking of %s\n", URL);
1463#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001464 /*
1465 * Check that the top element is a grammar
1466 */
1467 root = xmlDocGetRootElement(doc);
1468 if (root == NULL) {
1469 if (ctxt->error != NULL)
1470 ctxt->error(ctxt->userData,
1471 "xmlRelaxNG: included document is empty %s\n", URL);
1472 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001473 return (NULL);
1474 }
1475 if (!IS_RELAXNG(root, "grammar")) {
1476 if (ctxt->error != NULL)
1477 ctxt->error(ctxt->userData,
1478 "xmlRelaxNG: included document %s root is not a grammar\n",
1479 URL);
1480 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001481 return (NULL);
1482 }
1483
1484 /*
1485 * Elimination of redefined rules in the include.
1486 */
1487 cur = node->children;
1488 while (cur != NULL) {
1489 if (IS_RELAXNG(cur, "start")) {
1490 int found = 0;
1491
Daniel Veillard5add8682003-03-10 13:13:58 +00001492 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001493 if (!found) {
1494 if (ctxt->error != NULL)
1495 ctxt->error(ctxt->userData,
1496 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1497 URL);
1498 ctxt->nbErrors++;
1499 }
1500 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001501 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001502
1503 name = xmlGetProp(cur, BAD_CAST "name");
1504 if (name == NULL) {
1505 if (ctxt->error != NULL)
1506 ctxt->error(ctxt->userData,
1507 "xmlRelaxNG: include %s has define without name\n",
1508 URL);
1509 ctxt->nbErrors++;
1510 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001511 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001512
Daniel Veillardd2298792003-02-14 16:54:11 +00001513 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001514 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1515 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001516 if (!found) {
1517 if (ctxt->error != NULL)
1518 ctxt->error(ctxt->userData,
1519 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1520 URL, name);
1521 ctxt->nbErrors++;
1522 }
1523 xmlFree(name);
1524 }
1525 }
1526 cur = cur->next;
1527 }
1528
1529
1530 return(ret);
1531}
1532
1533/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001534 * xmlRelaxNGValidErrorPush:
1535 * @ctxt: the validation context
1536 * @err: the error code
1537 * @arg1: the first string argument
1538 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001539 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001540 *
1541 * Pushes a new error on top of the error stack
1542 *
1543 * Returns 0 in case of error, the index in the stack otherwise
1544 */
1545static int
1546xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001547 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001548{
1549 xmlRelaxNGValidErrorPtr cur;
1550 if (ctxt->errTab == NULL) {
1551 ctxt->errMax = 8;
1552 ctxt->errNr = 0;
1553 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1554 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1555 if (ctxt->errTab == NULL) {
1556 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1557 return (0);
1558 }
Daniel Veillard20863822003-03-22 17:51:47 +00001559 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001560 }
1561 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard20863822003-03-22 17:51:47 +00001562 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001563 ctxt->errTab =
1564 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard20863822003-03-22 17:51:47 +00001565 ctxt->errMax * sizeof(xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001566 if (ctxt->errTab == NULL) {
1567 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1568 return (0);
1569 }
Daniel Veillard20863822003-03-22 17:51:47 +00001570 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001571 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001572 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001573 (ctxt->err->node == ctxt->state->node) &&
1574 (ctxt->err->err == err))
1575 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001576 cur = &ctxt->errTab[ctxt->errNr];
1577 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001578 if (dup) {
1579 cur->arg1 = xmlStrdup(arg1);
1580 cur->arg2 = xmlStrdup(arg2);
1581 cur->flags = ERROR_IS_DUP;
1582 } else {
1583 cur->arg1 = arg1;
1584 cur->arg2 = arg2;
1585 cur->flags = 0;
1586 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001587 if (ctxt->state != NULL) {
1588 cur->node = ctxt->state->node;
1589 cur->seq = ctxt->state->seq;
1590 } else {
1591 cur->node = NULL;
1592 cur->seq = NULL;
1593 }
1594 ctxt->err = cur;
1595 return (ctxt->errNr++);
1596}
1597
1598/**
1599 * xmlRelaxNGValidErrorPop:
1600 * @ctxt: the validation context
1601 *
1602 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001603 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001604static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001605xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1606{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001607 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001608
Daniel Veillard580ced82003-03-21 21:22:48 +00001609 if (ctxt->errNr <= 0) {
1610 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001611 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001612 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001613 ctxt->errNr--;
1614 if (ctxt->errNr > 0)
1615 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1616 else
1617 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001618 cur = &ctxt->errTab[ctxt->errNr];
1619 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001620 if (cur->arg1 != NULL)
1621 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001622 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001623 if (cur->arg2 != NULL)
1624 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001625 cur->arg2 = NULL;
1626 cur->flags = 0;
1627 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001628}
1629
Daniel Veillard42f12e92003-03-07 18:32:59 +00001630/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001631 * xmlRelaxNGDocumentPush:
1632 * @ctxt: the parser context
1633 * @value: the element doc
1634 *
1635 * Pushes a new doc on top of the doc stack
1636 *
1637 * Returns 0 in case of error, the index in the stack otherwise
1638 */
1639static int
1640xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1641 xmlRelaxNGDocumentPtr value)
1642{
1643 if (ctxt->docTab == NULL) {
1644 ctxt->docMax = 4;
1645 ctxt->docNr = 0;
1646 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1647 ctxt->docMax * sizeof(ctxt->docTab[0]));
1648 if (ctxt->docTab == NULL) {
1649 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1650 return (0);
1651 }
1652 }
1653 if (ctxt->docNr >= ctxt->docMax) {
1654 ctxt->docMax *= 2;
1655 ctxt->docTab =
1656 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1657 ctxt->docMax *
1658 sizeof(ctxt->docTab[0]));
1659 if (ctxt->docTab == NULL) {
1660 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1661 return (0);
1662 }
1663 }
1664 ctxt->docTab[ctxt->docNr] = value;
1665 ctxt->doc = value;
1666 return (ctxt->docNr++);
1667}
1668
1669/**
1670 * xmlRelaxNGDocumentPop:
1671 * @ctxt: the parser context
1672 *
1673 * Pops the top doc from the doc stack
1674 *
1675 * Returns the doc just removed
1676 */
1677static xmlRelaxNGDocumentPtr
1678xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1679{
1680 xmlRelaxNGDocumentPtr ret;
1681
1682 if (ctxt->docNr <= 0)
1683 return (0);
1684 ctxt->docNr--;
1685 if (ctxt->docNr > 0)
1686 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1687 else
1688 ctxt->doc = NULL;
1689 ret = ctxt->docTab[ctxt->docNr];
1690 ctxt->docTab[ctxt->docNr] = 0;
1691 return (ret);
1692}
1693
1694/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001695 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001696 * @ctxt: the parser context
1697 * @URL: the normalized URL
1698 * @ns: the inherited ns if any
1699 *
1700 * First lookup if the document is already loaded into the parser context,
1701 * check against recursion. If not found the resource is loaded and
1702 * the content is preprocessed before being returned back to the caller.
1703 *
1704 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1705 */
1706static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001707xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001708 const xmlChar *ns) {
1709 xmlRelaxNGDocumentPtr ret = NULL;
1710 xmlDocPtr doc;
1711 xmlNodePtr root;
1712 int i;
1713
1714 /*
1715 * check against recursion in the stack
1716 */
1717 for (i = 0;i < ctxt->docNr;i++) {
1718 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1719 if (ctxt->error != NULL)
1720 ctxt->error(ctxt->userData,
1721 "Detected an externalRef recursion for %s\n",
1722 URL);
1723 ctxt->nbErrors++;
1724 return(NULL);
1725 }
1726 }
1727
1728 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001729 * load the document
1730 */
1731 doc = xmlParseFile((const char *) URL);
1732 if (doc == NULL) {
1733 if (ctxt->error != NULL)
1734 ctxt->error(ctxt->userData,
1735 "xmlRelaxNG: could not load %s\n", URL);
1736 ctxt->nbErrors++;
1737 return (NULL);
1738 }
1739
1740 /*
1741 * Allocate the document structures and register it first.
1742 */
1743 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1744 if (ret == NULL) {
1745 if (ctxt->error != NULL)
1746 ctxt->error(ctxt->userData,
1747 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1748 ctxt->nbErrors++;
1749 xmlFreeDoc(doc);
1750 return (NULL);
1751 }
1752 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1753 ret->doc = doc;
1754 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001755 ret->next = ctxt->documents;
1756 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001757
1758 /*
1759 * transmit the ns if needed
1760 */
1761 if (ns != NULL) {
1762 root = xmlDocGetRootElement(doc);
1763 if (root != NULL) {
1764 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1765 xmlSetProp(root, BAD_CAST"ns", ns);
1766 }
1767 }
1768 }
1769
1770 /*
1771 * push it on the stack and register it in the hash table
1772 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001773 xmlRelaxNGDocumentPush(ctxt, ret);
1774
1775 /*
1776 * Some preprocessing of the document content
1777 */
1778 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1779 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001780 ctxt->doc = NULL;
1781 return(NULL);
1782 }
1783
1784 xmlRelaxNGDocumentPop(ctxt);
1785
1786 return(ret);
1787}
1788
1789/************************************************************************
1790 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001791 * Error functions *
1792 * *
1793 ************************************************************************/
1794
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001795#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1796#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1797#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1798#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1799#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001800
Daniel Veillardfd573f12003-03-16 17:52:32 +00001801#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001802static const char *
1803xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1804 if (def == NULL)
1805 return("none");
1806 switch(def->type) {
1807 case XML_RELAXNG_EMPTY: return("empty");
1808 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1809 case XML_RELAXNG_EXCEPT: return("except");
1810 case XML_RELAXNG_TEXT: return("text");
1811 case XML_RELAXNG_ELEMENT: return("element");
1812 case XML_RELAXNG_DATATYPE: return("datatype");
1813 case XML_RELAXNG_VALUE: return("value");
1814 case XML_RELAXNG_LIST: return("list");
1815 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1816 case XML_RELAXNG_DEF: return("def");
1817 case XML_RELAXNG_REF: return("ref");
1818 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1819 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001820 case XML_RELAXNG_OPTIONAL: return("optional");
1821 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001822 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1823 case XML_RELAXNG_CHOICE: return("choice");
1824 case XML_RELAXNG_GROUP: return("group");
1825 case XML_RELAXNG_INTERLEAVE: return("interleave");
1826 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001827 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001828 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001829 }
1830 return("unknown");
1831}
Daniel Veillardfd573f12003-03-16 17:52:32 +00001832#endif
Daniel Veillardd2298792003-02-14 16:54:11 +00001833
Daniel Veillard6eadf632003-01-23 18:29:16 +00001834/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001835 * xmlRelaxNGGetErrorString:
1836 * @err: the error code
1837 * @arg1: the first string argument
1838 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001839 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001840 * computes a formatted error string for the given error code and args
1841 *
1842 * Returns the error string, it must be deallocated by the caller
1843 */
1844static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001845xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1846 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001847 char msg[1000];
1848
1849 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001850 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001851 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001852 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001853
1854 msg[0] = 0;
1855 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001856 case XML_RELAXNG_OK:
1857 return(NULL);
1858 case XML_RELAXNG_ERR_MEMORY:
1859 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001860 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001861 snprintf(msg, 1000, "failed to validate type %s", arg1);
1862 break;
1863 case XML_RELAXNG_ERR_TYPEVAL:
Daniel Veillardc4c21552003-03-29 10:53:38 +00001864 snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001865 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001866 case XML_RELAXNG_ERR_DUPID:
1867 snprintf(msg, 1000, "ID %s redefined", arg1);
1868 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001869 case XML_RELAXNG_ERR_TYPECMP:
1870 snprintf(msg, 1000, "failed to compare type %s", arg1);
1871 break;
1872 case XML_RELAXNG_ERR_NOSTATE:
1873 return(xmlCharStrdup("Internal error: no state"));
1874 case XML_RELAXNG_ERR_NODEFINE:
1875 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001876 case XML_RELAXNG_ERR_INTERNAL:
1877 snprintf(msg, 1000, "Internal error: %s", arg1);
1878 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001879 case XML_RELAXNG_ERR_LISTEXTRA:
1880 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1881 break;
1882 case XML_RELAXNG_ERR_INTERNODATA:
1883 return(xmlCharStrdup("Internal: interleave block has no data"));
1884 case XML_RELAXNG_ERR_INTERSEQ:
1885 return(xmlCharStrdup("Invalid sequence in interleave"));
1886 case XML_RELAXNG_ERR_INTEREXTRA:
1887 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1888 break;
1889 case XML_RELAXNG_ERR_ELEMNAME:
1890 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1891 break;
1892 case XML_RELAXNG_ERR_ELEMNONS:
1893 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1894 break;
1895 case XML_RELAXNG_ERR_ELEMWRONGNS:
1896 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1897 arg1, arg2);
1898 break;
1899 case XML_RELAXNG_ERR_ELEMEXTRANS:
1900 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1901 break;
1902 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1903 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1904 break;
1905 case XML_RELAXNG_ERR_NOELEM:
1906 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1907 break;
1908 case XML_RELAXNG_ERR_NOTELEM:
1909 return(xmlCharStrdup("Expecting an element got text"));
1910 case XML_RELAXNG_ERR_ATTRVALID:
1911 snprintf(msg, 1000, "Element %s failed to validate attributes",
1912 arg1);
1913 break;
1914 case XML_RELAXNG_ERR_CONTENTVALID:
1915 snprintf(msg, 1000, "Element %s failed to validate content",
1916 arg1);
1917 break;
1918 case XML_RELAXNG_ERR_EXTRACONTENT:
1919 snprintf(msg, 1000, "Element %s has extra content: %s",
1920 arg1, arg2);
1921 break;
1922 case XML_RELAXNG_ERR_INVALIDATTR:
1923 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1924 arg1, arg2);
1925 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +00001926 case XML_RELAXNG_ERR_LACKDATA:
1927 snprintf(msg, 1000, "Datatype element %s contains no data",
1928 arg1);
1929 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001930 case XML_RELAXNG_ERR_DATAELEM:
1931 snprintf(msg, 1000, "Datatype element %s has child elements",
1932 arg1);
1933 break;
1934 case XML_RELAXNG_ERR_VALELEM:
1935 snprintf(msg, 1000, "Value element %s has child elements",
1936 arg1);
1937 break;
1938 case XML_RELAXNG_ERR_LISTELEM:
1939 snprintf(msg, 1000, "List element %s has child elements",
1940 arg1);
1941 break;
1942 case XML_RELAXNG_ERR_DATATYPE:
1943 snprintf(msg, 1000, "Error validating datatype %s",
1944 arg1);
1945 break;
1946 case XML_RELAXNG_ERR_VALUE:
1947 snprintf(msg, 1000, "Error validating value %s",
1948 arg1);
1949 break;
1950 case XML_RELAXNG_ERR_LIST:
1951 return(xmlCharStrdup("Error validating list"));
1952 case XML_RELAXNG_ERR_NOGRAMMAR:
1953 return(xmlCharStrdup("No top grammar defined"));
1954 case XML_RELAXNG_ERR_EXTRADATA:
1955 return(xmlCharStrdup("Extra data in the document"));
1956 default:
1957 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001958 }
1959 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001960 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001961 }
1962 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001963 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001964}
1965
1966/**
1967 * xmlRelaxNGValidErrorContext:
1968 * @ctxt: the validation context
1969 * @node: the node
1970 * @child: the node child generating the problem.
1971 *
1972 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001973 */
1974static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001975xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1976 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001977{
1978 int line = 0;
1979 const xmlChar *file = NULL;
1980 const xmlChar *name = NULL;
1981 const char *type = "error";
1982
1983 if ((ctxt == NULL) || (ctxt->error == NULL))
1984 return;
1985
1986 if (child != NULL)
1987 node = child;
1988
1989 if (node != NULL) {
1990 if ((node->type == XML_DOCUMENT_NODE) ||
1991 (node->type == XML_HTML_DOCUMENT_NODE)) {
1992 xmlDocPtr doc = (xmlDocPtr) node;
1993
1994 file = doc->URL;
1995 } else {
1996 /*
1997 * Try to find contextual informations to report
1998 */
1999 if (node->type == XML_ELEMENT_NODE) {
2000 line = (int) node->content;
2001 } else if ((node->prev != NULL) &&
2002 (node->prev->type == XML_ELEMENT_NODE)) {
2003 line = (int) node->prev->content;
2004 } else if ((node->parent != NULL) &&
2005 (node->parent->type == XML_ELEMENT_NODE)) {
2006 line = (int) node->parent->content;
2007 }
2008 if ((node->doc != NULL) && (node->doc->URL != NULL))
2009 file = node->doc->URL;
2010 if (node->name != NULL)
2011 name = node->name;
2012 }
2013 }
2014
Daniel Veillard42f12e92003-03-07 18:32:59 +00002015 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002016
2017 if ((file != NULL) && (line != 0) && (name != NULL))
2018 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2019 type, file, line, name);
2020 else if ((file != NULL) && (name != NULL))
2021 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2022 type, file, name);
2023 else if ((file != NULL) && (line != 0))
2024 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2025 else if (file != NULL)
2026 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2027 else if (name != NULL)
2028 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2029 else
2030 ctxt->error(ctxt->userData, "%s\n", type);
2031}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002032
2033/**
2034 * xmlRelaxNGShowValidError:
2035 * @ctxt: the validation context
2036 * @err: the error number
2037 * @node: the node
2038 * @child: the node child generating the problem.
2039 * @arg1: the first argument
2040 * @arg2: the second argument
2041 *
2042 * Show a validation error.
2043 */
2044static void
2045xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2046 xmlNodePtr node, xmlNodePtr child,
2047 const xmlChar *arg1, const xmlChar *arg2)
2048{
2049 xmlChar *msg;
2050
2051 if (ctxt->error == NULL)
2052 return;
2053
2054 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2055 if (msg == NULL)
2056 return;
2057
2058 xmlRelaxNGValidErrorContext(ctxt, node, child);
2059 ctxt->error(ctxt->userData, "%s\n", msg);
2060 xmlFree(msg);
2061}
2062
2063/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002064 * xmlRelaxNGPopErrors:
2065 * @ctxt: the validation context
2066 * @level: the error level in the stack
2067 *
2068 * pop and discard all errors until the given level is reached
2069 */
2070static void
2071xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2072 int i;
2073 xmlRelaxNGValidErrorPtr err;
2074
2075 for (i = level;i < ctxt->errNr;i++) {
2076 err = &ctxt->errTab[i];
2077 if (err->flags & ERROR_IS_DUP) {
2078 if (err->arg1 != NULL)
2079 xmlFree((xmlChar *)err->arg1);
2080 err->arg1 = NULL;
2081 if (err->arg2 != NULL)
2082 xmlFree((xmlChar *)err->arg2);
2083 err->arg2 = NULL;
2084 err->flags = 0;
2085 }
2086 }
2087 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002088 if (ctxt->errNr <= 0)
2089 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002090}
2091/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002092 * xmlRelaxNGDumpValidError:
2093 * @ctxt: the validation context
2094 *
2095 * Show all validation error over a given index.
2096 */
2097static void
2098xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard580ced82003-03-21 21:22:48 +00002099 int i, j;
2100 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002101
2102 for (i = 0;i < ctxt->errNr;i++) {
2103 err = &ctxt->errTab[i];
Daniel Veillard580ced82003-03-21 21:22:48 +00002104 for (j = 0;j < i;j++) {
2105 dup = &ctxt->errTab[j];
2106 if ((err->err == dup->err) && (err->node == dup->node) &&
2107 (xmlStrEqual(err->arg1, dup->arg1)) &&
2108 (xmlStrEqual(err->arg2, dup->arg2))) {
2109 goto skip;
2110 }
2111 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002112 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2113 err->arg1, err->arg2);
Daniel Veillard580ced82003-03-21 21:22:48 +00002114skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002115 if (err->flags & ERROR_IS_DUP) {
2116 if (err->arg1 != NULL)
2117 xmlFree((xmlChar *)err->arg1);
2118 err->arg1 = NULL;
2119 if (err->arg2 != NULL)
2120 xmlFree((xmlChar *)err->arg2);
2121 err->arg2 = NULL;
2122 err->flags = 0;
2123 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002124 }
2125 ctxt->errNr = 0;
2126}
2127/**
2128 * xmlRelaxNGAddValidError:
2129 * @ctxt: the validation context
2130 * @err: the error number
2131 * @arg1: the first argument
2132 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002133 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002134 *
2135 * Register a validation error, either generating it if it's sure
2136 * or stacking it for later handling if unsure.
2137 */
2138static void
2139xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002140 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002141{
2142 if ((ctxt == NULL) || (ctxt->error == NULL))
2143 return;
2144
2145 /*
2146 * generate the error directly
2147 */
2148 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2149 xmlNodePtr node, seq;
2150 /*
2151 * Flush first any stacked error which might be the
2152 * real cause of the problem.
2153 */
2154 if (ctxt->errNr != 0)
2155 xmlRelaxNGDumpValidError(ctxt);
2156 if (ctxt->state != NULL) {
2157 node = ctxt->state->node;
2158 seq = ctxt->state->seq;
2159 } else {
2160 node = seq = NULL;
2161 }
2162 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2163 }
2164 /*
2165 * Stack the error for later processing if needed
2166 */
2167 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002168 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002169 }
2170}
2171
Daniel Veillard6eadf632003-01-23 18:29:16 +00002172
2173/************************************************************************
2174 * *
2175 * Type library hooks *
2176 * *
2177 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002178static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2179 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002180
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002181/**
2182 * xmlRelaxNGSchemaTypeHave:
2183 * @data: data needed for the library
2184 * @type: the type name
2185 *
2186 * Check if the given type is provided by
2187 * the W3C XMLSchema Datatype library.
2188 *
2189 * Returns 1 if yes, 0 if no and -1 in case of error.
2190 */
2191static int
2192xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002193 const xmlChar *type) {
2194 xmlSchemaTypePtr typ;
2195
2196 if (type == NULL)
2197 return(-1);
2198 typ = xmlSchemaGetPredefinedType(type,
2199 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2200 if (typ == NULL)
2201 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002202 return(1);
2203}
2204
2205/**
2206 * xmlRelaxNGSchemaTypeCheck:
2207 * @data: data needed for the library
2208 * @type: the type name
2209 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002210 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002211 *
2212 * Check if the given type and value are validated by
2213 * the W3C XMLSchema Datatype library.
2214 *
2215 * Returns 1 if yes, 0 if no and -1 in case of error.
2216 */
2217static int
2218xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002219 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002220 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002221 void **result,
2222 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002223 xmlSchemaTypePtr typ;
2224 int ret;
2225
2226 /*
2227 * TODO: the type should be cached ab provided back, interface subject
2228 * to changes.
2229 * TODO: handle facets, may require an additional interface and keep
2230 * the value returned from the validation.
2231 */
2232 if ((type == NULL) || (value == NULL))
2233 return(-1);
2234 typ = xmlSchemaGetPredefinedType(type,
2235 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2236 if (typ == NULL)
2237 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002238 ret = xmlSchemaValPredefTypeNode(typ, value,
2239 (xmlSchemaValPtr *) result, node);
2240 if (ret == 2) /* special ID error code */
2241 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002242 if (ret == 0)
2243 return(1);
2244 if (ret > 0)
2245 return(0);
2246 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002247}
2248
2249/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002250 * xmlRelaxNGSchemaFacetCheck:
2251 * @data: data needed for the library
2252 * @type: the type name
2253 * @facet: the facet name
2254 * @val: the facet value
2255 * @strval: the string value
2256 * @value: the value to check
2257 *
2258 * Function provided by a type library to check a value facet
2259 *
2260 * Returns 1 if yes, 0 if no and -1 in case of error.
2261 */
2262static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002263xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002264 const xmlChar *facetname, const xmlChar *val,
2265 const xmlChar *strval, void *value) {
2266 xmlSchemaFacetPtr facet;
2267 xmlSchemaTypePtr typ;
2268 int ret;
2269
2270 if ((type == NULL) || (strval == NULL))
2271 return(-1);
2272 typ = xmlSchemaGetPredefinedType(type,
2273 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2274 if (typ == NULL)
2275 return(-1);
2276
2277 facet = xmlSchemaNewFacet();
2278 if (facet == NULL)
2279 return(-1);
2280
2281 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2282 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2283 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2284 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2285 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2286 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2287 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2288 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2289 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2290 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2291 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2292 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2293 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2294 facet->type = XML_SCHEMA_FACET_PATTERN;
2295 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2296 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2297 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2298 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2299 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2300 facet->type = XML_SCHEMA_FACET_LENGTH;
2301 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2302 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2303 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2304 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2305 } else {
2306 xmlSchemaFreeFacet(facet);
2307 return(-1);
2308 }
2309 facet->value = xmlStrdup(val);
2310 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2311 if (ret != 0) {
2312 xmlSchemaFreeFacet(facet);
2313 return(-1);
2314 }
2315 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2316 xmlSchemaFreeFacet(facet);
2317 if (ret != 0)
2318 return(-1);
2319 return(0);
2320}
2321
2322/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002323 * xmlRelaxNGSchemaFreeValue:
2324 * @data: data needed for the library
2325 * @value: the value to free
2326 *
2327 * Function provided by a type library to free a Schemas value
2328 *
2329 * Returns 1 if yes, 0 if no and -1 in case of error.
2330 */
2331static void
2332xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2333 xmlSchemaFreeValue(value);
2334}
2335
2336/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002337 * xmlRelaxNGSchemaTypeCompare:
2338 * @data: data needed for the library
2339 * @type: the type name
2340 * @value1: the first value
2341 * @value2: the second value
2342 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002343 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002344 * Datatype library.
2345 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002346 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002347 */
2348static int
2349xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002350 const xmlChar *type,
2351 const xmlChar *value1,
2352 xmlNodePtr ctxt1,
2353 void *comp1,
2354 const xmlChar *value2,
2355 xmlNodePtr ctxt2) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002356 int ret;
2357 xmlSchemaTypePtr typ;
2358 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2359
2360 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2361 return(-1);
2362 typ = xmlSchemaGetPredefinedType(type,
2363 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2364 if (typ == NULL)
2365 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002366 if (comp1 == NULL) {
2367 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2368 if (ret != 0)
2369 return(-1);
2370 if (res1 == NULL)
2371 return(-1);
2372 } else {
2373 res1 = (xmlSchemaValPtr) comp1;
2374 }
2375 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002376 if (ret != 0) {
2377 xmlSchemaFreeValue(res1);
2378 return(-1);
2379 }
2380 if (res1 == NULL) {
2381 xmlSchemaFreeValue(res1);
2382 return(-1);
2383 }
2384 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002385 if (res1 != (xmlSchemaValPtr) comp1)
2386 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002387 xmlSchemaFreeValue(res2);
2388 if (ret == -2)
2389 return(-1);
2390 if (ret == 0)
2391 return(1);
2392 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002393}
2394
2395/**
2396 * xmlRelaxNGDefaultTypeHave:
2397 * @data: data needed for the library
2398 * @type: the type name
2399 *
2400 * Check if the given type is provided by
2401 * the default datatype library.
2402 *
2403 * Returns 1 if yes, 0 if no and -1 in case of error.
2404 */
2405static int
2406xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2407 if (type == NULL)
2408 return(-1);
2409 if (xmlStrEqual(type, BAD_CAST "string"))
2410 return(1);
2411 if (xmlStrEqual(type, BAD_CAST "token"))
2412 return(1);
2413 return(0);
2414}
2415
2416/**
2417 * xmlRelaxNGDefaultTypeCheck:
2418 * @data: data needed for the library
2419 * @type: the type name
2420 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002421 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002422 *
2423 * Check if the given type and value are validated by
2424 * the default datatype library.
2425 *
2426 * Returns 1 if yes, 0 if no and -1 in case of error.
2427 */
2428static int
2429xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2430 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002431 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002432 void **result ATTRIBUTE_UNUSED,
2433 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002434 if (value == NULL)
2435 return(-1);
2436 if (xmlStrEqual(type, BAD_CAST "string"))
2437 return(1);
2438 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002439 return(1);
2440 }
2441
2442 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002443}
2444
2445/**
2446 * xmlRelaxNGDefaultTypeCompare:
2447 * @data: data needed for the library
2448 * @type: the type name
2449 * @value1: the first value
2450 * @value2: the second value
2451 *
2452 * Compare two values accordingly a type from the default
2453 * datatype library.
2454 *
2455 * Returns 1 if yes, 0 if no and -1 in case of error.
2456 */
2457static int
2458xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002459 const xmlChar *type,
2460 const xmlChar *value1,
2461 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2462 void *comp1 ATTRIBUTE_UNUSED,
2463 const xmlChar *value2,
2464 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002465 int ret = -1;
2466
2467 if (xmlStrEqual(type, BAD_CAST "string")) {
2468 ret = xmlStrEqual(value1, value2);
2469 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2470 if (!xmlStrEqual(value1, value2)) {
2471 xmlChar *nval, *nvalue;
2472
2473 /*
2474 * TODO: trivial optimizations are possible by
2475 * computing at compile-time
2476 */
2477 nval = xmlRelaxNGNormalize(NULL, value1);
2478 nvalue = xmlRelaxNGNormalize(NULL, value2);
2479
Daniel Veillardd4310742003-02-18 21:12:46 +00002480 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002481 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002482 else if (xmlStrEqual(nval, nvalue))
2483 ret = 1;
2484 else
2485 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002486 if (nval != NULL)
2487 xmlFree(nval);
2488 if (nvalue != NULL)
2489 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002490 } else
2491 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002492 }
2493 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002494}
2495
2496static int xmlRelaxNGTypeInitialized = 0;
2497static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2498
2499/**
2500 * xmlRelaxNGFreeTypeLibrary:
2501 * @lib: the type library structure
2502 * @namespace: the URI bound to the library
2503 *
2504 * Free the structure associated to the type library
2505 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002506static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002507xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2508 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2509 if (lib == NULL)
2510 return;
2511 if (lib->namespace != NULL)
2512 xmlFree((xmlChar *)lib->namespace);
2513 xmlFree(lib);
2514}
2515
2516/**
2517 * xmlRelaxNGRegisterTypeLibrary:
2518 * @namespace: the URI bound to the library
2519 * @data: data associated to the library
2520 * @have: the provide function
2521 * @check: the checking function
2522 * @comp: the comparison function
2523 *
2524 * Register a new type library
2525 *
2526 * Returns 0 in case of success and -1 in case of error.
2527 */
2528static int
2529xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2530 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002531 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2532 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002533 xmlRelaxNGTypeLibraryPtr lib;
2534 int ret;
2535
2536 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2537 (check == NULL) || (comp == NULL))
2538 return(-1);
2539 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2540 xmlGenericError(xmlGenericErrorContext,
2541 "Relax-NG types library '%s' already registered\n",
2542 namespace);
2543 return(-1);
2544 }
2545 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2546 if (lib == NULL) {
2547 xmlGenericError(xmlGenericErrorContext,
2548 "Relax-NG types library '%s' malloc() failed\n",
2549 namespace);
2550 return (-1);
2551 }
2552 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2553 lib->namespace = xmlStrdup(namespace);
2554 lib->data = data;
2555 lib->have = have;
2556 lib->comp = comp;
2557 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002558 lib->facet = facet;
2559 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002560 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2561 if (ret < 0) {
2562 xmlGenericError(xmlGenericErrorContext,
2563 "Relax-NG types library failed to register '%s'\n",
2564 namespace);
2565 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2566 return(-1);
2567 }
2568 return(0);
2569}
2570
2571/**
2572 * xmlRelaxNGInitTypes:
2573 *
2574 * Initilize the default type libraries.
2575 *
2576 * Returns 0 in case of success and -1 in case of error.
2577 */
2578static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002579xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002580 if (xmlRelaxNGTypeInitialized != 0)
2581 return(0);
2582 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2583 if (xmlRelaxNGRegisteredTypes == NULL) {
2584 xmlGenericError(xmlGenericErrorContext,
2585 "Failed to allocate sh table for Relax-NG types\n");
2586 return(-1);
2587 }
2588 xmlRelaxNGRegisterTypeLibrary(
2589 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2590 NULL,
2591 xmlRelaxNGSchemaTypeHave,
2592 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002593 xmlRelaxNGSchemaTypeCompare,
2594 xmlRelaxNGSchemaFacetCheck,
Daniel Veillard80b19092003-03-28 13:29:53 +00002595 xmlRelaxNGSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002596 xmlRelaxNGRegisterTypeLibrary(
2597 xmlRelaxNGNs,
2598 NULL,
2599 xmlRelaxNGDefaultTypeHave,
2600 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002601 xmlRelaxNGDefaultTypeCompare,
2602 NULL,
2603 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002604 xmlRelaxNGTypeInitialized = 1;
2605 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002606}
2607
2608/**
2609 * xmlRelaxNGCleanupTypes:
2610 *
2611 * Cleanup the default Schemas type library associated to RelaxNG
2612 */
2613void
2614xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002615 if (xmlRelaxNGTypeInitialized == 0)
2616 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002617 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002618 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2619 xmlRelaxNGFreeTypeLibrary);
2620 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002621}
2622
2623/************************************************************************
2624 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002625 * Compiling element content into regexp *
2626 * *
2627 * Sometime the element content can be compiled into a pure regexp, *
2628 * This allows a faster execution and streamability at that level *
2629 * *
2630 ************************************************************************/
2631
2632/**
2633 * xmlRelaxNGIsCompileable:
2634 * @define: the definition to check
2635 *
2636 * Check if a definition is nullable.
2637 *
2638 * Returns 1 if yes, 0 if no and -1 in case of error
2639 */
2640static int
2641xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2642 if (def == NULL) {
2643 return(-1);
2644 }
2645 switch(def->type) {
2646 case XML_RELAXNG_REF:
2647 case XML_RELAXNG_EXTERNALREF:
2648 case XML_RELAXNG_PARENTREF:
2649 case XML_RELAXNG_NOOP:
2650 case XML_RELAXNG_START:
2651 return(xmlRelaxNGIsCompileable(def->content));
2652 case XML_RELAXNG_TEXT:
2653 case XML_RELAXNG_DATATYPE:
2654 case XML_RELAXNG_LIST:
2655 case XML_RELAXNG_PARAM:
2656 case XML_RELAXNG_VALUE:
2657
2658 case XML_RELAXNG_EMPTY:
2659 case XML_RELAXNG_ELEMENT:
2660 return(1);
2661 case XML_RELAXNG_OPTIONAL:
2662 case XML_RELAXNG_ZEROORMORE:
2663 case XML_RELAXNG_ONEORMORE:
2664 case XML_RELAXNG_CHOICE:
2665 case XML_RELAXNG_GROUP:
2666 case XML_RELAXNG_DEF: {
2667 xmlRelaxNGDefinePtr list;
2668 int ret;
2669
2670 list = def->content;
2671 while (list != NULL) {
2672 ret = xmlRelaxNGIsCompileable(list);
2673 if (ret != 1)
2674 return(ret);
2675 list = list->next;
2676 }
2677 return(1);
2678 }
2679 case XML_RELAXNG_EXCEPT:
2680 case XML_RELAXNG_ATTRIBUTE:
2681 case XML_RELAXNG_INTERLEAVE:
2682 return(0);
2683 case XML_RELAXNG_NOT_ALLOWED:
2684 return(-1);
2685 }
2686 return(-1);
2687}
2688
2689/************************************************************************
2690 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002691 * Parsing functions *
2692 * *
2693 ************************************************************************/
2694
2695static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2696 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2697static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2698 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2699static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002700 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002701static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2702 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002703static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2704 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002705static int xmlRelaxNGParseGrammarContent(
2706 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002707static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2708 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2709 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002710static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2711 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002712static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2713 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002714
2715
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002716#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002717
2718/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002719 * xmlRelaxNGIsNullable:
2720 * @define: the definition to verify
2721 *
2722 * Check if a definition is nullable.
2723 *
2724 * Returns 1 if yes, 0 if no and -1 in case of error
2725 */
2726static int
2727xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2728 int ret;
2729 if (define == NULL)
2730 return(-1);
2731
Daniel Veillarde063f482003-03-21 16:53:17 +00002732 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002733 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00002734 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002735 return(0);
2736 switch (define->type) {
2737 case XML_RELAXNG_EMPTY:
2738 case XML_RELAXNG_TEXT:
2739 ret = 1; break;
2740 case XML_RELAXNG_NOOP:
2741 case XML_RELAXNG_DEF:
2742 case XML_RELAXNG_REF:
2743 case XML_RELAXNG_EXTERNALREF:
2744 case XML_RELAXNG_PARENTREF:
2745 case XML_RELAXNG_ONEORMORE:
2746 ret = xmlRelaxNGIsNullable(define->content);
2747 break;
2748 case XML_RELAXNG_EXCEPT:
2749 case XML_RELAXNG_NOT_ALLOWED:
2750 case XML_RELAXNG_ELEMENT:
2751 case XML_RELAXNG_DATATYPE:
2752 case XML_RELAXNG_PARAM:
2753 case XML_RELAXNG_VALUE:
2754 case XML_RELAXNG_LIST:
2755 case XML_RELAXNG_ATTRIBUTE:
2756 ret = 0; break;
2757 case XML_RELAXNG_CHOICE: {
2758 xmlRelaxNGDefinePtr list = define->content;
2759
2760 while (list != NULL) {
2761 ret = xmlRelaxNGIsNullable(list);
2762 if (ret != 0)
2763 goto done;
2764 list = list->next;
2765 }
2766 ret = 0; break;
2767 }
2768 case XML_RELAXNG_START:
2769 case XML_RELAXNG_INTERLEAVE:
2770 case XML_RELAXNG_GROUP: {
2771 xmlRelaxNGDefinePtr list = define->content;
2772
2773 while (list != NULL) {
2774 ret = xmlRelaxNGIsNullable(list);
2775 if (ret != 1)
2776 goto done;
2777 list = list->next;
2778 }
2779 return(1);
2780 }
2781 default:
2782 return(-1);
2783 }
2784done:
2785 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00002786 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002787 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00002788 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002789 return(ret);
2790}
2791
2792/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002793 * xmlRelaxNGIsBlank:
2794 * @str: a string
2795 *
2796 * Check if a string is ignorable c.f. 4.2. Whitespace
2797 *
2798 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2799 */
2800static int
2801xmlRelaxNGIsBlank(xmlChar *str) {
2802 if (str == NULL)
2803 return(1);
2804 while (*str != 0) {
2805 if (!(IS_BLANK(*str))) return(0);
2806 str++;
2807 }
2808 return(1);
2809}
2810
Daniel Veillard6eadf632003-01-23 18:29:16 +00002811/**
2812 * xmlRelaxNGGetDataTypeLibrary:
2813 * @ctxt: a Relax-NG parser context
2814 * @node: the current data or value element
2815 *
2816 * Applies algorithm from 4.3. datatypeLibrary attribute
2817 *
2818 * Returns the datatypeLibary value or NULL if not found
2819 */
2820static xmlChar *
2821xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2822 xmlNodePtr node) {
2823 xmlChar *ret, *escape;
2824
Daniel Veillard6eadf632003-01-23 18:29:16 +00002825 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2826 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2827 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002828 if (ret[0] == 0) {
2829 xmlFree(ret);
2830 return(NULL);
2831 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002832 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002833 if (escape == NULL) {
2834 return(ret);
2835 }
2836 xmlFree(ret);
2837 return(escape);
2838 }
2839 }
2840 node = node->parent;
2841 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002842 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2843 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002844 if (ret[0] == 0) {
2845 xmlFree(ret);
2846 return(NULL);
2847 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002848 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2849 if (escape == NULL) {
2850 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002851 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002852 xmlFree(ret);
2853 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002854 }
2855 node = node->parent;
2856 }
2857 return(NULL);
2858}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002859
2860/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002861 * xmlRelaxNGParseValue:
2862 * @ctxt: a Relax-NG parser context
2863 * @node: the data node.
2864 *
2865 * parse the content of a RelaxNG value node.
2866 *
2867 * Returns the definition pointer or NULL in case of error
2868 */
2869static xmlRelaxNGDefinePtr
2870xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2871 xmlRelaxNGDefinePtr def = NULL;
2872 xmlRelaxNGTypeLibraryPtr lib;
2873 xmlChar *type;
2874 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002875 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00002876
Daniel Veillardfd573f12003-03-16 17:52:32 +00002877 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002878 if (def == NULL)
2879 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002880 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002881
2882 type = xmlGetProp(node, BAD_CAST "type");
2883 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002884 xmlRelaxNGNormExtSpace(type);
2885 if (xmlValidateNCName(type, 0)) {
2886 if (ctxt->error != NULL)
2887 ctxt->error(ctxt->userData,
2888 "value type '%s' is not an NCName\n",
2889 type);
2890 ctxt->nbErrors++;
2891 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002892 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2893 if (library == NULL)
2894 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2895
2896 def->name = type;
2897 def->ns = library;
2898
2899 lib = (xmlRelaxNGTypeLibraryPtr)
2900 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2901 if (lib == NULL) {
2902 if (ctxt->error != NULL)
2903 ctxt->error(ctxt->userData,
2904 "Use of unregistered type library '%s'\n",
2905 library);
2906 ctxt->nbErrors++;
2907 def->data = NULL;
2908 } else {
2909 def->data = lib;
2910 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002911 if (ctxt->error != NULL)
2912 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002913 "Internal error with type library '%s': no 'have'\n",
2914 library);
2915 ctxt->nbErrors++;
2916 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002917 success = lib->have(lib->data, def->name);
2918 if (success != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002919 if (ctxt->error != NULL)
2920 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002921 "Error type '%s' is not exported by type library '%s'\n",
2922 def->name, library);
2923 ctxt->nbErrors++;
2924 }
2925 }
2926 }
2927 }
2928 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002929 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002930 } else if (((node->children->type != XML_TEXT_NODE) &&
2931 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002932 (node->children->next != NULL)) {
2933 if (ctxt->error != NULL)
2934 ctxt->error(ctxt->userData,
2935 "Expecting a single text value for <value>content\n");
2936 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002937 } else if (def != NULL) {
Daniel Veillardedc91922003-01-26 00:52:04 +00002938 def->value = xmlNodeGetContent(node);
2939 if (def->value == NULL) {
2940 if (ctxt->error != NULL)
2941 ctxt->error(ctxt->userData,
2942 "Element <value> has no content\n");
2943 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002944 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
2945 void *val = NULL;
2946
2947 success = lib->check(lib->data, def->name, def->value, &val, node);
2948 if (success != 1) {
2949 if (ctxt->error != NULL)
2950 ctxt->error(ctxt->userData,
2951 "Value '%s' is not acceptable for type '%s'\n",
2952 def->value, def->name);
2953 ctxt->nbErrors++;
2954 } else {
2955 if (val != NULL)
2956 def->attrs = val;
2957 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002958 }
2959 }
2960 /* TODO check ahead of time that the value is okay per the type */
2961 return(def);
2962}
2963
2964/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002965 * xmlRelaxNGParseData:
2966 * @ctxt: a Relax-NG parser context
2967 * @node: the data node.
2968 *
2969 * parse the content of a RelaxNG data node.
2970 *
2971 * Returns the definition pointer or NULL in case of error
2972 */
2973static xmlRelaxNGDefinePtr
2974xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00002975 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00002976 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002977 xmlRelaxNGTypeLibraryPtr lib;
2978 xmlChar *type;
2979 xmlChar *library;
2980 xmlNodePtr content;
2981 int tmp;
2982
2983 type = xmlGetProp(node, BAD_CAST "type");
2984 if (type == NULL) {
2985 if (ctxt->error != NULL)
2986 ctxt->error(ctxt->userData,
2987 "data has no type\n");
2988 ctxt->nbErrors++;
2989 return(NULL);
2990 }
Daniel Veillardd2298792003-02-14 16:54:11 +00002991 xmlRelaxNGNormExtSpace(type);
2992 if (xmlValidateNCName(type, 0)) {
2993 if (ctxt->error != NULL)
2994 ctxt->error(ctxt->userData,
2995 "data type '%s' is not an NCName\n",
2996 type);
2997 ctxt->nbErrors++;
2998 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002999 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3000 if (library == NULL)
3001 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3002
Daniel Veillardfd573f12003-03-16 17:52:32 +00003003 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003004 if (def == NULL) {
3005 xmlFree(type);
3006 return(NULL);
3007 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003008 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003009 def->name = type;
3010 def->ns = library;
3011
3012 lib = (xmlRelaxNGTypeLibraryPtr)
3013 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3014 if (lib == NULL) {
3015 if (ctxt->error != NULL)
3016 ctxt->error(ctxt->userData,
3017 "Use of unregistered type library '%s'\n",
3018 library);
3019 ctxt->nbErrors++;
3020 def->data = NULL;
3021 } else {
3022 def->data = lib;
3023 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003024 if (ctxt->error != NULL)
3025 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003026 "Internal error with type library '%s': no 'have'\n",
3027 library);
3028 ctxt->nbErrors++;
3029 } else {
3030 tmp = lib->have(lib->data, def->name);
3031 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003032 if (ctxt->error != NULL)
3033 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003034 "Error type '%s' is not exported by type library '%s'\n",
3035 def->name, library);
3036 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003037 } else if ((xmlStrEqual(library, BAD_CAST
3038 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3039 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3040 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3041 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003042 }
3043 }
3044 }
3045 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003046
3047 /*
3048 * Handle optional params
3049 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003050 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003051 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3052 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003053 if (xmlStrEqual(library,
3054 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3055 if (ctxt->error != NULL)
3056 ctxt->error(ctxt->userData,
3057 "Type library '%s' does not allow type parameters\n",
3058 library);
3059 ctxt->nbErrors++;
3060 content = content->next;
3061 while ((content != NULL) &&
3062 (xmlStrEqual(content->name, BAD_CAST "param")))
3063 content = content->next;
3064 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003065 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003066 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003067 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003068 param->name = xmlGetProp(content, BAD_CAST "name");
3069 if (param->name == NULL) {
3070 if (ctxt->error != NULL)
3071 ctxt->error(ctxt->userData,
3072 "param has no name\n");
3073 ctxt->nbErrors++;
3074 }
3075 param->value = xmlNodeGetContent(content);
3076 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003077 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003078 } else {
3079 lastparam->next = param;
3080 lastparam = param;
3081 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003082 if (lib != NULL) {
3083 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003084 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003085 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003086 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003087 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003088 /*
3089 * Handle optional except
3090 */
3091 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3092 xmlNodePtr child;
3093 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3094
Daniel Veillardfd573f12003-03-16 17:52:32 +00003095 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003096 if (except == NULL) {
3097 return(def);
3098 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003099 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003100 child = content->children;
3101 if (last == NULL) {
3102 def->content = except;
3103 } else {
3104 last->next = except;
3105 }
3106 if (child == NULL) {
3107 if (ctxt->error != NULL)
3108 ctxt->error(ctxt->userData,
3109 "except has no content\n");
3110 ctxt->nbErrors++;
3111 }
3112 while (child != NULL) {
3113 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3114 if (tmp2 != NULL) {
3115 if (last2 == NULL) {
3116 except->content = last2 = tmp2;
3117 } else {
3118 last2->next = tmp2;
3119 last2 = tmp2;
3120 }
3121 }
3122 child = child->next;
3123 }
3124 content = content->next;
3125 }
3126 /*
3127 * Check there is no unhandled data
3128 */
3129 if (content != NULL) {
3130 if (ctxt->error != NULL)
3131 ctxt->error(ctxt->userData,
3132 "Element data has unexpected content %s\n", content->name);
3133 ctxt->nbErrors++;
3134 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003135
3136 return(def);
3137}
3138
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003139static const xmlChar *invalidName = BAD_CAST "\1";
3140
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003141/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003142 * xmlRelaxNGCompareNameClasses:
3143 * @defs1: the first element/attribute defs
3144 * @defs2: the second element/attribute defs
3145 * @name: the restriction on the name
3146 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003147 *
3148 * Compare the 2 lists of element definitions. The comparison is
3149 * that if both lists do not accept the same QNames, it returns 1
3150 * If the 2 lists can accept the same QName the comparison returns 0
3151 *
3152 * Returns 1 disttinct, 0 if equal
3153 */
3154static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003155xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3156 xmlRelaxNGDefinePtr def2) {
3157 int ret = 1;
3158 xmlNode node;
3159 xmlNs ns;
3160 xmlRelaxNGValidCtxt ctxt;
3161 ctxt.flags = FLAGS_IGNORABLE;
3162
Daniel Veillard42f12e92003-03-07 18:32:59 +00003163 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3164
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003165 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3166 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3167 if (def2->type == XML_RELAXNG_TEXT)
3168 return(1);
3169 if (def1->name != NULL) {
3170 node.name = def1->name;
3171 } else {
3172 node.name = invalidName;
3173 }
3174 node.ns = &ns;
3175 if (def1->ns != NULL) {
3176 if (def1->ns[0] == 0) {
3177 node.ns = NULL;
3178 } else {
3179 ns.href = def1->ns;
3180 }
3181 } else {
3182 ns.href = invalidName;
3183 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003184 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003185 if (def1->nameClass != NULL) {
3186 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3187 } else {
3188 ret = 0;
3189 }
3190 } else {
3191 ret = 1;
3192 }
3193 } else if (def1->type == XML_RELAXNG_TEXT) {
3194 if (def2->type == XML_RELAXNG_TEXT)
3195 return(0);
3196 return(1);
3197 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003198 TODO
3199 ret = 0;
3200 } else {
3201 TODO
3202 ret = 0;
3203 }
3204 if (ret == 0)
3205 return(ret);
3206 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3207 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3208 if (def2->name != NULL) {
3209 node.name = def2->name;
3210 } else {
3211 node.name = invalidName;
3212 }
3213 node.ns = &ns;
3214 if (def2->ns != NULL) {
3215 if (def2->ns[0] == 0) {
3216 node.ns = NULL;
3217 } else {
3218 ns.href = def2->ns;
3219 }
3220 } else {
3221 ns.href = invalidName;
3222 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003223 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003224 if (def2->nameClass != NULL) {
3225 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3226 } else {
3227 ret = 0;
3228 }
3229 } else {
3230 ret = 1;
3231 }
3232 } else {
3233 TODO
3234 ret = 0;
3235 }
3236
3237 return(ret);
3238}
3239
3240/**
3241 * xmlRelaxNGCompareElemDefLists:
3242 * @ctxt: a Relax-NG parser context
3243 * @defs1: the first list of element/attribute defs
3244 * @defs2: the second list of element/attribute defs
3245 *
3246 * Compare the 2 lists of element or attribute definitions. The comparison
3247 * is that if both lists do not accept the same QNames, it returns 1
3248 * If the 2 lists can accept the same QName the comparison returns 0
3249 *
3250 * Returns 1 disttinct, 0 if equal
3251 */
3252static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003253xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3254 xmlRelaxNGDefinePtr *def1,
3255 xmlRelaxNGDefinePtr *def2) {
3256 xmlRelaxNGDefinePtr *basedef2 = def2;
3257
Daniel Veillard154877e2003-01-30 12:17:05 +00003258 if ((def1 == NULL) || (def2 == NULL))
3259 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003260 if ((*def1 == NULL) || (*def2 == NULL))
3261 return(1);
3262 while (*def1 != NULL) {
3263 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003264 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3265 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003266 def2++;
3267 }
3268 def2 = basedef2;
3269 def1++;
3270 }
3271 return(1);
3272}
3273
3274/**
3275 * xmlRelaxNGGetElements:
3276 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003277 * @def: the definition definition
3278 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003279 *
3280 * Compute the list of top elements a definition can generate
3281 *
3282 * Returns a list of elements or NULL if none was found.
3283 */
3284static xmlRelaxNGDefinePtr *
3285xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003286 xmlRelaxNGDefinePtr def,
3287 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003288 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003289 int len = 0;
3290 int max = 0;
3291
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003292 /*
3293 * Don't run that check in case of error. Infinite recursion
3294 * becomes possible.
3295 */
3296 if (ctxt->nbErrors != 0)
3297 return(NULL);
3298
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003299 parent = NULL;
3300 cur = def;
3301 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003302 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3303 (cur->type == XML_RELAXNG_TEXT))) ||
3304 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003305 if (ret == NULL) {
3306 max = 10;
3307 ret = (xmlRelaxNGDefinePtr *)
3308 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3309 if (ret == NULL) {
3310 if (ctxt->error != NULL)
3311 ctxt->error(ctxt->userData,
3312 "Out of memory in element search\n");
3313 ctxt->nbErrors++;
3314 return(NULL);
3315 }
3316 } else if (max <= len) {
3317 max *= 2;
3318 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3319 if (ret == NULL) {
3320 if (ctxt->error != NULL)
3321 ctxt->error(ctxt->userData,
3322 "Out of memory in element search\n");
3323 ctxt->nbErrors++;
3324 return(NULL);
3325 }
3326 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003327 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003328 ret[len] = NULL;
3329 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3330 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3331 (cur->type == XML_RELAXNG_GROUP) ||
3332 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003333 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3334 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003335 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003336 (cur->type == XML_RELAXNG_REF) ||
3337 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003338 /*
3339 * Don't go within elements or attributes or string values.
3340 * Just gather the element top list
3341 */
3342 if (cur->content != NULL) {
3343 parent = cur;
3344 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003345 tmp = cur;
3346 while (tmp != NULL) {
3347 tmp->parent = parent;
3348 tmp = tmp->next;
3349 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003350 continue;
3351 }
3352 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003353 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003354 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003355 if (cur->next != NULL) {
3356 cur = cur->next;
3357 continue;
3358 }
3359 do {
3360 cur = cur->parent;
3361 if (cur == NULL) break;
3362 if (cur == def) return(ret);
3363 if (cur->next != NULL) {
3364 cur = cur->next;
3365 break;
3366 }
3367 } while (cur != NULL);
3368 }
3369 return(ret);
3370}
3371
3372/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003373 * xmlRelaxNGCheckChoiceDeterminism:
3374 * @ctxt: a Relax-NG parser context
3375 * @def: the choice definition
3376 *
3377 * Also used to find indeterministic pattern in choice
3378 */
3379static void
3380xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3381 xmlRelaxNGDefinePtr def) {
3382 xmlRelaxNGDefinePtr **list;
3383 xmlRelaxNGDefinePtr cur;
3384 int nbchild = 0, i, j, ret;
3385 int is_nullable = 0;
3386 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003387 xmlHashTablePtr triage = NULL;
3388 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003389
3390 if ((def == NULL) ||
3391 (def->type != XML_RELAXNG_CHOICE))
3392 return;
3393
Daniel Veillarde063f482003-03-21 16:53:17 +00003394 if (def->dflags & IS_PROCESSED)
3395 return;
3396
Daniel Veillardfd573f12003-03-16 17:52:32 +00003397 /*
3398 * Don't run that check in case of error. Infinite recursion
3399 * becomes possible.
3400 */
3401 if (ctxt->nbErrors != 0)
3402 return;
3403
3404 is_nullable = xmlRelaxNGIsNullable(def);
3405
3406 cur = def->content;
3407 while (cur != NULL) {
3408 nbchild++;
3409 cur = cur->next;
3410 }
3411
3412 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3413 sizeof(xmlRelaxNGDefinePtr *));
3414 if (list == NULL) {
3415 if (ctxt->error != NULL)
3416 ctxt->error(ctxt->userData,
3417 "Out of memory in choice computation\n");
3418 ctxt->nbErrors++;
3419 return;
3420 }
3421 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003422 /*
3423 * a bit strong but safe
3424 */
3425 if (is_nullable == 0) {
3426 triage = xmlHashCreate(10);
3427 } else {
3428 is_triable = 0;
3429 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003430 cur = def->content;
3431 while (cur != NULL) {
3432 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003433 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3434 is_triable = 0;
3435 } else if (is_triable == 1) {
3436 xmlRelaxNGDefinePtr *tmp;
3437 int res;
3438
3439 tmp = list[i];
3440 while ((*tmp != NULL) && (is_triable == 1)) {
3441 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3442 res = xmlHashAddEntry2(triage,
3443 BAD_CAST "#text", NULL,
3444 (void *)cur);
3445 if (res != 0)
3446 is_triable = -1;
3447 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3448 ((*tmp)->name != NULL)) {
3449 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3450 res = xmlHashAddEntry2(triage,
3451 (*tmp)->name, NULL,
3452 (void *)cur);
3453 else
3454 res = xmlHashAddEntry2(triage,
3455 (*tmp)->name, (*tmp)->ns,
3456 (void *)cur);
3457 if (res != 0)
3458 is_triable = -1;
3459 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3460 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3461 res = xmlHashAddEntry2(triage,
3462 BAD_CAST "#any", NULL,
3463 (void *)cur);
3464 else
3465 res = xmlHashAddEntry2(triage,
3466 BAD_CAST "#any", (*tmp)->ns,
3467 (void *)cur);
3468 if (res != 0)
3469 is_triable = -1;
3470 } else {
3471 is_triable = -1;
3472 }
3473 tmp++;
3474 }
3475 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003476 i++;
3477 cur = cur->next;
3478 }
3479
3480 for (i = 0;i < nbchild;i++) {
3481 if (list[i] == NULL)
3482 continue;
3483 for (j = 0;j < i;j++) {
3484 if (list[j] == NULL)
3485 continue;
3486 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3487 if (ret == 0) {
3488 is_indeterminist = 1;
3489 }
3490 }
3491 }
3492 for (i = 0;i < nbchild;i++) {
3493 if (list[i] != NULL)
3494 xmlFree(list[i]);
3495 }
3496
3497 xmlFree(list);
3498 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003499 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003500 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003501 if (is_triable == 1) {
3502 def->dflags |= IS_TRIABLE;
3503 def->data = triage;
3504 } else if (triage != NULL) {
3505 xmlHashFree(triage, NULL);
3506 }
3507 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003508}
3509
3510/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003511 * xmlRelaxNGCheckGroupAttrs:
3512 * @ctxt: a Relax-NG parser context
3513 * @def: the group definition
3514 *
3515 * Detects violations of rule 7.3
3516 */
3517static void
3518xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3519 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003520 xmlRelaxNGDefinePtr **list;
3521 xmlRelaxNGDefinePtr cur;
3522 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003523
3524 if ((def == NULL) ||
3525 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003526 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003527 return;
3528
Daniel Veillarde063f482003-03-21 16:53:17 +00003529 if (def->dflags & IS_PROCESSED)
3530 return;
3531
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003532 /*
3533 * Don't run that check in case of error. Infinite recursion
3534 * becomes possible.
3535 */
3536 if (ctxt->nbErrors != 0)
3537 return;
3538
Daniel Veillardfd573f12003-03-16 17:52:32 +00003539 cur = def->attrs;
3540 while (cur != NULL) {
3541 nbchild++;
3542 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003543 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003544 cur = def->content;
3545 while (cur != NULL) {
3546 nbchild++;
3547 cur = cur->next;
3548 }
3549
3550 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3551 sizeof(xmlRelaxNGDefinePtr *));
3552 if (list == NULL) {
3553 if (ctxt->error != NULL)
3554 ctxt->error(ctxt->userData,
3555 "Out of memory in group computation\n");
3556 ctxt->nbErrors++;
3557 return;
3558 }
3559 i = 0;
3560 cur = def->attrs;
3561 while (cur != NULL) {
3562 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3563 i++;
3564 cur = cur->next;
3565 }
3566 cur = def->content;
3567 while (cur != NULL) {
3568 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3569 i++;
3570 cur = cur->next;
3571 }
3572
3573 for (i = 0;i < nbchild;i++) {
3574 if (list[i] == NULL)
3575 continue;
3576 for (j = 0;j < i;j++) {
3577 if (list[j] == NULL)
3578 continue;
3579 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3580 if (ret == 0) {
3581 if (ctxt->error != NULL)
3582 ctxt->error(ctxt->userData,
3583 "Attributes conflicts in group\n");
3584 ctxt->nbErrors++;
3585 }
3586 }
3587 }
3588 for (i = 0;i < nbchild;i++) {
3589 if (list[i] != NULL)
3590 xmlFree(list[i]);
3591 }
3592
3593 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00003594 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003595}
3596
3597/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003598 * xmlRelaxNGComputeInterleaves:
3599 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003600 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003601 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003602 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003603 * A lot of work for preprocessing interleave definitions
3604 * is potentially needed to get a decent execution speed at runtime
3605 * - trying to get a total order on the element nodes generated
3606 * by the interleaves, order the list of interleave definitions
3607 * following that order.
3608 * - if <text/> is used to handle mixed content, it is better to
3609 * flag this in the define and simplify the runtime checking
3610 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003611 */
3612static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003613xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3614 xmlRelaxNGParserCtxtPtr ctxt,
3615 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003616 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003617
Daniel Veillardfd573f12003-03-16 17:52:32 +00003618 xmlRelaxNGPartitionPtr partitions = NULL;
3619 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3620 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003621 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003622 int nbgroups = 0;
3623 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003624 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003625 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003626
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003627 /*
3628 * Don't run that check in case of error. Infinite recursion
3629 * becomes possible.
3630 */
3631 if (ctxt->nbErrors != 0)
3632 return;
3633
Daniel Veillardfd573f12003-03-16 17:52:32 +00003634#ifdef DEBUG_INTERLEAVE
3635 xmlGenericError(xmlGenericErrorContext,
3636 "xmlRelaxNGComputeInterleaves(%s)\n",
3637 name);
3638#endif
3639 cur = def->content;
3640 while (cur != NULL) {
3641 nbchild++;
3642 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003643 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003644
3645#ifdef DEBUG_INTERLEAVE
3646 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3647#endif
3648 groups = (xmlRelaxNGInterleaveGroupPtr *)
3649 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3650 if (groups == NULL)
3651 goto error;
3652 cur = def->content;
3653 while (cur != NULL) {
3654 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3655 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3656 if (groups[nbgroups] == NULL)
3657 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003658 if (cur->type == XML_RELAXNG_TEXT)
3659 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003660 groups[nbgroups]->rule = cur;
3661 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3662 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3663 nbgroups++;
3664 cur = cur->next;
3665 }
3666#ifdef DEBUG_INTERLEAVE
3667 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3668#endif
3669
3670 /*
3671 * Let's check that all rules makes a partitions according to 7.4
3672 */
3673 partitions = (xmlRelaxNGPartitionPtr)
3674 xmlMalloc(sizeof(xmlRelaxNGPartition));
3675 if (partitions == NULL)
3676 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00003677 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00003678 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003679 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003680 for (i = 0;i < nbgroups;i++) {
3681 group = groups[i];
3682 for (j = i+1;j < nbgroups;j++) {
3683 if (groups[j] == NULL)
3684 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003685
Daniel Veillardfd573f12003-03-16 17:52:32 +00003686 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3687 groups[j]->defs);
3688 if (ret == 0) {
3689 if (ctxt->error != NULL)
3690 ctxt->error(ctxt->userData,
3691 "Element or text conflicts in interleave\n");
3692 ctxt->nbErrors++;
3693 }
3694 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3695 groups[j]->attrs);
3696 if (ret == 0) {
3697 if (ctxt->error != NULL)
3698 ctxt->error(ctxt->userData,
3699 "Attributes conflicts in interleave\n");
3700 ctxt->nbErrors++;
3701 }
3702 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003703 tmp = group->defs;
3704 if ((tmp != NULL) && (*tmp != NULL)) {
3705 while (*tmp != NULL) {
3706 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3707 res = xmlHashAddEntry2(partitions->triage,
3708 BAD_CAST "#text", NULL,
3709 (void *)(i + 1));
3710 if (res != 0)
3711 is_determinist = -1;
3712 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3713 ((*tmp)->name != NULL)) {
3714 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3715 res = xmlHashAddEntry2(partitions->triage,
3716 (*tmp)->name, NULL,
3717 (void *)(i + 1));
3718 else
3719 res = xmlHashAddEntry2(partitions->triage,
3720 (*tmp)->name, (*tmp)->ns,
3721 (void *)(i + 1));
3722 if (res != 0)
3723 is_determinist = -1;
3724 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3725 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3726 res = xmlHashAddEntry2(partitions->triage,
3727 BAD_CAST "#any", NULL,
3728 (void *)(i + 1));
3729 else
3730 res = xmlHashAddEntry2(partitions->triage,
3731 BAD_CAST "#any", (*tmp)->ns,
3732 (void *)(i + 1));
3733 if ((*tmp)->nameClass != NULL)
3734 is_determinist = 2;
3735 if (res != 0)
3736 is_determinist = -1;
3737 } else {
3738 is_determinist = -1;
3739 }
3740 tmp++;
3741 }
3742 } else {
3743 is_determinist = 0;
3744 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003745 }
3746 partitions->groups = groups;
3747
3748 /*
3749 * and save the partition list back in the def
3750 */
3751 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003752 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003753 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003754 if (is_determinist == 1)
3755 partitions->flags = IS_DETERMINIST;
3756 if (is_determinist == 2)
3757 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003758 return;
3759
3760error:
3761 if (ctxt->error != NULL)
3762 ctxt->error(ctxt->userData,
3763 "Out of memory in interleave computation\n");
3764 ctxt->nbErrors++;
3765 if (groups != NULL) {
3766 for (i = 0;i < nbgroups;i++)
3767 if (groups[i] != NULL) {
3768 if (groups[i]->defs != NULL)
3769 xmlFree(groups[i]->defs);
3770 xmlFree(groups[i]);
3771 }
3772 xmlFree(groups);
3773 }
3774 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003775}
3776
3777/**
3778 * xmlRelaxNGParseInterleave:
3779 * @ctxt: a Relax-NG parser context
3780 * @node: the data node.
3781 *
3782 * parse the content of a RelaxNG interleave node.
3783 *
3784 * Returns the definition pointer or NULL in case of error
3785 */
3786static xmlRelaxNGDefinePtr
3787xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3788 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003789 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003790 xmlNodePtr child;
3791
Daniel Veillardfd573f12003-03-16 17:52:32 +00003792 def = xmlRelaxNGNewDefine(ctxt, node);
3793 if (def == NULL) {
3794 return(NULL);
3795 }
3796 def->type = XML_RELAXNG_INTERLEAVE;
3797
3798 if (ctxt->interleaves == NULL)
3799 ctxt->interleaves = xmlHashCreate(10);
3800 if (ctxt->interleaves == NULL) {
3801 if (ctxt->error != NULL)
3802 ctxt->error(ctxt->userData,
3803 "Failed to create interleaves hash table\n");
3804 ctxt->nbErrors++;
3805 } else {
3806 char name[32];
3807
3808 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3809 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3810 if (ctxt->error != NULL)
3811 ctxt->error(ctxt->userData,
3812 "Failed to add %s to hash table\n", name);
3813 ctxt->nbErrors++;
3814 }
3815 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003816 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003817 if (child == NULL) {
3818 if (ctxt->error != NULL)
3819 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3820 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003821 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003822 while (child != NULL) {
3823 if (IS_RELAXNG(child, "element")) {
3824 cur = xmlRelaxNGParseElement(ctxt, child);
3825 } else {
3826 cur = xmlRelaxNGParsePattern(ctxt, child);
3827 }
3828 if (cur != NULL) {
3829 cur->parent = def;
3830 if (last == NULL) {
3831 def->content = last = cur;
3832 } else {
3833 last->next = cur;
3834 last = cur;
3835 }
3836 }
3837 child = child->next;
3838 }
3839
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003840 return(def);
3841}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003842
3843/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003844 * xmlRelaxNGParseInclude:
3845 * @ctxt: a Relax-NG parser context
3846 * @node: the include node
3847 *
3848 * Integrate the content of an include node in the current grammar
3849 *
3850 * Returns 0 in case of success or -1 in case of error
3851 */
3852static int
3853xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3854 xmlRelaxNGIncludePtr incl;
3855 xmlNodePtr root;
3856 int ret = 0, tmp;
3857
3858 incl = node->_private;
3859 if (incl == NULL) {
3860 if (ctxt->error != NULL)
3861 ctxt->error(ctxt->userData,
3862 "Include node has no data\n");
3863 ctxt->nbErrors++;
3864 return(-1);
3865 }
3866 root = xmlDocGetRootElement(incl->doc);
3867 if (root == NULL) {
3868 if (ctxt->error != NULL)
3869 ctxt->error(ctxt->userData,
3870 "Include document is empty\n");
3871 ctxt->nbErrors++;
3872 return(-1);
3873 }
3874 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3875 if (ctxt->error != NULL)
3876 ctxt->error(ctxt->userData,
3877 "Include document root is not a grammar\n");
3878 ctxt->nbErrors++;
3879 return(-1);
3880 }
3881
3882 /*
3883 * Merge the definition from both the include and the internal list
3884 */
3885 if (root->children != NULL) {
3886 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3887 if (tmp != 0)
3888 ret = -1;
3889 }
3890 if (node->children != NULL) {
3891 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3892 if (tmp != 0)
3893 ret = -1;
3894 }
3895 return(ret);
3896}
3897
3898/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003899 * xmlRelaxNGParseDefine:
3900 * @ctxt: a Relax-NG parser context
3901 * @node: the define node
3902 *
3903 * parse the content of a RelaxNG define element node.
3904 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003905 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003906 */
3907static int
3908xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3909 xmlChar *name;
3910 int ret = 0, tmp;
3911 xmlRelaxNGDefinePtr def;
3912 const xmlChar *olddefine;
3913
3914 name = xmlGetProp(node, BAD_CAST "name");
3915 if (name == NULL) {
3916 if (ctxt->error != NULL)
3917 ctxt->error(ctxt->userData,
3918 "define has no name\n");
3919 ctxt->nbErrors++;
3920 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003921 xmlRelaxNGNormExtSpace(name);
3922 if (xmlValidateNCName(name, 0)) {
3923 if (ctxt->error != NULL)
3924 ctxt->error(ctxt->userData,
3925 "define name '%s' is not an NCName\n",
3926 name);
3927 ctxt->nbErrors++;
3928 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003929 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003930 if (def == NULL) {
3931 xmlFree(name);
3932 return(-1);
3933 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003934 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003935 def->name = name;
3936 if (node->children == NULL) {
3937 if (ctxt->error != NULL)
3938 ctxt->error(ctxt->userData,
3939 "define has no children\n");
3940 ctxt->nbErrors++;
3941 } else {
3942 olddefine = ctxt->define;
3943 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003944 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003945 ctxt->define = olddefine;
3946 }
3947 if (ctxt->grammar->defs == NULL)
3948 ctxt->grammar->defs = xmlHashCreate(10);
3949 if (ctxt->grammar->defs == NULL) {
3950 if (ctxt->error != NULL)
3951 ctxt->error(ctxt->userData,
3952 "Could not create definition hash\n");
3953 ctxt->nbErrors++;
3954 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003955 } else {
3956 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3957 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003958 xmlRelaxNGDefinePtr prev;
3959
3960 prev = xmlHashLookup(ctxt->grammar->defs, name);
3961 if (prev == NULL) {
3962 if (ctxt->error != NULL)
3963 ctxt->error(ctxt->userData,
3964 "Internal error on define aggregation of %s\n",
3965 name);
3966 ctxt->nbErrors++;
3967 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003968 } else {
3969 while (prev->nextHash != NULL)
3970 prev = prev->nextHash;
3971 prev->nextHash = def;
3972 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00003973 }
3974 }
3975 }
3976 return(ret);
3977}
3978
3979/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00003980 * xmlRelaxNGProcessExternalRef:
3981 * @ctxt: the parser context
3982 * @node: the externlRef node
3983 *
3984 * Process and compile an externlRef node
3985 *
3986 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
3987 */
3988static xmlRelaxNGDefinePtr
3989xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3990 xmlRelaxNGDocumentPtr docu;
3991 xmlNodePtr root, tmp;
3992 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00003993 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00003994 xmlRelaxNGDefinePtr def;
3995
3996 docu = node->_private;
3997 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003998 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00003999 if (def == NULL)
4000 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004001 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004002
4003 if (docu->content == NULL) {
4004 /*
4005 * Then do the parsing for good
4006 */
4007 root = xmlDocGetRootElement(docu->doc);
4008 if (root == NULL) {
4009 if (ctxt->error != NULL)
4010 ctxt->error(ctxt->userData,
4011 "xmlRelaxNGParse: %s is empty\n",
4012 ctxt->URL);
4013 ctxt->nbErrors++;
4014 return (NULL);
4015 }
4016 /*
4017 * ns transmission rules
4018 */
4019 ns = xmlGetProp(root, BAD_CAST "ns");
4020 if (ns == NULL) {
4021 tmp = node;
4022 while ((tmp != NULL) &&
4023 (tmp->type == XML_ELEMENT_NODE)) {
4024 ns = xmlGetProp(tmp, BAD_CAST "ns");
4025 if (ns != NULL) {
4026 break;
4027 }
4028 tmp = tmp->parent;
4029 }
4030 if (ns != NULL) {
4031 xmlSetProp(root, BAD_CAST "ns", ns);
4032 newNs = 1;
4033 xmlFree(ns);
4034 }
4035 } else {
4036 xmlFree(ns);
4037 }
4038
4039 /*
4040 * Parsing to get a precompiled schemas.
4041 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004042 oldflags = ctxt->flags;
4043 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004044 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004045 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004046 if ((docu->schema != NULL) &&
4047 (docu->schema->topgrammar != NULL)) {
4048 docu->content = docu->schema->topgrammar->start;
4049 }
4050
4051 /*
4052 * the externalRef may be reused in a different ns context
4053 */
4054 if (newNs == 1) {
4055 xmlUnsetProp(root, BAD_CAST "ns");
4056 }
4057 }
4058 def->content = docu->content;
4059 } else {
4060 def = NULL;
4061 }
4062 return(def);
4063}
4064
4065/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004066 * xmlRelaxNGParsePattern:
4067 * @ctxt: a Relax-NG parser context
4068 * @node: the pattern node.
4069 *
4070 * parse the content of a RelaxNG pattern node.
4071 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004072 * Returns the definition pointer or NULL in case of error or if no
4073 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004074 */
4075static xmlRelaxNGDefinePtr
4076xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4077 xmlRelaxNGDefinePtr def = NULL;
4078
Daniel Veillardd2298792003-02-14 16:54:11 +00004079 if (node == NULL) {
4080 return(NULL);
4081 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004082 if (IS_RELAXNG(node, "element")) {
4083 def = xmlRelaxNGParseElement(ctxt, node);
4084 } else if (IS_RELAXNG(node, "attribute")) {
4085 def = xmlRelaxNGParseAttribute(ctxt, node);
4086 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004087 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004088 if (def == NULL)
4089 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004090 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004091 if (node->children != NULL) {
4092 if (ctxt->error != NULL)
4093 ctxt->error(ctxt->userData, "empty: had a child node\n");
4094 ctxt->nbErrors++;
4095 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004096 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004097 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004098 if (def == NULL)
4099 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004100 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004101 if (node->children != NULL) {
4102 if (ctxt->error != NULL)
4103 ctxt->error(ctxt->userData, "text: had a child node\n");
4104 ctxt->nbErrors++;
4105 }
4106 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004107 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004108 if (def == NULL)
4109 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004110 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004111 if (node->children == NULL) {
4112 if (ctxt->error != NULL)
4113 ctxt->error(ctxt->userData,
4114 "Element %s is empty\n", node->name);
4115 ctxt->nbErrors++;
4116 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004117 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004118 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004119 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004120 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004121 if (def == NULL)
4122 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004123 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004124 if (node->children == NULL) {
4125 if (ctxt->error != NULL)
4126 ctxt->error(ctxt->userData,
4127 "Element %s is empty\n", node->name);
4128 ctxt->nbErrors++;
4129 } else {
4130 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4131 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004132 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004133 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004134 if (def == NULL)
4135 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004136 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004137 if (node->children == NULL) {
4138 if (ctxt->error != NULL)
4139 ctxt->error(ctxt->userData,
4140 "Element %s is empty\n", node->name);
4141 ctxt->nbErrors++;
4142 } else {
4143 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4144 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004145 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004146 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004147 if (def == NULL)
4148 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004149 def->type = XML_RELAXNG_CHOICE;
4150 if (node->children == NULL) {
4151 if (ctxt->error != NULL)
4152 ctxt->error(ctxt->userData,
4153 "Element %s is empty\n", node->name);
4154 ctxt->nbErrors++;
4155 } else {
4156 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4157 }
4158 } else if (IS_RELAXNG(node, "group")) {
4159 def = xmlRelaxNGNewDefine(ctxt, node);
4160 if (def == NULL)
4161 return(NULL);
4162 def->type = XML_RELAXNG_GROUP;
4163 if (node->children == NULL) {
4164 if (ctxt->error != NULL)
4165 ctxt->error(ctxt->userData,
4166 "Element %s is empty\n", node->name);
4167 ctxt->nbErrors++;
4168 } else {
4169 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4170 }
4171 } else if (IS_RELAXNG(node, "ref")) {
4172 def = xmlRelaxNGNewDefine(ctxt, node);
4173 if (def == NULL)
4174 return(NULL);
4175 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004176 def->name = xmlGetProp(node, BAD_CAST "name");
4177 if (def->name == NULL) {
4178 if (ctxt->error != NULL)
4179 ctxt->error(ctxt->userData,
4180 "ref has no name\n");
4181 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004182 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004183 xmlRelaxNGNormExtSpace(def->name);
4184 if (xmlValidateNCName(def->name, 0)) {
4185 if (ctxt->error != NULL)
4186 ctxt->error(ctxt->userData,
4187 "ref name '%s' is not an NCName\n",
4188 def->name);
4189 ctxt->nbErrors++;
4190 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004191 }
4192 if (node->children != NULL) {
4193 if (ctxt->error != NULL)
4194 ctxt->error(ctxt->userData,
4195 "ref is not empty\n");
4196 ctxt->nbErrors++;
4197 }
4198 if (ctxt->grammar->refs == NULL)
4199 ctxt->grammar->refs = xmlHashCreate(10);
4200 if (ctxt->grammar->refs == NULL) {
4201 if (ctxt->error != NULL)
4202 ctxt->error(ctxt->userData,
4203 "Could not create references hash\n");
4204 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004205 def = NULL;
4206 } else {
4207 int tmp;
4208
4209 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4210 if (tmp < 0) {
4211 xmlRelaxNGDefinePtr prev;
4212
4213 prev = (xmlRelaxNGDefinePtr)
4214 xmlHashLookup(ctxt->grammar->refs, def->name);
4215 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004216 if (def->name != NULL) {
4217 if (ctxt->error != NULL)
4218 ctxt->error(ctxt->userData,
4219 "Error refs definitions '%s'\n",
4220 def->name);
4221 } else {
4222 if (ctxt->error != NULL)
4223 ctxt->error(ctxt->userData,
4224 "Error refs definitions\n");
4225 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004226 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004227 def = NULL;
4228 } else {
4229 def->nextHash = prev->nextHash;
4230 prev->nextHash = def;
4231 }
4232 }
4233 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004234 } else if (IS_RELAXNG(node, "data")) {
4235 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004236 } else if (IS_RELAXNG(node, "value")) {
4237 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004238 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004239 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004240 if (def == NULL)
4241 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004242 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004243 if (node->children == NULL) {
4244 if (ctxt->error != NULL)
4245 ctxt->error(ctxt->userData,
4246 "Element %s is empty\n", node->name);
4247 ctxt->nbErrors++;
4248 } else {
4249 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4250 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004251 } else if (IS_RELAXNG(node, "interleave")) {
4252 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004253 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004254 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004255 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004256 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004257 if (def == NULL)
4258 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004259 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004260 if (node->children != NULL) {
4261 if (ctxt->error != NULL)
4262 ctxt->error(ctxt->userData,
4263 "xmlRelaxNGParse: notAllowed element is not empty\n");
4264 ctxt->nbErrors++;
4265 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004266 } else if (IS_RELAXNG(node, "grammar")) {
4267 xmlRelaxNGGrammarPtr grammar, old;
4268 xmlRelaxNGGrammarPtr oldparent;
4269
Daniel Veillardc482e262003-02-26 14:48:48 +00004270#ifdef DEBUG_GRAMMAR
4271 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4272#endif
4273
Daniel Veillard419a7682003-02-03 23:22:49 +00004274 oldparent = ctxt->parentgrammar;
4275 old = ctxt->grammar;
4276 ctxt->parentgrammar = old;
4277 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4278 if (old != NULL) {
4279 ctxt->grammar = old;
4280 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004281#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004282 if (grammar != NULL) {
4283 grammar->next = old->next;
4284 old->next = grammar;
4285 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004286#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004287 }
4288 if (grammar != NULL)
4289 def = grammar->start;
4290 else
4291 def = NULL;
4292 } else if (IS_RELAXNG(node, "parentRef")) {
4293 if (ctxt->parentgrammar == NULL) {
4294 if (ctxt->error != NULL)
4295 ctxt->error(ctxt->userData,
4296 "Use of parentRef without a parent grammar\n");
4297 ctxt->nbErrors++;
4298 return(NULL);
4299 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004300 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004301 if (def == NULL)
4302 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004303 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004304 def->name = xmlGetProp(node, BAD_CAST "name");
4305 if (def->name == NULL) {
4306 if (ctxt->error != NULL)
4307 ctxt->error(ctxt->userData,
4308 "parentRef has no name\n");
4309 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004310 } else {
4311 xmlRelaxNGNormExtSpace(def->name);
4312 if (xmlValidateNCName(def->name, 0)) {
4313 if (ctxt->error != NULL)
4314 ctxt->error(ctxt->userData,
4315 "parentRef name '%s' is not an NCName\n",
4316 def->name);
4317 ctxt->nbErrors++;
4318 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004319 }
4320 if (node->children != NULL) {
4321 if (ctxt->error != NULL)
4322 ctxt->error(ctxt->userData,
4323 "parentRef is not empty\n");
4324 ctxt->nbErrors++;
4325 }
4326 if (ctxt->parentgrammar->refs == NULL)
4327 ctxt->parentgrammar->refs = xmlHashCreate(10);
4328 if (ctxt->parentgrammar->refs == NULL) {
4329 if (ctxt->error != NULL)
4330 ctxt->error(ctxt->userData,
4331 "Could not create references hash\n");
4332 ctxt->nbErrors++;
4333 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004334 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004335 int tmp;
4336
4337 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4338 if (tmp < 0) {
4339 xmlRelaxNGDefinePtr prev;
4340
4341 prev = (xmlRelaxNGDefinePtr)
4342 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4343 if (prev == NULL) {
4344 if (ctxt->error != NULL)
4345 ctxt->error(ctxt->userData,
4346 "Internal error parentRef definitions '%s'\n",
4347 def->name);
4348 ctxt->nbErrors++;
4349 def = NULL;
4350 } else {
4351 def->nextHash = prev->nextHash;
4352 prev->nextHash = def;
4353 }
4354 }
4355 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004356 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004357 if (node->children == NULL) {
4358 if (ctxt->error != NULL)
4359 ctxt->error(ctxt->userData,
4360 "Mixed is empty\n");
4361 ctxt->nbErrors++;
4362 def = NULL;
4363 } else {
4364 def = xmlRelaxNGParseInterleave(ctxt, node);
4365 if (def != NULL) {
4366 xmlRelaxNGDefinePtr tmp;
4367
4368 if ((def->content != NULL) && (def->content->next != NULL)) {
4369 tmp = xmlRelaxNGNewDefine(ctxt, node);
4370 if (tmp != NULL) {
4371 tmp->type = XML_RELAXNG_GROUP;
4372 tmp->content = def->content;
4373 def->content = tmp;
4374 }
4375 }
4376
4377 tmp = xmlRelaxNGNewDefine(ctxt, node);
4378 if (tmp == NULL)
4379 return(def);
4380 tmp->type = XML_RELAXNG_TEXT;
4381 tmp->next = def->content;
4382 def->content = tmp;
4383 }
4384 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004385 } else {
4386 if (ctxt->error != NULL)
4387 ctxt->error(ctxt->userData,
4388 "Unexpected node %s is not a pattern\n",
4389 node->name);
4390 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004391 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004392 }
4393 return(def);
4394}
4395
4396/**
4397 * xmlRelaxNGParseAttribute:
4398 * @ctxt: a Relax-NG parser context
4399 * @node: the element node
4400 *
4401 * parse the content of a RelaxNG attribute node.
4402 *
4403 * Returns the definition pointer or NULL in case of error.
4404 */
4405static xmlRelaxNGDefinePtr
4406xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004407 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004408 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004409 int old_flags;
4410
Daniel Veillardfd573f12003-03-16 17:52:32 +00004411 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004412 if (ret == NULL)
4413 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004414 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004415 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004416 child = node->children;
4417 if (child == NULL) {
4418 if (ctxt->error != NULL)
4419 ctxt->error(ctxt->userData,
4420 "xmlRelaxNGParseattribute: attribute has no children\n");
4421 ctxt->nbErrors++;
4422 return(ret);
4423 }
4424 old_flags = ctxt->flags;
4425 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004426 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4427 if (cur != NULL)
4428 child = child->next;
4429
Daniel Veillardd2298792003-02-14 16:54:11 +00004430 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004431 cur = xmlRelaxNGParsePattern(ctxt, child);
4432 if (cur != NULL) {
4433 switch (cur->type) {
4434 case XML_RELAXNG_EMPTY:
4435 case XML_RELAXNG_NOT_ALLOWED:
4436 case XML_RELAXNG_TEXT:
4437 case XML_RELAXNG_ELEMENT:
4438 case XML_RELAXNG_DATATYPE:
4439 case XML_RELAXNG_VALUE:
4440 case XML_RELAXNG_LIST:
4441 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004442 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004443 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004444 case XML_RELAXNG_DEF:
4445 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004446 case XML_RELAXNG_ZEROORMORE:
4447 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004448 case XML_RELAXNG_CHOICE:
4449 case XML_RELAXNG_GROUP:
4450 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004451 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004452 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004453 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004454 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004455 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004456 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004457 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004458 if (ctxt->error != NULL)
4459 ctxt->error(ctxt->userData,
4460 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004461 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004462 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004463 case XML_RELAXNG_NOOP:
4464 TODO
4465 if (ctxt->error != NULL)
4466 ctxt->error(ctxt->userData,
4467 "Internal error, noop found\n");
4468 ctxt->nbErrors++;
4469 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004470 }
4471 }
4472 child = child->next;
4473 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004474 if (child != NULL) {
4475 if (ctxt->error != NULL)
4476 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4477 ctxt->nbErrors++;
4478 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004479 ctxt->flags = old_flags;
4480 return(ret);
4481}
4482
4483/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004484 * xmlRelaxNGParseExceptNameClass:
4485 * @ctxt: a Relax-NG parser context
4486 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004487 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004488 *
4489 * parse the content of a RelaxNG nameClass node.
4490 *
4491 * Returns the definition pointer or NULL in case of error.
4492 */
4493static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004494xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4495 xmlNodePtr node, int attr) {
4496 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4497 xmlNodePtr child;
4498
Daniel Veillardd2298792003-02-14 16:54:11 +00004499 if (!IS_RELAXNG(node, "except")) {
4500 if (ctxt->error != NULL)
4501 ctxt->error(ctxt->userData,
4502 "Expecting an except node\n");
4503 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004504 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004505 }
4506 if (node->next != NULL) {
4507 if (ctxt->error != NULL)
4508 ctxt->error(ctxt->userData,
4509 "exceptNameClass allows only a single except node\n");
4510 ctxt->nbErrors++;
4511 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004512 if (node->children == NULL) {
4513 if (ctxt->error != NULL)
4514 ctxt->error(ctxt->userData,
4515 "except has no content\n");
4516 ctxt->nbErrors++;
4517 return(NULL);
4518 }
4519
Daniel Veillardfd573f12003-03-16 17:52:32 +00004520 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004521 if (ret == NULL)
4522 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004523 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004524 child = node->children;
4525 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004526 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004527 if (cur == NULL)
4528 break;
4529 if (attr)
4530 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004531 else
4532 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004533
Daniel Veillard419a7682003-02-03 23:22:49 +00004534 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004535 if (last == NULL) {
4536 ret->content = cur;
4537 } else {
4538 last->next = cur;
4539 }
4540 last = cur;
4541 }
4542 child = child->next;
4543 }
4544
4545 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004546}
4547
4548/**
4549 * xmlRelaxNGParseNameClass:
4550 * @ctxt: a Relax-NG parser context
4551 * @node: the nameClass node
4552 * @def: the current definition
4553 *
4554 * parse the content of a RelaxNG nameClass node.
4555 *
4556 * Returns the definition pointer or NULL in case of error.
4557 */
4558static xmlRelaxNGDefinePtr
4559xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4560 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004561 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004562 xmlChar *val;
4563
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004564 ret = def;
4565 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4566 (IS_RELAXNG(node, "nsName"))) {
4567 if ((def->type != XML_RELAXNG_ELEMENT) &&
4568 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004569 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004570 if (ret == NULL)
4571 return(NULL);
4572 ret->parent = def;
4573 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4574 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004575 else
4576 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004577 }
4578 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004579 if (IS_RELAXNG(node, "name")) {
4580 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004581 xmlRelaxNGNormExtSpace(val);
4582 if (xmlValidateNCName(val, 0)) {
4583 if (ctxt->error != NULL) {
4584 if (node->parent != NULL)
4585 ctxt->error(ctxt->userData,
4586 "Element %s name '%s' is not an NCName\n",
4587 node->parent->name, val);
4588 else
4589 ctxt->error(ctxt->userData,
4590 "name '%s' is not an NCName\n",
4591 val);
4592 }
4593 ctxt->nbErrors++;
4594 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004595 ret->name = val;
4596 val = xmlGetProp(node, BAD_CAST "ns");
4597 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004598 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4599 (val != NULL) &&
4600 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4601 ctxt->error(ctxt->userData,
4602 "Attribute with namespace '%s' is not allowed\n",
4603 val);
4604 ctxt->nbErrors++;
4605 }
4606 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4607 (val != NULL) &&
4608 (val[0] == 0) &&
4609 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4610 ctxt->error(ctxt->userData,
4611 "Attribute with QName 'xmlns' is not allowed\n",
4612 val);
4613 ctxt->nbErrors++;
4614 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004615 } else if (IS_RELAXNG(node, "anyName")) {
4616 ret->name = NULL;
4617 ret->ns = NULL;
4618 if (node->children != NULL) {
4619 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004620 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4621 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004622 }
4623 } else if (IS_RELAXNG(node, "nsName")) {
4624 ret->name = NULL;
4625 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4626 if (ret->ns == NULL) {
4627 if (ctxt->error != NULL)
4628 ctxt->error(ctxt->userData,
4629 "nsName has no ns attribute\n");
4630 ctxt->nbErrors++;
4631 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004632 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4633 (ret->ns != NULL) &&
4634 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4635 ctxt->error(ctxt->userData,
4636 "Attribute with namespace '%s' is not allowed\n",
4637 ret->ns);
4638 ctxt->nbErrors++;
4639 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004640 if (node->children != NULL) {
4641 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004642 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4643 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004644 }
4645 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004646 xmlNodePtr child;
4647 xmlRelaxNGDefinePtr last = NULL;
4648
4649 ret = xmlRelaxNGNewDefine(ctxt, node);
4650 if (ret == NULL)
4651 return(NULL);
4652 ret->parent = def;
4653 ret->type = XML_RELAXNG_CHOICE;
4654
Daniel Veillardd2298792003-02-14 16:54:11 +00004655 if (node->children == NULL) {
4656 if (ctxt->error != NULL)
4657 ctxt->error(ctxt->userData,
4658 "Element choice is empty\n");
4659 ctxt->nbErrors++;
4660 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004661
4662 child = node->children;
4663 while (child != NULL) {
4664 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4665 if (tmp != NULL) {
4666 if (last == NULL) {
4667 last = ret->nameClass = tmp;
4668 } else {
4669 last->next = tmp;
4670 last = tmp;
4671 }
4672 }
4673 child = child->next;
4674 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004675 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004676 } else {
4677 if (ctxt->error != NULL)
4678 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004679 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004680 node->name);
4681 ctxt->nbErrors++;
4682 return(NULL);
4683 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004684 if (ret != def) {
4685 if (def->nameClass == NULL) {
4686 def->nameClass = ret;
4687 } else {
4688 tmp = def->nameClass;
4689 while (tmp->next != NULL) {
4690 tmp = tmp->next;
4691 }
4692 tmp->next = ret;
4693 }
4694 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004695 return(ret);
4696}
4697
4698/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004699 * xmlRelaxNGParseElement:
4700 * @ctxt: a Relax-NG parser context
4701 * @node: the element node
4702 *
4703 * parse the content of a RelaxNG element node.
4704 *
4705 * Returns the definition pointer or NULL in case of error.
4706 */
4707static xmlRelaxNGDefinePtr
4708xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4709 xmlRelaxNGDefinePtr ret, cur, last;
4710 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004711 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004712
Daniel Veillardfd573f12003-03-16 17:52:32 +00004713 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004714 if (ret == NULL)
4715 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004716 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004717 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004718 child = node->children;
4719 if (child == NULL) {
4720 if (ctxt->error != NULL)
4721 ctxt->error(ctxt->userData,
4722 "xmlRelaxNGParseElement: element has no children\n");
4723 ctxt->nbErrors++;
4724 return(ret);
4725 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004726 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4727 if (cur != NULL)
4728 child = child->next;
4729
Daniel Veillard6eadf632003-01-23 18:29:16 +00004730 if (child == NULL) {
4731 if (ctxt->error != NULL)
4732 ctxt->error(ctxt->userData,
4733 "xmlRelaxNGParseElement: element has no content\n");
4734 ctxt->nbErrors++;
4735 return(ret);
4736 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004737 olddefine = ctxt->define;
4738 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004739 last = NULL;
4740 while (child != NULL) {
4741 cur = xmlRelaxNGParsePattern(ctxt, child);
4742 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004743 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004744 switch (cur->type) {
4745 case XML_RELAXNG_EMPTY:
4746 case XML_RELAXNG_NOT_ALLOWED:
4747 case XML_RELAXNG_TEXT:
4748 case XML_RELAXNG_ELEMENT:
4749 case XML_RELAXNG_DATATYPE:
4750 case XML_RELAXNG_VALUE:
4751 case XML_RELAXNG_LIST:
4752 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004753 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004754 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004755 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004756 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004757 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004758 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004759 case XML_RELAXNG_CHOICE:
4760 case XML_RELAXNG_GROUP:
4761 case XML_RELAXNG_INTERLEAVE:
4762 if (last == NULL) {
4763 ret->content = last = cur;
4764 } else {
4765 if ((last->type == XML_RELAXNG_ELEMENT) &&
4766 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004767 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004768 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004769 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004770 ret->content->content = last;
4771 } else {
4772 ret->content = last;
4773 }
4774 }
4775 last->next = cur;
4776 last = cur;
4777 }
4778 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004779 case XML_RELAXNG_ATTRIBUTE:
4780 cur->next = ret->attrs;
4781 ret->attrs = cur;
4782 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004783 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004784 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004785 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004786 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004787 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004788 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004789 case XML_RELAXNG_NOOP:
4790 TODO
4791 if (ctxt->error != NULL)
4792 ctxt->error(ctxt->userData,
4793 "Internal error, noop found\n");
4794 ctxt->nbErrors++;
4795 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004796 }
4797 }
4798 child = child->next;
4799 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004800 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004801 return(ret);
4802}
4803
4804/**
4805 * xmlRelaxNGParsePatterns:
4806 * @ctxt: a Relax-NG parser context
4807 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004808 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004809 *
4810 * parse the content of a RelaxNG start node.
4811 *
4812 * Returns the definition pointer or NULL in case of error.
4813 */
4814static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004815xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4816 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004817 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004818
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004819 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004820 while (nodes != NULL) {
4821 if (IS_RELAXNG(nodes, "element")) {
4822 cur = xmlRelaxNGParseElement(ctxt, nodes);
4823 if (def == NULL) {
4824 def = last = cur;
4825 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004826 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4827 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004828 def = xmlRelaxNGNewDefine(ctxt, nodes);
4829 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004830 def->content = last;
4831 }
4832 last->next = cur;
4833 last = cur;
4834 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004835 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004836 } else {
4837 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004838 if (cur != NULL) {
4839 if (def == NULL) {
4840 def = last = cur;
4841 } else {
4842 last->next = cur;
4843 last = cur;
4844 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004845 }
4846 }
4847 nodes = nodes->next;
4848 }
4849 return(def);
4850}
4851
4852/**
4853 * xmlRelaxNGParseStart:
4854 * @ctxt: a Relax-NG parser context
4855 * @nodes: start children nodes
4856 *
4857 * parse the content of a RelaxNG start node.
4858 *
4859 * Returns 0 in case of success, -1 in case of error
4860 */
4861static int
4862xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4863 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004864 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004865
Daniel Veillardd2298792003-02-14 16:54:11 +00004866 if (nodes == NULL) {
4867 if (ctxt->error != NULL)
4868 ctxt->error(ctxt->userData,
4869 "start has no children\n");
4870 ctxt->nbErrors++;
4871 return(-1);
4872 }
4873 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004874 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004875 if (def == NULL)
4876 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004877 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004878 if (nodes->children != NULL) {
4879 if (ctxt->error != NULL)
4880 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004881 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004882 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004883 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004884 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004885 if (def == NULL)
4886 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004887 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004888 if (nodes->children != NULL) {
4889 if (ctxt->error != NULL)
4890 ctxt->error(ctxt->userData,
4891 "element notAllowed is not empty\n");
4892 ctxt->nbErrors++;
4893 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004894 } else {
4895 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004896 }
4897 if (ctxt->grammar->start != NULL) {
4898 last = ctxt->grammar->start;
4899 while (last->next != NULL)
4900 last = last->next;
4901 last->next = def;
4902 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004903 ctxt->grammar->start = def;
4904 }
4905 nodes = nodes->next;
4906 if (nodes != NULL) {
4907 if (ctxt->error != NULL)
4908 ctxt->error(ctxt->userData,
4909 "start more than one children\n");
4910 ctxt->nbErrors++;
4911 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004912 }
4913 return(ret);
4914}
4915
4916/**
4917 * xmlRelaxNGParseGrammarContent:
4918 * @ctxt: a Relax-NG parser context
4919 * @nodes: grammar children nodes
4920 *
4921 * parse the content of a RelaxNG grammar node.
4922 *
4923 * Returns 0 in case of success, -1 in case of error
4924 */
4925static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004926xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004927{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004928 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004929
4930 if (nodes == NULL) {
4931 if (ctxt->error != NULL)
4932 ctxt->error(ctxt->userData,
4933 "grammar has no children\n");
4934 ctxt->nbErrors++;
4935 return(-1);
4936 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004937 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004938 if (IS_RELAXNG(nodes, "start")) {
4939 if (nodes->children == NULL) {
4940 if (ctxt->error != NULL)
4941 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004942 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004943 ctxt->nbErrors++;
4944 } else {
4945 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4946 if (tmp != 0)
4947 ret = -1;
4948 }
4949 } else if (IS_RELAXNG(nodes, "define")) {
4950 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4951 if (tmp != 0)
4952 ret = -1;
4953 } else if (IS_RELAXNG(nodes, "include")) {
4954 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4955 if (tmp != 0)
4956 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004957 } else {
4958 if (ctxt->error != NULL)
4959 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004960 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004961 ctxt->nbErrors++;
4962 ret = -1;
4963 }
4964 nodes = nodes->next;
4965 }
4966 return (ret);
4967}
4968
4969/**
4970 * xmlRelaxNGCheckReference:
4971 * @ref: the ref
4972 * @ctxt: a Relax-NG parser context
4973 * @name: the name associated to the defines
4974 *
4975 * Applies the 4.17. combine attribute rule for all the define
4976 * element of a given grammar using the same name.
4977 */
4978static void
4979xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
4980 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
4981 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004982 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004983
4984 grammar = ctxt->grammar;
4985 if (grammar == NULL) {
4986 if (ctxt->error != NULL)
4987 ctxt->error(ctxt->userData,
4988 "Internal error: no grammar in CheckReference %s\n",
4989 name);
4990 ctxt->nbErrors++;
4991 return;
4992 }
4993 if (ref->content != NULL) {
4994 if (ctxt->error != NULL)
4995 ctxt->error(ctxt->userData,
4996 "Internal error: reference has content in CheckReference %s\n",
4997 name);
4998 ctxt->nbErrors++;
4999 return;
5000 }
5001 if (grammar->defs != NULL) {
5002 def = xmlHashLookup(grammar->defs, name);
5003 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00005004 cur = ref;
5005 while (cur != NULL) {
5006 cur->content = def;
5007 cur = cur->nextHash;
5008 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005009 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00005010 if (ctxt->error != NULL)
5011 ctxt->error(ctxt->userData,
5012 "Reference %s has no matching definition\n",
5013 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005014 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005015 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005016 } else {
5017 if (ctxt->error != NULL)
5018 ctxt->error(ctxt->userData,
5019 "Reference %s has no matching definition\n",
5020 name);
5021 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005022 }
5023 /*
5024 * TODO: make a closure and verify there is no loop !
5025 */
5026}
5027
5028/**
5029 * xmlRelaxNGCheckCombine:
5030 * @define: the define(s) list
5031 * @ctxt: a Relax-NG parser context
5032 * @name: the name associated to the defines
5033 *
5034 * Applies the 4.17. combine attribute rule for all the define
5035 * element of a given grammar using the same name.
5036 */
5037static void
5038xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5039 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5040 xmlChar *combine;
5041 int choiceOrInterleave = -1;
5042 int missing = 0;
5043 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5044
5045 if (define->nextHash == NULL)
5046 return;
5047 cur = define;
5048 while (cur != NULL) {
5049 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5050 if (combine != NULL) {
5051 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5052 if (choiceOrInterleave == -1)
5053 choiceOrInterleave = 1;
5054 else if (choiceOrInterleave == 0) {
5055 if (ctxt->error != NULL)
5056 ctxt->error(ctxt->userData,
5057 "Defines for %s use both 'choice' and 'interleave'\n",
5058 name);
5059 ctxt->nbErrors++;
5060 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005061 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005062 if (choiceOrInterleave == -1)
5063 choiceOrInterleave = 0;
5064 else if (choiceOrInterleave == 1) {
5065 if (ctxt->error != NULL)
5066 ctxt->error(ctxt->userData,
5067 "Defines for %s use both 'choice' and 'interleave'\n",
5068 name);
5069 ctxt->nbErrors++;
5070 }
5071 } else {
5072 if (ctxt->error != NULL)
5073 ctxt->error(ctxt->userData,
5074 "Defines for %s use unknown combine value '%s''\n",
5075 name, combine);
5076 ctxt->nbErrors++;
5077 }
5078 xmlFree(combine);
5079 } else {
5080 if (missing == 0)
5081 missing = 1;
5082 else {
5083 if (ctxt->error != NULL)
5084 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005085 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005086 name);
5087 ctxt->nbErrors++;
5088 }
5089 }
5090
5091 cur = cur->nextHash;
5092 }
5093#ifdef DEBUG
5094 xmlGenericError(xmlGenericErrorContext,
5095 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5096 name, choiceOrInterleave);
5097#endif
5098 if (choiceOrInterleave == -1)
5099 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005100 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005101 if (cur == NULL)
5102 return;
5103 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005104 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005105 else
5106 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005107 tmp = define;
5108 last = NULL;
5109 while (tmp != NULL) {
5110 if (tmp->content != NULL) {
5111 if (tmp->content->next != NULL) {
5112 /*
5113 * we need first to create a wrapper.
5114 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005115 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005116 if (tmp2 == NULL)
5117 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005118 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005119 tmp2->content = tmp->content;
5120 } else {
5121 tmp2 = tmp->content;
5122 }
5123 if (last == NULL) {
5124 cur->content = tmp2;
5125 } else {
5126 last->next = tmp2;
5127 }
5128 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005129 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005130 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005131 tmp = tmp->nextHash;
5132 }
5133 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005134 if (choiceOrInterleave == 0) {
5135 if (ctxt->interleaves == NULL)
5136 ctxt->interleaves = xmlHashCreate(10);
5137 if (ctxt->interleaves == NULL) {
5138 if (ctxt->error != NULL)
5139 ctxt->error(ctxt->userData,
5140 "Failed to create interleaves hash table\n");
5141 ctxt->nbErrors++;
5142 } else {
5143 char tmpname[32];
5144
5145 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5146 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5147 if (ctxt->error != NULL)
5148 ctxt->error(ctxt->userData,
5149 "Failed to add %s to hash table\n", tmpname);
5150 ctxt->nbErrors++;
5151 }
5152 }
5153 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005154}
5155
5156/**
5157 * xmlRelaxNGCombineStart:
5158 * @ctxt: a Relax-NG parser context
5159 * @grammar: the grammar
5160 *
5161 * Applies the 4.17. combine rule for all the start
5162 * element of a given grammar.
5163 */
5164static void
5165xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5166 xmlRelaxNGGrammarPtr grammar) {
5167 xmlRelaxNGDefinePtr starts;
5168 xmlChar *combine;
5169 int choiceOrInterleave = -1;
5170 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005171 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005172
Daniel Veillard2df2de22003-02-17 23:34:33 +00005173 starts = grammar->start;
5174 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005175 return;
5176 cur = starts;
5177 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005178 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5179 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5180 combine = NULL;
5181 if (ctxt->error != NULL)
5182 ctxt->error(ctxt->userData,
5183 "Internal error: start element not found\n");
5184 ctxt->nbErrors++;
5185 } else {
5186 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5187 }
5188
Daniel Veillard6eadf632003-01-23 18:29:16 +00005189 if (combine != NULL) {
5190 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5191 if (choiceOrInterleave == -1)
5192 choiceOrInterleave = 1;
5193 else if (choiceOrInterleave == 0) {
5194 if (ctxt->error != NULL)
5195 ctxt->error(ctxt->userData,
5196 "<start> use both 'choice' and 'interleave'\n");
5197 ctxt->nbErrors++;
5198 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005199 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005200 if (choiceOrInterleave == -1)
5201 choiceOrInterleave = 0;
5202 else if (choiceOrInterleave == 1) {
5203 if (ctxt->error != NULL)
5204 ctxt->error(ctxt->userData,
5205 "<start> use both 'choice' and 'interleave'\n");
5206 ctxt->nbErrors++;
5207 }
5208 } else {
5209 if (ctxt->error != NULL)
5210 ctxt->error(ctxt->userData,
5211 "<start> uses unknown combine value '%s''\n", combine);
5212 ctxt->nbErrors++;
5213 }
5214 xmlFree(combine);
5215 } else {
5216 if (missing == 0)
5217 missing = 1;
5218 else {
5219 if (ctxt->error != NULL)
5220 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005221 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005222 ctxt->nbErrors++;
5223 }
5224 }
5225
Daniel Veillard2df2de22003-02-17 23:34:33 +00005226 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005227 }
5228#ifdef DEBUG
5229 xmlGenericError(xmlGenericErrorContext,
5230 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5231 choiceOrInterleave);
5232#endif
5233 if (choiceOrInterleave == -1)
5234 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005235 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005236 if (cur == NULL)
5237 return;
5238 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005239 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005240 else
5241 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005242 cur->content = grammar->start;
5243 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005244 if (choiceOrInterleave == 0) {
5245 if (ctxt->interleaves == NULL)
5246 ctxt->interleaves = xmlHashCreate(10);
5247 if (ctxt->interleaves == NULL) {
5248 if (ctxt->error != NULL)
5249 ctxt->error(ctxt->userData,
5250 "Failed to create interleaves hash table\n");
5251 ctxt->nbErrors++;
5252 } else {
5253 char tmpname[32];
5254
5255 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5256 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5257 if (ctxt->error != NULL)
5258 ctxt->error(ctxt->userData,
5259 "Failed to add %s to hash table\n", tmpname);
5260 ctxt->nbErrors++;
5261 }
5262 }
5263 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005264}
5265
5266/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005267 * xmlRelaxNGCheckCycles:
5268 * @ctxt: a Relax-NG parser context
5269 * @nodes: grammar children nodes
5270 * @depth: the counter
5271 *
5272 * Check for cycles.
5273 *
5274 * Returns 0 if check passed, and -1 in case of error
5275 */
5276static int
5277xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5278 xmlRelaxNGDefinePtr cur, int depth) {
5279 int ret = 0;
5280
5281 while ((ret == 0) && (cur != NULL)) {
5282 if ((cur->type == XML_RELAXNG_REF) ||
5283 (cur->type == XML_RELAXNG_PARENTREF)) {
5284 if (cur->depth == -1) {
5285 cur->depth = depth;
5286 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5287 cur->depth = -2;
5288 } else if (depth == cur->depth) {
5289 if (ctxt->error != NULL)
5290 ctxt->error(ctxt->userData,
5291 "Detected a cycle in %s references\n", cur->name);
5292 ctxt->nbErrors++;
5293 return(-1);
5294 }
5295 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5296 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5297 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005298 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005299 }
5300 cur = cur->next;
5301 }
5302 return(ret);
5303}
5304
5305/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005306 * xmlRelaxNGTryUnlink:
5307 * @ctxt: a Relax-NG parser context
5308 * @cur: the definition to unlink
5309 * @parent: the parent definition
5310 * @prev: the previous sibling definition
5311 *
5312 * Try to unlink a definition. If not possble make it a NOOP
5313 *
5314 * Returns the new prev definition
5315 */
5316static xmlRelaxNGDefinePtr
5317xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5318 xmlRelaxNGDefinePtr cur,
5319 xmlRelaxNGDefinePtr parent,
5320 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005321 if (prev != NULL) {
5322 prev->next = cur->next;
5323 } else {
5324 if (parent != NULL) {
5325 if (parent->content == cur)
5326 parent->content = cur->next;
5327 else if (parent->attrs == cur)
5328 parent->attrs = cur->next;
5329 else if (parent->nameClass == cur)
5330 parent->nameClass = cur->next;
5331 } else {
5332 cur->type = XML_RELAXNG_NOOP;
5333 prev = cur;
5334 }
5335 }
5336 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005337}
5338
5339/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005340 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005341 * @ctxt: a Relax-NG parser context
5342 * @nodes: grammar children nodes
5343 *
5344 * Check for simplification of empty and notAllowed
5345 */
5346static void
5347xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5348 xmlRelaxNGDefinePtr cur,
5349 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005350 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005351
Daniel Veillardfd573f12003-03-16 17:52:32 +00005352 while (cur != NULL) {
5353 if ((cur->type == XML_RELAXNG_REF) ||
5354 (cur->type == XML_RELAXNG_PARENTREF)) {
5355 if (cur->depth != -3) {
5356 cur->depth = -3;
5357 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005358 }
5359 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005360 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005361 if ((parent != NULL) &&
5362 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5363 (parent->type == XML_RELAXNG_LIST) ||
5364 (parent->type == XML_RELAXNG_GROUP) ||
5365 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005366 (parent->type == XML_RELAXNG_ONEORMORE) ||
5367 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005368 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005369 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005370 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005371 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005372 (parent->type == XML_RELAXNG_CHOICE)) {
5373 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5374 } else
5375 prev = cur;
5376 } else if (cur->type == XML_RELAXNG_EMPTY){
5377 cur->parent = parent;
5378 if ((parent != NULL) &&
5379 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5380 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005381 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005382 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005383 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005384 if ((parent != NULL) &&
5385 ((parent->type == XML_RELAXNG_GROUP) ||
5386 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5387 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5388 } else
5389 prev = cur;
5390 } else {
5391 cur->parent = parent;
5392 if (cur->content != NULL)
5393 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005394 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
Daniel Veillardfd573f12003-03-16 17:52:32 +00005395 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5396 if (cur->nameClass != NULL)
5397 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5398 /*
5399 * This may result in a simplification
5400 */
5401 if ((cur->type == XML_RELAXNG_GROUP) ||
5402 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5403 if (cur->content == NULL)
5404 cur->type = XML_RELAXNG_EMPTY;
5405 else if (cur->content->next == NULL) {
5406 if ((parent == NULL) && (prev == NULL)) {
5407 cur->type = XML_RELAXNG_NOOP;
5408 } else if (prev == NULL) {
5409 parent->content = cur->content;
5410 cur->content->next = cur->next;
5411 cur = cur->content;
5412 } else {
5413 cur->content->next = cur->next;
5414 prev->next = cur->content;
5415 cur = cur->content;
5416 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005417 }
5418 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005419 /*
5420 * the current node may have been transformed back
5421 */
5422 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5423 (cur->content != NULL) &&
5424 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5425 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5426 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5427 if ((parent != NULL) &&
5428 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5429 (parent->type == XML_RELAXNG_LIST) ||
5430 (parent->type == XML_RELAXNG_GROUP) ||
5431 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5432 (parent->type == XML_RELAXNG_ONEORMORE) ||
5433 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5434 parent->type = XML_RELAXNG_NOT_ALLOWED;
5435 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005436 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005437 if ((parent != NULL) &&
5438 (parent->type == XML_RELAXNG_CHOICE)) {
5439 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5440 } else
5441 prev = cur;
5442 } else if (cur->type == XML_RELAXNG_EMPTY){
5443 if ((parent != NULL) &&
5444 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5445 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5446 parent->type = XML_RELAXNG_EMPTY;
5447 break;
5448 }
5449 if ((parent != NULL) &&
5450 ((parent->type == XML_RELAXNG_GROUP) ||
5451 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5452 (parent->type == XML_RELAXNG_CHOICE))) {
5453 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5454 } else
5455 prev = cur;
5456 } else {
5457 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005458 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005459 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005460 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005461 }
5462}
5463
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005464/**
5465 * xmlRelaxNGGroupContentType:
5466 * @ct1: the first content type
5467 * @ct2: the second content type
5468 *
5469 * Try to group 2 content types
5470 *
5471 * Returns the content type
5472 */
5473static xmlRelaxNGContentType
5474xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5475 xmlRelaxNGContentType ct2) {
5476 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5477 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5478 return(XML_RELAXNG_CONTENT_ERROR);
5479 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5480 return(ct2);
5481 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5482 return(ct1);
5483 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5484 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5485 return(XML_RELAXNG_CONTENT_COMPLEX);
5486 return(XML_RELAXNG_CONTENT_ERROR);
5487}
5488
5489/**
5490 * xmlRelaxNGMaxContentType:
5491 * @ct1: the first content type
5492 * @ct2: the second content type
5493 *
5494 * Compute the max content-type
5495 *
5496 * Returns the content type
5497 */
5498static xmlRelaxNGContentType
5499xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5500 xmlRelaxNGContentType ct2) {
5501 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5502 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5503 return(XML_RELAXNG_CONTENT_ERROR);
5504 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5505 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5506 return(XML_RELAXNG_CONTENT_SIMPLE);
5507 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5508 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5509 return(XML_RELAXNG_CONTENT_COMPLEX);
5510 return(XML_RELAXNG_CONTENT_EMPTY);
5511}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005512
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005513/**
5514 * xmlRelaxNGCheckRules:
5515 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005516 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005517 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005518 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005519 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005520 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005521 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005522 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005523 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005524static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005525xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5526 xmlRelaxNGDefinePtr cur, int flags,
5527 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005528 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005529 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005530
Daniel Veillardfd573f12003-03-16 17:52:32 +00005531 while (cur != NULL) {
5532 ret = XML_RELAXNG_CONTENT_EMPTY;
5533 if ((cur->type == XML_RELAXNG_REF) ||
5534 (cur->type == XML_RELAXNG_PARENTREF)) {
5535 if (flags & XML_RELAXNG_IN_LIST) {
5536 if (ctxt->error != NULL)
5537 ctxt->error(ctxt->userData,
5538 "Found forbidden pattern list//ref\n");
5539 ctxt->nbErrors++;
5540 }
5541 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5542 if (ctxt->error != NULL)
5543 ctxt->error(ctxt->userData,
5544 "Found forbidden pattern data/except//ref\n");
5545 ctxt->nbErrors++;
5546 }
5547 if (cur->depth > -4) {
5548 cur->depth = -4;
5549 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5550 flags, cur->type);
5551 cur->depth = ret - 15 ;
5552 } else if (cur->depth == -4) {
5553 ret = XML_RELAXNG_CONTENT_COMPLEX;
5554 } else {
5555 ret = (xmlRelaxNGContentType) cur->depth + 15;
5556 }
5557 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5558 /*
5559 * The 7.3 Attribute derivation rule for groups is plugged there
5560 */
5561 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5562 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5563 if (ctxt->error != NULL)
5564 ctxt->error(ctxt->userData,
5565 "Found forbidden pattern data/except//element(ref)\n");
5566 ctxt->nbErrors++;
5567 }
5568 if (flags & XML_RELAXNG_IN_LIST) {
5569 if (ctxt->error != NULL)
5570 ctxt->error(ctxt->userData,
5571 "Found forbidden pattern list//element(ref)\n");
5572 ctxt->nbErrors++;
5573 }
5574 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5575 if (ctxt->error != NULL)
5576 ctxt->error(ctxt->userData,
5577 "Found forbidden pattern attribute//element(ref)\n");
5578 ctxt->nbErrors++;
5579 }
5580 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5581 if (ctxt->error != NULL)
5582 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005583 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005584 ctxt->nbErrors++;
5585 }
5586 /*
5587 * reset since in the simple form elements are only child
5588 * of grammar/define
5589 */
5590 nflags = 0;
5591 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5592 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5593 if (ctxt->error != NULL)
5594 ctxt->error(ctxt->userData,
5595 "Element %s attributes have a content type error\n",
5596 cur->name);
5597 ctxt->nbErrors++;
5598 }
5599 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5600 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5601 if (ctxt->error != NULL)
5602 ctxt->error(ctxt->userData,
5603 "Element %s has a content type error\n",
5604 cur->name);
5605 ctxt->nbErrors++;
5606 } else {
5607 ret = XML_RELAXNG_CONTENT_COMPLEX;
5608 }
5609 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5610 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5611 if (ctxt->error != NULL)
5612 ctxt->error(ctxt->userData,
5613 "Found forbidden pattern attribute//attribute\n");
5614 ctxt->nbErrors++;
5615 }
5616 if (flags & XML_RELAXNG_IN_LIST) {
5617 if (ctxt->error != NULL)
5618 ctxt->error(ctxt->userData,
5619 "Found forbidden pattern list//attribute\n");
5620 ctxt->nbErrors++;
5621 }
5622 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5623 if (ctxt->error != NULL)
5624 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005625 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005626 ctxt->nbErrors++;
5627 }
5628 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5629 if (ctxt->error != NULL)
5630 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005631 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005632 ctxt->nbErrors++;
5633 }
5634 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5635 if (ctxt->error != NULL)
5636 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005637 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005638 ctxt->nbErrors++;
5639 }
5640 if (flags & XML_RELAXNG_IN_START) {
5641 if (ctxt->error != NULL)
5642 ctxt->error(ctxt->userData,
5643 "Found forbidden pattern start//attribute\n");
5644 ctxt->nbErrors++;
5645 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005646 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5647 if (cur->ns == NULL) {
5648 if (ctxt->error != NULL)
5649 ctxt->error(ctxt->userData,
5650 "Found anyName attribute without oneOrMore ancestor\n");
5651 ctxt->nbErrors++;
5652 } else {
5653 if (ctxt->error != NULL)
5654 ctxt->error(ctxt->userData,
5655 "Found nsName attribute without oneOrMore ancestor\n");
5656 ctxt->nbErrors++;
5657 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005658 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005659 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5660 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5661 ret = XML_RELAXNG_CONTENT_EMPTY;
5662 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5663 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5664 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5665 if (ctxt->error != NULL)
5666 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005667 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005668 ctxt->nbErrors++;
5669 }
5670 if (flags & XML_RELAXNG_IN_START) {
5671 if (ctxt->error != NULL)
5672 ctxt->error(ctxt->userData,
5673 "Found forbidden pattern start//oneOrMore\n");
5674 ctxt->nbErrors++;
5675 }
5676 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5677 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5678 ret = xmlRelaxNGGroupContentType(ret, ret);
5679 } else if (cur->type == XML_RELAXNG_LIST) {
5680 if (flags & XML_RELAXNG_IN_LIST) {
5681 if (ctxt->error != NULL)
5682 ctxt->error(ctxt->userData,
5683 "Found forbidden pattern list//list\n");
5684 ctxt->nbErrors++;
5685 }
5686 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5687 if (ctxt->error != NULL)
5688 ctxt->error(ctxt->userData,
5689 "Found forbidden pattern data/except//list\n");
5690 ctxt->nbErrors++;
5691 }
5692 if (flags & XML_RELAXNG_IN_START) {
5693 if (ctxt->error != NULL)
5694 ctxt->error(ctxt->userData,
5695 "Found forbidden pattern start//list\n");
5696 ctxt->nbErrors++;
5697 }
5698 nflags = flags | XML_RELAXNG_IN_LIST;
5699 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5700 } else if (cur->type == XML_RELAXNG_GROUP) {
5701 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5702 if (ctxt->error != NULL)
5703 ctxt->error(ctxt->userData,
5704 "Found forbidden pattern data/except//group\n");
5705 ctxt->nbErrors++;
5706 }
5707 if (flags & XML_RELAXNG_IN_START) {
5708 if (ctxt->error != NULL)
5709 ctxt->error(ctxt->userData,
5710 "Found forbidden pattern start//group\n");
5711 ctxt->nbErrors++;
5712 }
5713 if (flags & XML_RELAXNG_IN_ONEORMORE)
5714 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5715 else
5716 nflags = flags;
5717 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5718 /*
5719 * The 7.3 Attribute derivation rule for groups is plugged there
5720 */
5721 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5722 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5723 if (flags & XML_RELAXNG_IN_LIST) {
5724 if (ctxt->error != NULL)
5725 ctxt->error(ctxt->userData,
5726 "Found forbidden pattern list//interleave\n");
5727 ctxt->nbErrors++;
5728 }
5729 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5730 if (ctxt->error != NULL)
5731 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005732 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005733 ctxt->nbErrors++;
5734 }
5735 if (flags & XML_RELAXNG_IN_START) {
5736 if (ctxt->error != NULL)
5737 ctxt->error(ctxt->userData,
5738 "Found forbidden pattern start//interleave\n");
5739 ctxt->nbErrors++;
5740 }
5741 if (flags & XML_RELAXNG_IN_ONEORMORE)
5742 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5743 else
5744 nflags = flags;
5745 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5746 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5747 if ((cur->parent != NULL) &&
5748 (cur->parent->type == XML_RELAXNG_DATATYPE))
5749 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5750 else
5751 nflags = flags;
5752 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5753 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5754 if (flags & XML_RELAXNG_IN_START) {
5755 if (ctxt->error != NULL)
5756 ctxt->error(ctxt->userData,
5757 "Found forbidden pattern start//data\n");
5758 ctxt->nbErrors++;
5759 }
5760 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5761 ret = XML_RELAXNG_CONTENT_SIMPLE;
5762 } else if (cur->type == XML_RELAXNG_VALUE) {
5763 if (flags & XML_RELAXNG_IN_START) {
5764 if (ctxt->error != NULL)
5765 ctxt->error(ctxt->userData,
5766 "Found forbidden pattern start//value\n");
5767 ctxt->nbErrors++;
5768 }
5769 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5770 ret = XML_RELAXNG_CONTENT_SIMPLE;
5771 } else if (cur->type == XML_RELAXNG_TEXT) {
5772 if (flags & XML_RELAXNG_IN_LIST) {
5773 if (ctxt->error != NULL)
5774 ctxt->error(ctxt->userData,
5775 "Found forbidden pattern list//text\n");
5776 ctxt->nbErrors++;
5777 }
5778 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5779 if (ctxt->error != NULL)
5780 ctxt->error(ctxt->userData,
5781 "Found forbidden pattern data/except//text\n");
5782 ctxt->nbErrors++;
5783 }
5784 if (flags & XML_RELAXNG_IN_START) {
5785 if (ctxt->error != NULL)
5786 ctxt->error(ctxt->userData,
5787 "Found forbidden pattern start//text\n");
5788 ctxt->nbErrors++;
5789 }
5790 ret = XML_RELAXNG_CONTENT_COMPLEX;
5791 } else if (cur->type == XML_RELAXNG_EMPTY) {
5792 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5793 if (ctxt->error != NULL)
5794 ctxt->error(ctxt->userData,
5795 "Found forbidden pattern data/except//empty\n");
5796 ctxt->nbErrors++;
5797 }
5798 if (flags & XML_RELAXNG_IN_START) {
5799 if (ctxt->error != NULL)
5800 ctxt->error(ctxt->userData,
5801 "Found forbidden pattern start//empty\n");
5802 ctxt->nbErrors++;
5803 }
5804 ret = XML_RELAXNG_CONTENT_EMPTY;
5805 } else if (cur->type == XML_RELAXNG_CHOICE) {
5806 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5807 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5808 } else {
5809 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5810 }
5811 cur = cur->next;
5812 if (ptype == XML_RELAXNG_GROUP) {
5813 val = xmlRelaxNGGroupContentType(val, ret);
5814 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5815 tmp = xmlRelaxNGGroupContentType(val, ret);
5816 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5817 tmp = xmlRelaxNGMaxContentType(val, ret);
5818 } else if (ptype == XML_RELAXNG_CHOICE) {
5819 val = xmlRelaxNGMaxContentType(val, ret);
5820 } else if (ptype == XML_RELAXNG_LIST) {
5821 val = XML_RELAXNG_CONTENT_SIMPLE;
5822 } else if (ptype == XML_RELAXNG_EXCEPT) {
5823 if (ret == XML_RELAXNG_CONTENT_ERROR)
5824 val = XML_RELAXNG_CONTENT_ERROR;
5825 else
5826 val = XML_RELAXNG_CONTENT_SIMPLE;
5827 } else {
5828 val = xmlRelaxNGGroupContentType(val, ret);
5829 }
5830
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005831 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005832 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005833}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005834
5835/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005836 * xmlRelaxNGParseGrammar:
5837 * @ctxt: a Relax-NG parser context
5838 * @nodes: grammar children nodes
5839 *
5840 * parse a Relax-NG <grammar> node
5841 *
5842 * Returns the internal xmlRelaxNGGrammarPtr built or
5843 * NULL in case of error
5844 */
5845static xmlRelaxNGGrammarPtr
5846xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5847 xmlRelaxNGGrammarPtr ret, tmp, old;
5848
Daniel Veillardc482e262003-02-26 14:48:48 +00005849#ifdef DEBUG_GRAMMAR
5850 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5851#endif
5852
Daniel Veillard6eadf632003-01-23 18:29:16 +00005853 ret = xmlRelaxNGNewGrammar(ctxt);
5854 if (ret == NULL)
5855 return(NULL);
5856
5857 /*
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 }
5871
5872 old = ctxt->grammar;
5873 ctxt->grammar = ret;
5874 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5875 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005876 if (ctxt->grammar == NULL) {
5877 if (ctxt->error != NULL)
5878 ctxt->error(ctxt->userData,
5879 "Failed to parse <grammar> content\n");
5880 ctxt->nbErrors++;
5881 } else if (ctxt->grammar->start == NULL) {
5882 if (ctxt->error != NULL)
5883 ctxt->error(ctxt->userData,
5884 "Element <grammar> has no <start>\n");
5885 ctxt->nbErrors++;
5886 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005887
5888 /*
5889 * Apply 4.17 mergingd rules to defines and starts
5890 */
5891 xmlRelaxNGCombineStart(ctxt, ret);
5892 if (ret->defs != NULL) {
5893 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5894 ctxt);
5895 }
5896
5897 /*
5898 * link together defines and refs in this grammar
5899 */
5900 if (ret->refs != NULL) {
5901 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5902 ctxt);
5903 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005904
Daniel Veillard6eadf632003-01-23 18:29:16 +00005905 ctxt->grammar = old;
5906 return(ret);
5907}
5908
5909/**
5910 * xmlRelaxNGParseDocument:
5911 * @ctxt: a Relax-NG parser context
5912 * @node: the root node of the RelaxNG schema
5913 *
5914 * parse a Relax-NG definition resource and build an internal
5915 * xmlRelaxNG struture which can be used to validate instances.
5916 *
5917 * Returns the internal XML RelaxNG structure built or
5918 * NULL in case of error
5919 */
5920static xmlRelaxNGPtr
5921xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5922 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005923 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005924 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005925
5926 if ((ctxt == NULL) || (node == NULL))
5927 return (NULL);
5928
5929 schema = xmlRelaxNGNewRelaxNG(ctxt);
5930 if (schema == NULL)
5931 return(NULL);
5932
Daniel Veillard276be4a2003-01-24 01:03:34 +00005933 olddefine = ctxt->define;
5934 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005935 if (IS_RELAXNG(node, "grammar")) {
5936 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5937 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005938 xmlRelaxNGGrammarPtr tmp, ret;
5939
5940 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005941 if (schema->topgrammar == NULL) {
5942 return(schema);
5943 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005944 /*
5945 * Link the new grammar in the tree
5946 */
5947 ret->parent = ctxt->grammar;
5948 if (ctxt->grammar != NULL) {
5949 tmp = ctxt->grammar->children;
5950 if (tmp == NULL) {
5951 ctxt->grammar->children = ret;
5952 } else {
5953 while (tmp->next != NULL)
5954 tmp = tmp->next;
5955 tmp->next = ret;
5956 }
5957 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005958 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005959 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005960 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005961 if (old != NULL)
5962 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005963 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005964 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005965 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005966 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005967 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005968 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5969 while ((schema->topgrammar->start != NULL) &&
5970 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
5971 (schema->topgrammar->start->next != NULL))
5972 schema->topgrammar->start = schema->topgrammar->start->content;
5973 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
5974 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005975 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005976 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005977
5978#ifdef DEBUG
5979 if (schema == NULL)
5980 xmlGenericError(xmlGenericErrorContext,
5981 "xmlRelaxNGParseDocument() failed\n");
5982#endif
5983
5984 return (schema);
5985}
5986
5987/************************************************************************
5988 * *
5989 * Reading RelaxNGs *
5990 * *
5991 ************************************************************************/
5992
5993/**
5994 * xmlRelaxNGNewParserCtxt:
5995 * @URL: the location of the schema
5996 *
5997 * Create an XML RelaxNGs parse context for that file/resource expected
5998 * to contain an XML RelaxNGs file.
5999 *
6000 * Returns the parser context or NULL in case of error
6001 */
6002xmlRelaxNGParserCtxtPtr
6003xmlRelaxNGNewParserCtxt(const char *URL) {
6004 xmlRelaxNGParserCtxtPtr ret;
6005
6006 if (URL == NULL)
6007 return(NULL);
6008
6009 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6010 if (ret == NULL) {
6011 xmlGenericError(xmlGenericErrorContext,
6012 "Failed to allocate new schama parser context for %s\n", URL);
6013 return (NULL);
6014 }
6015 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6016 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006017 ret->error = xmlGenericError;
6018 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006019 return (ret);
6020}
6021
6022/**
6023 * xmlRelaxNGNewMemParserCtxt:
6024 * @buffer: a pointer to a char array containing the schemas
6025 * @size: the size of the array
6026 *
6027 * Create an XML RelaxNGs parse context for that memory buffer expected
6028 * to contain an XML RelaxNGs file.
6029 *
6030 * Returns the parser context or NULL in case of error
6031 */
6032xmlRelaxNGParserCtxtPtr
6033xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6034 xmlRelaxNGParserCtxtPtr ret;
6035
6036 if ((buffer == NULL) || (size <= 0))
6037 return(NULL);
6038
6039 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6040 if (ret == NULL) {
6041 xmlGenericError(xmlGenericErrorContext,
6042 "Failed to allocate new schama parser context\n");
6043 return (NULL);
6044 }
6045 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6046 ret->buffer = buffer;
6047 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006048 ret->error = xmlGenericError;
6049 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006050 return (ret);
6051}
6052
6053/**
6054 * xmlRelaxNGFreeParserCtxt:
6055 * @ctxt: the schema parser context
6056 *
6057 * Free the resources associated to the schema parser context
6058 */
6059void
6060xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6061 if (ctxt == NULL)
6062 return;
6063 if (ctxt->URL != NULL)
6064 xmlFree(ctxt->URL);
6065 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006066 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006067 if (ctxt->interleaves != NULL)
6068 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006069 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006070 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006071 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006072 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006073 if (ctxt->docTab != NULL)
6074 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006075 if (ctxt->incTab != NULL)
6076 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006077 if (ctxt->defTab != NULL) {
6078 int i;
6079
6080 for (i = 0;i < ctxt->defNr;i++)
6081 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6082 xmlFree(ctxt->defTab);
6083 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006084 xmlFree(ctxt);
6085}
6086
Daniel Veillard6eadf632003-01-23 18:29:16 +00006087/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006088 * xmlRelaxNGNormExtSpace:
6089 * @value: a value
6090 *
6091 * Removes the leading and ending spaces of the value
6092 * The string is modified "in situ"
6093 */
6094static void
6095xmlRelaxNGNormExtSpace(xmlChar *value) {
6096 xmlChar *start = value;
6097 xmlChar *cur = value;
6098 if (value == NULL)
6099 return;
6100
6101 while (IS_BLANK(*cur)) cur++;
6102 if (cur == start) {
6103 do {
6104 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6105 if (*cur == 0)
6106 return;
6107 start = cur;
6108 while (IS_BLANK(*cur)) cur++;
6109 if (*cur == 0) {
6110 *start = 0;
6111 return;
6112 }
6113 } while (1);
6114 } else {
6115 do {
6116 while ((*cur != 0) && (!IS_BLANK(*cur)))
6117 *start++ = *cur++;
6118 if (*cur == 0) {
6119 *start = 0;
6120 return;
6121 }
6122 /* don't try to normalize the inner spaces */
6123 while (IS_BLANK(*cur)) cur++;
6124 *start++ = *cur++;
6125 if (*cur == 0) {
6126 *start = 0;
6127 return;
6128 }
6129 } while (1);
6130 }
6131}
6132
6133/**
6134 * xmlRelaxNGCheckAttributes:
6135 * @ctxt: a Relax-NG parser context
6136 * @node: a Relax-NG node
6137 *
6138 * Check all the attributes on the given node
6139 */
6140static void
6141xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6142 xmlAttrPtr cur, next;
6143
6144 cur = node->properties;
6145 while (cur != NULL) {
6146 next = cur->next;
6147 if ((cur->ns == NULL) ||
6148 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6149 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6150 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6151 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6152 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6153 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006154 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006155 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6156 if (ctxt->error != NULL)
6157 ctxt->error(ctxt->userData,
6158 "Attribute %s is not allowed on %s\n",
6159 cur->name, node->name);
6160 ctxt->nbErrors++;
6161 }
6162 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6163 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6164 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6165 if (ctxt->error != NULL)
6166 ctxt->error(ctxt->userData,
6167 "Attribute %s is not allowed on %s\n",
6168 cur->name, node->name);
6169 ctxt->nbErrors++;
6170 }
6171 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6172 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6173 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6174 if (ctxt->error != NULL)
6175 ctxt->error(ctxt->userData,
6176 "Attribute %s is not allowed on %s\n",
6177 cur->name, node->name);
6178 ctxt->nbErrors++;
6179 }
6180 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6181 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6182 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6183 if (ctxt->error != NULL)
6184 ctxt->error(ctxt->userData,
6185 "Attribute %s is not allowed on %s\n",
6186 cur->name, node->name);
6187 ctxt->nbErrors++;
6188 }
6189 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6190 xmlChar *val;
6191 xmlURIPtr uri;
6192
6193 val = xmlNodeListGetString(node->doc, cur->children, 1);
6194 if (val != NULL) {
6195 if (val[0] != 0) {
6196 uri = xmlParseURI((const char *) val);
6197 if (uri == NULL) {
6198 if (ctxt->error != NULL)
6199 ctxt->error(ctxt->userData,
6200 "Attribute %s contains invalid URI %s\n",
6201 cur->name, val);
6202 ctxt->nbErrors++;
6203 } else {
6204 if (uri->scheme == NULL) {
6205 if (ctxt->error != NULL)
6206 ctxt->error(ctxt->userData,
6207 "Attribute %s URI %s is not absolute\n",
6208 cur->name, val);
6209 ctxt->nbErrors++;
6210 }
6211 if (uri->fragment != NULL) {
6212 if (ctxt->error != NULL)
6213 ctxt->error(ctxt->userData,
6214 "Attribute %s URI %s has a fragment ID\n",
6215 cur->name, val);
6216 ctxt->nbErrors++;
6217 }
6218 xmlFreeURI(uri);
6219 }
6220 }
6221 xmlFree(val);
6222 }
6223 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6224 if (ctxt->error != NULL)
6225 ctxt->error(ctxt->userData,
6226 "Unknown attribute %s on %s\n",
6227 cur->name, node->name);
6228 ctxt->nbErrors++;
6229 }
6230 }
6231 cur = next;
6232 }
6233}
6234
6235/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006236 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006237 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006238 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006239 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006240 * Cleanup the subtree from unwanted nodes for parsing, resolve
6241 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006242 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006243static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006244xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006245 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006246
Daniel Veillard6eadf632003-01-23 18:29:16 +00006247 delete = NULL;
6248 cur = root;
6249 while (cur != NULL) {
6250 if (delete != NULL) {
6251 xmlUnlinkNode(delete);
6252 xmlFreeNode(delete);
6253 delete = NULL;
6254 }
6255 if (cur->type == XML_ELEMENT_NODE) {
6256 /*
6257 * Simplification 4.1. Annotations
6258 */
6259 if ((cur->ns == NULL) ||
6260 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006261 if ((cur->parent != NULL) &&
6262 (cur->parent->type == XML_ELEMENT_NODE) &&
6263 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6264 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6265 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6266 if (ctxt->error != NULL)
6267 ctxt->error(ctxt->userData,
6268 "element %s doesn't allow foreign elements\n",
6269 cur->parent->name);
6270 ctxt->nbErrors++;
6271 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006272 delete = cur;
6273 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006274 } else {
6275 xmlRelaxNGCleanupAttributes(ctxt, cur);
6276 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6277 xmlChar *href, *ns, *base, *URL;
6278 xmlRelaxNGDocumentPtr docu;
6279 xmlNodePtr tmp;
6280
6281 ns = xmlGetProp(cur, BAD_CAST "ns");
6282 if (ns == NULL) {
6283 tmp = cur->parent;
6284 while ((tmp != NULL) &&
6285 (tmp->type == XML_ELEMENT_NODE)) {
6286 ns = xmlGetProp(tmp, BAD_CAST "ns");
6287 if (ns != NULL)
6288 break;
6289 tmp = tmp->parent;
6290 }
6291 }
6292 href = xmlGetProp(cur, BAD_CAST "href");
6293 if (href == NULL) {
6294 if (ctxt->error != NULL)
6295 ctxt->error(ctxt->userData,
6296 "xmlRelaxNGParse: externalRef has no href attribute\n");
6297 ctxt->nbErrors++;
6298 delete = cur;
6299 goto skip_children;
6300 }
6301 base = xmlNodeGetBase(cur->doc, cur);
6302 URL = xmlBuildURI(href, base);
6303 if (URL == NULL) {
6304 if (ctxt->error != NULL)
6305 ctxt->error(ctxt->userData,
6306 "Failed to compute URL for externalRef %s\n", href);
6307 ctxt->nbErrors++;
6308 if (href != NULL)
6309 xmlFree(href);
6310 if (base != NULL)
6311 xmlFree(base);
6312 delete = cur;
6313 goto skip_children;
6314 }
6315 if (href != NULL)
6316 xmlFree(href);
6317 if (base != NULL)
6318 xmlFree(base);
6319 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6320 if (docu == NULL) {
6321 if (ctxt->error != NULL)
6322 ctxt->error(ctxt->userData,
6323 "Failed to load externalRef %s\n", URL);
6324 ctxt->nbErrors++;
6325 xmlFree(URL);
6326 delete = cur;
6327 goto skip_children;
6328 }
6329 if (ns != NULL)
6330 xmlFree(ns);
6331 xmlFree(URL);
6332 cur->_private = docu;
6333 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6334 xmlChar *href, *ns, *base, *URL;
6335 xmlRelaxNGIncludePtr incl;
6336 xmlNodePtr tmp;
6337
6338 href = xmlGetProp(cur, BAD_CAST "href");
6339 if (href == NULL) {
6340 if (ctxt->error != NULL)
6341 ctxt->error(ctxt->userData,
6342 "xmlRelaxNGParse: include has no href attribute\n");
6343 ctxt->nbErrors++;
6344 delete = cur;
6345 goto skip_children;
6346 }
6347 base = xmlNodeGetBase(cur->doc, cur);
6348 URL = xmlBuildURI(href, base);
6349 if (URL == NULL) {
6350 if (ctxt->error != NULL)
6351 ctxt->error(ctxt->userData,
6352 "Failed to compute URL for include %s\n", href);
6353 ctxt->nbErrors++;
6354 if (href != NULL)
6355 xmlFree(href);
6356 if (base != NULL)
6357 xmlFree(base);
6358 delete = cur;
6359 goto skip_children;
6360 }
6361 if (href != NULL)
6362 xmlFree(href);
6363 if (base != NULL)
6364 xmlFree(base);
6365 ns = xmlGetProp(cur, BAD_CAST "ns");
6366 if (ns == NULL) {
6367 tmp = cur->parent;
6368 while ((tmp != NULL) &&
6369 (tmp->type == XML_ELEMENT_NODE)) {
6370 ns = xmlGetProp(tmp, BAD_CAST "ns");
6371 if (ns != NULL)
6372 break;
6373 tmp = tmp->parent;
6374 }
6375 }
6376 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6377 if (ns != NULL)
6378 xmlFree(ns);
6379 if (incl == NULL) {
6380 if (ctxt->error != NULL)
6381 ctxt->error(ctxt->userData,
6382 "Failed to load include %s\n", URL);
6383 ctxt->nbErrors++;
6384 xmlFree(URL);
6385 delete = cur;
6386 goto skip_children;
6387 }
6388 xmlFree(URL);
6389 cur->_private = incl;
6390 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6391 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6392 xmlChar *name, *ns;
6393 xmlNodePtr text = NULL;
6394
6395 /*
6396 * Simplification 4.8. name attribute of element
6397 * and attribute elements
6398 */
6399 name = xmlGetProp(cur, BAD_CAST "name");
6400 if (name != NULL) {
6401 if (cur->children == NULL) {
6402 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6403 name);
6404 } else {
6405 xmlNodePtr node;
6406 node = xmlNewNode(cur->ns, BAD_CAST "name");
6407 if (node != NULL) {
6408 xmlAddPrevSibling(cur->children, node);
6409 text = xmlNewText(name);
6410 xmlAddChild(node, text);
6411 text = node;
6412 }
6413 }
6414 if (text == NULL) {
6415 if (ctxt->error != NULL)
6416 ctxt->error(ctxt->userData,
6417 "Failed to create a name %s element\n", name);
6418 ctxt->nbErrors++;
6419 }
6420 xmlUnsetProp(cur, BAD_CAST "name");
6421 xmlFree(name);
6422 ns = xmlGetProp(cur, BAD_CAST "ns");
6423 if (ns != NULL) {
6424 if (text != NULL) {
6425 xmlSetProp(text, BAD_CAST "ns", ns);
6426 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6427 }
6428 xmlFree(ns);
6429 } else if (xmlStrEqual(cur->name,
6430 BAD_CAST "attribute")) {
6431 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6432 }
6433 }
6434 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6435 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6436 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6437 /*
6438 * Simplification 4.8. name attribute of element
6439 * and attribute elements
6440 */
6441 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6442 xmlNodePtr node;
6443 xmlChar *ns = NULL;
6444
6445 node = cur->parent;
6446 while ((node != NULL) &&
6447 (node->type == XML_ELEMENT_NODE)) {
6448 ns = xmlGetProp(node, BAD_CAST "ns");
6449 if (ns != NULL) {
6450 break;
6451 }
6452 node = node->parent;
6453 }
6454 if (ns == NULL) {
6455 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6456 } else {
6457 xmlSetProp(cur, BAD_CAST "ns", ns);
6458 xmlFree(ns);
6459 }
6460 }
6461 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6462 xmlChar *name, *local, *prefix;
6463
6464 /*
6465 * Simplification: 4.10. QNames
6466 */
6467 name = xmlNodeGetContent(cur);
6468 if (name != NULL) {
6469 local = xmlSplitQName2(name, &prefix);
6470 if (local != NULL) {
6471 xmlNsPtr ns;
6472
6473 ns = xmlSearchNs(cur->doc, cur, prefix);
6474 if (ns == NULL) {
6475 if (ctxt->error != NULL)
6476 ctxt->error(ctxt->userData,
6477 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6478 ctxt->nbErrors++;
6479 } else {
6480 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6481 xmlNodeSetContent(cur, local);
6482 }
6483 xmlFree(local);
6484 xmlFree(prefix);
6485 }
6486 xmlFree(name);
6487 }
6488 }
6489 /*
6490 * 4.16
6491 */
6492 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6493 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6494 if (ctxt->error != NULL)
6495 ctxt->error(ctxt->userData,
6496 "Found nsName/except//nsName forbidden construct\n");
6497 ctxt->nbErrors++;
6498 }
6499 }
6500 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6501 (cur != root)) {
6502 int oldflags = ctxt->flags;
6503
6504 /*
6505 * 4.16
6506 */
6507 if ((cur->parent != NULL) &&
6508 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6509 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6510 xmlRelaxNGCleanupTree(ctxt, cur);
6511 ctxt->flags = oldflags;
6512 goto skip_children;
6513 } else if ((cur->parent != NULL) &&
6514 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6515 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6516 xmlRelaxNGCleanupTree(ctxt, cur);
6517 ctxt->flags = oldflags;
6518 goto skip_children;
6519 }
6520 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6521 /*
6522 * 4.16
6523 */
6524 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6525 if (ctxt->error != NULL)
6526 ctxt->error(ctxt->userData,
6527 "Found anyName/except//anyName forbidden construct\n");
6528 ctxt->nbErrors++;
6529 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6530 if (ctxt->error != NULL)
6531 ctxt->error(ctxt->userData,
6532 "Found nsName/except//anyName forbidden construct\n");
6533 ctxt->nbErrors++;
6534 }
6535 }
6536 /*
6537 * Thisd is not an else since "include" is transformed
6538 * into a div
6539 */
6540 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6541 xmlChar *ns;
6542 xmlNodePtr child, ins, tmp;
6543
6544 /*
6545 * implements rule 4.11
6546 */
6547
6548 ns = xmlGetProp(cur, BAD_CAST "ns");
6549
6550 child = cur->children;
6551 ins = cur;
6552 while (child != NULL) {
6553 if (ns != NULL) {
6554 if (!xmlHasProp(child, BAD_CAST "ns")) {
6555 xmlSetProp(child, BAD_CAST "ns", ns);
6556 }
6557 }
6558 tmp = child->next;
6559 xmlUnlinkNode(child);
6560 ins = xmlAddNextSibling(ins, child);
6561 child = tmp;
6562 }
6563 if (ns != NULL)
6564 xmlFree(ns);
6565 delete = cur;
6566 goto skip_children;
6567 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006568 }
6569 }
6570 /*
6571 * Simplification 4.2 whitespaces
6572 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006573 else if ((cur->type == XML_TEXT_NODE) ||
6574 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006575 if (IS_BLANK_NODE(cur)) {
6576 if (cur->parent->type == XML_ELEMENT_NODE) {
6577 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6578 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6579 delete = cur;
6580 } else {
6581 delete = cur;
6582 goto skip_children;
6583 }
6584 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006585 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006586 delete = cur;
6587 goto skip_children;
6588 }
6589
6590 /*
6591 * Skip to next node
6592 */
6593 if (cur->children != NULL) {
6594 if ((cur->children->type != XML_ENTITY_DECL) &&
6595 (cur->children->type != XML_ENTITY_REF_NODE) &&
6596 (cur->children->type != XML_ENTITY_NODE)) {
6597 cur = cur->children;
6598 continue;
6599 }
6600 }
6601skip_children:
6602 if (cur->next != NULL) {
6603 cur = cur->next;
6604 continue;
6605 }
6606
6607 do {
6608 cur = cur->parent;
6609 if (cur == NULL)
6610 break;
6611 if (cur == root) {
6612 cur = NULL;
6613 break;
6614 }
6615 if (cur->next != NULL) {
6616 cur = cur->next;
6617 break;
6618 }
6619 } while (cur != NULL);
6620 }
6621 if (delete != NULL) {
6622 xmlUnlinkNode(delete);
6623 xmlFreeNode(delete);
6624 delete = NULL;
6625 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006626}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006627
Daniel Veillardc5312d72003-02-21 17:14:10 +00006628/**
6629 * xmlRelaxNGCleanupDoc:
6630 * @ctxt: a Relax-NG parser context
6631 * @doc: an xmldocPtr document pointer
6632 *
6633 * Cleanup the document from unwanted nodes for parsing, resolve
6634 * Include and externalRef lookups.
6635 *
6636 * Returns the cleaned up document or NULL in case of error
6637 */
6638static xmlDocPtr
6639xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6640 xmlNodePtr root;
6641
6642 /*
6643 * Extract the root
6644 */
6645 root = xmlDocGetRootElement(doc);
6646 if (root == NULL) {
6647 if (ctxt->error != NULL)
6648 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6649 ctxt->URL);
6650 ctxt->nbErrors++;
6651 return (NULL);
6652 }
6653 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006654 return(doc);
6655}
6656
6657/**
6658 * xmlRelaxNGParse:
6659 * @ctxt: a Relax-NG parser context
6660 *
6661 * parse a schema definition resource and build an internal
6662 * XML Shema struture which can be used to validate instances.
6663 * *WARNING* this interface is highly subject to change
6664 *
6665 * Returns the internal XML RelaxNG structure built from the resource or
6666 * NULL in case of error
6667 */
6668xmlRelaxNGPtr
6669xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6670{
6671 xmlRelaxNGPtr ret = NULL;
6672 xmlDocPtr doc;
6673 xmlNodePtr root;
6674
6675 xmlRelaxNGInitTypes();
6676
6677 if (ctxt == NULL)
6678 return (NULL);
6679
6680 /*
6681 * First step is to parse the input document into an DOM/Infoset
6682 */
6683 if (ctxt->URL != NULL) {
6684 doc = xmlParseFile((const char *) ctxt->URL);
6685 if (doc == NULL) {
6686 if (ctxt->error != NULL)
6687 ctxt->error(ctxt->userData,
6688 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6689 ctxt->nbErrors++;
6690 return (NULL);
6691 }
6692 } else if (ctxt->buffer != NULL) {
6693 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6694 if (doc == NULL) {
6695 if (ctxt->error != NULL)
6696 ctxt->error(ctxt->userData,
6697 "xmlRelaxNGParse: could not parse schemas\n");
6698 ctxt->nbErrors++;
6699 return (NULL);
6700 }
6701 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6702 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6703 } else {
6704 if (ctxt->error != NULL)
6705 ctxt->error(ctxt->userData,
6706 "xmlRelaxNGParse: nothing to parse\n");
6707 ctxt->nbErrors++;
6708 return (NULL);
6709 }
6710 ctxt->document = doc;
6711
6712 /*
6713 * Some preprocessing of the document content
6714 */
6715 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6716 if (doc == NULL) {
6717 xmlFreeDoc(ctxt->document);
6718 ctxt->document = NULL;
6719 return(NULL);
6720 }
6721
Daniel Veillard6eadf632003-01-23 18:29:16 +00006722 /*
6723 * Then do the parsing for good
6724 */
6725 root = xmlDocGetRootElement(doc);
6726 if (root == NULL) {
6727 if (ctxt->error != NULL)
6728 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6729 ctxt->URL);
6730 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006731 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006732 return (NULL);
6733 }
6734 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006735 if (ret == NULL) {
6736 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006737 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006738 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006739
6740 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006741 * Check the ref/defines links
6742 */
6743 /*
6744 * try to preprocess interleaves
6745 */
6746 if (ctxt->interleaves != NULL) {
6747 xmlHashScan(ctxt->interleaves,
6748 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6749 }
6750
6751 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006752 * if there was a parsing error return NULL
6753 */
6754 if (ctxt->nbErrors > 0) {
6755 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006756 ctxt->document = NULL;
6757 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006758 return(NULL);
6759 }
6760
6761 /*
6762 * Transfer the pointer for cleanup at the schema level.
6763 */
6764 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006765 ctxt->document = NULL;
6766 ret->documents = ctxt->documents;
6767 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006768
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006769 ret->includes = ctxt->includes;
6770 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006771 ret->defNr = ctxt->defNr;
6772 ret->defTab = ctxt->defTab;
6773 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006774 if (ctxt->idref == 1)
6775 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006776
6777 return (ret);
6778}
6779
6780/**
6781 * xmlRelaxNGSetParserErrors:
6782 * @ctxt: a Relax-NG validation context
6783 * @err: the error callback
6784 * @warn: the warning callback
6785 * @ctx: contextual data for the callbacks
6786 *
6787 * Set the callback functions used to handle errors for a validation context
6788 */
6789void
6790xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6791 xmlRelaxNGValidityErrorFunc err,
6792 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6793 if (ctxt == NULL)
6794 return;
6795 ctxt->error = err;
6796 ctxt->warning = warn;
6797 ctxt->userData = ctx;
6798}
6799/************************************************************************
6800 * *
6801 * Dump back a compiled form *
6802 * *
6803 ************************************************************************/
6804static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6805
6806/**
6807 * xmlRelaxNGDumpDefines:
6808 * @output: the file output
6809 * @defines: a list of define structures
6810 *
6811 * Dump a RelaxNG structure back
6812 */
6813static void
6814xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6815 while (defines != NULL) {
6816 xmlRelaxNGDumpDefine(output, defines);
6817 defines = defines->next;
6818 }
6819}
6820
6821/**
6822 * xmlRelaxNGDumpDefine:
6823 * @output: the file output
6824 * @define: a define structure
6825 *
6826 * Dump a RelaxNG structure back
6827 */
6828static void
6829xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6830 if (define == NULL)
6831 return;
6832 switch(define->type) {
6833 case XML_RELAXNG_EMPTY:
6834 fprintf(output, "<empty/>\n");
6835 break;
6836 case XML_RELAXNG_NOT_ALLOWED:
6837 fprintf(output, "<notAllowed/>\n");
6838 break;
6839 case XML_RELAXNG_TEXT:
6840 fprintf(output, "<text/>\n");
6841 break;
6842 case XML_RELAXNG_ELEMENT:
6843 fprintf(output, "<element>\n");
6844 if (define->name != NULL) {
6845 fprintf(output, "<name");
6846 if (define->ns != NULL)
6847 fprintf(output, " ns=\"%s\"", define->ns);
6848 fprintf(output, ">%s</name>\n", define->name);
6849 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006850 xmlRelaxNGDumpDefines(output, define->attrs);
6851 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006852 fprintf(output, "</element>\n");
6853 break;
6854 case XML_RELAXNG_LIST:
6855 fprintf(output, "<list>\n");
6856 xmlRelaxNGDumpDefines(output, define->content);
6857 fprintf(output, "</list>\n");
6858 break;
6859 case XML_RELAXNG_ONEORMORE:
6860 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006861 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006862 fprintf(output, "</oneOrMore>\n");
6863 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006864 case XML_RELAXNG_ZEROORMORE:
6865 fprintf(output, "<zeroOrMore>\n");
6866 xmlRelaxNGDumpDefines(output, define->content);
6867 fprintf(output, "</zeroOrMore>\n");
6868 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006869 case XML_RELAXNG_CHOICE:
6870 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006871 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006872 fprintf(output, "</choice>\n");
6873 break;
6874 case XML_RELAXNG_GROUP:
6875 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006876 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006877 fprintf(output, "</group>\n");
6878 break;
6879 case XML_RELAXNG_INTERLEAVE:
6880 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006881 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006882 fprintf(output, "</interleave>\n");
6883 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006884 case XML_RELAXNG_OPTIONAL:
6885 fprintf(output, "<optional>\n");
6886 xmlRelaxNGDumpDefines(output, define->content);
6887 fprintf(output, "</optional>\n");
6888 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006889 case XML_RELAXNG_ATTRIBUTE:
6890 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006891 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006892 fprintf(output, "</attribute>\n");
6893 break;
6894 case XML_RELAXNG_DEF:
6895 fprintf(output, "<define");
6896 if (define->name != NULL)
6897 fprintf(output, " name=\"%s\"", define->name);
6898 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006899 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006900 fprintf(output, "</define>\n");
6901 break;
6902 case XML_RELAXNG_REF:
6903 fprintf(output, "<ref");
6904 if (define->name != NULL)
6905 fprintf(output, " name=\"%s\"", define->name);
6906 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006907 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006908 fprintf(output, "</ref>\n");
6909 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006910 case XML_RELAXNG_PARENTREF:
6911 fprintf(output, "<parentRef");
6912 if (define->name != NULL)
6913 fprintf(output, " name=\"%s\"", define->name);
6914 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006915 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006916 fprintf(output, "</parentRef>\n");
6917 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006918 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006919 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006920 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006921 fprintf(output, "</externalRef>\n");
6922 break;
6923 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006924 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006925 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006926 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006927 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006928 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006929 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006930 TODO
6931 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006932 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006933 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006934 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006935 }
6936}
6937
6938/**
6939 * xmlRelaxNGDumpGrammar:
6940 * @output: the file output
6941 * @grammar: a grammar structure
6942 * @top: is this a top grammar
6943 *
6944 * Dump a RelaxNG structure back
6945 */
6946static void
6947xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6948{
6949 if (grammar == NULL)
6950 return;
6951
6952 fprintf(output, "<grammar");
6953 if (top)
6954 fprintf(output,
6955 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6956 switch(grammar->combine) {
6957 case XML_RELAXNG_COMBINE_UNDEFINED:
6958 break;
6959 case XML_RELAXNG_COMBINE_CHOICE:
6960 fprintf(output, " combine=\"choice\"");
6961 break;
6962 case XML_RELAXNG_COMBINE_INTERLEAVE:
6963 fprintf(output, " combine=\"interleave\"");
6964 break;
6965 default:
6966 fprintf(output, " <!-- invalid combine value -->");
6967 }
6968 fprintf(output, ">\n");
6969 if (grammar->start == NULL) {
6970 fprintf(output, " <!-- grammar had no start -->");
6971 } else {
6972 fprintf(output, "<start>\n");
6973 xmlRelaxNGDumpDefine(output, grammar->start);
6974 fprintf(output, "</start>\n");
6975 }
6976 /* TODO ? Dump the defines ? */
6977 fprintf(output, "</grammar>\n");
6978}
6979
6980/**
6981 * xmlRelaxNGDump:
6982 * @output: the file output
6983 * @schema: a schema structure
6984 *
6985 * Dump a RelaxNG structure back
6986 */
6987void
6988xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
6989{
6990 if (schema == NULL) {
6991 fprintf(output, "RelaxNG empty or failed to compile\n");
6992 return;
6993 }
6994 fprintf(output, "RelaxNG: ");
6995 if (schema->doc == NULL) {
6996 fprintf(output, "no document\n");
6997 } else if (schema->doc->URL != NULL) {
6998 fprintf(output, "%s\n", schema->doc->URL);
6999 } else {
7000 fprintf(output, "\n");
7001 }
7002 if (schema->topgrammar == NULL) {
7003 fprintf(output, "RelaxNG has no top grammar\n");
7004 return;
7005 }
7006 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7007}
7008
Daniel Veillardfebcca42003-02-16 15:44:18 +00007009/**
7010 * xmlRelaxNGDumpTree:
7011 * @output: the file output
7012 * @schema: a schema structure
7013 *
7014 * Dump the transformed RelaxNG tree.
7015 */
7016void
7017xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7018{
7019 if (schema == NULL) {
7020 fprintf(output, "RelaxNG empty or failed to compile\n");
7021 return;
7022 }
7023 if (schema->doc == NULL) {
7024 fprintf(output, "no document\n");
7025 } else {
7026 xmlDocDump(output, schema->doc);
7027 }
7028}
7029
Daniel Veillard6eadf632003-01-23 18:29:16 +00007030/************************************************************************
7031 * *
7032 * Validation implementation *
7033 * *
7034 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00007035static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7036 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007037static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7038 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007039
7040/**
7041 * xmlRelaxNGSkipIgnored:
7042 * @ctxt: a schema validation context
7043 * @node: the top node.
7044 *
7045 * Skip ignorable nodes in that context
7046 *
7047 * Returns the new sibling or NULL in case of error.
7048 */
7049static xmlNodePtr
7050xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
7051 xmlNodePtr node) {
7052 /*
7053 * TODO complete and handle entities
7054 */
7055 while ((node != NULL) &&
7056 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007057 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007058 (((node->type == XML_TEXT_NODE) ||
7059 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007060 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
7061 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007062 node = node->next;
7063 }
7064 return(node);
7065}
7066
7067/**
Daniel Veillardedc91922003-01-26 00:52:04 +00007068 * xmlRelaxNGNormalize:
7069 * @ctxt: a schema validation context
7070 * @str: the string to normalize
7071 *
7072 * Implements the normalizeWhiteSpace( s ) function from
7073 * section 6.2.9 of the spec
7074 *
7075 * Returns the new string or NULL in case of error.
7076 */
7077static xmlChar *
7078xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
7079 xmlChar *ret, *p;
7080 const xmlChar *tmp;
7081 int len;
7082
7083 if (str == NULL)
7084 return(NULL);
7085 tmp = str;
7086 while (*tmp != 0) tmp++;
7087 len = tmp - str;
7088
7089 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
7090 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007091 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007092 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007093 } else {
7094 xmlGenericError(xmlGenericErrorContext,
7095 "xmlRelaxNGNormalize: out of memory\n");
7096 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007097 return(NULL);
7098 }
7099 p = ret;
7100 while (IS_BLANK(*str)) str++;
7101 while (*str != 0) {
7102 if (IS_BLANK(*str)) {
7103 while (IS_BLANK(*str)) str++;
7104 if (*str == 0)
7105 break;
7106 *p++ = ' ';
7107 } else
7108 *p++ = *str++;
7109 }
7110 *p = 0;
7111 return(ret);
7112}
7113
7114/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007115 * xmlRelaxNGValidateDatatype:
7116 * @ctxt: a Relax-NG validation context
7117 * @value: the string value
7118 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007119 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007120 *
7121 * Validate the given value against the dataype
7122 *
7123 * Returns 0 if the validation succeeded or an error code.
7124 */
7125static int
7126xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007127 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007128 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007129 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007130 void *result = NULL;
7131 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007132
7133 if ((define == NULL) || (define->data == NULL)) {
7134 return(-1);
7135 }
7136 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007137 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007138 if ((define->attrs != NULL) &&
7139 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007140 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007141 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007142 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007143 }
7144 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007145 ret = -1;
7146 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007147 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007148 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7149 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007150 return(-1);
7151 } else if (ret == 1) {
7152 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007153 } else if (ret == 2) {
7154 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007155 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007156 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007157 ret = -1;
7158 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007159 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007160 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
7161 if (lib->facet != NULL) {
7162 tmp = lib->facet(lib->data, define->name, cur->name,
7163 cur->value, value, result);
7164 if (tmp != 0)
7165 ret = -1;
7166 }
7167 cur = cur->next;
7168 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007169 if ((ret == 0) && (define->content != NULL)) {
7170 const xmlChar *oldvalue, *oldendvalue;
7171
7172 oldvalue = ctxt->state->value;
7173 oldendvalue = ctxt->state->endvalue;
7174 ctxt->state->value = (xmlChar *) value;
7175 ctxt->state->endvalue = NULL;
7176 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7177 ctxt->state->value = (xmlChar *) oldvalue;
7178 ctxt->state->endvalue = (xmlChar *) oldendvalue;
7179 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007180 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7181 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007182 return(ret);
7183}
7184
7185/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007186 * xmlRelaxNGNextValue:
7187 * @ctxt: a Relax-NG validation context
7188 *
7189 * Skip to the next value when validating within a list
7190 *
7191 * Returns 0 if the operation succeeded or an error code.
7192 */
7193static int
7194xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
7195 xmlChar *cur;
7196
7197 cur = ctxt->state->value;
7198 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
7199 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007200 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007201 return(0);
7202 }
7203 while (*cur != 0) cur++;
7204 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
7205 if (cur == ctxt->state->endvalue)
7206 ctxt->state->value = NULL;
7207 else
7208 ctxt->state->value = cur;
7209 return(0);
7210}
7211
7212/**
7213 * xmlRelaxNGValidateValueList:
7214 * @ctxt: a Relax-NG validation context
7215 * @defines: the list of definitions to verify
7216 *
7217 * Validate the given set of definitions for the current value
7218 *
7219 * Returns 0 if the validation succeeded or an error code.
7220 */
7221static int
7222xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
7223 xmlRelaxNGDefinePtr defines) {
7224 int ret = 0;
7225
7226 while (defines != NULL) {
7227 ret = xmlRelaxNGValidateValue(ctxt, defines);
7228 if (ret != 0)
7229 break;
7230 defines = defines->next;
7231 }
7232 return(ret);
7233}
7234
7235/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007236 * xmlRelaxNGValidateValue:
7237 * @ctxt: a Relax-NG validation context
7238 * @define: the definition to verify
7239 *
7240 * Validate the given definition for the current value
7241 *
7242 * Returns 0 if the validation succeeded or an error code.
7243 */
7244static int
7245xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7246 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00007247 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007248 xmlChar *value;
7249
7250 value = ctxt->state->value;
7251 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007252 case XML_RELAXNG_EMPTY: {
7253 if ((value != NULL) && (value[0] != 0)) {
7254 int idx = 0;
7255
7256 while (IS_BLANK(value[idx]))
7257 idx++;
7258 if (value[idx] != 0)
7259 ret = -1;
7260 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007261 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00007262 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007263 case XML_RELAXNG_TEXT:
7264 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00007265 case XML_RELAXNG_VALUE: {
7266 if (!xmlStrEqual(value, define->value)) {
7267 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007268 xmlRelaxNGTypeLibraryPtr lib;
7269
7270 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00007271 if ((lib != NULL) && (lib->comp != NULL)) {
7272 ret = lib->comp(lib->data, define->name,
7273 define->value, define->node,
7274 (void *) define->attrs,
7275 value, ctxt->state->node);
7276 } else
Daniel Veillardea3f3982003-01-26 19:45:18 +00007277 ret = -1;
7278 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007279 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007280 return(-1);
7281 } else if (ret == 1) {
7282 ret = 0;
7283 } else {
7284 ret = -1;
7285 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007286 } else {
7287 xmlChar *nval, *nvalue;
7288
7289 /*
7290 * TODO: trivial optimizations are possible by
7291 * computing at compile-time
7292 */
7293 nval = xmlRelaxNGNormalize(ctxt, define->value);
7294 nvalue = xmlRelaxNGNormalize(ctxt, value);
7295
Daniel Veillardea3f3982003-01-26 19:45:18 +00007296 if ((nval == NULL) || (nvalue == NULL) ||
7297 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00007298 ret = -1;
7299 if (nval != NULL)
7300 xmlFree(nval);
7301 if (nvalue != NULL)
7302 xmlFree(nvalue);
7303 }
7304 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007305 if (ret == 0)
7306 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00007307 break;
7308 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007309 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007310 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
7311 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007312 if (ret == 0)
7313 xmlRelaxNGNextValue(ctxt);
7314
7315 break;
7316 }
7317 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007318 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007319 xmlChar *oldvalue;
7320
7321 oldflags = ctxt->flags;
7322 ctxt->flags |= FLAGS_IGNORABLE;
7323
7324 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007325 while (list != NULL) {
7326 ret = xmlRelaxNGValidateValue(ctxt, list);
7327 if (ret == 0) {
7328 break;
7329 }
7330 ctxt->state->value = oldvalue;
7331 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007332 }
7333 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007334 if (ret != 0) {
7335 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7336 xmlRelaxNGDumpValidError(ctxt);
7337 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007338 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007339 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007340 if (ret == 0)
7341 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007342 break;
7343 }
7344 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007345 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007346 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00007347#ifdef DEBUG_LIST
7348 int nb_values = 0;
7349#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007350
7351 oldvalue = ctxt->state->value;
7352 oldend = ctxt->state->endvalue;
7353
7354 val = xmlStrdup(oldvalue);
7355 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007356 val = xmlStrdup(BAD_CAST "");
7357 }
7358 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007359 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007360 return(-1);
7361 }
7362 cur = val;
7363 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007364 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007365 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007366 cur++;
7367#ifdef DEBUG_LIST
7368 nb_values++;
7369#endif
7370 while (IS_BLANK(*cur))
7371 *cur++ = 0;
7372 } else
7373 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007374 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007375#ifdef DEBUG_LIST
7376 xmlGenericError(xmlGenericErrorContext,
7377 "list value: '%s' found %d items\n", oldvalue, nb_values);
7378 nb_values = 0;
7379#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007380 ctxt->state->endvalue = cur;
7381 cur = val;
7382 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007383
Daniel Veillardfd573f12003-03-16 17:52:32 +00007384 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007385
Daniel Veillardfd573f12003-03-16 17:52:32 +00007386 while (list != NULL) {
7387 if (ctxt->state->value == ctxt->state->endvalue)
7388 ctxt->state->value = NULL;
7389 ret = xmlRelaxNGValidateValue(ctxt, list);
7390 if (ret != 0) {
7391#ifdef DEBUG_LIST
7392 xmlGenericError(xmlGenericErrorContext,
7393 "Failed to validate value: '%s' with %d rule\n",
7394 ctxt->state->value, nb_values);
7395#endif
7396 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007397 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007398#ifdef DEBUG_LIST
7399 nb_values++;
7400#endif
7401 list = list->next;
7402 }
7403
7404 if ((ret == 0) && (ctxt->state->value != NULL) &&
7405 (ctxt->state->value != ctxt->state->endvalue)) {
7406 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7407 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007408 }
7409 xmlFree(val);
7410 ctxt->state->value = oldvalue;
7411 ctxt->state->endvalue = oldend;
7412 break;
7413 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007414 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007415 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7416 if (ret != 0) {
7417 break;
7418 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007419 /* no break on purpose */
7420 case XML_RELAXNG_ZEROORMORE: {
7421 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007422
7423 oldflags = ctxt->flags;
7424 ctxt->flags |= FLAGS_IGNORABLE;
7425 cur = ctxt->state->value;
7426 temp = NULL;
7427 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7428 (temp != cur)) {
7429 temp = cur;
7430 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7431 if (ret != 0) {
7432 ctxt->state->value = temp;
7433 ret = 0;
7434 break;
7435 }
7436 cur = ctxt->state->value;
7437 }
7438 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007439 if (ret != 0) {
7440 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7441 xmlRelaxNGDumpValidError(ctxt);
7442 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007443 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007444 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007445 break;
7446 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007447 case XML_RELAXNG_EXCEPT: {
7448 xmlRelaxNGDefinePtr list;
7449
7450 list = define->content;
7451 while (list != NULL) {
7452 ret = xmlRelaxNGValidateValue(ctxt, list);
7453 if (ret == 0) {
7454 ret = -1;
7455 break;
7456 } else
7457 ret = 0;
7458 list = list->next;
7459 }
7460 break;
7461 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007462 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007463 case XML_RELAXNG_GROUP: {
7464 xmlRelaxNGDefinePtr list;
7465
7466 list = define->content;
7467 while (list != NULL) {
7468 ret = xmlRelaxNGValidateValue(ctxt, list);
7469 if (ret != 0) {
7470 ret = -1;
7471 break;
7472 } else
7473 ret = 0;
7474 list = list->next;
7475 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007476 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007477 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007478 case XML_RELAXNG_REF:
7479 case XML_RELAXNG_PARENTREF:
7480 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7481 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007482 default:
7483 TODO
7484 ret = -1;
7485 }
7486 return(ret);
7487}
7488
7489/**
7490 * xmlRelaxNGValidateValueContent:
7491 * @ctxt: a Relax-NG validation context
7492 * @defines: the list of definitions to verify
7493 *
7494 * Validate the given definitions for the current value
7495 *
7496 * Returns 0 if the validation succeeded or an error code.
7497 */
7498static int
7499xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7500 xmlRelaxNGDefinePtr defines) {
7501 int ret = 0;
7502
7503 while (defines != NULL) {
7504 ret = xmlRelaxNGValidateValue(ctxt, defines);
7505 if (ret != 0)
7506 break;
7507 defines = defines->next;
7508 }
7509 return(ret);
7510}
7511
7512/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007513 * xmlRelaxNGAttributeMatch:
7514 * @ctxt: a Relax-NG validation context
7515 * @define: the definition to check
7516 * @prop: the attribute
7517 *
7518 * Check if the attribute matches the definition nameClass
7519 *
7520 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7521 */
7522static int
7523xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7524 xmlRelaxNGDefinePtr define,
7525 xmlAttrPtr prop) {
7526 int ret;
7527
7528 if (define->name != NULL) {
7529 if (!xmlStrEqual(define->name, prop->name))
7530 return(0);
7531 }
7532 if (define->ns != NULL) {
7533 if (define->ns[0] == 0) {
7534 if (prop->ns != NULL)
7535 return(0);
7536 } else {
7537 if ((prop->ns == NULL) ||
7538 (!xmlStrEqual(define->ns, prop->ns->href)))
7539 return(0);
7540 }
7541 }
7542 if (define->nameClass == NULL)
7543 return(1);
7544 define = define->nameClass;
7545 if (define->type == XML_RELAXNG_EXCEPT) {
7546 xmlRelaxNGDefinePtr list;
7547
7548 list = define->content;
7549 while (list != NULL) {
7550 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7551 if (ret == 1)
7552 return(0);
7553 if (ret < 0)
7554 return(ret);
7555 list = list->next;
7556 }
7557 } else {
7558 TODO
7559 }
7560 return(1);
7561}
7562
7563/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007564 * xmlRelaxNGValidateAttribute:
7565 * @ctxt: a Relax-NG validation context
7566 * @define: the definition to verify
7567 *
7568 * Validate the given attribute definition for that node
7569 *
7570 * Returns 0 if the validation succeeded or an error code.
7571 */
7572static int
7573xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7574 xmlRelaxNGDefinePtr define) {
7575 int ret = 0, i;
7576 xmlChar *value, *oldvalue;
7577 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007578 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007579
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007580 if (ctxt->state->nbAttrLeft <= 0)
7581 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007582 if (define->name != NULL) {
7583 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7584 tmp = ctxt->state->attrs[i];
7585 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7586 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7587 (tmp->ns == NULL)) ||
7588 ((tmp->ns != NULL) &&
7589 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7590 prop = tmp;
7591 break;
7592 }
7593 }
7594 }
7595 if (prop != NULL) {
7596 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7597 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007598 oldseq = ctxt->state->seq;
7599 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007600 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007601 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007602 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007603 if (ctxt->state->value != NULL)
7604 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007605 if (value != NULL)
7606 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007607 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007608 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007609 if (ret == 0) {
7610 /*
7611 * flag the attribute as processed
7612 */
7613 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007614 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007615 }
7616 } else {
7617 ret = -1;
7618 }
7619#ifdef DEBUG
7620 xmlGenericError(xmlGenericErrorContext,
7621 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7622#endif
7623 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007624 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7625 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007626 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007627 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007628 prop = tmp;
7629 break;
7630 }
7631 }
7632 if (prop != NULL) {
7633 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7634 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007635 oldseq = ctxt->state->seq;
7636 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007637 ctxt->state->value = value;
7638 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007639 if (ctxt->state->value != NULL)
7640 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007641 if (value != NULL)
7642 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007643 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007644 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007645 if (ret == 0) {
7646 /*
7647 * flag the attribute as processed
7648 */
7649 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007650 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007651 }
7652 } else {
7653 ret = -1;
7654 }
7655#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007656 if (define->ns != NULL) {
7657 xmlGenericError(xmlGenericErrorContext,
7658 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7659 define->ns, ret);
7660 } else {
7661 xmlGenericError(xmlGenericErrorContext,
7662 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7663 ret);
7664 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007665#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007666 }
7667
7668 return(ret);
7669}
7670
7671/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007672 * xmlRelaxNGValidateAttributeList:
7673 * @ctxt: a Relax-NG validation context
7674 * @define: the list of definition to verify
7675 *
7676 * Validate the given node against the list of attribute definitions
7677 *
7678 * Returns 0 if the validation succeeded or an error code.
7679 */
7680static int
7681xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7682 xmlRelaxNGDefinePtr defines) {
7683 int ret = 0;
7684 while (defines != NULL) {
7685 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7686 ret = -1;
7687 defines = defines->next;
7688 }
7689 return(ret);
7690}
7691
7692/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007693 * xmlRelaxNGNodeMatchesList:
7694 * @node: the node
7695 * @list: a NULL terminated array of definitions
7696 *
7697 * Check if a node can be matched by one of the definitions
7698 *
7699 * Returns 1 if matches 0 otherwise
7700 */
7701static int
7702xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7703 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007704 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007705
7706 if ((node == NULL) || (list == NULL))
7707 return(0);
7708
7709 cur = list[i++];
7710 while (cur != NULL) {
7711 if ((node->type == XML_ELEMENT_NODE) &&
7712 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007713 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
7714 if (tmp == 1)
7715 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007716 } else if (((node->type == XML_TEXT_NODE) ||
7717 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007718 (cur->type == XML_RELAXNG_TEXT)) {
7719 return(1);
7720 }
7721 cur = list[i++];
7722 }
7723 return(0);
7724}
7725
7726/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007727 * xmlRelaxNGValidateInterleave:
7728 * @ctxt: a Relax-NG validation context
7729 * @define: the definition to verify
7730 *
7731 * Validate an interleave definition for a node.
7732 *
7733 * Returns 0 if the validation succeeded or an error code.
7734 */
7735static int
7736xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7737 xmlRelaxNGDefinePtr define) {
7738 int ret = 0, i, nbgroups, left;
7739 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007740 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007741
7742 xmlRelaxNGValidStatePtr oldstate;
7743 xmlRelaxNGPartitionPtr partitions;
7744 xmlRelaxNGInterleaveGroupPtr group = NULL;
7745 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7746 xmlNodePtr *list = NULL, *lasts = NULL;
7747
7748 if (define->data != NULL) {
7749 partitions = (xmlRelaxNGPartitionPtr) define->data;
7750 nbgroups = partitions->nbgroups;
7751 left = nbgroups;
7752 } else {
7753 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7754 return(-1);
7755 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007756 /*
7757 * Optimizations for MIXED
7758 */
7759 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00007760 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007761 ctxt->flags |= FLAGS_MIXED_CONTENT;
7762 if (nbgroups == 2) {
7763 /*
7764 * this is a pure <mixed> case
7765 */
7766 if (ctxt->state != NULL)
7767 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7768 ctxt->state->seq);
7769 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
7770 ret = xmlRelaxNGValidateDefinition(ctxt,
7771 partitions->groups[1]->rule);
7772 else
7773 ret = xmlRelaxNGValidateDefinition(ctxt,
7774 partitions->groups[0]->rule);
7775 if (ret == 0) {
7776 if (ctxt->state != NULL)
7777 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7778 ctxt->state->seq);
7779 }
7780 ctxt->flags = oldflags;
7781 return(ret);
7782 }
7783 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007784
7785 /*
7786 * Build arrays to store the first and last node of the chain
7787 * pertaining to each group
7788 */
7789 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7790 if (list == NULL) {
7791 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7792 return(-1);
7793 }
7794 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7795 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7796 if (lasts == NULL) {
7797 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7798 return(-1);
7799 }
7800 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7801
7802 /*
7803 * Walk the sequence of children finding the right group and
7804 * sorting them in sequences.
7805 */
7806 cur = ctxt->state->seq;
7807 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7808 start = cur;
7809 while (cur != NULL) {
7810 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007811 if ((partitions->triage != NULL) &&
7812 (partitions->flags & IS_DETERMINIST)) {
7813 void *tmp = NULL;
7814
7815 if ((cur->type == XML_TEXT_NODE) ||
7816 (cur->type == XML_CDATA_SECTION_NODE)) {
7817 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
7818 NULL);
7819 } else if (cur->type == XML_ELEMENT_NODE) {
7820 if (cur->ns != NULL) {
7821 tmp = xmlHashLookup2(partitions->triage, cur->name,
7822 cur->ns->href);
7823 if (tmp == NULL)
7824 tmp = xmlHashLookup2(partitions->triage,
7825 BAD_CAST "#any", cur->ns->href);
7826 } else
7827 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
7828 if (tmp == NULL)
7829 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
7830 NULL);
7831 }
7832
7833 if (tmp == NULL) {
7834 i = nbgroups;
7835 } else {
7836 i = ((long) tmp) - 1;
7837 if (partitions->flags & IS_NEEDCHECK) {
7838 group = partitions->groups[i];
7839 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
7840 i = nbgroups;
7841 }
7842 }
7843 } else {
7844 for (i = 0;i < nbgroups;i++) {
7845 group = partitions->groups[i];
7846 if (group == NULL)
7847 continue;
7848 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7849 break;
7850 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007851 }
7852 /*
7853 * We break as soon as an element not matched is found
7854 */
7855 if (i >= nbgroups) {
7856 break;
7857 }
7858 if (lasts[i] != NULL) {
7859 lasts[i]->next = cur;
7860 lasts[i] = cur;
7861 } else {
7862 list[i] = cur;
7863 lasts[i] = cur;
7864 }
7865 if (cur->next != NULL)
7866 lastchg = cur->next;
7867 else
7868 lastchg = cur;
7869 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7870 }
7871 if (ret != 0) {
7872 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7873 ret = -1;
7874 goto done;
7875 }
7876 lastelem = cur;
7877 oldstate = ctxt->state;
7878 for (i = 0;i < nbgroups;i++) {
7879 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7880 group = partitions->groups[i];
7881 if (lasts[i] != NULL) {
7882 last = lasts[i]->next;
7883 lasts[i]->next = NULL;
7884 }
7885 ctxt->state->seq = list[i];
7886 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7887 if (ret != 0)
7888 break;
7889 if (ctxt->state != NULL) {
7890 cur = ctxt->state->seq;
7891 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00007892 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007893 oldstate = ctxt->state;
7894 ctxt->state = NULL;
7895 if (cur != NULL) {
7896 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7897 ret = -1;
7898 ctxt->state = oldstate;
7899 goto done;
7900 }
7901 } else if (ctxt->states != NULL) {
7902 int j;
7903 int found = 0;
7904
7905 for (j = 0;j < ctxt->states->nbState;j++) {
7906 cur = ctxt->states->tabState[j]->seq;
7907 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7908 if (cur == NULL) {
7909 found = 1;
7910 break;
7911 }
7912 }
7913 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007914 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007915 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7916 }
7917 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007918 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007919 }
7920 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7921 ctxt->states = NULL;
7922 if (found == 0) {
7923 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7924 ret = -1;
7925 ctxt->state = oldstate;
7926 goto done;
7927 }
7928 } else {
7929 ret = -1;
7930 break;
7931 }
7932 if (lasts[i] != NULL) {
7933 lasts[i]->next = last;
7934 }
7935 }
7936 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00007937 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007938 ctxt->state = oldstate;
7939 ctxt->state->seq = lastelem;
7940 if (ret != 0) {
7941 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7942 ret = -1;
7943 goto done;
7944 }
7945
7946done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007947 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007948 /*
7949 * builds the next links chain from the prev one
7950 */
7951 cur = lastchg;
7952 while (cur != NULL) {
7953 if ((cur == start) || (cur->prev == NULL))
7954 break;
7955 cur->prev->next = cur;
7956 cur = cur->prev;
7957 }
7958 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007959 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007960 }
7961
7962 xmlFree(list);
7963 xmlFree(lasts);
7964 return(ret);
7965}
7966
7967/**
7968 * xmlRelaxNGValidateDefinitionList:
7969 * @ctxt: a Relax-NG validation context
7970 * @define: the list of definition to verify
7971 *
7972 * Validate the given node content against the (list) of definitions
7973 *
7974 * Returns 0 if the validation succeeded or an error code.
7975 */
7976static int
7977xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
7978 xmlRelaxNGDefinePtr defines) {
7979 int ret = 0, res;
7980
7981
Daniel Veillard952379b2003-03-17 15:37:12 +00007982 if (defines == NULL) {
7983 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
7984 return(-1);
7985 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007986 while (defines != NULL) {
7987 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
7988 res = xmlRelaxNGValidateDefinition(ctxt, defines);
7989 if (res < 0)
7990 ret = -1;
7991 } else {
7992 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
7993 return(-1);
7994 }
7995 if (ret < 0)
7996 break;
7997 defines = defines->next;
7998 }
7999
8000 return(ret);
8001}
8002
8003/**
8004 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00008005 * @ctxt: a Relax-NG validation context
8006 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00008007 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00008008 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008009 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00008010 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008011 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00008012 */
8013static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008014xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
8015 xmlRelaxNGDefinePtr define,
8016 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008017 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008018
Daniel Veillardfd573f12003-03-16 17:52:32 +00008019 if (define->name != NULL) {
8020 if (!xmlStrEqual(elem->name, define->name)) {
8021 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
8022 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008023 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008024 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008025 if ((define->ns != NULL) && (define->ns[0] != 0)) {
8026 if (elem->ns == NULL) {
8027 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
8028 elem->name);
8029 return(0);
8030 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
8031 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
8032 elem->name, define->ns);
8033 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008034 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008035 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
8036 (define->name == NULL)) {
8037 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8038 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008039 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008040 } else if ((elem->ns != NULL) && (define->name != NULL)) {
8041 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8042 define->name);
8043 return(0);
8044 }
8045
8046 if (define->nameClass == NULL)
8047 return(1);
8048
8049 define = define->nameClass;
8050 if (define->type == XML_RELAXNG_EXCEPT) {
8051 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008052 if (ctxt != NULL) {
8053 oldflags = ctxt->flags;
8054 ctxt->flags |= FLAGS_IGNORABLE;
8055 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008056
8057 list = define->content;
8058 while (list != NULL) {
8059 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8060 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008061 if (ctxt != NULL)
8062 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008063 return(0);
8064 }
8065 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008066 if (ctxt != NULL)
8067 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008068 return(ret);
8069 }
8070 list = list->next;
8071 }
8072 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008073 if (ctxt != NULL) {
8074 ctxt->flags = oldflags;
8075 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008076 } else if (define->type == XML_RELAXNG_CHOICE) {
8077 xmlRelaxNGDefinePtr list;
8078
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008079 if (ctxt != NULL) {
8080 oldflags = ctxt->flags;
8081 ctxt->flags |= FLAGS_IGNORABLE;
8082 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008083
8084 list = define->nameClass;
8085 while (list != NULL) {
8086 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8087 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008088 if (ctxt != NULL)
8089 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008090 return(1);
8091 }
8092 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008093 if (ctxt != NULL)
8094 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008095 return(ret);
8096 }
8097 list = list->next;
8098 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008099 if (ctxt != NULL) {
8100 if (ret != 0) {
8101 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8102 xmlRelaxNGDumpValidError(ctxt);
8103 } else {
8104 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8105 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008106 }
8107 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008108 if (ctxt != NULL) {
8109 ctxt->flags = oldflags;
8110 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008111 } else {
8112 TODO
8113 ret = -1;
8114 }
8115 return(ret);
8116}
8117
8118/**
8119 * xmlRelaxNGValidateElementEnd:
8120 * @ctxt: a Relax-NG validation context
8121 *
8122 * Validate the end of the element, implements check that
8123 * there is nothing left not consumed in the element content
8124 * or in the attribute list.
8125 *
8126 * Returns 0 if the validation succeeded or an error code.
8127 */
8128static int
8129xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
8130 int ret = 0, i;
8131 xmlRelaxNGValidStatePtr state;
8132
8133 state = ctxt->state;
8134 if (state->seq != NULL) {
8135 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
8136 if (state->seq != NULL) {
8137 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
8138 state->node->name, state->seq->name);
8139 ret = -1;
8140 }
8141 }
8142 for (i = 0;i < state->nbAttrs;i++) {
8143 if (state->attrs[i] != NULL) {
8144 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
8145 state->attrs[i]->name, state->node->name);
8146 ret = -1;
8147 }
8148 }
8149 return(ret);
8150}
8151
8152/**
8153 * xmlRelaxNGValidateState:
8154 * @ctxt: a Relax-NG validation context
8155 * @define: the definition to verify
8156 *
8157 * Validate the current state against the definition
8158 *
8159 * Returns 0 if the validation succeeded or an error code.
8160 */
8161static int
8162xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
8163 xmlRelaxNGDefinePtr define) {
8164 xmlNodePtr node;
8165 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008166 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008167
8168 if (define == NULL) {
8169 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8170 return(-1);
8171 }
8172
8173 if (ctxt->state != NULL) {
8174 node = ctxt->state->seq;
8175 } else {
8176 node = NULL;
8177 }
8178#ifdef DEBUG
8179 for (i = 0;i < ctxt->depth;i++)
8180 xmlGenericError(xmlGenericErrorContext, " ");
8181 xmlGenericError(xmlGenericErrorContext,
8182 "Start validating %s ", xmlRelaxNGDefName(define));
8183 if (define->name != NULL)
8184 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8185 if ((node != NULL) && (node->name != NULL))
8186 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
8187 else
8188 xmlGenericError(xmlGenericErrorContext, "\n");
8189#endif
8190 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008191 switch (define->type) {
8192 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008193 node = xmlRelaxNGSkipIgnored(ctxt, node);
8194 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008195 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008196 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008197 ret = -1;
8198 break;
8199 case XML_RELAXNG_TEXT:
8200 while ((node != NULL) &&
8201 ((node->type == XML_TEXT_NODE) ||
8202 (node->type == XML_COMMENT_NODE) ||
8203 (node->type == XML_PI_NODE) ||
8204 (node->type == XML_CDATA_SECTION_NODE)))
8205 node = node->next;
8206 ctxt->state->seq = node;
8207 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008208 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008209 errNr = ctxt->errNr;
8210 node = xmlRelaxNGSkipIgnored(ctxt, node);
8211 if (node == NULL) {
8212 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
8213 ret = -1;
8214 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8215 xmlRelaxNGDumpValidError(ctxt);
8216 break;
8217 }
8218 if (node->type != XML_ELEMENT_NODE) {
8219 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8220 ret = -1;
8221 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8222 xmlRelaxNGDumpValidError(ctxt);
8223 break;
8224 }
8225 /*
8226 * This node was already validated successfully against
8227 * this definition.
8228 */
8229 if (node->_private == define) {
8230 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillard580ced82003-03-21 21:22:48 +00008231 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008232 if (ctxt->errNr != 0) {
8233 while ((ctxt->err != NULL) &&
8234 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8235 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008236 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8237 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008238 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8239 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8240 xmlRelaxNGValidErrorPop(ctxt);
8241 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008242 break;
8243 }
8244
8245 ret = xmlRelaxNGElementMatch(ctxt, define, node);
8246 if (ret <= 0) {
8247 ret = -1;
8248 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8249 xmlRelaxNGDumpValidError(ctxt);
8250 break;
8251 }
8252 ret = 0;
8253 if (ctxt->errNr != 0) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008254 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008255 while ((ctxt->err != NULL) &&
8256 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8257 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008258 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8259 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00008260 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8261 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8262 xmlRelaxNGValidErrorPop(ctxt);
8263 }
8264 errNr = ctxt->errNr;
8265
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008266 oldflags = ctxt->flags;
8267 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
8268 ctxt->flags -= FLAGS_MIXED_CONTENT;
8269 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008270 state = xmlRelaxNGNewValidState(ctxt, node);
8271 if (state == NULL) {
8272 ret = -1;
8273 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8274 xmlRelaxNGDumpValidError(ctxt);
8275 break;
8276 }
8277
8278 oldstate = ctxt->state;
8279 ctxt->state = state;
8280 if (define->attrs != NULL) {
8281 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8282 if (tmp != 0) {
8283 ret = -1;
8284 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8285 }
8286 }
8287 if (define->content != NULL) {
8288 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8289 if (tmp != 0) {
8290 ret = -1;
8291 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
8292 }
8293 }
8294 if (ctxt->states != NULL) {
8295 tmp = -1;
8296
Daniel Veillardfd573f12003-03-16 17:52:32 +00008297 ctxt->flags |= FLAGS_IGNORABLE;
8298
8299 for (i = 0;i < ctxt->states->nbState;i++) {
8300 state = ctxt->states->tabState[i];
8301 ctxt->state = state;
8302
8303 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
8304 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008305 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008306 }
8307 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8308 ctxt->flags = oldflags;
8309 ctxt->states = NULL;
8310 if ((ret == 0) && (tmp == -1))
8311 ret = -1;
8312 } else {
8313 state = ctxt->state;
8314 if (ret == 0)
8315 ret = xmlRelaxNGValidateElementEnd(ctxt);
Daniel Veillard798024a2003-03-19 10:36:09 +00008316 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008317 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008318 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008319 ctxt->state = oldstate;
8320 if (oldstate != NULL)
8321 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
8322 if (ret == 0) {
8323 node->_private = define;
8324 }
8325 if (ret != 0) {
8326 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8327 xmlRelaxNGDumpValidError(ctxt);
8328 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008329 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008330 }
8331
8332#ifdef DEBUG
8333 xmlGenericError(xmlGenericErrorContext,
8334 "xmlRelaxNGValidateDefinition(): validated %s : %d",
8335 node->name, ret);
8336 if (oldstate == NULL)
8337 xmlGenericError(xmlGenericErrorContext, ": no state\n");
8338 else if (oldstate->seq == NULL)
8339 xmlGenericError(xmlGenericErrorContext, ": done\n");
8340 else if (oldstate->seq->type == XML_ELEMENT_NODE)
8341 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
8342 oldstate->seq->name);
8343 else
8344 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
8345 oldstate->seq->name, oldstate->seq->type);
8346#endif
8347 break;
8348 case XML_RELAXNG_OPTIONAL: {
8349 oldflags = ctxt->flags;
8350 ctxt->flags |= FLAGS_IGNORABLE;
8351 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8352 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8353 if (ret != 0) {
8354 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008355 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008356 ctxt->state = oldstate;
8357 ctxt->flags = oldflags;
8358 ret = 0;
8359 break;
8360 }
8361 if (ctxt->states != NULL) {
8362 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8363 } else {
8364 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
8365 if (ctxt->states == NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008366 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008367 ctxt->flags = oldflags;
8368 ret = -1;
8369 break;
8370 }
8371 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8372 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
8373 ctxt->state = NULL;
8374 }
8375 ctxt->flags = oldflags;
8376 ret = 0;
8377 break;
8378 }
8379 case XML_RELAXNG_ONEORMORE:
8380 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8381 if (ret != 0) {
8382 break;
8383 }
8384 /* no break on purpose */
8385 case XML_RELAXNG_ZEROORMORE: {
8386 int progress;
8387 xmlRelaxNGStatesPtr states = NULL, res = NULL;
8388 int base, j;
8389
8390 res = xmlRelaxNGNewStates(ctxt, 1);
8391 if (res == NULL) {
8392 ret = -1;
8393 break;
8394 }
8395 /*
8396 * All the input states are also exit states
8397 */
8398 if (ctxt->state != NULL) {
8399 xmlRelaxNGAddStates(ctxt, res,
8400 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
8401 } else {
8402 for (j = 0;j < ctxt->states->nbState;j++) {
8403 xmlRelaxNGAddStates(ctxt, res,
8404 xmlRelaxNGCopyValidState(ctxt,
8405 ctxt->states->tabState[j]));
8406 }
8407 }
8408 oldflags = ctxt->flags;
8409 ctxt->flags |= FLAGS_IGNORABLE;
8410 do {
8411 progress = 0;
8412 base = res->nbState;
8413
8414 if (ctxt->states != NULL) {
8415 states = ctxt->states;
8416 for (i = 0;i < states->nbState;i++) {
8417 ctxt->state = states->tabState[i];
8418 ctxt->states = NULL;
8419 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8420 define->content);
8421 if (ret == 0) {
8422 if (ctxt->state != NULL) {
8423 tmp = xmlRelaxNGAddStates(ctxt, res,
8424 ctxt->state);
8425 ctxt->state = NULL;
8426 if (tmp == 1)
8427 progress = 1;
8428 } else if (ctxt->states != NULL) {
8429 for (j = 0;j < ctxt->states->nbState;j++) {
8430 tmp = xmlRelaxNGAddStates(ctxt, res,
8431 ctxt->states->tabState[j]);
8432 if (tmp == 1)
8433 progress = 1;
8434 }
8435 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8436 ctxt->states = NULL;
8437 }
8438 } else {
8439 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008440 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008441 ctxt->state = NULL;
8442 }
8443 }
8444 }
8445 } else {
8446 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8447 define->content);
8448 if (ret != 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008449 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008450 ctxt->state = NULL;
8451 } else {
8452 base = res->nbState;
8453 if (ctxt->state != NULL) {
8454 tmp = xmlRelaxNGAddStates(ctxt, res,
8455 ctxt->state);
8456 ctxt->state = NULL;
8457 if (tmp == 1)
8458 progress = 1;
8459 } else if (ctxt->states != NULL) {
8460 for (j = 0;j < ctxt->states->nbState;j++) {
8461 tmp = xmlRelaxNGAddStates(ctxt, res,
8462 ctxt->states->tabState[j]);
8463 if (tmp == 1)
8464 progress = 1;
8465 }
8466 if (states == NULL) {
8467 states = ctxt->states;
8468 } else {
8469 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8470 }
8471 ctxt->states = NULL;
8472 }
8473 }
8474 }
8475 if (progress) {
8476 /*
8477 * Collect all the new nodes added at that step
8478 * and make them the new node set
8479 */
8480 if (res->nbState - base == 1) {
8481 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
8482 res->tabState[base]);
8483 } else {
8484 if (states == NULL) {
8485 xmlRelaxNGNewStates(ctxt, res->nbState - base);
8486 }
8487 states->nbState = 0;
8488 for (i = base;i < res->nbState;i++)
8489 xmlRelaxNGAddStates(ctxt, states,
8490 xmlRelaxNGCopyValidState(ctxt,
8491 res->tabState[i]));
8492 ctxt->states = states;
8493 }
8494 }
8495 } while (progress == 1);
8496 if (states != NULL) {
8497 xmlRelaxNGFreeStates(ctxt, states);
8498 }
8499 ctxt->states = res;
8500 ctxt->flags = oldflags;
8501 ret = 0;
8502 break;
8503 }
8504 case XML_RELAXNG_CHOICE: {
Daniel Veillard580ced82003-03-21 21:22:48 +00008505 xmlRelaxNGDefinePtr list = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008506 xmlRelaxNGStatesPtr states = NULL;
8507
Daniel Veillarde063f482003-03-21 16:53:17 +00008508 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008509
Daniel Veillarde063f482003-03-21 16:53:17 +00008510 if ((define->dflags & IS_TRIABLE) && (define->data != NULL)) {
8511 xmlHashTablePtr triage = (xmlHashTablePtr) define->data;
8512
8513 /*
8514 * Something we can optimize cleanly there is only one
8515 * possble branch out !
8516 */
8517 if (node == NULL) {
8518 ret = -1;
8519 break;
8520 }
8521 if ((node->type == XML_TEXT_NODE) ||
8522 (node->type == XML_CDATA_SECTION_NODE)) {
8523 list = xmlHashLookup2(triage, BAD_CAST "#text", NULL);
8524 } else if (node->type == XML_ELEMENT_NODE) {
8525 if (node->ns != NULL) {
8526 list = xmlHashLookup2(triage, node->name,
8527 node->ns->href);
8528 if (list == NULL)
8529 list = xmlHashLookup2(triage, BAD_CAST "#any",
8530 node->ns->href);
8531 } else
8532 list = xmlHashLookup2(triage, node->name, NULL);
8533 if (list == NULL)
8534 list = xmlHashLookup2(triage, BAD_CAST "#any", NULL);
8535 }
8536 if (list == NULL) {
8537 ret = -1;
8538 break;
8539 }
8540 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8541 break;
8542 }
8543
8544 list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008545 oldflags = ctxt->flags;
8546 errNr = ctxt->errNr;
8547 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008548
8549 while (list != NULL) {
8550 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8551 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8552 if (ret == 0) {
8553 if (states == NULL) {
8554 states = xmlRelaxNGNewStates(ctxt, 1);
8555 }
8556 if (ctxt->state != NULL) {
8557 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8558 } else if (ctxt->states != NULL) {
8559 for (i = 0;i < ctxt->states->nbState;i++) {
8560 xmlRelaxNGAddStates(ctxt, states,
8561 ctxt->states->tabState[i]);
8562 }
8563 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8564 ctxt->states = NULL;
8565 }
8566 } else {
Daniel Veillard798024a2003-03-19 10:36:09 +00008567 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008568 }
8569 ctxt->state = oldstate;
8570 list = list->next;
8571 }
8572 if (states != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008573 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008574 ctxt->states = states;
8575 ctxt->state = NULL;
8576 ret = 0;
8577 } else {
8578 ctxt->states = NULL;
8579 }
8580 ctxt->flags = oldflags;
8581 if (ret != 0) {
8582 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8583 xmlRelaxNGDumpValidError(ctxt);
8584 } else if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008585 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008586 }
8587 break;
8588 }
8589 case XML_RELAXNG_DEF:
8590 case XML_RELAXNG_GROUP:
8591 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008592 break;
8593 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008594 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008595 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008596 case XML_RELAXNG_ATTRIBUTE:
8597 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8598 break;
8599 case XML_RELAXNG_NOOP:
8600 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008601 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008602 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8603 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008604 case XML_RELAXNG_PARENTREF:
8605 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8606 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008607 case XML_RELAXNG_DATATYPE: {
8608 xmlNodePtr child;
8609 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008610
Daniel Veillardfd573f12003-03-16 17:52:32 +00008611 child = node;
8612 while (child != NULL) {
8613 if (child->type == XML_ELEMENT_NODE) {
8614 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8615 node->parent->name);
8616 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008617 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008618 } else if ((child->type == XML_TEXT_NODE) ||
8619 (child->type == XML_CDATA_SECTION_NODE)) {
8620 content = xmlStrcat(content, child->content);
8621 }
8622 /* TODO: handle entities ... */
8623 child = child->next;
8624 }
8625 if (ret == -1) {
8626 if (content != NULL)
8627 xmlFree(content);
8628 break;
8629 }
8630 if (content == NULL) {
8631 content = xmlStrdup(BAD_CAST "");
8632 if (content == NULL) {
8633 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8634 ret = -1;
8635 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008636 }
8637 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008638 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8639 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008640 if (ret == -1) {
8641 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8642 } else if (ret == 0) {
8643 ctxt->state->seq = NULL;
8644 }
8645 if (content != NULL)
8646 xmlFree(content);
8647 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008648 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008649 case XML_RELAXNG_VALUE: {
8650 xmlChar *content = NULL;
8651 xmlChar *oldvalue;
8652 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008653
Daniel Veillardfd573f12003-03-16 17:52:32 +00008654 child = node;
8655 while (child != NULL) {
8656 if (child->type == XML_ELEMENT_NODE) {
8657 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8658 node->parent->name);
8659 ret = -1;
8660 break;
8661 } else if ((child->type == XML_TEXT_NODE) ||
8662 (child->type == XML_CDATA_SECTION_NODE)) {
8663 content = xmlStrcat(content, child->content);
8664 }
8665 /* TODO: handle entities ... */
8666 child = child->next;
8667 }
8668 if (ret == -1) {
8669 if (content != NULL)
8670 xmlFree(content);
8671 break;
8672 }
8673 if (content == NULL) {
8674 content = xmlStrdup(BAD_CAST "");
8675 if (content == NULL) {
8676 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8677 ret = -1;
8678 break;
8679 }
8680 }
8681 oldvalue = ctxt->state->value;
8682 ctxt->state->value = content;
8683 ret = xmlRelaxNGValidateValue(ctxt, define);
8684 ctxt->state->value = oldvalue;
8685 if (ret == -1) {
8686 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8687 } else if (ret == 0) {
8688 ctxt->state->seq = NULL;
8689 }
8690 if (content != NULL)
8691 xmlFree(content);
8692 break;
8693 }
8694 case XML_RELAXNG_LIST: {
8695 xmlChar *content;
8696 xmlNodePtr child;
8697 xmlChar *oldvalue, *oldendvalue;
8698 int len;
8699
8700 /*
8701 * Make sure it's only text nodes
8702 */
8703
8704 content = NULL;
8705 child = node;
8706 while (child != NULL) {
8707 if (child->type == XML_ELEMENT_NODE) {
8708 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8709 node->parent->name);
8710 ret = -1;
8711 break;
8712 } else if ((child->type == XML_TEXT_NODE) ||
8713 (child->type == XML_CDATA_SECTION_NODE)) {
8714 content = xmlStrcat(content, child->content);
8715 }
8716 /* TODO: handle entities ... */
8717 child = child->next;
8718 }
8719 if (ret == -1) {
8720 if (content != NULL)
8721 xmlFree(content);
8722 break;
8723 }
8724 if (content == NULL) {
8725 content = xmlStrdup(BAD_CAST "");
8726 if (content == NULL) {
8727 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8728 ret = -1;
8729 break;
8730 }
8731 }
8732 len = xmlStrlen(content);
8733 oldvalue = ctxt->state->value;
8734 oldendvalue = ctxt->state->endvalue;
8735 ctxt->state->value = content;
8736 ctxt->state->endvalue = content + len;
8737 ret = xmlRelaxNGValidateValue(ctxt, define);
8738 ctxt->state->value = oldvalue;
8739 ctxt->state->endvalue = oldendvalue;
8740 if (ret == -1) {
8741 VALID_ERR(XML_RELAXNG_ERR_LIST);
8742 } else if ((ret == 0) && (node != NULL)) {
8743 ctxt->state->seq = node->next;
8744 }
8745 if (content != NULL)
8746 xmlFree(content);
8747 break;
8748 }
8749 case XML_RELAXNG_START:
8750 case XML_RELAXNG_EXCEPT:
8751 case XML_RELAXNG_PARAM:
8752 TODO
8753 ret = -1;
8754 break;
8755 }
8756 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008757#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008758 for (i = 0;i < ctxt->depth;i++)
8759 xmlGenericError(xmlGenericErrorContext, " ");
8760 xmlGenericError(xmlGenericErrorContext,
8761 "Validating %s ", xmlRelaxNGDefName(define));
8762 if (define->name != NULL)
8763 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8764 if (ret == 0)
8765 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8766 else
8767 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008768#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008769 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008770}
8771
8772/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008773 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008774 * @ctxt: a Relax-NG validation context
8775 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008776 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008777 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008778 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008779 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008780 */
8781static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008782xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8783 xmlRelaxNGDefinePtr define) {
8784 xmlRelaxNGStatesPtr states, res;
8785 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008786
Daniel Veillardfd573f12003-03-16 17:52:32 +00008787 /*
8788 * We should NOT have both ctxt->state and ctxt->states
8789 */
8790 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8791 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008792 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008793 ctxt->state = NULL;
8794 }
8795
8796 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8797 if (ctxt->states != NULL) {
8798 ctxt->state = ctxt->states->tabState[0];
8799 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8800 ctxt->states = NULL;
8801 }
8802 ret = xmlRelaxNGValidateState(ctxt, define);
8803 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8804 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008805 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008806 ctxt->state = NULL;
8807 }
8808 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8809 ctxt->state = ctxt->states->tabState[0];
8810 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8811 ctxt->states = NULL;
8812 }
8813 return(ret);
8814 }
8815
8816 states = ctxt->states;
8817 ctxt->states = NULL;
8818 res = NULL;
8819 j = 0;
8820 oldflags = ctxt->flags;
8821 ctxt->flags |= FLAGS_IGNORABLE;
8822 for (i = 0;i < states->nbState;i++) {
8823 ctxt->state = states->tabState[i];
8824 ctxt->states = NULL;
8825 ret = xmlRelaxNGValidateState(ctxt, define);
8826 /*
8827 * We should NOT have both ctxt->state and ctxt->states
8828 */
8829 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8830 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008831 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008832 ctxt->state = NULL;
8833 }
8834 if (ret == 0) {
8835 if (ctxt->states == NULL) {
8836 if (res != NULL) {
8837 /* add the state to the container */
8838 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8839 ctxt->state = NULL;
8840 } else {
8841 /* add the state directly in states */
8842 states->tabState[j++] = ctxt->state;
8843 ctxt->state = NULL;
8844 }
8845 } else {
8846 if (res == NULL) {
8847 /* make it the new container and copy other results */
8848 res = ctxt->states;
8849 ctxt->states = NULL;
8850 for (k = 0;k < j;k++)
8851 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8852 } else {
8853 /* add all the new results to res and reff the container */
8854 for (k = 0;k < ctxt->states->nbState;k++)
8855 xmlRelaxNGAddStates(ctxt, res,
8856 ctxt->states->tabState[k]);
8857 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8858 ctxt->states = NULL;
8859 }
8860 }
8861 } else {
8862 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008863 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008864 ctxt->state = NULL;
8865 } else if (ctxt->states != NULL) {
8866 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00008867 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008868 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8869 ctxt->states = NULL;
8870 }
8871 }
8872 }
8873 ctxt->flags = oldflags;
8874 if (res != NULL) {
8875 xmlRelaxNGFreeStates(ctxt, states);
8876 ctxt->states = res;
8877 ret = 0;
8878 } else if (j > 1) {
8879 states->nbState = j;
8880 ctxt->states = states;
8881 ret =0;
8882 } else if (j == 1) {
8883 ctxt->state = states->tabState[0];
8884 xmlRelaxNGFreeStates(ctxt, states);
8885 ret = 0;
8886 } else {
8887 ret = -1;
8888 xmlRelaxNGFreeStates(ctxt, states);
8889 if (ctxt->states != NULL) {
8890 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8891 ctxt->states = NULL;
8892 }
8893 }
8894 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8895 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008896 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008897 ctxt->state = NULL;
8898 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008899 return(ret);
8900}
8901
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008902/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008903 * xmlRelaxNGValidateDocument:
8904 * @ctxt: a Relax-NG validation context
8905 * @doc: the document
8906 *
8907 * Validate the given document
8908 *
8909 * Returns 0 if the validation succeeded or an error code.
8910 */
8911static int
8912xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8913 int ret;
8914 xmlRelaxNGPtr schema;
8915 xmlRelaxNGGrammarPtr grammar;
8916 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008917 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008918
8919 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8920 return(-1);
8921
8922 schema = ctxt->schema;
8923 grammar = schema->topgrammar;
8924 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008925 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008926 return(-1);
8927 }
8928 state = xmlRelaxNGNewValidState(ctxt, NULL);
8929 ctxt->state = state;
8930 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008931 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8932 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008933 node = state->seq;
8934 node = xmlRelaxNGSkipIgnored(ctxt, node);
8935 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008936 if (ret != -1) {
8937 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8938 ret = -1;
8939 }
8940 }
8941 } else if (ctxt->states != NULL) {
8942 int i;
8943 int tmp = -1;
8944
8945 for (i = 0;i < ctxt->states->nbState;i++) {
8946 state = ctxt->states->tabState[i];
8947 node = state->seq;
8948 node = xmlRelaxNGSkipIgnored(ctxt, node);
8949 if (node == NULL)
8950 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008951 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008952 }
8953 if (tmp == -1) {
8954 if (ret != -1) {
8955 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8956 ret = -1;
8957 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008958 }
8959 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008960 if (ctxt->state != NULL) {
8961 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8962 ctxt->state = NULL;
8963 }
Daniel Veillard580ced82003-03-21 21:22:48 +00008964 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +00008965 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +00008966#ifdef DEBUG
8967 else if (ctxt->errNr != 0) {
8968 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
8969 ctxt->errNr);
8970 xmlRelaxNGDumpValidError(ctxt);
8971 }
8972#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008973 if (ctxt->idref == 1) {
8974 xmlValidCtxt vctxt;
8975
8976 memset(&vctxt, 0, sizeof(xmlValidCtxt));
8977 vctxt.valid = 1;
8978 vctxt.error = ctxt->error;
8979 vctxt.warning = ctxt->warning;
8980 vctxt.userData = ctxt->userData;
8981
8982 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
8983 ret = -1;
8984 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008985
8986 return(ret);
8987}
8988
Daniel Veillardfd573f12003-03-16 17:52:32 +00008989/************************************************************************
8990 * *
8991 * Validation interfaces *
8992 * *
8993 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00008994/**
8995 * xmlRelaxNGNewValidCtxt:
8996 * @schema: a precompiled XML RelaxNGs
8997 *
8998 * Create an XML RelaxNGs validation context based on the given schema
8999 *
9000 * Returns the validation context or NULL in case of error
9001 */
9002xmlRelaxNGValidCtxtPtr
9003xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
9004 xmlRelaxNGValidCtxtPtr ret;
9005
9006 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
9007 if (ret == NULL) {
9008 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00009009 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00009010 return (NULL);
9011 }
9012 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
9013 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00009014 ret->error = xmlGenericError;
9015 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00009016 ret->errNr = 0;
9017 ret->errMax = 0;
9018 ret->err = NULL;
9019 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00009020 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00009021 ret->states = NULL;
9022 ret->freeState = NULL;
9023 ret->freeStates = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009024 return (ret);
9025}
9026
9027/**
9028 * xmlRelaxNGFreeValidCtxt:
9029 * @ctxt: the schema validation context
9030 *
9031 * Free the resources associated to the schema validation context
9032 */
9033void
9034xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009035 int k;
9036
Daniel Veillard6eadf632003-01-23 18:29:16 +00009037 if (ctxt == NULL)
9038 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009039 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00009040 xmlRelaxNGFreeStates(NULL, ctxt->states);
9041 if (ctxt->freeState != NULL) {
9042 for (k = 0;k < ctxt->freeState->nbState;k++) {
9043 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
9044 }
9045 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
9046 }
Daniel Veillard798024a2003-03-19 10:36:09 +00009047 if (ctxt->freeStates != NULL) {
9048 for (k = 0;k < ctxt->freeStatesNr;k++) {
9049 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
9050 }
9051 xmlFree(ctxt->freeStates);
9052 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00009053 if (ctxt->errTab != NULL)
9054 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009055 xmlFree(ctxt);
9056}
9057
9058/**
9059 * xmlRelaxNGSetValidErrors:
9060 * @ctxt: a Relax-NG validation context
9061 * @err: the error function
9062 * @warn: the warning function
9063 * @ctx: the functions context
9064 *
9065 * Set the error and warning callback informations
9066 */
9067void
9068xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
9069 xmlRelaxNGValidityErrorFunc err,
9070 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
9071 if (ctxt == NULL)
9072 return;
9073 ctxt->error = err;
9074 ctxt->warning = warn;
9075 ctxt->userData = ctx;
9076}
9077
9078/**
9079 * xmlRelaxNGValidateDoc:
9080 * @ctxt: a Relax-NG validation context
9081 * @doc: a parsed document tree
9082 *
9083 * Validate a document tree in memory.
9084 *
9085 * Returns 0 if the document is valid, a positive error code
9086 * number otherwise and -1 in case of internal or API error.
9087 */
9088int
9089xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
9090 int ret;
9091
9092 if ((ctxt == NULL) || (doc == NULL))
9093 return(-1);
9094
9095 ctxt->doc = doc;
9096
9097 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00009098 /*
9099 * TODO: build error codes
9100 */
9101 if (ret == -1)
9102 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009103 return(ret);
9104}
9105
9106#endif /* LIBXML_SCHEMAS_ENABLED */
9107