blob: 4a00024da17ba252ed4f1f2ab6ad86a990cd4bf9 [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 Veillarda507fbf2003-03-31 16:09:37 +000058/* #define DEBUG_ERROR 1 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000059/* #define DEBUG_COMPILE 1 */
Daniel Veillard6eadf632003-01-23 18:29:16 +000060
61#define UNBOUNDED (1 << 30)
Daniel Veillard5f1946a2003-03-31 16:38:16 +000062#define MAX_ERROR 5
63
Daniel Veillard6eadf632003-01-23 18:29:16 +000064#define TODO \
65 xmlGenericError(xmlGenericErrorContext, \
66 "Unimplemented block at %s:%d\n", \
67 __FILE__, __LINE__);
68
69typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
70typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
71
72typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
73typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
74
Daniel Veillardd41f4f42003-01-29 21:07:52 +000075typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
76typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
77
Daniel Veillarda9d912d2003-02-01 17:43:10 +000078typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
79typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
80
Daniel Veillard6eadf632003-01-23 18:29:16 +000081typedef enum {
82 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
83 XML_RELAXNG_COMBINE_CHOICE, /* choice */
84 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
85} xmlRelaxNGCombine;
86
Daniel Veillard4c5cf702003-02-21 15:40:34 +000087typedef enum {
88 XML_RELAXNG_CONTENT_ERROR = -1,
89 XML_RELAXNG_CONTENT_EMPTY = 0,
90 XML_RELAXNG_CONTENT_SIMPLE,
91 XML_RELAXNG_CONTENT_COMPLEX
92} xmlRelaxNGContentType;
93
Daniel Veillard6eadf632003-01-23 18:29:16 +000094typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
95typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
96
97struct _xmlRelaxNGGrammar {
98 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
99 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
100 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
101 xmlRelaxNGDefinePtr start; /* <start> content */
102 xmlRelaxNGCombine combine; /* the default combine value */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000103 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000104 xmlHashTablePtr defs; /* define* */
105 xmlHashTablePtr refs; /* references */
106};
107
108
Daniel Veillard6eadf632003-01-23 18:29:16 +0000109typedef enum {
Daniel Veillard77648bb2003-02-20 15:03:22 +0000110 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000111 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
112 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000113 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000114 XML_RELAXNG_TEXT, /* textual content */
115 XML_RELAXNG_ELEMENT, /* an element */
116 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000117 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000118 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
119 XML_RELAXNG_LIST, /* a list of patterns */
120 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
121 XML_RELAXNG_DEF, /* a definition */
122 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000123 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000124 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000125 XML_RELAXNG_OPTIONAL, /* optional patterns */
126 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000127 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
128 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
129 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000130 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000131 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000132} xmlRelaxNGType;
133
Daniel Veillard52b48c72003-04-13 19:53:42 +0000134#define IS_NULLABLE (1 << 0)
135#define IS_NOT_NULLABLE (1 << 1)
136#define IS_INDETERMINIST (1 << 2)
137#define IS_MIXED (1 << 3)
138#define IS_TRIABLE (1 << 4)
139#define IS_PROCESSED (1 << 5)
140#define IS_COMPILABLE (1 << 6)
141#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000142
Daniel Veillard6eadf632003-01-23 18:29:16 +0000143struct _xmlRelaxNGDefine {
144 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000145 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000146 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000147 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000148 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000149 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000150 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000151 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000152 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000153 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000154 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000155 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000156 short depth; /* used for the cycle detection */
Daniel Veillarde063f482003-03-21 16:53:17 +0000157 short dflags; /* define related flags */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000158 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000159};
160
161/**
162 * _xmlRelaxNG:
163 *
164 * A RelaxNGs definition
165 */
166struct _xmlRelaxNG {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000167 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000168 xmlRelaxNGGrammarPtr topgrammar;
169 xmlDocPtr doc;
170
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000171 int idref; /* requires idref checking */
172
Daniel Veillard6eadf632003-01-23 18:29:16 +0000173 xmlHashTablePtr defs; /* define */
174 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000175 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
176 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000177 int defNr; /* number of defines used */
178 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000179
Daniel Veillard6eadf632003-01-23 18:29:16 +0000180};
181
Daniel Veillard77648bb2003-02-20 15:03:22 +0000182#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
183#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
184#define XML_RELAXNG_IN_LIST (1 << 2)
185#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
186#define XML_RELAXNG_IN_START (1 << 4)
187#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
188#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
189#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000190#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
191#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000192
193struct _xmlRelaxNGParserCtxt {
194 void *userData; /* user specific data block */
195 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
196 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000197 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000198
199 xmlRelaxNGPtr schema; /* The schema in use */
200 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000201 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000202 int flags; /* parser flags */
203 int nbErrors; /* number of errors at parse time */
204 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000205 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000206 xmlRelaxNGDefinePtr def; /* the current define */
207
208 int nbInterleaves;
209 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000210
Daniel Veillardc482e262003-02-26 14:48:48 +0000211 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
212 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000213 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000214 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000215
Daniel Veillard419a7682003-02-03 23:22:49 +0000216 int defNr; /* number of defines used */
217 int defMax; /* number of defines aloocated */
218 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
219
Daniel Veillard6eadf632003-01-23 18:29:16 +0000220 const char *buffer;
221 int size;
222
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000223 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000224 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000225 int docNr; /* Depth of the parsing stack */
226 int docMax; /* Max depth of the parsing stack */
227 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000228
229 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000230 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000231 int incNr; /* Depth of the include parsing stack */
232 int incMax; /* Max depth of the parsing stack */
233 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000234
235 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000236
237 /* used to compile content models */
238 xmlAutomataPtr am; /* the automata */
239 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000240};
241
242#define FLAGS_IGNORABLE 1
243#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000244#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000245
246/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000247 * xmlRelaxNGInterleaveGroup:
248 *
249 * A RelaxNGs partition set associated to lists of definitions
250 */
251typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
252typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
253struct _xmlRelaxNGInterleaveGroup {
254 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
255 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000256 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000257};
258
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000259#define IS_DETERMINIST 1
260#define IS_NEEDCHECK 2
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000261/**
262 * xmlRelaxNGPartitions:
263 *
264 * A RelaxNGs partition associated to an interleave group
265 */
266typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
267typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
268struct _xmlRelaxNGPartition {
269 int nbgroups; /* number of groups in the partitions */
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000270 xmlHashTablePtr triage; /* hash table used to direct nodes to the
271 right group when possible */
272 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000273 xmlRelaxNGInterleaveGroupPtr *groups;
274};
275
276/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000277 * xmlRelaxNGValidState:
278 *
279 * A RelaxNGs validation state
280 */
281#define MAX_ATTR 20
282typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
283typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
284struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000285 xmlNodePtr node; /* the current node */
286 xmlNodePtr seq; /* the sequence of children left to validate */
287 int nbAttrs; /* the number of attributes */
Daniel Veillard798024a2003-03-19 10:36:09 +0000288 int maxAttrs; /* the size of attrs */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000289 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000290 xmlChar *value; /* the value when operating on string */
291 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard798024a2003-03-19 10:36:09 +0000292 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000293};
294
295/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000296 * xmlRelaxNGStates:
297 *
298 * A RelaxNGs container for validation state
299 */
300typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
301typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
302struct _xmlRelaxNGStates {
303 int nbState; /* the number of states */
304 int maxState; /* the size of the array */
305 xmlRelaxNGValidStatePtr *tabState;
306};
307
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000308#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000309/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000310 * xmlRelaxNGValidError:
311 *
312 * A RelaxNGs validation error
313 */
314typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
315typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
316struct _xmlRelaxNGValidError {
317 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000318 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000319 xmlNodePtr node; /* the current node */
320 xmlNodePtr seq; /* the current child */
321 const xmlChar * arg1; /* first arg */
322 const xmlChar * arg2; /* second arg */
323};
324
325/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000326 * xmlRelaxNGValidCtxt:
327 *
328 * A RelaxNGs validation context
329 */
330
331struct _xmlRelaxNGValidCtxt {
332 void *userData; /* user specific data block */
333 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
334 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
335
336 xmlRelaxNGPtr schema; /* The schema in use */
337 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000338 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000339 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000340 int idref; /* requires idref checking */
Daniel Veillarda507fbf2003-03-31 16:09:37 +0000341 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000342
343 /*
344 * Errors accumulated in branches may have to be stacked to be
345 * provided back when it's sure they affect validation.
346 */
347 xmlRelaxNGValidErrorPtr err; /* Last error */
348 int errNr; /* Depth of the error stack */
349 int errMax; /* Max depth of the error stack */
350 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000351
Daniel Veillardfd573f12003-03-16 17:52:32 +0000352 xmlRelaxNGValidStatePtr state; /* the current validation state */
353 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000354
355 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
356 int freeStatesNr;
357 int freeStatesMax;
358 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000359};
360
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000361/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000362 * xmlRelaxNGInclude:
363 *
364 * Structure associated to a RelaxNGs document element
365 */
366struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000367 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000368 xmlChar *href; /* the normalized href value */
369 xmlDocPtr doc; /* the associated XML document */
370 xmlRelaxNGDefinePtr content;/* the definitions */
371 xmlRelaxNGPtr schema; /* the schema */
372};
373
374/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000375 * xmlRelaxNGDocument:
376 *
377 * Structure associated to a RelaxNGs document element
378 */
379struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000380 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000381 xmlChar *href; /* the normalized href value */
382 xmlDocPtr doc; /* the associated XML document */
383 xmlRelaxNGDefinePtr content;/* the definitions */
384 xmlRelaxNGPtr schema; /* the schema */
385};
386
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000387
Daniel Veillard6eadf632003-01-23 18:29:16 +0000388/************************************************************************
389 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000390 * Preliminary type checking interfaces *
391 * *
392 ************************************************************************/
393/**
394 * xmlRelaxNGTypeHave:
395 * @data: data needed for the library
396 * @type: the type name
397 * @value: the value to check
398 *
399 * Function provided by a type library to check if a type is exported
400 *
401 * Returns 1 if yes, 0 if no and -1 in case of error.
402 */
403typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
404
405/**
406 * xmlRelaxNGTypeCheck:
407 * @data: data needed for the library
408 * @type: the type name
409 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000410 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000411 *
412 * Function provided by a type library to check if a value match a type
413 *
414 * Returns 1 if yes, 0 if no and -1 in case of error.
415 */
416typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000417 const xmlChar *value, void **result,
418 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000419
420/**
421 * xmlRelaxNGFacetCheck:
422 * @data: data needed for the library
423 * @type: the type name
424 * @facet: the facet name
425 * @val: the facet value
426 * @strval: the string value
427 * @value: the value to check
428 *
429 * Function provided by a type library to check a value facet
430 *
431 * Returns 1 if yes, 0 if no and -1 in case of error.
432 */
433typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
434 const xmlChar *facet, const xmlChar *val,
435 const xmlChar *strval, void *value);
436
437/**
438 * xmlRelaxNGTypeFree:
439 * @data: data needed for the library
440 * @result: the value to free
441 *
442 * Function provided by a type library to free a returned result
443 */
444typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000445
446/**
447 * xmlRelaxNGTypeCompare:
448 * @data: data needed for the library
449 * @type: the type name
450 * @value1: the first value
451 * @value2: the second value
452 *
453 * Function provided by a type library to compare two values accordingly
454 * to a type.
455 *
456 * Returns 1 if yes, 0 if no and -1 in case of error.
457 */
458typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
459 const xmlChar *value1,
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000460 xmlNodePtr ctxt1,
461 void *comp1,
462 const xmlChar *value2,
463 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000464typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
465typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
466struct _xmlRelaxNGTypeLibrary {
467 const xmlChar *namespace; /* the datatypeLibrary value */
468 void *data; /* data needed for the library */
469 xmlRelaxNGTypeHave have; /* the export function */
470 xmlRelaxNGTypeCheck check; /* the checking function */
471 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000472 xmlRelaxNGFacetCheck facet; /* the facet check function */
473 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000474};
475
476/************************************************************************
477 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000478 * Allocation functions *
479 * *
480 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000481static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
482static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000483static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000484static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000485static int xmlRelaxNGEqualValidState(
486 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
487 xmlRelaxNGValidStatePtr state1,
488 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000489static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
490 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000491
492/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000493 * xmlRelaxNGFreeDocument:
494 * @docu: a document structure
495 *
496 * Deallocate a RelaxNG document structure.
497 */
498static void
499xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
500{
501 if (docu == NULL)
502 return;
503
504 if (docu->href != NULL)
505 xmlFree(docu->href);
506 if (docu->doc != NULL)
507 xmlFreeDoc(docu->doc);
508 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000509 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000510 xmlFree(docu);
511}
512
513/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000514 * xmlRelaxNGFreeDocumentList:
515 * @docu: a list of document structure
516 *
517 * Deallocate a RelaxNG document structures.
518 */
519static void
520xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
521{
522 xmlRelaxNGDocumentPtr next;
523 while (docu != NULL) {
524 next = docu->next;
525 xmlRelaxNGFreeDocument(docu);
526 docu = next;
527 }
528}
529
530/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000531 * xmlRelaxNGFreeInclude:
532 * @incl: a include structure
533 *
534 * Deallocate a RelaxNG include structure.
535 */
536static void
537xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
538{
539 if (incl == NULL)
540 return;
541
542 if (incl->href != NULL)
543 xmlFree(incl->href);
544 if (incl->doc != NULL)
545 xmlFreeDoc(incl->doc);
546 if (incl->schema != NULL)
547 xmlRelaxNGFree(incl->schema);
548 xmlFree(incl);
549}
550
551/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000552 * xmlRelaxNGFreeIncludeList:
553 * @incl: a include structure list
554 *
555 * Deallocate a RelaxNG include structure.
556 */
557static void
558xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
559{
560 xmlRelaxNGIncludePtr next;
561 while (incl != NULL) {
562 next = incl->next;
563 xmlRelaxNGFreeInclude(incl);
564 incl = next;
565 }
566}
567
568/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000569 * xmlRelaxNGNewRelaxNG:
570 * @ctxt: a Relax-NG validation context (optional)
571 *
572 * Allocate a new RelaxNG structure.
573 *
574 * Returns the newly allocated structure or NULL in case or error
575 */
576static xmlRelaxNGPtr
577xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
578{
579 xmlRelaxNGPtr ret;
580
581 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
582 if (ret == NULL) {
583 if ((ctxt != NULL) && (ctxt->error != NULL))
584 ctxt->error(ctxt->userData, "Out of memory\n");
585 ctxt->nbErrors++;
586 return (NULL);
587 }
588 memset(ret, 0, sizeof(xmlRelaxNG));
589
590 return (ret);
591}
592
593/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000594 * xmlRelaxNGFreeInnerSchema:
595 * @schema: a schema structure
596 *
597 * Deallocate a RelaxNG schema structure.
598 */
599static void
600xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
601{
602 if (schema == NULL)
603 return;
604
605 if (schema->doc != NULL)
606 xmlFreeDoc(schema->doc);
607 if (schema->defTab != NULL) {
608 int i;
609
610 for (i = 0;i < schema->defNr;i++)
611 xmlRelaxNGFreeDefine(schema->defTab[i]);
612 xmlFree(schema->defTab);
613 }
614
615 xmlFree(schema);
616}
617
618/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000619 * xmlRelaxNGFree:
620 * @schema: a schema structure
621 *
622 * Deallocate a RelaxNG structure.
623 */
624void
625xmlRelaxNGFree(xmlRelaxNGPtr schema)
626{
627 if (schema == NULL)
628 return;
629
Daniel Veillard6eadf632003-01-23 18:29:16 +0000630 if (schema->topgrammar != NULL)
631 xmlRelaxNGFreeGrammar(schema->topgrammar);
632 if (schema->doc != NULL)
633 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000634 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000635 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000636 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000637 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000638 if (schema->defTab != NULL) {
639 int i;
640
641 for (i = 0;i < schema->defNr;i++)
642 xmlRelaxNGFreeDefine(schema->defTab[i]);
643 xmlFree(schema->defTab);
644 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000645
646 xmlFree(schema);
647}
648
649/**
650 * xmlRelaxNGNewGrammar:
651 * @ctxt: a Relax-NG validation context (optional)
652 *
653 * Allocate a new RelaxNG grammar.
654 *
655 * Returns the newly allocated structure or NULL in case or error
656 */
657static xmlRelaxNGGrammarPtr
658xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
659{
660 xmlRelaxNGGrammarPtr ret;
661
662 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
663 if (ret == NULL) {
664 if ((ctxt != NULL) && (ctxt->error != NULL))
665 ctxt->error(ctxt->userData, "Out of memory\n");
666 ctxt->nbErrors++;
667 return (NULL);
668 }
669 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
670
671 return (ret);
672}
673
674/**
675 * xmlRelaxNGFreeGrammar:
676 * @grammar: a grammar structure
677 *
678 * Deallocate a RelaxNG grammar structure.
679 */
680static void
681xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
682{
683 if (grammar == NULL)
684 return;
685
Daniel Veillardc482e262003-02-26 14:48:48 +0000686 if (grammar->children != NULL) {
687 xmlRelaxNGFreeGrammar(grammar->children);
688 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000689 if (grammar->next != NULL) {
690 xmlRelaxNGFreeGrammar(grammar->next);
691 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000692 if (grammar->refs != NULL) {
693 xmlHashFree(grammar->refs, NULL);
694 }
695 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000696 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000697 }
698
699 xmlFree(grammar);
700}
701
702/**
703 * xmlRelaxNGNewDefine:
704 * @ctxt: a Relax-NG validation context
705 * @node: the node in the input document.
706 *
707 * Allocate a new RelaxNG define.
708 *
709 * Returns the newly allocated structure or NULL in case or error
710 */
711static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000712xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000713{
714 xmlRelaxNGDefinePtr ret;
715
Daniel Veillard419a7682003-02-03 23:22:49 +0000716 if (ctxt->defMax == 0) {
717 ctxt->defMax = 16;
718 ctxt->defNr = 0;
719 ctxt->defTab = (xmlRelaxNGDefinePtr *)
720 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
721 if (ctxt->defTab == NULL) {
722 if ((ctxt != NULL) && (ctxt->error != NULL))
723 ctxt->error(ctxt->userData, "Out of memory\n");
724 ctxt->nbErrors++;
725 return (NULL);
726 }
727 } else if (ctxt->defMax <= ctxt->defNr) {
728 xmlRelaxNGDefinePtr *tmp;
729 ctxt->defMax *= 2;
730 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
731 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
732 if (tmp == NULL) {
733 if ((ctxt != NULL) && (ctxt->error != NULL))
734 ctxt->error(ctxt->userData, "Out of memory\n");
735 ctxt->nbErrors++;
736 return (NULL);
737 }
738 ctxt->defTab = tmp;
739 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000740 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
741 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000742 if ((ctxt != NULL) && (ctxt->error != NULL))
743 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000744 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000745 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000746 }
747 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000748 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000749 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000750 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000751 return (ret);
752}
753
754/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000755 * xmlRelaxNGFreePartition:
756 * @partitions: a partition set structure
757 *
758 * Deallocate RelaxNG partition set structures.
759 */
760static void
761xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
762 xmlRelaxNGInterleaveGroupPtr group;
763 int j;
764
765 if (partitions != NULL) {
766 if (partitions->groups != NULL) {
767 for (j = 0;j < partitions->nbgroups;j++) {
768 group = partitions->groups[j];
769 if (group != NULL) {
770 if (group->defs != NULL)
771 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000772 if (group->attrs != NULL)
773 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000774 xmlFree(group);
775 }
776 }
777 xmlFree(partitions->groups);
778 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000779 if (partitions->triage != NULL) {
780 xmlHashFree(partitions->triage, NULL);
781 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000782 xmlFree(partitions);
783 }
784}
785/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000786 * xmlRelaxNGFreeDefine:
787 * @define: a define structure
788 *
789 * Deallocate a RelaxNG define structure.
790 */
791static void
792xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
793{
794 if (define == NULL)
795 return;
796
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000797 if ((define->type == XML_RELAXNG_VALUE) &&
798 (define->attrs != NULL)) {
799 xmlRelaxNGTypeLibraryPtr lib;
800
801 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
802 if ((lib != NULL) && (lib->freef != NULL))
803 lib->freef(lib->data, (void *) define->attrs);
804 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000805 if ((define->data != NULL) &&
806 (define->type == XML_RELAXNG_INTERLEAVE))
807 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillarde063f482003-03-21 16:53:17 +0000808 if ((define->data != NULL) &&
809 (define->type == XML_RELAXNG_CHOICE))
810 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000811 if (define->name != NULL)
812 xmlFree(define->name);
813 if (define->ns != NULL)
814 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000815 if (define->value != NULL)
816 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000817 if (define->contModel != NULL)
818 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000819 xmlFree(define);
820}
821
822/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000823 * xmlRelaxNGNewStates:
824 * @ctxt: a Relax-NG validation context
825 * @size: the default size for the container
826 *
827 * Allocate a new RelaxNG validation state container
828 * TODO: keep a pool in the ctxt
829 *
830 * Returns the newly allocated structure or NULL in case or error
831 */
832static xmlRelaxNGStatesPtr
833xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
834{
835 xmlRelaxNGStatesPtr ret;
836
Daniel Veillard798024a2003-03-19 10:36:09 +0000837 if ((ctxt != NULL) &&
838 (ctxt->freeState != NULL) &&
839 (ctxt->freeStatesNr > 0)) {
840 ctxt->freeStatesNr--;
841 ret = ctxt->freeStates[ctxt->freeStatesNr];
842 ret->nbState = 0;
843 return(ret);
844 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000845 if (size < 16) size = 16;
846
847 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
848 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
849 if (ret == NULL) {
850 if ((ctxt != NULL) && (ctxt->error != NULL))
851 ctxt->error(ctxt->userData, "Out of memory\n");
852 return (NULL);
853 }
854 ret->nbState = 0;
855 ret->maxState = size;
856 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
857 (size) * sizeof(xmlRelaxNGValidStatePtr));
858 if (ret->tabState == NULL) {
859 if ((ctxt != NULL) && (ctxt->error != NULL))
860 ctxt->error(ctxt->userData, "Out of memory\n");
861 xmlFree(ret->tabState);
862 return (NULL);
863 }
864 return(ret);
865}
866
867/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000868 * xmlRelaxNGAddStateUniq:
869 * @ctxt: a Relax-NG validation context
870 * @states: the states container
871 * @state: the validation state
872 *
873 * Add a RelaxNG validation state to the container without checking
874 * for unicity.
875 *
876 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
877 */
878static int
879xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
880 xmlRelaxNGStatesPtr states,
881 xmlRelaxNGValidStatePtr state)
882{
883 if (state == NULL) {
884 return(-1);
885 }
886 if (states->nbState >= states->maxState) {
887 xmlRelaxNGValidStatePtr *tmp;
888 int size;
889
890 size = states->maxState * 2;
891 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
892 (size) * sizeof(xmlRelaxNGValidStatePtr));
893 if (tmp == NULL) {
894 if ((ctxt != NULL) && (ctxt->error != NULL))
895 ctxt->error(ctxt->userData, "Out of memory\n");
896 return(-1);
897 }
898 states->tabState = tmp;
899 states->maxState = size;
900 }
901 states->tabState[states->nbState++] = state;
902 return(1);
903}
904
905/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000906 * xmlRelaxNGAddState:
907 * @ctxt: a Relax-NG validation context
908 * @states: the states container
909 * @state: the validation state
910 *
911 * Add a RelaxNG validation state to the container
912 *
913 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
914 */
915static int
916xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
917 xmlRelaxNGValidStatePtr state)
918{
919 int i;
920
921 if (state == NULL) {
922 return(-1);
923 }
924 if (states->nbState >= states->maxState) {
925 xmlRelaxNGValidStatePtr *tmp;
926 int size;
927
928 size = states->maxState * 2;
929 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
930 (size) * sizeof(xmlRelaxNGValidStatePtr));
931 if (tmp == NULL) {
932 if ((ctxt != NULL) && (ctxt->error != NULL))
933 ctxt->error(ctxt->userData, "Out of memory\n");
934 return(-1);
935 }
936 states->tabState = tmp;
937 states->maxState = size;
938 }
939 for (i = 0;i < states->nbState;i++) {
940 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000941 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000942 return(0);
943 }
944 }
945 states->tabState[states->nbState++] = state;
946 return(1);
947}
948
949/**
950 * xmlRelaxNGFreeStates:
951 * @ctxt: a Relax-NG validation context
952 * @states: teh container
953 *
954 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000955 */
956static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000957xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000958 xmlRelaxNGStatesPtr states)
959{
Daniel Veillard798024a2003-03-19 10:36:09 +0000960 if (states == NULL)
961 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000962 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
963 ctxt->freeStatesMax = 40;
964 ctxt->freeStatesNr = 0;
965 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
966 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
967 if (ctxt->freeStates == NULL) {
968 if ((ctxt != NULL) && (ctxt->error != NULL))
969 ctxt->error(ctxt->userData, "Out of memory\n");
970 }
971 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
972 xmlRelaxNGStatesPtr *tmp;
973
974 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
975 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
976 if (tmp == NULL) {
977 if ((ctxt != NULL) && (ctxt->error != NULL))
978 ctxt->error(ctxt->userData, "Out of memory\n");
979 xmlFree(states->tabState);
980 xmlFree(states);
981 return;
982 }
983 ctxt->freeStates = tmp;
984 ctxt->freeStatesMax *= 2;
985 }
986 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000987 xmlFree(states->tabState);
988 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +0000989 } else {
990 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000991 }
992}
993
994/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000995 * xmlRelaxNGNewValidState:
996 * @ctxt: a Relax-NG validation context
997 * @node: the current node or NULL for the document
998 *
999 * Allocate a new RelaxNG validation state
1000 *
1001 * Returns the newly allocated structure or NULL in case or error
1002 */
1003static xmlRelaxNGValidStatePtr
1004xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1005{
1006 xmlRelaxNGValidStatePtr ret;
1007 xmlAttrPtr attr;
1008 xmlAttrPtr attrs[MAX_ATTR];
1009 int nbAttrs = 0;
1010 xmlNodePtr root = NULL;
1011
1012 if (node == NULL) {
1013 root = xmlDocGetRootElement(ctxt->doc);
1014 if (root == NULL)
1015 return(NULL);
1016 } else {
1017 attr = node->properties;
1018 while (attr != NULL) {
1019 if (nbAttrs < MAX_ATTR)
1020 attrs[nbAttrs++] = attr;
1021 else
1022 nbAttrs++;
1023 attr = attr->next;
1024 }
1025 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001026 if ((ctxt->freeState != NULL) &&
1027 (ctxt->freeState->nbState > 0)) {
1028 ctxt->freeState->nbState--;
1029 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1030 } else {
1031 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1032 if (ret == NULL) {
1033 if ((ctxt != NULL) && (ctxt->error != NULL))
1034 ctxt->error(ctxt->userData, "Out of memory\n");
1035 return (NULL);
1036 }
1037 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001038 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001039 ret->value = NULL;
1040 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001041 if (node == NULL) {
1042 ret->node = (xmlNodePtr) ctxt->doc;
1043 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001044 } else {
1045 ret->node = node;
1046 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001047 }
1048 ret->nbAttrs = 0;
1049 if (nbAttrs > 0) {
1050 if (ret->attrs == NULL) {
1051 if (nbAttrs < 4) ret->maxAttrs = 4;
1052 else ret->maxAttrs = nbAttrs;
1053 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1054 sizeof(xmlAttrPtr));
1055 if (ret->attrs == NULL) {
1056 if ((ctxt != NULL) && (ctxt->error != NULL))
1057 ctxt->error(ctxt->userData, "Out of memory\n");
1058 return (ret);
1059 }
1060 } else if (ret->maxAttrs < nbAttrs) {
1061 xmlAttrPtr *tmp;
1062
1063 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1064 sizeof(xmlAttrPtr));
1065 if (tmp == NULL) {
1066 if ((ctxt != NULL) && (ctxt->error != NULL))
1067 ctxt->error(ctxt->userData, "Out of memory\n");
1068 return (ret);
1069 }
1070 ret->attrs = tmp;
1071 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001072 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001073 if (nbAttrs < MAX_ATTR) {
1074 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1075 } else {
1076 attr = node->properties;
1077 nbAttrs = 0;
1078 while (attr != NULL) {
1079 ret->attrs[nbAttrs++] = attr;
1080 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001081 }
1082 }
1083 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001084 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001085 return (ret);
1086}
1087
1088/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001089 * xmlRelaxNGCopyValidState:
1090 * @ctxt: a Relax-NG validation context
1091 * @state: a validation state
1092 *
1093 * Copy the validation state
1094 *
1095 * Returns the newly allocated structure or NULL in case or error
1096 */
1097static xmlRelaxNGValidStatePtr
1098xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1099 xmlRelaxNGValidStatePtr state)
1100{
1101 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001102 unsigned int maxAttrs;
1103 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001104
1105 if (state == NULL)
1106 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001107 if ((ctxt->freeState != NULL) &&
1108 (ctxt->freeState->nbState > 0)) {
1109 ctxt->freeState->nbState--;
1110 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1111 } else {
1112 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1113 if (ret == NULL) {
1114 if ((ctxt != NULL) && (ctxt->error != NULL))
1115 ctxt->error(ctxt->userData, "Out of memory\n");
1116 return (NULL);
1117 }
1118 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001119 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001120 attrs = ret->attrs;
1121 maxAttrs = ret->maxAttrs;
1122 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1123 ret->attrs = attrs;
1124 ret->maxAttrs = maxAttrs;
1125 if (state->nbAttrs > 0) {
1126 if (ret->attrs == NULL) {
1127 ret->maxAttrs = state->maxAttrs;
1128 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1129 sizeof(xmlAttrPtr));
1130 if (ret->attrs == NULL) {
1131 if ((ctxt != NULL) && (ctxt->error != NULL))
1132 ctxt->error(ctxt->userData, "Out of memory\n");
1133 ret->nbAttrs = 0;
1134 return (ret);
1135 }
1136 } else if (ret->maxAttrs < state->nbAttrs) {
1137 xmlAttrPtr *tmp;
1138
1139 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1140 sizeof(xmlAttrPtr));
1141 if (tmp == NULL) {
1142 if ((ctxt != NULL) && (ctxt->error != NULL))
1143 ctxt->error(ctxt->userData, "Out of memory\n");
1144 ret->nbAttrs = 0;
1145 return (ret);
1146 }
1147 ret->maxAttrs = state->maxAttrs;
1148 }
1149 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1150 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001151 return(ret);
1152}
1153
1154/**
1155 * xmlRelaxNGEqualValidState:
1156 * @ctxt: a Relax-NG validation context
1157 * @state1: a validation state
1158 * @state2: a validation state
1159 *
1160 * Compare the validation states for equality
1161 *
1162 * Returns 1 if equald, 0 otherwise
1163 */
1164static int
1165xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1166 xmlRelaxNGValidStatePtr state1,
1167 xmlRelaxNGValidStatePtr state2)
1168{
1169 int i;
1170
1171 if ((state1 == NULL) || (state2 == NULL))
1172 return(0);
1173 if (state1 == state2)
1174 return(1);
1175 if (state1->node != state2->node)
1176 return(0);
1177 if (state1->seq != state2->seq)
1178 return(0);
1179 if (state1->nbAttrLeft != state2->nbAttrLeft)
1180 return(0);
1181 if (state1->nbAttrs != state2->nbAttrs)
1182 return(0);
1183 if (state1->endvalue != state2->endvalue)
1184 return(0);
1185 if ((state1->value != state2->value) &&
1186 (!xmlStrEqual(state1->value, state2->value)))
1187 return(0);
1188 for (i = 0;i < state1->nbAttrs;i++) {
1189 if (state1->attrs[i] != state2->attrs[i])
1190 return(0);
1191 }
1192 return(1);
1193}
1194
1195/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001196 * xmlRelaxNGFreeValidState:
1197 * @state: a validation state structure
1198 *
1199 * Deallocate a RelaxNG validation state structure.
1200 */
1201static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001202xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1203 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001204{
1205 if (state == NULL)
1206 return;
1207
Daniel Veillard798024a2003-03-19 10:36:09 +00001208 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1209 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1210 }
1211 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1212 if (state->attrs != NULL)
1213 xmlFree(state->attrs);
1214 xmlFree(state);
1215 } else {
1216 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1217 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001218}
1219
1220/************************************************************************
1221 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001222 * Document functions *
1223 * *
1224 ************************************************************************/
1225static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1226 xmlDocPtr doc);
1227
1228/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001229 * xmlRelaxNGIncludePush:
1230 * @ctxt: the parser context
1231 * @value: the element doc
1232 *
1233 * Pushes a new include on top of the include stack
1234 *
1235 * Returns 0 in case of error, the index in the stack otherwise
1236 */
1237static int
1238xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1239 xmlRelaxNGIncludePtr value)
1240{
1241 if (ctxt->incTab == NULL) {
1242 ctxt->incMax = 4;
1243 ctxt->incNr = 0;
1244 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1245 ctxt->incMax * sizeof(ctxt->incTab[0]));
1246 if (ctxt->incTab == NULL) {
1247 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1248 return (0);
1249 }
1250 }
1251 if (ctxt->incNr >= ctxt->incMax) {
1252 ctxt->incMax *= 2;
1253 ctxt->incTab =
1254 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1255 ctxt->incMax *
1256 sizeof(ctxt->incTab[0]));
1257 if (ctxt->incTab == NULL) {
1258 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1259 return (0);
1260 }
1261 }
1262 ctxt->incTab[ctxt->incNr] = value;
1263 ctxt->inc = value;
1264 return (ctxt->incNr++);
1265}
1266
1267/**
1268 * xmlRelaxNGIncludePop:
1269 * @ctxt: the parser context
1270 *
1271 * Pops the top include from the include stack
1272 *
1273 * Returns the include just removed
1274 */
1275static xmlRelaxNGIncludePtr
1276xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1277{
1278 xmlRelaxNGIncludePtr ret;
1279
1280 if (ctxt->incNr <= 0)
1281 return (0);
1282 ctxt->incNr--;
1283 if (ctxt->incNr > 0)
1284 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1285 else
1286 ctxt->inc = NULL;
1287 ret = ctxt->incTab[ctxt->incNr];
1288 ctxt->incTab[ctxt->incNr] = 0;
1289 return (ret);
1290}
1291
1292/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001293 * xmlRelaxNGRemoveRedefine:
1294 * @ctxt: the parser context
1295 * @URL: the normalized URL
1296 * @target: the included target
1297 * @name: the define name to eliminate
1298 *
1299 * Applies the elimination algorithm of 4.7
1300 *
1301 * Returns 0 in case of error, 1 in case of success.
1302 */
1303static int
1304xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1305 const xmlChar *URL ATTRIBUTE_UNUSED,
1306 xmlNodePtr target, const xmlChar *name) {
1307 int found = 0;
1308 xmlNodePtr tmp, tmp2;
1309 xmlChar *name2;
1310
1311#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001312 if (name == NULL)
1313 xmlGenericError(xmlGenericErrorContext,
1314 "Elimination of <include> start from %s\n", URL);
1315 else
1316 xmlGenericError(xmlGenericErrorContext,
1317 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001318#endif
1319 tmp = target;
1320 while (tmp != NULL) {
1321 tmp2 = tmp->next;
1322 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1323 found = 1;
1324 xmlUnlinkNode(tmp);
1325 xmlFreeNode(tmp);
1326 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1327 name2 = xmlGetProp(tmp, BAD_CAST "name");
1328 xmlRelaxNGNormExtSpace(name2);
1329 if (name2 != NULL) {
1330 if (xmlStrEqual(name, name2)) {
1331 found = 1;
1332 xmlUnlinkNode(tmp);
1333 xmlFreeNode(tmp);
1334 }
1335 xmlFree(name2);
1336 }
1337 } else if (IS_RELAXNG(tmp, "include")) {
1338 xmlChar *href = NULL;
1339 xmlRelaxNGDocumentPtr inc = tmp->_private;
1340
1341 if ((inc != NULL) && (inc->doc != NULL) &&
1342 (inc->doc->children != NULL)) {
1343
1344 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1345#ifdef DEBUG_INCLUDE
1346 href = xmlGetProp(tmp, BAD_CAST "href");
1347#endif
1348 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1349 inc->doc->children->children, name) == 1) {
1350 found = 1;
1351 }
1352 if (href != NULL)
1353 xmlFree(href);
1354 }
1355 }
1356 }
1357 tmp = tmp2;
1358 }
1359 return(found);
1360}
1361
1362/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001363 * xmlRelaxNGLoadInclude:
1364 * @ctxt: the parser context
1365 * @URL: the normalized URL
1366 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001367 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001368 *
1369 * First lookup if the document is already loaded into the parser context,
1370 * check against recursion. If not found the resource is loaded and
1371 * the content is preprocessed before being returned back to the caller.
1372 *
1373 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1374 */
1375static xmlRelaxNGIncludePtr
1376xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001377 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001378 xmlRelaxNGIncludePtr ret = NULL;
1379 xmlDocPtr doc;
1380 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001381 xmlNodePtr root, cur;
1382
1383#ifdef DEBUG_INCLUDE
1384 xmlGenericError(xmlGenericErrorContext,
1385 "xmlRelaxNGLoadInclude(%s)\n", URL);
1386#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001387
1388 /*
1389 * check against recursion in the stack
1390 */
1391 for (i = 0;i < ctxt->incNr;i++) {
1392 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1393 if (ctxt->error != NULL)
1394 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001395 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001396 URL);
1397 ctxt->nbErrors++;
1398 return(NULL);
1399 }
1400 }
1401
1402 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001403 * load the document
1404 */
1405 doc = xmlParseFile((const char *) URL);
1406 if (doc == NULL) {
1407 if (ctxt->error != NULL)
1408 ctxt->error(ctxt->userData,
1409 "xmlRelaxNG: could not load %s\n", URL);
1410 ctxt->nbErrors++;
1411 return (NULL);
1412 }
1413
Daniel Veillard5add8682003-03-10 13:13:58 +00001414#ifdef DEBUG_INCLUDE
1415 xmlGenericError(xmlGenericErrorContext,
1416 "Parsed %s Okay\n", URL);
1417#endif
1418
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001419 /*
1420 * Allocate the document structures and register it first.
1421 */
1422 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1423 if (ret == NULL) {
1424 if (ctxt->error != NULL)
1425 ctxt->error(ctxt->userData,
1426 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1427 ctxt->nbErrors++;
1428 xmlFreeDoc(doc);
1429 return (NULL);
1430 }
1431 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1432 ret->doc = doc;
1433 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001434 ret->next = ctxt->includes;
1435 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001436
1437 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001438 * transmit the ns if needed
1439 */
1440 if (ns != NULL) {
1441 root = xmlDocGetRootElement(doc);
1442 if (root != NULL) {
1443 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1444 xmlSetProp(root, BAD_CAST"ns", ns);
1445 }
1446 }
1447 }
1448
1449 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001450 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001451 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001452 xmlRelaxNGIncludePush(ctxt, ret);
1453
1454 /*
1455 * Some preprocessing of the document content, this include recursing
1456 * in the include stack.
1457 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001458#ifdef DEBUG_INCLUDE
1459 xmlGenericError(xmlGenericErrorContext,
1460 "cleanup of %s\n", URL);
1461#endif
1462
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001463 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1464 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001465 ctxt->inc = NULL;
1466 return(NULL);
1467 }
1468
1469 /*
1470 * Pop up the include from the stack
1471 */
1472 xmlRelaxNGIncludePop(ctxt);
1473
Daniel Veillard5add8682003-03-10 13:13:58 +00001474#ifdef DEBUG_INCLUDE
1475 xmlGenericError(xmlGenericErrorContext,
1476 "Checking of %s\n", URL);
1477#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001478 /*
1479 * Check that the top element is a grammar
1480 */
1481 root = xmlDocGetRootElement(doc);
1482 if (root == NULL) {
1483 if (ctxt->error != NULL)
1484 ctxt->error(ctxt->userData,
1485 "xmlRelaxNG: included document is empty %s\n", URL);
1486 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001487 return (NULL);
1488 }
1489 if (!IS_RELAXNG(root, "grammar")) {
1490 if (ctxt->error != NULL)
1491 ctxt->error(ctxt->userData,
1492 "xmlRelaxNG: included document %s root is not a grammar\n",
1493 URL);
1494 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001495 return (NULL);
1496 }
1497
1498 /*
1499 * Elimination of redefined rules in the include.
1500 */
1501 cur = node->children;
1502 while (cur != NULL) {
1503 if (IS_RELAXNG(cur, "start")) {
1504 int found = 0;
1505
Daniel Veillard5add8682003-03-10 13:13:58 +00001506 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001507 if (!found) {
1508 if (ctxt->error != NULL)
1509 ctxt->error(ctxt->userData,
1510 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1511 URL);
1512 ctxt->nbErrors++;
1513 }
1514 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001515 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001516
1517 name = xmlGetProp(cur, BAD_CAST "name");
1518 if (name == NULL) {
1519 if (ctxt->error != NULL)
1520 ctxt->error(ctxt->userData,
1521 "xmlRelaxNG: include %s has define without name\n",
1522 URL);
1523 ctxt->nbErrors++;
1524 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001525 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001526
Daniel Veillardd2298792003-02-14 16:54:11 +00001527 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001528 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1529 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001530 if (!found) {
1531 if (ctxt->error != NULL)
1532 ctxt->error(ctxt->userData,
1533 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1534 URL, name);
1535 ctxt->nbErrors++;
1536 }
1537 xmlFree(name);
1538 }
1539 }
1540 cur = cur->next;
1541 }
1542
1543
1544 return(ret);
1545}
1546
1547/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001548 * xmlRelaxNGValidErrorPush:
1549 * @ctxt: the validation context
1550 * @err: the error code
1551 * @arg1: the first string argument
1552 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001553 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001554 *
1555 * Pushes a new error on top of the error stack
1556 *
1557 * Returns 0 in case of error, the index in the stack otherwise
1558 */
1559static int
1560xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001561 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001562{
1563 xmlRelaxNGValidErrorPtr cur;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001564#ifdef DEBUG_ERROR
1565 xmlGenericError(xmlGenericErrorContext,
1566 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1567#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001568 if (ctxt->errTab == NULL) {
1569 ctxt->errMax = 8;
1570 ctxt->errNr = 0;
1571 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1572 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1573 if (ctxt->errTab == NULL) {
1574 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1575 return (0);
1576 }
Daniel Veillard20863822003-03-22 17:51:47 +00001577 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001578 }
1579 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard20863822003-03-22 17:51:47 +00001580 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001581 ctxt->errTab =
1582 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard20863822003-03-22 17:51:47 +00001583 ctxt->errMax * sizeof(xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001584 if (ctxt->errTab == NULL) {
1585 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1586 return (0);
1587 }
Daniel Veillard20863822003-03-22 17:51:47 +00001588 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001589 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001590 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001591 (ctxt->err->node == ctxt->state->node) &&
1592 (ctxt->err->err == err))
1593 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001594 cur = &ctxt->errTab[ctxt->errNr];
1595 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001596 if (dup) {
1597 cur->arg1 = xmlStrdup(arg1);
1598 cur->arg2 = xmlStrdup(arg2);
1599 cur->flags = ERROR_IS_DUP;
1600 } else {
1601 cur->arg1 = arg1;
1602 cur->arg2 = arg2;
1603 cur->flags = 0;
1604 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001605 if (ctxt->state != NULL) {
1606 cur->node = ctxt->state->node;
1607 cur->seq = ctxt->state->seq;
1608 } else {
1609 cur->node = NULL;
1610 cur->seq = NULL;
1611 }
1612 ctxt->err = cur;
1613 return (ctxt->errNr++);
1614}
1615
1616/**
1617 * xmlRelaxNGValidErrorPop:
1618 * @ctxt: the validation context
1619 *
1620 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001621 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001622static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001623xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1624{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001625 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001626
Daniel Veillard580ced82003-03-21 21:22:48 +00001627 if (ctxt->errNr <= 0) {
1628 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001629 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001630 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001631 ctxt->errNr--;
1632 if (ctxt->errNr > 0)
1633 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1634 else
1635 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001636 cur = &ctxt->errTab[ctxt->errNr];
1637 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001638 if (cur->arg1 != NULL)
1639 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001640 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001641 if (cur->arg2 != NULL)
1642 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001643 cur->arg2 = NULL;
1644 cur->flags = 0;
1645 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001646}
1647
Daniel Veillard42f12e92003-03-07 18:32:59 +00001648/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001649 * xmlRelaxNGDocumentPush:
1650 * @ctxt: the parser context
1651 * @value: the element doc
1652 *
1653 * Pushes a new doc on top of the doc stack
1654 *
1655 * Returns 0 in case of error, the index in the stack otherwise
1656 */
1657static int
1658xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1659 xmlRelaxNGDocumentPtr value)
1660{
1661 if (ctxt->docTab == NULL) {
1662 ctxt->docMax = 4;
1663 ctxt->docNr = 0;
1664 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1665 ctxt->docMax * sizeof(ctxt->docTab[0]));
1666 if (ctxt->docTab == NULL) {
1667 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1668 return (0);
1669 }
1670 }
1671 if (ctxt->docNr >= ctxt->docMax) {
1672 ctxt->docMax *= 2;
1673 ctxt->docTab =
1674 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1675 ctxt->docMax *
1676 sizeof(ctxt->docTab[0]));
1677 if (ctxt->docTab == NULL) {
1678 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1679 return (0);
1680 }
1681 }
1682 ctxt->docTab[ctxt->docNr] = value;
1683 ctxt->doc = value;
1684 return (ctxt->docNr++);
1685}
1686
1687/**
1688 * xmlRelaxNGDocumentPop:
1689 * @ctxt: the parser context
1690 *
1691 * Pops the top doc from the doc stack
1692 *
1693 * Returns the doc just removed
1694 */
1695static xmlRelaxNGDocumentPtr
1696xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1697{
1698 xmlRelaxNGDocumentPtr ret;
1699
1700 if (ctxt->docNr <= 0)
1701 return (0);
1702 ctxt->docNr--;
1703 if (ctxt->docNr > 0)
1704 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1705 else
1706 ctxt->doc = NULL;
1707 ret = ctxt->docTab[ctxt->docNr];
1708 ctxt->docTab[ctxt->docNr] = 0;
1709 return (ret);
1710}
1711
1712/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001713 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001714 * @ctxt: the parser context
1715 * @URL: the normalized URL
1716 * @ns: the inherited ns if any
1717 *
1718 * First lookup if the document is already loaded into the parser context,
1719 * check against recursion. If not found the resource is loaded and
1720 * the content is preprocessed before being returned back to the caller.
1721 *
1722 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1723 */
1724static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001725xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001726 const xmlChar *ns) {
1727 xmlRelaxNGDocumentPtr ret = NULL;
1728 xmlDocPtr doc;
1729 xmlNodePtr root;
1730 int i;
1731
1732 /*
1733 * check against recursion in the stack
1734 */
1735 for (i = 0;i < ctxt->docNr;i++) {
1736 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1737 if (ctxt->error != NULL)
1738 ctxt->error(ctxt->userData,
1739 "Detected an externalRef recursion for %s\n",
1740 URL);
1741 ctxt->nbErrors++;
1742 return(NULL);
1743 }
1744 }
1745
1746 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001747 * load the document
1748 */
1749 doc = xmlParseFile((const char *) URL);
1750 if (doc == NULL) {
1751 if (ctxt->error != NULL)
1752 ctxt->error(ctxt->userData,
1753 "xmlRelaxNG: could not load %s\n", URL);
1754 ctxt->nbErrors++;
1755 return (NULL);
1756 }
1757
1758 /*
1759 * Allocate the document structures and register it first.
1760 */
1761 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1762 if (ret == NULL) {
1763 if (ctxt->error != NULL)
1764 ctxt->error(ctxt->userData,
1765 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1766 ctxt->nbErrors++;
1767 xmlFreeDoc(doc);
1768 return (NULL);
1769 }
1770 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1771 ret->doc = doc;
1772 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001773 ret->next = ctxt->documents;
1774 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001775
1776 /*
1777 * transmit the ns if needed
1778 */
1779 if (ns != NULL) {
1780 root = xmlDocGetRootElement(doc);
1781 if (root != NULL) {
1782 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1783 xmlSetProp(root, BAD_CAST"ns", ns);
1784 }
1785 }
1786 }
1787
1788 /*
1789 * push it on the stack and register it in the hash table
1790 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001791 xmlRelaxNGDocumentPush(ctxt, ret);
1792
1793 /*
1794 * Some preprocessing of the document content
1795 */
1796 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1797 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001798 ctxt->doc = NULL;
1799 return(NULL);
1800 }
1801
1802 xmlRelaxNGDocumentPop(ctxt);
1803
1804 return(ret);
1805}
1806
1807/************************************************************************
1808 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001809 * Error functions *
1810 * *
1811 ************************************************************************/
1812
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001813#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1814#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1815#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1816#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1817#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001818
Daniel Veillard231d7912003-02-09 14:22:17 +00001819static const char *
1820xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1821 if (def == NULL)
1822 return("none");
1823 switch(def->type) {
1824 case XML_RELAXNG_EMPTY: return("empty");
1825 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1826 case XML_RELAXNG_EXCEPT: return("except");
1827 case XML_RELAXNG_TEXT: return("text");
1828 case XML_RELAXNG_ELEMENT: return("element");
1829 case XML_RELAXNG_DATATYPE: return("datatype");
1830 case XML_RELAXNG_VALUE: return("value");
1831 case XML_RELAXNG_LIST: return("list");
1832 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1833 case XML_RELAXNG_DEF: return("def");
1834 case XML_RELAXNG_REF: return("ref");
1835 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1836 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001837 case XML_RELAXNG_OPTIONAL: return("optional");
1838 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001839 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1840 case XML_RELAXNG_CHOICE: return("choice");
1841 case XML_RELAXNG_GROUP: return("group");
1842 case XML_RELAXNG_INTERLEAVE: return("interleave");
1843 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001844 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001845 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001846 }
1847 return("unknown");
1848}
Daniel Veillardd2298792003-02-14 16:54:11 +00001849
Daniel Veillard6eadf632003-01-23 18:29:16 +00001850/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001851 * xmlRelaxNGGetErrorString:
1852 * @err: the error code
1853 * @arg1: the first string argument
1854 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001855 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001856 * computes a formatted error string for the given error code and args
1857 *
1858 * Returns the error string, it must be deallocated by the caller
1859 */
1860static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001861xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1862 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001863 char msg[1000];
1864
1865 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001866 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001867 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001868 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001869
1870 msg[0] = 0;
1871 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001872 case XML_RELAXNG_OK:
1873 return(NULL);
1874 case XML_RELAXNG_ERR_MEMORY:
1875 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001876 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001877 snprintf(msg, 1000, "failed to validate type %s", arg1);
1878 break;
1879 case XML_RELAXNG_ERR_TYPEVAL:
Daniel Veillardc4c21552003-03-29 10:53:38 +00001880 snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001881 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001882 case XML_RELAXNG_ERR_DUPID:
1883 snprintf(msg, 1000, "ID %s redefined", arg1);
1884 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001885 case XML_RELAXNG_ERR_TYPECMP:
1886 snprintf(msg, 1000, "failed to compare type %s", arg1);
1887 break;
1888 case XML_RELAXNG_ERR_NOSTATE:
1889 return(xmlCharStrdup("Internal error: no state"));
1890 case XML_RELAXNG_ERR_NODEFINE:
1891 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001892 case XML_RELAXNG_ERR_INTERNAL:
1893 snprintf(msg, 1000, "Internal error: %s", arg1);
1894 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001895 case XML_RELAXNG_ERR_LISTEXTRA:
1896 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1897 break;
1898 case XML_RELAXNG_ERR_INTERNODATA:
1899 return(xmlCharStrdup("Internal: interleave block has no data"));
1900 case XML_RELAXNG_ERR_INTERSEQ:
1901 return(xmlCharStrdup("Invalid sequence in interleave"));
1902 case XML_RELAXNG_ERR_INTEREXTRA:
1903 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1904 break;
1905 case XML_RELAXNG_ERR_ELEMNAME:
1906 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1907 break;
1908 case XML_RELAXNG_ERR_ELEMNONS:
1909 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1910 break;
1911 case XML_RELAXNG_ERR_ELEMWRONGNS:
1912 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1913 arg1, arg2);
1914 break;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00001915 case XML_RELAXNG_ERR_ELEMWRONG:
1916 snprintf(msg, 1000, "Did not expect element %s there",
1917 arg1);
1918 break;
1919 case XML_RELAXNG_ERR_TEXTWRONG:
1920 snprintf(msg, 1000, "Did not expect text in element %s content",
1921 arg1);
1922 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001923 case XML_RELAXNG_ERR_ELEMEXTRANS:
1924 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1925 break;
1926 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1927 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1928 break;
1929 case XML_RELAXNG_ERR_NOELEM:
1930 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1931 break;
1932 case XML_RELAXNG_ERR_NOTELEM:
1933 return(xmlCharStrdup("Expecting an element got text"));
1934 case XML_RELAXNG_ERR_ATTRVALID:
1935 snprintf(msg, 1000, "Element %s failed to validate attributes",
1936 arg1);
1937 break;
1938 case XML_RELAXNG_ERR_CONTENTVALID:
1939 snprintf(msg, 1000, "Element %s failed to validate content",
1940 arg1);
1941 break;
1942 case XML_RELAXNG_ERR_EXTRACONTENT:
1943 snprintf(msg, 1000, "Element %s has extra content: %s",
1944 arg1, arg2);
1945 break;
1946 case XML_RELAXNG_ERR_INVALIDATTR:
1947 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1948 arg1, arg2);
1949 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +00001950 case XML_RELAXNG_ERR_LACKDATA:
1951 snprintf(msg, 1000, "Datatype element %s contains no data",
1952 arg1);
1953 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001954 case XML_RELAXNG_ERR_DATAELEM:
1955 snprintf(msg, 1000, "Datatype element %s has child elements",
1956 arg1);
1957 break;
1958 case XML_RELAXNG_ERR_VALELEM:
1959 snprintf(msg, 1000, "Value element %s has child elements",
1960 arg1);
1961 break;
1962 case XML_RELAXNG_ERR_LISTELEM:
1963 snprintf(msg, 1000, "List element %s has child elements",
1964 arg1);
1965 break;
1966 case XML_RELAXNG_ERR_DATATYPE:
1967 snprintf(msg, 1000, "Error validating datatype %s",
1968 arg1);
1969 break;
1970 case XML_RELAXNG_ERR_VALUE:
1971 snprintf(msg, 1000, "Error validating value %s",
1972 arg1);
1973 break;
1974 case XML_RELAXNG_ERR_LIST:
1975 return(xmlCharStrdup("Error validating list"));
1976 case XML_RELAXNG_ERR_NOGRAMMAR:
1977 return(xmlCharStrdup("No top grammar defined"));
1978 case XML_RELAXNG_ERR_EXTRADATA:
1979 return(xmlCharStrdup("Extra data in the document"));
1980 default:
1981 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001982 }
1983 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001984 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001985 }
1986 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001987 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001988}
1989
1990/**
1991 * xmlRelaxNGValidErrorContext:
1992 * @ctxt: the validation context
1993 * @node: the node
1994 * @child: the node child generating the problem.
1995 *
1996 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001997 */
1998static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001999xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
2000 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00002001{
2002 int line = 0;
2003 const xmlChar *file = NULL;
2004 const xmlChar *name = NULL;
2005 const char *type = "error";
2006
2007 if ((ctxt == NULL) || (ctxt->error == NULL))
2008 return;
2009
2010 if (child != NULL)
2011 node = child;
2012
2013 if (node != NULL) {
2014 if ((node->type == XML_DOCUMENT_NODE) ||
2015 (node->type == XML_HTML_DOCUMENT_NODE)) {
2016 xmlDocPtr doc = (xmlDocPtr) node;
2017
2018 file = doc->URL;
2019 } else {
2020 /*
2021 * Try to find contextual informations to report
2022 */
2023 if (node->type == XML_ELEMENT_NODE) {
2024 line = (int) node->content;
2025 } else if ((node->prev != NULL) &&
2026 (node->prev->type == XML_ELEMENT_NODE)) {
2027 line = (int) node->prev->content;
2028 } else if ((node->parent != NULL) &&
2029 (node->parent->type == XML_ELEMENT_NODE)) {
2030 line = (int) node->parent->content;
2031 }
2032 if ((node->doc != NULL) && (node->doc->URL != NULL))
2033 file = node->doc->URL;
2034 if (node->name != NULL)
2035 name = node->name;
2036 }
2037 }
2038
Daniel Veillard42f12e92003-03-07 18:32:59 +00002039 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002040
2041 if ((file != NULL) && (line != 0) && (name != NULL))
2042 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2043 type, file, line, name);
2044 else if ((file != NULL) && (name != NULL))
2045 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2046 type, file, name);
2047 else if ((file != NULL) && (line != 0))
2048 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2049 else if (file != NULL)
2050 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2051 else if (name != NULL)
2052 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2053 else
2054 ctxt->error(ctxt->userData, "%s\n", type);
2055}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002056
2057/**
2058 * xmlRelaxNGShowValidError:
2059 * @ctxt: the validation context
2060 * @err: the error number
2061 * @node: the node
2062 * @child: the node child generating the problem.
2063 * @arg1: the first argument
2064 * @arg2: the second argument
2065 *
2066 * Show a validation error.
2067 */
2068static void
2069xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2070 xmlNodePtr node, xmlNodePtr child,
2071 const xmlChar *arg1, const xmlChar *arg2)
2072{
2073 xmlChar *msg;
2074
2075 if (ctxt->error == NULL)
2076 return;
2077
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002078#ifdef DEBUG_ERROR
2079 xmlGenericError(xmlGenericErrorContext,
2080 "Show error %d\n", err);
2081#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002082 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2083 if (msg == NULL)
2084 return;
2085
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002086 if (ctxt->errNo == XML_RELAXNG_OK)
2087 ctxt->errNo = err;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002088 xmlRelaxNGValidErrorContext(ctxt, node, child);
2089 ctxt->error(ctxt->userData, "%s\n", msg);
2090 xmlFree(msg);
2091}
2092
2093/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002094 * xmlRelaxNGPopErrors:
2095 * @ctxt: the validation context
2096 * @level: the error level in the stack
2097 *
2098 * pop and discard all errors until the given level is reached
2099 */
2100static void
2101xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2102 int i;
2103 xmlRelaxNGValidErrorPtr err;
2104
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002105#ifdef DEBUG_ERROR
2106 xmlGenericError(xmlGenericErrorContext,
2107 "Pop errors till level %d\n", level);
2108#endif
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002109 for (i = level;i < ctxt->errNr;i++) {
2110 err = &ctxt->errTab[i];
2111 if (err->flags & ERROR_IS_DUP) {
2112 if (err->arg1 != NULL)
2113 xmlFree((xmlChar *)err->arg1);
2114 err->arg1 = NULL;
2115 if (err->arg2 != NULL)
2116 xmlFree((xmlChar *)err->arg2);
2117 err->arg2 = NULL;
2118 err->flags = 0;
2119 }
2120 }
2121 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002122 if (ctxt->errNr <= 0)
2123 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002124}
2125/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002126 * xmlRelaxNGDumpValidError:
2127 * @ctxt: the validation context
2128 *
2129 * Show all validation error over a given index.
2130 */
2131static void
2132xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002133 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002134 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002135
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002136#ifdef DEBUG_ERROR
2137 xmlGenericError(xmlGenericErrorContext,
2138 "Dumping error stack %d errors\n", ctxt->errNr);
2139#endif
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002140 for (i = 0, k = 0;i < ctxt->errNr;i++) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00002141 err = &ctxt->errTab[i];
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002142 if (k < MAX_ERROR) {
2143 for (j = 0;j < i;j++) {
2144 dup = &ctxt->errTab[j];
2145 if ((err->err == dup->err) && (err->node == dup->node) &&
2146 (xmlStrEqual(err->arg1, dup->arg1)) &&
2147 (xmlStrEqual(err->arg2, dup->arg2))) {
2148 goto skip;
2149 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002150 }
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002151 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2152 err->arg1, err->arg2);
2153 k++;
Daniel Veillard580ced82003-03-21 21:22:48 +00002154 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002155skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002156 if (err->flags & ERROR_IS_DUP) {
2157 if (err->arg1 != NULL)
2158 xmlFree((xmlChar *)err->arg1);
2159 err->arg1 = NULL;
2160 if (err->arg2 != NULL)
2161 xmlFree((xmlChar *)err->arg2);
2162 err->arg2 = NULL;
2163 err->flags = 0;
2164 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002165 }
2166 ctxt->errNr = 0;
2167}
2168/**
2169 * xmlRelaxNGAddValidError:
2170 * @ctxt: the validation context
2171 * @err: the error number
2172 * @arg1: the first argument
2173 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002174 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002175 *
2176 * Register a validation error, either generating it if it's sure
2177 * or stacking it for later handling if unsure.
2178 */
2179static void
2180xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002181 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002182{
2183 if ((ctxt == NULL) || (ctxt->error == NULL))
2184 return;
2185
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002186#ifdef DEBUG_ERROR
2187 xmlGenericError(xmlGenericErrorContext,
2188 "Adding error %d\n", err);
2189#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002190 /*
2191 * generate the error directly
2192 */
2193 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2194 xmlNodePtr node, seq;
2195 /*
2196 * Flush first any stacked error which might be the
2197 * real cause of the problem.
2198 */
2199 if (ctxt->errNr != 0)
2200 xmlRelaxNGDumpValidError(ctxt);
2201 if (ctxt->state != NULL) {
2202 node = ctxt->state->node;
2203 seq = ctxt->state->seq;
2204 } else {
2205 node = seq = NULL;
2206 }
2207 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2208 }
2209 /*
2210 * Stack the error for later processing if needed
2211 */
2212 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002213 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002214 }
2215}
2216
Daniel Veillard6eadf632003-01-23 18:29:16 +00002217
2218/************************************************************************
2219 * *
2220 * Type library hooks *
2221 * *
2222 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002223static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2224 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002225
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002226/**
2227 * xmlRelaxNGSchemaTypeHave:
2228 * @data: data needed for the library
2229 * @type: the type name
2230 *
2231 * Check if the given type is provided by
2232 * the W3C XMLSchema Datatype library.
2233 *
2234 * Returns 1 if yes, 0 if no and -1 in case of error.
2235 */
2236static int
2237xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002238 const xmlChar *type) {
2239 xmlSchemaTypePtr typ;
2240
2241 if (type == NULL)
2242 return(-1);
2243 typ = xmlSchemaGetPredefinedType(type,
2244 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2245 if (typ == NULL)
2246 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002247 return(1);
2248}
2249
2250/**
2251 * xmlRelaxNGSchemaTypeCheck:
2252 * @data: data needed for the library
2253 * @type: the type name
2254 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002255 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002256 *
2257 * Check if the given type and value are validated by
2258 * the W3C XMLSchema Datatype library.
2259 *
2260 * Returns 1 if yes, 0 if no and -1 in case of error.
2261 */
2262static int
2263xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002264 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002265 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002266 void **result,
2267 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002268 xmlSchemaTypePtr typ;
2269 int ret;
2270
2271 /*
2272 * TODO: the type should be cached ab provided back, interface subject
2273 * to changes.
2274 * TODO: handle facets, may require an additional interface and keep
2275 * the value returned from the validation.
2276 */
2277 if ((type == NULL) || (value == NULL))
2278 return(-1);
2279 typ = xmlSchemaGetPredefinedType(type,
2280 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2281 if (typ == NULL)
2282 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002283 ret = xmlSchemaValPredefTypeNode(typ, value,
2284 (xmlSchemaValPtr *) result, node);
2285 if (ret == 2) /* special ID error code */
2286 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002287 if (ret == 0)
2288 return(1);
2289 if (ret > 0)
2290 return(0);
2291 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002292}
2293
2294/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002295 * xmlRelaxNGSchemaFacetCheck:
2296 * @data: data needed for the library
2297 * @type: the type name
2298 * @facet: the facet name
2299 * @val: the facet value
2300 * @strval: the string value
2301 * @value: the value to check
2302 *
2303 * Function provided by a type library to check a value facet
2304 *
2305 * Returns 1 if yes, 0 if no and -1 in case of error.
2306 */
2307static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002308xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002309 const xmlChar *facetname, const xmlChar *val,
2310 const xmlChar *strval, void *value) {
2311 xmlSchemaFacetPtr facet;
2312 xmlSchemaTypePtr typ;
2313 int ret;
2314
2315 if ((type == NULL) || (strval == NULL))
2316 return(-1);
2317 typ = xmlSchemaGetPredefinedType(type,
2318 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2319 if (typ == NULL)
2320 return(-1);
2321
2322 facet = xmlSchemaNewFacet();
2323 if (facet == NULL)
2324 return(-1);
2325
2326 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2327 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2328 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2329 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2330 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2331 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2332 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2333 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2334 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2335 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2336 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2337 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2338 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2339 facet->type = XML_SCHEMA_FACET_PATTERN;
2340 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2341 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2342 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2343 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2344 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2345 facet->type = XML_SCHEMA_FACET_LENGTH;
2346 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2347 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2348 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2349 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2350 } else {
2351 xmlSchemaFreeFacet(facet);
2352 return(-1);
2353 }
2354 facet->value = xmlStrdup(val);
2355 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2356 if (ret != 0) {
2357 xmlSchemaFreeFacet(facet);
2358 return(-1);
2359 }
2360 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2361 xmlSchemaFreeFacet(facet);
2362 if (ret != 0)
2363 return(-1);
2364 return(0);
2365}
2366
2367/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002368 * xmlRelaxNGSchemaFreeValue:
2369 * @data: data needed for the library
2370 * @value: the value to free
2371 *
2372 * Function provided by a type library to free a Schemas value
2373 *
2374 * Returns 1 if yes, 0 if no and -1 in case of error.
2375 */
2376static void
2377xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2378 xmlSchemaFreeValue(value);
2379}
2380
2381/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002382 * xmlRelaxNGSchemaTypeCompare:
2383 * @data: data needed for the library
2384 * @type: the type name
2385 * @value1: the first value
2386 * @value2: the second value
2387 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002388 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002389 * Datatype library.
2390 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002391 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002392 */
2393static int
2394xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002395 const xmlChar *type,
2396 const xmlChar *value1,
2397 xmlNodePtr ctxt1,
2398 void *comp1,
2399 const xmlChar *value2,
2400 xmlNodePtr ctxt2) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002401 int ret;
2402 xmlSchemaTypePtr typ;
2403 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2404
2405 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2406 return(-1);
2407 typ = xmlSchemaGetPredefinedType(type,
2408 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2409 if (typ == NULL)
2410 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002411 if (comp1 == NULL) {
2412 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2413 if (ret != 0)
2414 return(-1);
2415 if (res1 == NULL)
2416 return(-1);
2417 } else {
2418 res1 = (xmlSchemaValPtr) comp1;
2419 }
2420 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002421 if (ret != 0) {
2422 xmlSchemaFreeValue(res1);
2423 return(-1);
2424 }
2425 if (res1 == NULL) {
2426 xmlSchemaFreeValue(res1);
2427 return(-1);
2428 }
2429 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002430 if (res1 != (xmlSchemaValPtr) comp1)
2431 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002432 xmlSchemaFreeValue(res2);
2433 if (ret == -2)
2434 return(-1);
2435 if (ret == 0)
2436 return(1);
2437 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002438}
2439
2440/**
2441 * xmlRelaxNGDefaultTypeHave:
2442 * @data: data needed for the library
2443 * @type: the type name
2444 *
2445 * Check if the given type is provided by
2446 * the default datatype library.
2447 *
2448 * Returns 1 if yes, 0 if no and -1 in case of error.
2449 */
2450static int
2451xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2452 if (type == NULL)
2453 return(-1);
2454 if (xmlStrEqual(type, BAD_CAST "string"))
2455 return(1);
2456 if (xmlStrEqual(type, BAD_CAST "token"))
2457 return(1);
2458 return(0);
2459}
2460
2461/**
2462 * xmlRelaxNGDefaultTypeCheck:
2463 * @data: data needed for the library
2464 * @type: the type name
2465 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002466 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002467 *
2468 * Check if the given type and value are validated by
2469 * the default datatype library.
2470 *
2471 * Returns 1 if yes, 0 if no and -1 in case of error.
2472 */
2473static int
2474xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2475 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002476 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002477 void **result ATTRIBUTE_UNUSED,
2478 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002479 if (value == NULL)
2480 return(-1);
2481 if (xmlStrEqual(type, BAD_CAST "string"))
2482 return(1);
2483 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002484 return(1);
2485 }
2486
2487 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002488}
2489
2490/**
2491 * xmlRelaxNGDefaultTypeCompare:
2492 * @data: data needed for the library
2493 * @type: the type name
2494 * @value1: the first value
2495 * @value2: the second value
2496 *
2497 * Compare two values accordingly a type from the default
2498 * datatype library.
2499 *
2500 * Returns 1 if yes, 0 if no and -1 in case of error.
2501 */
2502static int
2503xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002504 const xmlChar *type,
2505 const xmlChar *value1,
2506 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2507 void *comp1 ATTRIBUTE_UNUSED,
2508 const xmlChar *value2,
2509 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002510 int ret = -1;
2511
2512 if (xmlStrEqual(type, BAD_CAST "string")) {
2513 ret = xmlStrEqual(value1, value2);
2514 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2515 if (!xmlStrEqual(value1, value2)) {
2516 xmlChar *nval, *nvalue;
2517
2518 /*
2519 * TODO: trivial optimizations are possible by
2520 * computing at compile-time
2521 */
2522 nval = xmlRelaxNGNormalize(NULL, value1);
2523 nvalue = xmlRelaxNGNormalize(NULL, value2);
2524
Daniel Veillardd4310742003-02-18 21:12:46 +00002525 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002526 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002527 else if (xmlStrEqual(nval, nvalue))
2528 ret = 1;
2529 else
2530 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002531 if (nval != NULL)
2532 xmlFree(nval);
2533 if (nvalue != NULL)
2534 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002535 } else
2536 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002537 }
2538 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002539}
2540
2541static int xmlRelaxNGTypeInitialized = 0;
2542static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2543
2544/**
2545 * xmlRelaxNGFreeTypeLibrary:
2546 * @lib: the type library structure
2547 * @namespace: the URI bound to the library
2548 *
2549 * Free the structure associated to the type library
2550 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002551static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002552xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2553 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2554 if (lib == NULL)
2555 return;
2556 if (lib->namespace != NULL)
2557 xmlFree((xmlChar *)lib->namespace);
2558 xmlFree(lib);
2559}
2560
2561/**
2562 * xmlRelaxNGRegisterTypeLibrary:
2563 * @namespace: the URI bound to the library
2564 * @data: data associated to the library
2565 * @have: the provide function
2566 * @check: the checking function
2567 * @comp: the comparison function
2568 *
2569 * Register a new type library
2570 *
2571 * Returns 0 in case of success and -1 in case of error.
2572 */
2573static int
2574xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2575 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002576 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2577 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002578 xmlRelaxNGTypeLibraryPtr lib;
2579 int ret;
2580
2581 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2582 (check == NULL) || (comp == NULL))
2583 return(-1);
2584 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2585 xmlGenericError(xmlGenericErrorContext,
2586 "Relax-NG types library '%s' already registered\n",
2587 namespace);
2588 return(-1);
2589 }
2590 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2591 if (lib == NULL) {
2592 xmlGenericError(xmlGenericErrorContext,
2593 "Relax-NG types library '%s' malloc() failed\n",
2594 namespace);
2595 return (-1);
2596 }
2597 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2598 lib->namespace = xmlStrdup(namespace);
2599 lib->data = data;
2600 lib->have = have;
2601 lib->comp = comp;
2602 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002603 lib->facet = facet;
2604 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002605 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2606 if (ret < 0) {
2607 xmlGenericError(xmlGenericErrorContext,
2608 "Relax-NG types library failed to register '%s'\n",
2609 namespace);
2610 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2611 return(-1);
2612 }
2613 return(0);
2614}
2615
2616/**
2617 * xmlRelaxNGInitTypes:
2618 *
2619 * Initilize the default type libraries.
2620 *
2621 * Returns 0 in case of success and -1 in case of error.
2622 */
2623static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002624xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002625 if (xmlRelaxNGTypeInitialized != 0)
2626 return(0);
2627 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2628 if (xmlRelaxNGRegisteredTypes == NULL) {
2629 xmlGenericError(xmlGenericErrorContext,
2630 "Failed to allocate sh table for Relax-NG types\n");
2631 return(-1);
2632 }
2633 xmlRelaxNGRegisterTypeLibrary(
2634 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2635 NULL,
2636 xmlRelaxNGSchemaTypeHave,
2637 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002638 xmlRelaxNGSchemaTypeCompare,
2639 xmlRelaxNGSchemaFacetCheck,
Daniel Veillard80b19092003-03-28 13:29:53 +00002640 xmlRelaxNGSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002641 xmlRelaxNGRegisterTypeLibrary(
2642 xmlRelaxNGNs,
2643 NULL,
2644 xmlRelaxNGDefaultTypeHave,
2645 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002646 xmlRelaxNGDefaultTypeCompare,
2647 NULL,
2648 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002649 xmlRelaxNGTypeInitialized = 1;
2650 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002651}
2652
2653/**
2654 * xmlRelaxNGCleanupTypes:
2655 *
2656 * Cleanup the default Schemas type library associated to RelaxNG
2657 */
2658void
2659xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002660 if (xmlRelaxNGTypeInitialized == 0)
2661 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002662 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002663 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2664 xmlRelaxNGFreeTypeLibrary);
2665 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002666}
2667
2668/************************************************************************
2669 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002670 * Compiling element content into regexp *
2671 * *
2672 * Sometime the element content can be compiled into a pure regexp, *
2673 * This allows a faster execution and streamability at that level *
2674 * *
2675 ************************************************************************/
2676
Daniel Veillard52b48c72003-04-13 19:53:42 +00002677static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2678 xmlRelaxNGDefinePtr def);
2679
Daniel Veillard952379b2003-03-17 15:37:12 +00002680/**
2681 * xmlRelaxNGIsCompileable:
2682 * @define: the definition to check
2683 *
2684 * Check if a definition is nullable.
2685 *
2686 * Returns 1 if yes, 0 if no and -1 in case of error
2687 */
2688static int
2689xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00002690 int ret = -1;
2691
Daniel Veillard952379b2003-03-17 15:37:12 +00002692 if (def == NULL) {
2693 return(-1);
2694 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002695 if ((def->type != XML_RELAXNG_ELEMENT) &&
2696 (def->dflags & IS_COMPILABLE))
2697 return(1);
2698 if ((def->type != XML_RELAXNG_ELEMENT) &&
2699 (def->dflags & IS_NOT_COMPILABLE))
2700 return(0);
Daniel Veillard952379b2003-03-17 15:37:12 +00002701 switch(def->type) {
2702 case XML_RELAXNG_REF:
2703 case XML_RELAXNG_EXTERNALREF:
2704 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002705 if (def->depth == -20) {
2706 return(1);
2707 } else {
2708 def->depth = -20;
2709 ret = xmlRelaxNGIsCompileable(def->content);
2710 }
2711 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002712 case XML_RELAXNG_NOOP:
2713 case XML_RELAXNG_START:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002714 ret = xmlRelaxNGIsCompileable(def->content);
2715 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002716 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002717 case XML_RELAXNG_EMPTY:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002718 ret = 1;
2719 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002720 case XML_RELAXNG_ELEMENT:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002721 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2722 ((def->dflags & IS_COMPILABLE) == 0)) {
2723 ret = xmlRelaxNGIsCompileable(def->content);
2724 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2725 if (ret == 1) def->dflags |= IS_COMPILABLE;
2726 }
2727 if ((def->nameClass != NULL) || (def->name == NULL))
2728 return(0);
2729 else
2730 return(1);
2731 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002732 case XML_RELAXNG_OPTIONAL:
2733 case XML_RELAXNG_ZEROORMORE:
2734 case XML_RELAXNG_ONEORMORE:
2735 case XML_RELAXNG_CHOICE:
2736 case XML_RELAXNG_GROUP:
2737 case XML_RELAXNG_DEF: {
2738 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002739
2740 list = def->content;
2741 while (list != NULL) {
2742 ret = xmlRelaxNGIsCompileable(list);
2743 if (ret != 1)
Daniel Veillard52b48c72003-04-13 19:53:42 +00002744 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002745 list = list->next;
2746 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002747 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002748 }
2749 case XML_RELAXNG_EXCEPT:
2750 case XML_RELAXNG_ATTRIBUTE:
2751 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002752 case XML_RELAXNG_DATATYPE:
2753 case XML_RELAXNG_LIST:
2754 case XML_RELAXNG_PARAM:
2755 case XML_RELAXNG_VALUE:
2756 ret = 0;
2757 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002758 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002759 ret = -1;
2760 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002761 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002762 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2763 if (ret == 1) def->dflags |= IS_COMPILABLE;
2764 return(ret);
2765}
2766
2767/**
2768 * xmlRelaxNGCompile:
2769 * ctxt: the RelaxNG parser context
2770 * @define: the definition tree to compile
2771 *
2772 * Compile the set of definitions, it works recursively, till the
2773 * element boundaries, where it tries to compile the content if possible
2774 *
2775 * Returns 0 if success and -1 in case of error
2776 */
2777static int
2778xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2779 int ret = 0;
2780 xmlRelaxNGDefinePtr list;
2781
2782 if ((ctxt == NULL) || (def == NULL)) return(-1);
2783
2784 switch(def->type) {
2785 case XML_RELAXNG_START:
2786 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
2787 xmlAutomataPtr oldam = ctxt->am;
2788 xmlAutomataStatePtr oldstate = ctxt->state;
2789
2790 def->depth = -25;
2791
2792 list = def->content;
2793 ctxt->am = xmlNewAutomata();
2794 if (ctxt->am == NULL)
2795 return(-1);
2796 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2797 while (list != NULL) {
2798 xmlRelaxNGCompile(ctxt, list);
2799 list = list->next;
2800 }
2801 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2802 def->contModel = xmlAutomataCompile(ctxt->am);
2803 xmlRegexpIsDeterminist(def->contModel);
2804
2805 xmlFreeAutomata(ctxt->am);
2806 ctxt->state = oldstate;
2807 ctxt->am = oldam;
2808 }
2809 break;
2810 case XML_RELAXNG_ELEMENT:
2811 if ((ctxt->am != NULL) && (def->name != NULL)) {
2812 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002813 ctxt->state, NULL, def->name, def->ns, def);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002814 }
2815 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2816 xmlAutomataPtr oldam = ctxt->am;
2817 xmlAutomataStatePtr oldstate = ctxt->state;
2818
2819 def->depth = -25;
2820
2821 list = def->content;
2822 ctxt->am = xmlNewAutomata();
2823 if (ctxt->am == NULL)
2824 return(-1);
2825 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2826 while (list != NULL) {
2827 xmlRelaxNGCompile(ctxt, list);
2828 list = list->next;
2829 }
2830 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2831 def->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002832 if (!xmlRegexpIsDeterminist(def->contModel)) {
2833 /*
2834 * we can only use the automata if it is determinist
2835 */
2836 xmlRegFreeRegexp(def->contModel);
2837 def->contModel = NULL;
2838 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002839 xmlFreeAutomata(ctxt->am);
2840 ctxt->state = oldstate;
2841 ctxt->am = oldam;
2842 } else {
2843 xmlAutomataPtr oldam = ctxt->am;
2844
2845 /*
2846 * we can't build the content model for this element content
2847 * but it still might be possible to build it for some of its
2848 * children, recurse.
2849 */
2850 ret = xmlRelaxNGTryCompile(ctxt, def);
2851 ctxt->am = oldam;
2852 }
2853 break;
2854 case XML_RELAXNG_REF:
2855 case XML_RELAXNG_EXTERNALREF:
2856 case XML_RELAXNG_PARENTREF:
2857 case XML_RELAXNG_NOOP:
2858 ret = xmlRelaxNGCompile(ctxt, def->content);
2859 break;
2860 case XML_RELAXNG_OPTIONAL: {
2861 xmlAutomataStatePtr oldstate = ctxt->state;
2862
2863 xmlRelaxNGCompile(ctxt, def->content);
2864 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
2865 break;
2866 }
2867 case XML_RELAXNG_ZEROORMORE: {
2868 xmlAutomataStatePtr oldstate;
2869
2870 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2871 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002872 list = def->content;
2873 while (list != NULL) {
2874 xmlRelaxNGCompile(ctxt, list);
2875 list = list->next;
2876 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002877 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2878 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2879 break;
2880 }
2881 case XML_RELAXNG_ONEORMORE: {
2882 xmlAutomataStatePtr oldstate;
2883
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002884 list = def->content;
2885 while (list != NULL) {
2886 xmlRelaxNGCompile(ctxt, list);
2887 list = list->next;
2888 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002889 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002890 list = def->content;
2891 while (list != NULL) {
2892 xmlRelaxNGCompile(ctxt, list);
2893 list = list->next;
2894 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002895 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2896 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2897 break;
2898 }
2899 case XML_RELAXNG_CHOICE: {
2900 xmlAutomataStatePtr target = NULL;
2901 xmlAutomataStatePtr oldstate = ctxt->state;
2902
2903 list = def->content;
2904 while (list != NULL) {
2905 ctxt->state = oldstate;
2906 xmlRelaxNGCompile(ctxt, list);
2907 if (target == NULL)
2908 target = ctxt->state;
2909 else {
2910 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, target);
2911 }
2912 list = list->next;
2913 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002914 ctxt->state = target;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002915
2916 break;
2917 }
2918 case XML_RELAXNG_GROUP:
2919 case XML_RELAXNG_DEF:
2920 list = def->content;
2921 while (list != NULL) {
2922 xmlRelaxNGCompile(ctxt, list);
2923 list = list->next;
2924 }
2925 break;
2926 case XML_RELAXNG_TEXT: {
2927 xmlAutomataStatePtr oldstate;
2928
2929 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2930 oldstate = ctxt->state;
2931 xmlRelaxNGCompile(ctxt, def->content);
2932 xmlAutomataNewTransition(ctxt->am, ctxt->state, ctxt->state,
2933 BAD_CAST "#text", NULL);
2934 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2935 break;
2936 }
2937 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002938 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002939 break;
2940 case XML_RELAXNG_EXCEPT:
2941 case XML_RELAXNG_ATTRIBUTE:
2942 case XML_RELAXNG_INTERLEAVE:
2943 case XML_RELAXNG_NOT_ALLOWED:
2944 case XML_RELAXNG_DATATYPE:
2945 case XML_RELAXNG_LIST:
2946 case XML_RELAXNG_PARAM:
2947 case XML_RELAXNG_VALUE:
2948 TODO /* This should not happen and generate an internal error */
2949 printf("trying to compile %s\n", xmlRelaxNGDefName(def));
2950
2951 break;
2952 }
2953 return(ret);
2954}
2955
2956/**
2957 * xmlRelaxNGTryCompile:
2958 * ctxt: the RelaxNG parser context
2959 * @define: the definition tree to compile
2960 *
2961 * Try to compile the set of definitions, it works recursively,
2962 * possibly ignoring parts which cannot be compiled.
2963 *
2964 * Returns 0 if success and -1 in case of error
2965 */
2966static int
2967xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2968 int ret = 0;
2969 xmlRelaxNGDefinePtr list;
2970
2971 if ((ctxt == NULL) || (def == NULL)) return(-1);
2972
2973 if ((def->type == XML_RELAXNG_START) ||
2974 (def->type == XML_RELAXNG_ELEMENT)) {
2975 ret = xmlRelaxNGIsCompileable(def);
2976 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2977 ctxt->am = NULL;
2978 ret = xmlRelaxNGCompile(ctxt, def);
2979 return(ret);
2980 }
2981 }
2982 switch(def->type) {
2983 case XML_RELAXNG_REF:
2984 case XML_RELAXNG_EXTERNALREF:
2985 case XML_RELAXNG_PARENTREF:
2986 case XML_RELAXNG_NOOP:
2987 case XML_RELAXNG_START:
2988 ret = xmlRelaxNGTryCompile(ctxt, def->content);
2989 break;
2990 case XML_RELAXNG_TEXT:
2991 case XML_RELAXNG_DATATYPE:
2992 case XML_RELAXNG_LIST:
2993 case XML_RELAXNG_PARAM:
2994 case XML_RELAXNG_VALUE:
2995 case XML_RELAXNG_EMPTY:
2996 case XML_RELAXNG_ELEMENT:
2997 ret = 0;
2998 break;
2999 case XML_RELAXNG_OPTIONAL:
3000 case XML_RELAXNG_ZEROORMORE:
3001 case XML_RELAXNG_ONEORMORE:
3002 case XML_RELAXNG_CHOICE:
3003 case XML_RELAXNG_GROUP:
3004 case XML_RELAXNG_DEF:
3005 list = def->content;
3006 while (list != NULL) {
3007 ret = xmlRelaxNGTryCompile(ctxt, list);
3008 if (ret != 0)
3009 break;
3010 list = list->next;
3011 }
3012 break;
3013 case XML_RELAXNG_EXCEPT:
3014 case XML_RELAXNG_ATTRIBUTE:
3015 case XML_RELAXNG_INTERLEAVE:
3016 case XML_RELAXNG_NOT_ALLOWED:
3017 ret = 0;
3018 break;
3019 }
3020 return(ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003021}
3022
3023/************************************************************************
3024 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003025 * Parsing functions *
3026 * *
3027 ************************************************************************/
3028
3029static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
3030 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3031static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
3032 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3033static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00003034 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003035static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
3036 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003037static xmlRelaxNGPtr xmlRelaxNGParseDocument(
3038 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003039static int xmlRelaxNGParseGrammarContent(
3040 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003041static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
3042 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3043 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00003044static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
3045 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003046static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3047 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003048
3049
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003050#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003051
3052/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003053 * xmlRelaxNGIsNullable:
3054 * @define: the definition to verify
3055 *
3056 * Check if a definition is nullable.
3057 *
3058 * Returns 1 if yes, 0 if no and -1 in case of error
3059 */
3060static int
3061xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
3062 int ret;
3063 if (define == NULL)
3064 return(-1);
3065
Daniel Veillarde063f482003-03-21 16:53:17 +00003066 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003067 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003068 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003069 return(0);
3070 switch (define->type) {
3071 case XML_RELAXNG_EMPTY:
3072 case XML_RELAXNG_TEXT:
3073 ret = 1; break;
3074 case XML_RELAXNG_NOOP:
3075 case XML_RELAXNG_DEF:
3076 case XML_RELAXNG_REF:
3077 case XML_RELAXNG_EXTERNALREF:
3078 case XML_RELAXNG_PARENTREF:
3079 case XML_RELAXNG_ONEORMORE:
3080 ret = xmlRelaxNGIsNullable(define->content);
3081 break;
3082 case XML_RELAXNG_EXCEPT:
3083 case XML_RELAXNG_NOT_ALLOWED:
3084 case XML_RELAXNG_ELEMENT:
3085 case XML_RELAXNG_DATATYPE:
3086 case XML_RELAXNG_PARAM:
3087 case XML_RELAXNG_VALUE:
3088 case XML_RELAXNG_LIST:
3089 case XML_RELAXNG_ATTRIBUTE:
3090 ret = 0; break;
3091 case XML_RELAXNG_CHOICE: {
3092 xmlRelaxNGDefinePtr list = define->content;
3093
3094 while (list != NULL) {
3095 ret = xmlRelaxNGIsNullable(list);
3096 if (ret != 0)
3097 goto done;
3098 list = list->next;
3099 }
3100 ret = 0; break;
3101 }
3102 case XML_RELAXNG_START:
3103 case XML_RELAXNG_INTERLEAVE:
3104 case XML_RELAXNG_GROUP: {
3105 xmlRelaxNGDefinePtr list = define->content;
3106
3107 while (list != NULL) {
3108 ret = xmlRelaxNGIsNullable(list);
3109 if (ret != 1)
3110 goto done;
3111 list = list->next;
3112 }
3113 return(1);
3114 }
3115 default:
3116 return(-1);
3117 }
3118done:
3119 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003120 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003121 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00003122 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003123 return(ret);
3124}
3125
3126/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003127 * xmlRelaxNGIsBlank:
3128 * @str: a string
3129 *
3130 * Check if a string is ignorable c.f. 4.2. Whitespace
3131 *
3132 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3133 */
3134static int
3135xmlRelaxNGIsBlank(xmlChar *str) {
3136 if (str == NULL)
3137 return(1);
3138 while (*str != 0) {
3139 if (!(IS_BLANK(*str))) return(0);
3140 str++;
3141 }
3142 return(1);
3143}
3144
Daniel Veillard6eadf632003-01-23 18:29:16 +00003145/**
3146 * xmlRelaxNGGetDataTypeLibrary:
3147 * @ctxt: a Relax-NG parser context
3148 * @node: the current data or value element
3149 *
3150 * Applies algorithm from 4.3. datatypeLibrary attribute
3151 *
3152 * Returns the datatypeLibary value or NULL if not found
3153 */
3154static xmlChar *
3155xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3156 xmlNodePtr node) {
3157 xmlChar *ret, *escape;
3158
Daniel Veillard6eadf632003-01-23 18:29:16 +00003159 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3160 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3161 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003162 if (ret[0] == 0) {
3163 xmlFree(ret);
3164 return(NULL);
3165 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003166 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00003167 if (escape == NULL) {
3168 return(ret);
3169 }
3170 xmlFree(ret);
3171 return(escape);
3172 }
3173 }
3174 node = node->parent;
3175 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003176 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3177 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003178 if (ret[0] == 0) {
3179 xmlFree(ret);
3180 return(NULL);
3181 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003182 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3183 if (escape == NULL) {
3184 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003185 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003186 xmlFree(ret);
3187 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003188 }
3189 node = node->parent;
3190 }
3191 return(NULL);
3192}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003193
3194/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003195 * xmlRelaxNGParseValue:
3196 * @ctxt: a Relax-NG parser context
3197 * @node: the data node.
3198 *
3199 * parse the content of a RelaxNG value node.
3200 *
3201 * Returns the definition pointer or NULL in case of error
3202 */
3203static xmlRelaxNGDefinePtr
3204xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3205 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003206 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003207 xmlChar *type;
3208 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003209 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003210
Daniel Veillardfd573f12003-03-16 17:52:32 +00003211 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003212 if (def == NULL)
3213 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003214 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003215
3216 type = xmlGetProp(node, BAD_CAST "type");
3217 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003218 xmlRelaxNGNormExtSpace(type);
3219 if (xmlValidateNCName(type, 0)) {
3220 if (ctxt->error != NULL)
3221 ctxt->error(ctxt->userData,
3222 "value type '%s' is not an NCName\n",
3223 type);
3224 ctxt->nbErrors++;
3225 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003226 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3227 if (library == NULL)
3228 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3229
3230 def->name = type;
3231 def->ns = library;
3232
3233 lib = (xmlRelaxNGTypeLibraryPtr)
3234 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3235 if (lib == NULL) {
3236 if (ctxt->error != NULL)
3237 ctxt->error(ctxt->userData,
3238 "Use of unregistered type library '%s'\n",
3239 library);
3240 ctxt->nbErrors++;
3241 def->data = NULL;
3242 } else {
3243 def->data = lib;
3244 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003245 if (ctxt->error != NULL)
3246 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003247 "Internal error with type library '%s': no 'have'\n",
3248 library);
3249 ctxt->nbErrors++;
3250 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003251 success = lib->have(lib->data, def->name);
3252 if (success != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003253 if (ctxt->error != NULL)
3254 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003255 "Error type '%s' is not exported by type library '%s'\n",
3256 def->name, library);
3257 ctxt->nbErrors++;
3258 }
3259 }
3260 }
3261 }
3262 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00003263 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003264 } else if (((node->children->type != XML_TEXT_NODE) &&
3265 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00003266 (node->children->next != NULL)) {
3267 if (ctxt->error != NULL)
3268 ctxt->error(ctxt->userData,
3269 "Expecting a single text value for <value>content\n");
3270 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003271 } else if (def != NULL) {
Daniel Veillardedc91922003-01-26 00:52:04 +00003272 def->value = xmlNodeGetContent(node);
3273 if (def->value == NULL) {
3274 if (ctxt->error != NULL)
3275 ctxt->error(ctxt->userData,
3276 "Element <value> has no content\n");
3277 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003278 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3279 void *val = NULL;
3280
3281 success = lib->check(lib->data, def->name, def->value, &val, node);
3282 if (success != 1) {
3283 if (ctxt->error != NULL)
3284 ctxt->error(ctxt->userData,
3285 "Value '%s' is not acceptable for type '%s'\n",
3286 def->value, def->name);
3287 ctxt->nbErrors++;
3288 } else {
3289 if (val != NULL)
3290 def->attrs = val;
3291 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003292 }
3293 }
3294 /* TODO check ahead of time that the value is okay per the type */
3295 return(def);
3296}
3297
3298/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003299 * xmlRelaxNGParseData:
3300 * @ctxt: a Relax-NG parser context
3301 * @node: the data node.
3302 *
3303 * parse the content of a RelaxNG data node.
3304 *
3305 * Returns the definition pointer or NULL in case of error
3306 */
3307static xmlRelaxNGDefinePtr
3308xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003309 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003310 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003311 xmlRelaxNGTypeLibraryPtr lib;
3312 xmlChar *type;
3313 xmlChar *library;
3314 xmlNodePtr content;
3315 int tmp;
3316
3317 type = xmlGetProp(node, BAD_CAST "type");
3318 if (type == NULL) {
3319 if (ctxt->error != NULL)
3320 ctxt->error(ctxt->userData,
3321 "data has no type\n");
3322 ctxt->nbErrors++;
3323 return(NULL);
3324 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003325 xmlRelaxNGNormExtSpace(type);
3326 if (xmlValidateNCName(type, 0)) {
3327 if (ctxt->error != NULL)
3328 ctxt->error(ctxt->userData,
3329 "data type '%s' is not an NCName\n",
3330 type);
3331 ctxt->nbErrors++;
3332 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003333 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3334 if (library == NULL)
3335 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3336
Daniel Veillardfd573f12003-03-16 17:52:32 +00003337 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003338 if (def == NULL) {
3339 xmlFree(type);
3340 return(NULL);
3341 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003342 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003343 def->name = type;
3344 def->ns = library;
3345
3346 lib = (xmlRelaxNGTypeLibraryPtr)
3347 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3348 if (lib == NULL) {
3349 if (ctxt->error != NULL)
3350 ctxt->error(ctxt->userData,
3351 "Use of unregistered type library '%s'\n",
3352 library);
3353 ctxt->nbErrors++;
3354 def->data = NULL;
3355 } else {
3356 def->data = lib;
3357 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003358 if (ctxt->error != NULL)
3359 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003360 "Internal error with type library '%s': no 'have'\n",
3361 library);
3362 ctxt->nbErrors++;
3363 } else {
3364 tmp = lib->have(lib->data, def->name);
3365 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003366 if (ctxt->error != NULL)
3367 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003368 "Error type '%s' is not exported by type library '%s'\n",
3369 def->name, library);
3370 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003371 } else if ((xmlStrEqual(library, BAD_CAST
3372 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3373 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3374 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3375 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003376 }
3377 }
3378 }
3379 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003380
3381 /*
3382 * Handle optional params
3383 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003384 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003385 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3386 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003387 if (xmlStrEqual(library,
3388 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3389 if (ctxt->error != NULL)
3390 ctxt->error(ctxt->userData,
3391 "Type library '%s' does not allow type parameters\n",
3392 library);
3393 ctxt->nbErrors++;
3394 content = content->next;
3395 while ((content != NULL) &&
3396 (xmlStrEqual(content->name, BAD_CAST "param")))
3397 content = content->next;
3398 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003399 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003400 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003401 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003402 param->name = xmlGetProp(content, BAD_CAST "name");
3403 if (param->name == NULL) {
3404 if (ctxt->error != NULL)
3405 ctxt->error(ctxt->userData,
3406 "param has no name\n");
3407 ctxt->nbErrors++;
3408 }
3409 param->value = xmlNodeGetContent(content);
3410 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003411 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003412 } else {
3413 lastparam->next = param;
3414 lastparam = param;
3415 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003416 if (lib != NULL) {
3417 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003418 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003419 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003420 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003421 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003422 /*
3423 * Handle optional except
3424 */
3425 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3426 xmlNodePtr child;
3427 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3428
Daniel Veillardfd573f12003-03-16 17:52:32 +00003429 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003430 if (except == NULL) {
3431 return(def);
3432 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003433 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003434 child = content->children;
3435 if (last == NULL) {
3436 def->content = except;
3437 } else {
3438 last->next = except;
3439 }
3440 if (child == NULL) {
3441 if (ctxt->error != NULL)
3442 ctxt->error(ctxt->userData,
3443 "except has no content\n");
3444 ctxt->nbErrors++;
3445 }
3446 while (child != NULL) {
3447 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3448 if (tmp2 != NULL) {
3449 if (last2 == NULL) {
3450 except->content = last2 = tmp2;
3451 } else {
3452 last2->next = tmp2;
3453 last2 = tmp2;
3454 }
3455 }
3456 child = child->next;
3457 }
3458 content = content->next;
3459 }
3460 /*
3461 * Check there is no unhandled data
3462 */
3463 if (content != NULL) {
3464 if (ctxt->error != NULL)
3465 ctxt->error(ctxt->userData,
3466 "Element data has unexpected content %s\n", content->name);
3467 ctxt->nbErrors++;
3468 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003469
3470 return(def);
3471}
3472
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003473static const xmlChar *invalidName = BAD_CAST "\1";
3474
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003475/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003476 * xmlRelaxNGCompareNameClasses:
3477 * @defs1: the first element/attribute defs
3478 * @defs2: the second element/attribute defs
3479 * @name: the restriction on the name
3480 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003481 *
3482 * Compare the 2 lists of element definitions. The comparison is
3483 * that if both lists do not accept the same QNames, it returns 1
3484 * If the 2 lists can accept the same QName the comparison returns 0
3485 *
3486 * Returns 1 disttinct, 0 if equal
3487 */
3488static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003489xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3490 xmlRelaxNGDefinePtr def2) {
3491 int ret = 1;
3492 xmlNode node;
3493 xmlNs ns;
3494 xmlRelaxNGValidCtxt ctxt;
3495 ctxt.flags = FLAGS_IGNORABLE;
3496
Daniel Veillard42f12e92003-03-07 18:32:59 +00003497 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3498
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003499 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3500 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3501 if (def2->type == XML_RELAXNG_TEXT)
3502 return(1);
3503 if (def1->name != NULL) {
3504 node.name = def1->name;
3505 } else {
3506 node.name = invalidName;
3507 }
3508 node.ns = &ns;
3509 if (def1->ns != NULL) {
3510 if (def1->ns[0] == 0) {
3511 node.ns = NULL;
3512 } else {
3513 ns.href = def1->ns;
3514 }
3515 } else {
3516 ns.href = invalidName;
3517 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003518 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003519 if (def1->nameClass != NULL) {
3520 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3521 } else {
3522 ret = 0;
3523 }
3524 } else {
3525 ret = 1;
3526 }
3527 } else if (def1->type == XML_RELAXNG_TEXT) {
3528 if (def2->type == XML_RELAXNG_TEXT)
3529 return(0);
3530 return(1);
3531 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003532 TODO
3533 ret = 0;
3534 } else {
3535 TODO
3536 ret = 0;
3537 }
3538 if (ret == 0)
3539 return(ret);
3540 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3541 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3542 if (def2->name != NULL) {
3543 node.name = def2->name;
3544 } else {
3545 node.name = invalidName;
3546 }
3547 node.ns = &ns;
3548 if (def2->ns != NULL) {
3549 if (def2->ns[0] == 0) {
3550 node.ns = NULL;
3551 } else {
3552 ns.href = def2->ns;
3553 }
3554 } else {
3555 ns.href = invalidName;
3556 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003557 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003558 if (def2->nameClass != NULL) {
3559 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3560 } else {
3561 ret = 0;
3562 }
3563 } else {
3564 ret = 1;
3565 }
3566 } else {
3567 TODO
3568 ret = 0;
3569 }
3570
3571 return(ret);
3572}
3573
3574/**
3575 * xmlRelaxNGCompareElemDefLists:
3576 * @ctxt: a Relax-NG parser context
3577 * @defs1: the first list of element/attribute defs
3578 * @defs2: the second list of element/attribute defs
3579 *
3580 * Compare the 2 lists of element or attribute definitions. The comparison
3581 * is that if both lists do not accept the same QNames, it returns 1
3582 * If the 2 lists can accept the same QName the comparison returns 0
3583 *
3584 * Returns 1 disttinct, 0 if equal
3585 */
3586static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003587xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3588 xmlRelaxNGDefinePtr *def1,
3589 xmlRelaxNGDefinePtr *def2) {
3590 xmlRelaxNGDefinePtr *basedef2 = def2;
3591
Daniel Veillard154877e2003-01-30 12:17:05 +00003592 if ((def1 == NULL) || (def2 == NULL))
3593 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003594 if ((*def1 == NULL) || (*def2 == NULL))
3595 return(1);
3596 while (*def1 != NULL) {
3597 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003598 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3599 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003600 def2++;
3601 }
3602 def2 = basedef2;
3603 def1++;
3604 }
3605 return(1);
3606}
3607
3608/**
3609 * xmlRelaxNGGetElements:
3610 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003611 * @def: the definition definition
3612 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003613 *
3614 * Compute the list of top elements a definition can generate
3615 *
3616 * Returns a list of elements or NULL if none was found.
3617 */
3618static xmlRelaxNGDefinePtr *
3619xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003620 xmlRelaxNGDefinePtr def,
3621 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003622 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003623 int len = 0;
3624 int max = 0;
3625
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003626 /*
3627 * Don't run that check in case of error. Infinite recursion
3628 * becomes possible.
3629 */
3630 if (ctxt->nbErrors != 0)
3631 return(NULL);
3632
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003633 parent = NULL;
3634 cur = def;
3635 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003636 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3637 (cur->type == XML_RELAXNG_TEXT))) ||
3638 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003639 if (ret == NULL) {
3640 max = 10;
3641 ret = (xmlRelaxNGDefinePtr *)
3642 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3643 if (ret == NULL) {
3644 if (ctxt->error != NULL)
3645 ctxt->error(ctxt->userData,
3646 "Out of memory in element search\n");
3647 ctxt->nbErrors++;
3648 return(NULL);
3649 }
3650 } else if (max <= len) {
3651 max *= 2;
3652 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3653 if (ret == NULL) {
3654 if (ctxt->error != NULL)
3655 ctxt->error(ctxt->userData,
3656 "Out of memory in element search\n");
3657 ctxt->nbErrors++;
3658 return(NULL);
3659 }
3660 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003661 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003662 ret[len] = NULL;
3663 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3664 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3665 (cur->type == XML_RELAXNG_GROUP) ||
3666 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003667 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3668 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003669 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003670 (cur->type == XML_RELAXNG_REF) ||
3671 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003672 /*
3673 * Don't go within elements or attributes or string values.
3674 * Just gather the element top list
3675 */
3676 if (cur->content != NULL) {
3677 parent = cur;
3678 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003679 tmp = cur;
3680 while (tmp != NULL) {
3681 tmp->parent = parent;
3682 tmp = tmp->next;
3683 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003684 continue;
3685 }
3686 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003687 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003688 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003689 if (cur->next != NULL) {
3690 cur = cur->next;
3691 continue;
3692 }
3693 do {
3694 cur = cur->parent;
3695 if (cur == NULL) break;
3696 if (cur == def) return(ret);
3697 if (cur->next != NULL) {
3698 cur = cur->next;
3699 break;
3700 }
3701 } while (cur != NULL);
3702 }
3703 return(ret);
3704}
3705
3706/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003707 * xmlRelaxNGCheckChoiceDeterminism:
3708 * @ctxt: a Relax-NG parser context
3709 * @def: the choice definition
3710 *
3711 * Also used to find indeterministic pattern in choice
3712 */
3713static void
3714xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3715 xmlRelaxNGDefinePtr def) {
3716 xmlRelaxNGDefinePtr **list;
3717 xmlRelaxNGDefinePtr cur;
3718 int nbchild = 0, i, j, ret;
3719 int is_nullable = 0;
3720 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003721 xmlHashTablePtr triage = NULL;
3722 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003723
3724 if ((def == NULL) ||
3725 (def->type != XML_RELAXNG_CHOICE))
3726 return;
3727
Daniel Veillarde063f482003-03-21 16:53:17 +00003728 if (def->dflags & IS_PROCESSED)
3729 return;
3730
Daniel Veillardfd573f12003-03-16 17:52:32 +00003731 /*
3732 * Don't run that check in case of error. Infinite recursion
3733 * becomes possible.
3734 */
3735 if (ctxt->nbErrors != 0)
3736 return;
3737
3738 is_nullable = xmlRelaxNGIsNullable(def);
3739
3740 cur = def->content;
3741 while (cur != NULL) {
3742 nbchild++;
3743 cur = cur->next;
3744 }
3745
3746 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3747 sizeof(xmlRelaxNGDefinePtr *));
3748 if (list == NULL) {
3749 if (ctxt->error != NULL)
3750 ctxt->error(ctxt->userData,
3751 "Out of memory in choice computation\n");
3752 ctxt->nbErrors++;
3753 return;
3754 }
3755 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003756 /*
3757 * a bit strong but safe
3758 */
3759 if (is_nullable == 0) {
3760 triage = xmlHashCreate(10);
3761 } else {
3762 is_triable = 0;
3763 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003764 cur = def->content;
3765 while (cur != NULL) {
3766 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003767 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3768 is_triable = 0;
3769 } else if (is_triable == 1) {
3770 xmlRelaxNGDefinePtr *tmp;
3771 int res;
3772
3773 tmp = list[i];
3774 while ((*tmp != NULL) && (is_triable == 1)) {
3775 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3776 res = xmlHashAddEntry2(triage,
3777 BAD_CAST "#text", NULL,
3778 (void *)cur);
3779 if (res != 0)
3780 is_triable = -1;
3781 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3782 ((*tmp)->name != NULL)) {
3783 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3784 res = xmlHashAddEntry2(triage,
3785 (*tmp)->name, NULL,
3786 (void *)cur);
3787 else
3788 res = xmlHashAddEntry2(triage,
3789 (*tmp)->name, (*tmp)->ns,
3790 (void *)cur);
3791 if (res != 0)
3792 is_triable = -1;
3793 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3794 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3795 res = xmlHashAddEntry2(triage,
3796 BAD_CAST "#any", NULL,
3797 (void *)cur);
3798 else
3799 res = xmlHashAddEntry2(triage,
3800 BAD_CAST "#any", (*tmp)->ns,
3801 (void *)cur);
3802 if (res != 0)
3803 is_triable = -1;
3804 } else {
3805 is_triable = -1;
3806 }
3807 tmp++;
3808 }
3809 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003810 i++;
3811 cur = cur->next;
3812 }
3813
3814 for (i = 0;i < nbchild;i++) {
3815 if (list[i] == NULL)
3816 continue;
3817 for (j = 0;j < i;j++) {
3818 if (list[j] == NULL)
3819 continue;
3820 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3821 if (ret == 0) {
3822 is_indeterminist = 1;
3823 }
3824 }
3825 }
3826 for (i = 0;i < nbchild;i++) {
3827 if (list[i] != NULL)
3828 xmlFree(list[i]);
3829 }
3830
3831 xmlFree(list);
3832 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003833 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003834 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003835 if (is_triable == 1) {
3836 def->dflags |= IS_TRIABLE;
3837 def->data = triage;
3838 } else if (triage != NULL) {
3839 xmlHashFree(triage, NULL);
3840 }
3841 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003842}
3843
3844/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003845 * xmlRelaxNGCheckGroupAttrs:
3846 * @ctxt: a Relax-NG parser context
3847 * @def: the group definition
3848 *
3849 * Detects violations of rule 7.3
3850 */
3851static void
3852xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3853 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003854 xmlRelaxNGDefinePtr **list;
3855 xmlRelaxNGDefinePtr cur;
3856 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003857
3858 if ((def == NULL) ||
3859 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003860 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003861 return;
3862
Daniel Veillarde063f482003-03-21 16:53:17 +00003863 if (def->dflags & IS_PROCESSED)
3864 return;
3865
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003866 /*
3867 * Don't run that check in case of error. Infinite recursion
3868 * becomes possible.
3869 */
3870 if (ctxt->nbErrors != 0)
3871 return;
3872
Daniel Veillardfd573f12003-03-16 17:52:32 +00003873 cur = def->attrs;
3874 while (cur != NULL) {
3875 nbchild++;
3876 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003877 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003878 cur = def->content;
3879 while (cur != NULL) {
3880 nbchild++;
3881 cur = cur->next;
3882 }
3883
3884 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3885 sizeof(xmlRelaxNGDefinePtr *));
3886 if (list == NULL) {
3887 if (ctxt->error != NULL)
3888 ctxt->error(ctxt->userData,
3889 "Out of memory in group computation\n");
3890 ctxt->nbErrors++;
3891 return;
3892 }
3893 i = 0;
3894 cur = def->attrs;
3895 while (cur != NULL) {
3896 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3897 i++;
3898 cur = cur->next;
3899 }
3900 cur = def->content;
3901 while (cur != NULL) {
3902 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3903 i++;
3904 cur = cur->next;
3905 }
3906
3907 for (i = 0;i < nbchild;i++) {
3908 if (list[i] == NULL)
3909 continue;
3910 for (j = 0;j < i;j++) {
3911 if (list[j] == NULL)
3912 continue;
3913 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3914 if (ret == 0) {
3915 if (ctxt->error != NULL)
3916 ctxt->error(ctxt->userData,
3917 "Attributes conflicts in group\n");
3918 ctxt->nbErrors++;
3919 }
3920 }
3921 }
3922 for (i = 0;i < nbchild;i++) {
3923 if (list[i] != NULL)
3924 xmlFree(list[i]);
3925 }
3926
3927 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00003928 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003929}
3930
3931/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003932 * xmlRelaxNGComputeInterleaves:
3933 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003934 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003935 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003936 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003937 * A lot of work for preprocessing interleave definitions
3938 * is potentially needed to get a decent execution speed at runtime
3939 * - trying to get a total order on the element nodes generated
3940 * by the interleaves, order the list of interleave definitions
3941 * following that order.
3942 * - if <text/> is used to handle mixed content, it is better to
3943 * flag this in the define and simplify the runtime checking
3944 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003945 */
3946static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003947xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3948 xmlRelaxNGParserCtxtPtr ctxt,
3949 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003950 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003951
Daniel Veillardfd573f12003-03-16 17:52:32 +00003952 xmlRelaxNGPartitionPtr partitions = NULL;
3953 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3954 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003955 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003956 int nbgroups = 0;
3957 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003958 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003959 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003960
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003961 /*
3962 * Don't run that check in case of error. Infinite recursion
3963 * becomes possible.
3964 */
3965 if (ctxt->nbErrors != 0)
3966 return;
3967
Daniel Veillardfd573f12003-03-16 17:52:32 +00003968#ifdef DEBUG_INTERLEAVE
3969 xmlGenericError(xmlGenericErrorContext,
3970 "xmlRelaxNGComputeInterleaves(%s)\n",
3971 name);
3972#endif
3973 cur = def->content;
3974 while (cur != NULL) {
3975 nbchild++;
3976 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003977 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003978
3979#ifdef DEBUG_INTERLEAVE
3980 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3981#endif
3982 groups = (xmlRelaxNGInterleaveGroupPtr *)
3983 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3984 if (groups == NULL)
3985 goto error;
3986 cur = def->content;
3987 while (cur != NULL) {
3988 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3989 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3990 if (groups[nbgroups] == NULL)
3991 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003992 if (cur->type == XML_RELAXNG_TEXT)
3993 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003994 groups[nbgroups]->rule = cur;
3995 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3996 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3997 nbgroups++;
3998 cur = cur->next;
3999 }
4000#ifdef DEBUG_INTERLEAVE
4001 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4002#endif
4003
4004 /*
4005 * Let's check that all rules makes a partitions according to 7.4
4006 */
4007 partitions = (xmlRelaxNGPartitionPtr)
4008 xmlMalloc(sizeof(xmlRelaxNGPartition));
4009 if (partitions == NULL)
4010 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004011 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004012 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004013 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004014 for (i = 0;i < nbgroups;i++) {
4015 group = groups[i];
4016 for (j = i+1;j < nbgroups;j++) {
4017 if (groups[j] == NULL)
4018 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004019
Daniel Veillardfd573f12003-03-16 17:52:32 +00004020 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4021 groups[j]->defs);
4022 if (ret == 0) {
4023 if (ctxt->error != NULL)
4024 ctxt->error(ctxt->userData,
4025 "Element or text conflicts in interleave\n");
4026 ctxt->nbErrors++;
4027 }
4028 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4029 groups[j]->attrs);
4030 if (ret == 0) {
4031 if (ctxt->error != NULL)
4032 ctxt->error(ctxt->userData,
4033 "Attributes conflicts in interleave\n");
4034 ctxt->nbErrors++;
4035 }
4036 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004037 tmp = group->defs;
4038 if ((tmp != NULL) && (*tmp != NULL)) {
4039 while (*tmp != NULL) {
4040 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4041 res = xmlHashAddEntry2(partitions->triage,
4042 BAD_CAST "#text", NULL,
4043 (void *)(i + 1));
4044 if (res != 0)
4045 is_determinist = -1;
4046 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4047 ((*tmp)->name != NULL)) {
4048 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4049 res = xmlHashAddEntry2(partitions->triage,
4050 (*tmp)->name, NULL,
4051 (void *)(i + 1));
4052 else
4053 res = xmlHashAddEntry2(partitions->triage,
4054 (*tmp)->name, (*tmp)->ns,
4055 (void *)(i + 1));
4056 if (res != 0)
4057 is_determinist = -1;
4058 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4059 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4060 res = xmlHashAddEntry2(partitions->triage,
4061 BAD_CAST "#any", NULL,
4062 (void *)(i + 1));
4063 else
4064 res = xmlHashAddEntry2(partitions->triage,
4065 BAD_CAST "#any", (*tmp)->ns,
4066 (void *)(i + 1));
4067 if ((*tmp)->nameClass != NULL)
4068 is_determinist = 2;
4069 if (res != 0)
4070 is_determinist = -1;
4071 } else {
4072 is_determinist = -1;
4073 }
4074 tmp++;
4075 }
4076 } else {
4077 is_determinist = 0;
4078 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004079 }
4080 partitions->groups = groups;
4081
4082 /*
4083 * and save the partition list back in the def
4084 */
4085 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004086 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00004087 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004088 if (is_determinist == 1)
4089 partitions->flags = IS_DETERMINIST;
4090 if (is_determinist == 2)
4091 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004092 return;
4093
4094error:
4095 if (ctxt->error != NULL)
4096 ctxt->error(ctxt->userData,
4097 "Out of memory in interleave computation\n");
4098 ctxt->nbErrors++;
4099 if (groups != NULL) {
4100 for (i = 0;i < nbgroups;i++)
4101 if (groups[i] != NULL) {
4102 if (groups[i]->defs != NULL)
4103 xmlFree(groups[i]->defs);
4104 xmlFree(groups[i]);
4105 }
4106 xmlFree(groups);
4107 }
4108 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004109}
4110
4111/**
4112 * xmlRelaxNGParseInterleave:
4113 * @ctxt: a Relax-NG parser context
4114 * @node: the data node.
4115 *
4116 * parse the content of a RelaxNG interleave node.
4117 *
4118 * Returns the definition pointer or NULL in case of error
4119 */
4120static xmlRelaxNGDefinePtr
4121xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4122 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004123 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004124 xmlNodePtr child;
4125
Daniel Veillardfd573f12003-03-16 17:52:32 +00004126 def = xmlRelaxNGNewDefine(ctxt, node);
4127 if (def == NULL) {
4128 return(NULL);
4129 }
4130 def->type = XML_RELAXNG_INTERLEAVE;
4131
4132 if (ctxt->interleaves == NULL)
4133 ctxt->interleaves = xmlHashCreate(10);
4134 if (ctxt->interleaves == NULL) {
4135 if (ctxt->error != NULL)
4136 ctxt->error(ctxt->userData,
4137 "Failed to create interleaves hash table\n");
4138 ctxt->nbErrors++;
4139 } else {
4140 char name[32];
4141
4142 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4143 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4144 if (ctxt->error != NULL)
4145 ctxt->error(ctxt->userData,
4146 "Failed to add %s to hash table\n", name);
4147 ctxt->nbErrors++;
4148 }
4149 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004150 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004151 if (child == NULL) {
4152 if (ctxt->error != NULL)
4153 ctxt->error(ctxt->userData, "Element interleave is empty\n");
4154 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004155 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004156 while (child != NULL) {
4157 if (IS_RELAXNG(child, "element")) {
4158 cur = xmlRelaxNGParseElement(ctxt, child);
4159 } else {
4160 cur = xmlRelaxNGParsePattern(ctxt, child);
4161 }
4162 if (cur != NULL) {
4163 cur->parent = def;
4164 if (last == NULL) {
4165 def->content = last = cur;
4166 } else {
4167 last->next = cur;
4168 last = cur;
4169 }
4170 }
4171 child = child->next;
4172 }
4173
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004174 return(def);
4175}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004176
4177/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004178 * xmlRelaxNGParseInclude:
4179 * @ctxt: a Relax-NG parser context
4180 * @node: the include node
4181 *
4182 * Integrate the content of an include node in the current grammar
4183 *
4184 * Returns 0 in case of success or -1 in case of error
4185 */
4186static int
4187xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4188 xmlRelaxNGIncludePtr incl;
4189 xmlNodePtr root;
4190 int ret = 0, tmp;
4191
4192 incl = node->_private;
4193 if (incl == NULL) {
4194 if (ctxt->error != NULL)
4195 ctxt->error(ctxt->userData,
4196 "Include node has no data\n");
4197 ctxt->nbErrors++;
4198 return(-1);
4199 }
4200 root = xmlDocGetRootElement(incl->doc);
4201 if (root == NULL) {
4202 if (ctxt->error != NULL)
4203 ctxt->error(ctxt->userData,
4204 "Include document is empty\n");
4205 ctxt->nbErrors++;
4206 return(-1);
4207 }
4208 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4209 if (ctxt->error != NULL)
4210 ctxt->error(ctxt->userData,
4211 "Include document root is not a grammar\n");
4212 ctxt->nbErrors++;
4213 return(-1);
4214 }
4215
4216 /*
4217 * Merge the definition from both the include and the internal list
4218 */
4219 if (root->children != NULL) {
4220 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4221 if (tmp != 0)
4222 ret = -1;
4223 }
4224 if (node->children != NULL) {
4225 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4226 if (tmp != 0)
4227 ret = -1;
4228 }
4229 return(ret);
4230}
4231
4232/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004233 * xmlRelaxNGParseDefine:
4234 * @ctxt: a Relax-NG parser context
4235 * @node: the define node
4236 *
4237 * parse the content of a RelaxNG define element node.
4238 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004239 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004240 */
4241static int
4242xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4243 xmlChar *name;
4244 int ret = 0, tmp;
4245 xmlRelaxNGDefinePtr def;
4246 const xmlChar *olddefine;
4247
4248 name = xmlGetProp(node, BAD_CAST "name");
4249 if (name == NULL) {
4250 if (ctxt->error != NULL)
4251 ctxt->error(ctxt->userData,
4252 "define has no name\n");
4253 ctxt->nbErrors++;
4254 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004255 xmlRelaxNGNormExtSpace(name);
4256 if (xmlValidateNCName(name, 0)) {
4257 if (ctxt->error != NULL)
4258 ctxt->error(ctxt->userData,
4259 "define name '%s' is not an NCName\n",
4260 name);
4261 ctxt->nbErrors++;
4262 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004263 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004264 if (def == NULL) {
4265 xmlFree(name);
4266 return(-1);
4267 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004268 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004269 def->name = name;
4270 if (node->children == NULL) {
4271 if (ctxt->error != NULL)
4272 ctxt->error(ctxt->userData,
4273 "define has no children\n");
4274 ctxt->nbErrors++;
4275 } else {
4276 olddefine = ctxt->define;
4277 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00004278 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004279 ctxt->define = olddefine;
4280 }
4281 if (ctxt->grammar->defs == NULL)
4282 ctxt->grammar->defs = xmlHashCreate(10);
4283 if (ctxt->grammar->defs == NULL) {
4284 if (ctxt->error != NULL)
4285 ctxt->error(ctxt->userData,
4286 "Could not create definition hash\n");
4287 ctxt->nbErrors++;
4288 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004289 } else {
4290 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4291 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00004292 xmlRelaxNGDefinePtr prev;
4293
4294 prev = xmlHashLookup(ctxt->grammar->defs, name);
4295 if (prev == NULL) {
4296 if (ctxt->error != NULL)
4297 ctxt->error(ctxt->userData,
4298 "Internal error on define aggregation of %s\n",
4299 name);
4300 ctxt->nbErrors++;
4301 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00004302 } else {
4303 while (prev->nextHash != NULL)
4304 prev = prev->nextHash;
4305 prev->nextHash = def;
4306 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004307 }
4308 }
4309 }
4310 return(ret);
4311}
4312
4313/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004314 * xmlRelaxNGProcessExternalRef:
4315 * @ctxt: the parser context
4316 * @node: the externlRef node
4317 *
4318 * Process and compile an externlRef node
4319 *
4320 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4321 */
4322static xmlRelaxNGDefinePtr
4323xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4324 xmlRelaxNGDocumentPtr docu;
4325 xmlNodePtr root, tmp;
4326 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004327 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004328 xmlRelaxNGDefinePtr def;
4329
4330 docu = node->_private;
4331 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004332 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004333 if (def == NULL)
4334 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004335 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004336
4337 if (docu->content == NULL) {
4338 /*
4339 * Then do the parsing for good
4340 */
4341 root = xmlDocGetRootElement(docu->doc);
4342 if (root == NULL) {
4343 if (ctxt->error != NULL)
4344 ctxt->error(ctxt->userData,
4345 "xmlRelaxNGParse: %s is empty\n",
4346 ctxt->URL);
4347 ctxt->nbErrors++;
4348 return (NULL);
4349 }
4350 /*
4351 * ns transmission rules
4352 */
4353 ns = xmlGetProp(root, BAD_CAST "ns");
4354 if (ns == NULL) {
4355 tmp = node;
4356 while ((tmp != NULL) &&
4357 (tmp->type == XML_ELEMENT_NODE)) {
4358 ns = xmlGetProp(tmp, BAD_CAST "ns");
4359 if (ns != NULL) {
4360 break;
4361 }
4362 tmp = tmp->parent;
4363 }
4364 if (ns != NULL) {
4365 xmlSetProp(root, BAD_CAST "ns", ns);
4366 newNs = 1;
4367 xmlFree(ns);
4368 }
4369 } else {
4370 xmlFree(ns);
4371 }
4372
4373 /*
4374 * Parsing to get a precompiled schemas.
4375 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004376 oldflags = ctxt->flags;
4377 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004378 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004379 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004380 if ((docu->schema != NULL) &&
4381 (docu->schema->topgrammar != NULL)) {
4382 docu->content = docu->schema->topgrammar->start;
4383 }
4384
4385 /*
4386 * the externalRef may be reused in a different ns context
4387 */
4388 if (newNs == 1) {
4389 xmlUnsetProp(root, BAD_CAST "ns");
4390 }
4391 }
4392 def->content = docu->content;
4393 } else {
4394 def = NULL;
4395 }
4396 return(def);
4397}
4398
4399/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004400 * xmlRelaxNGParsePattern:
4401 * @ctxt: a Relax-NG parser context
4402 * @node: the pattern node.
4403 *
4404 * parse the content of a RelaxNG pattern node.
4405 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004406 * Returns the definition pointer or NULL in case of error or if no
4407 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004408 */
4409static xmlRelaxNGDefinePtr
4410xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4411 xmlRelaxNGDefinePtr def = NULL;
4412
Daniel Veillardd2298792003-02-14 16:54:11 +00004413 if (node == NULL) {
4414 return(NULL);
4415 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004416 if (IS_RELAXNG(node, "element")) {
4417 def = xmlRelaxNGParseElement(ctxt, node);
4418 } else if (IS_RELAXNG(node, "attribute")) {
4419 def = xmlRelaxNGParseAttribute(ctxt, node);
4420 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004421 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004422 if (def == NULL)
4423 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004424 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004425 if (node->children != NULL) {
4426 if (ctxt->error != NULL)
4427 ctxt->error(ctxt->userData, "empty: had a child node\n");
4428 ctxt->nbErrors++;
4429 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004430 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004431 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004432 if (def == NULL)
4433 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004434 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004435 if (node->children != NULL) {
4436 if (ctxt->error != NULL)
4437 ctxt->error(ctxt->userData, "text: had a child node\n");
4438 ctxt->nbErrors++;
4439 }
4440 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004441 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004442 if (def == NULL)
4443 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004444 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004445 if (node->children == NULL) {
4446 if (ctxt->error != NULL)
4447 ctxt->error(ctxt->userData,
4448 "Element %s is empty\n", node->name);
4449 ctxt->nbErrors++;
4450 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004451 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004452 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004453 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004454 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004455 if (def == NULL)
4456 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004457 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004458 if (node->children == NULL) {
4459 if (ctxt->error != NULL)
4460 ctxt->error(ctxt->userData,
4461 "Element %s is empty\n", node->name);
4462 ctxt->nbErrors++;
4463 } else {
4464 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4465 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004466 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004467 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004468 if (def == NULL)
4469 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004470 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004471 if (node->children == NULL) {
4472 if (ctxt->error != NULL)
4473 ctxt->error(ctxt->userData,
4474 "Element %s is empty\n", node->name);
4475 ctxt->nbErrors++;
4476 } else {
4477 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4478 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004479 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004480 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004481 if (def == NULL)
4482 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004483 def->type = XML_RELAXNG_CHOICE;
4484 if (node->children == NULL) {
4485 if (ctxt->error != NULL)
4486 ctxt->error(ctxt->userData,
4487 "Element %s is empty\n", node->name);
4488 ctxt->nbErrors++;
4489 } else {
4490 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4491 }
4492 } else if (IS_RELAXNG(node, "group")) {
4493 def = xmlRelaxNGNewDefine(ctxt, node);
4494 if (def == NULL)
4495 return(NULL);
4496 def->type = XML_RELAXNG_GROUP;
4497 if (node->children == NULL) {
4498 if (ctxt->error != NULL)
4499 ctxt->error(ctxt->userData,
4500 "Element %s is empty\n", node->name);
4501 ctxt->nbErrors++;
4502 } else {
4503 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4504 }
4505 } else if (IS_RELAXNG(node, "ref")) {
4506 def = xmlRelaxNGNewDefine(ctxt, node);
4507 if (def == NULL)
4508 return(NULL);
4509 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004510 def->name = xmlGetProp(node, BAD_CAST "name");
4511 if (def->name == NULL) {
4512 if (ctxt->error != NULL)
4513 ctxt->error(ctxt->userData,
4514 "ref has no name\n");
4515 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004516 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004517 xmlRelaxNGNormExtSpace(def->name);
4518 if (xmlValidateNCName(def->name, 0)) {
4519 if (ctxt->error != NULL)
4520 ctxt->error(ctxt->userData,
4521 "ref name '%s' is not an NCName\n",
4522 def->name);
4523 ctxt->nbErrors++;
4524 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004525 }
4526 if (node->children != NULL) {
4527 if (ctxt->error != NULL)
4528 ctxt->error(ctxt->userData,
4529 "ref is not empty\n");
4530 ctxt->nbErrors++;
4531 }
4532 if (ctxt->grammar->refs == NULL)
4533 ctxt->grammar->refs = xmlHashCreate(10);
4534 if (ctxt->grammar->refs == NULL) {
4535 if (ctxt->error != NULL)
4536 ctxt->error(ctxt->userData,
4537 "Could not create references hash\n");
4538 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004539 def = NULL;
4540 } else {
4541 int tmp;
4542
4543 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4544 if (tmp < 0) {
4545 xmlRelaxNGDefinePtr prev;
4546
4547 prev = (xmlRelaxNGDefinePtr)
4548 xmlHashLookup(ctxt->grammar->refs, def->name);
4549 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004550 if (def->name != NULL) {
4551 if (ctxt->error != NULL)
4552 ctxt->error(ctxt->userData,
4553 "Error refs definitions '%s'\n",
4554 def->name);
4555 } else {
4556 if (ctxt->error != NULL)
4557 ctxt->error(ctxt->userData,
4558 "Error refs definitions\n");
4559 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004560 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004561 def = NULL;
4562 } else {
4563 def->nextHash = prev->nextHash;
4564 prev->nextHash = def;
4565 }
4566 }
4567 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004568 } else if (IS_RELAXNG(node, "data")) {
4569 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004570 } else if (IS_RELAXNG(node, "value")) {
4571 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004572 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004573 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004574 if (def == NULL)
4575 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004576 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004577 if (node->children == NULL) {
4578 if (ctxt->error != NULL)
4579 ctxt->error(ctxt->userData,
4580 "Element %s is empty\n", node->name);
4581 ctxt->nbErrors++;
4582 } else {
4583 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4584 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004585 } else if (IS_RELAXNG(node, "interleave")) {
4586 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004587 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004588 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004589 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004590 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004591 if (def == NULL)
4592 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004593 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004594 if (node->children != NULL) {
4595 if (ctxt->error != NULL)
4596 ctxt->error(ctxt->userData,
4597 "xmlRelaxNGParse: notAllowed element is not empty\n");
4598 ctxt->nbErrors++;
4599 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004600 } else if (IS_RELAXNG(node, "grammar")) {
4601 xmlRelaxNGGrammarPtr grammar, old;
4602 xmlRelaxNGGrammarPtr oldparent;
4603
Daniel Veillardc482e262003-02-26 14:48:48 +00004604#ifdef DEBUG_GRAMMAR
4605 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4606#endif
4607
Daniel Veillard419a7682003-02-03 23:22:49 +00004608 oldparent = ctxt->parentgrammar;
4609 old = ctxt->grammar;
4610 ctxt->parentgrammar = old;
4611 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4612 if (old != NULL) {
4613 ctxt->grammar = old;
4614 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004615#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004616 if (grammar != NULL) {
4617 grammar->next = old->next;
4618 old->next = grammar;
4619 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004620#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004621 }
4622 if (grammar != NULL)
4623 def = grammar->start;
4624 else
4625 def = NULL;
4626 } else if (IS_RELAXNG(node, "parentRef")) {
4627 if (ctxt->parentgrammar == NULL) {
4628 if (ctxt->error != NULL)
4629 ctxt->error(ctxt->userData,
4630 "Use of parentRef without a parent grammar\n");
4631 ctxt->nbErrors++;
4632 return(NULL);
4633 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004634 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004635 if (def == NULL)
4636 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004637 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004638 def->name = xmlGetProp(node, BAD_CAST "name");
4639 if (def->name == NULL) {
4640 if (ctxt->error != NULL)
4641 ctxt->error(ctxt->userData,
4642 "parentRef has no name\n");
4643 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004644 } else {
4645 xmlRelaxNGNormExtSpace(def->name);
4646 if (xmlValidateNCName(def->name, 0)) {
4647 if (ctxt->error != NULL)
4648 ctxt->error(ctxt->userData,
4649 "parentRef name '%s' is not an NCName\n",
4650 def->name);
4651 ctxt->nbErrors++;
4652 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004653 }
4654 if (node->children != NULL) {
4655 if (ctxt->error != NULL)
4656 ctxt->error(ctxt->userData,
4657 "parentRef is not empty\n");
4658 ctxt->nbErrors++;
4659 }
4660 if (ctxt->parentgrammar->refs == NULL)
4661 ctxt->parentgrammar->refs = xmlHashCreate(10);
4662 if (ctxt->parentgrammar->refs == NULL) {
4663 if (ctxt->error != NULL)
4664 ctxt->error(ctxt->userData,
4665 "Could not create references hash\n");
4666 ctxt->nbErrors++;
4667 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004668 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004669 int tmp;
4670
4671 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4672 if (tmp < 0) {
4673 xmlRelaxNGDefinePtr prev;
4674
4675 prev = (xmlRelaxNGDefinePtr)
4676 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4677 if (prev == NULL) {
4678 if (ctxt->error != NULL)
4679 ctxt->error(ctxt->userData,
4680 "Internal error parentRef definitions '%s'\n",
4681 def->name);
4682 ctxt->nbErrors++;
4683 def = NULL;
4684 } else {
4685 def->nextHash = prev->nextHash;
4686 prev->nextHash = def;
4687 }
4688 }
4689 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004690 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004691 if (node->children == NULL) {
4692 if (ctxt->error != NULL)
4693 ctxt->error(ctxt->userData,
4694 "Mixed is empty\n");
4695 ctxt->nbErrors++;
4696 def = NULL;
4697 } else {
4698 def = xmlRelaxNGParseInterleave(ctxt, node);
4699 if (def != NULL) {
4700 xmlRelaxNGDefinePtr tmp;
4701
4702 if ((def->content != NULL) && (def->content->next != NULL)) {
4703 tmp = xmlRelaxNGNewDefine(ctxt, node);
4704 if (tmp != NULL) {
4705 tmp->type = XML_RELAXNG_GROUP;
4706 tmp->content = def->content;
4707 def->content = tmp;
4708 }
4709 }
4710
4711 tmp = xmlRelaxNGNewDefine(ctxt, node);
4712 if (tmp == NULL)
4713 return(def);
4714 tmp->type = XML_RELAXNG_TEXT;
4715 tmp->next = def->content;
4716 def->content = tmp;
4717 }
4718 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004719 } else {
4720 if (ctxt->error != NULL)
4721 ctxt->error(ctxt->userData,
4722 "Unexpected node %s is not a pattern\n",
4723 node->name);
4724 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004725 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004726 }
4727 return(def);
4728}
4729
4730/**
4731 * xmlRelaxNGParseAttribute:
4732 * @ctxt: a Relax-NG parser context
4733 * @node: the element node
4734 *
4735 * parse the content of a RelaxNG attribute node.
4736 *
4737 * Returns the definition pointer or NULL in case of error.
4738 */
4739static xmlRelaxNGDefinePtr
4740xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004741 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004742 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004743 int old_flags;
4744
Daniel Veillardfd573f12003-03-16 17:52:32 +00004745 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004746 if (ret == NULL)
4747 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004748 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004749 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004750 child = node->children;
4751 if (child == NULL) {
4752 if (ctxt->error != NULL)
4753 ctxt->error(ctxt->userData,
4754 "xmlRelaxNGParseattribute: attribute has no children\n");
4755 ctxt->nbErrors++;
4756 return(ret);
4757 }
4758 old_flags = ctxt->flags;
4759 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004760 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4761 if (cur != NULL)
4762 child = child->next;
4763
Daniel Veillardd2298792003-02-14 16:54:11 +00004764 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004765 cur = xmlRelaxNGParsePattern(ctxt, child);
4766 if (cur != NULL) {
4767 switch (cur->type) {
4768 case XML_RELAXNG_EMPTY:
4769 case XML_RELAXNG_NOT_ALLOWED:
4770 case XML_RELAXNG_TEXT:
4771 case XML_RELAXNG_ELEMENT:
4772 case XML_RELAXNG_DATATYPE:
4773 case XML_RELAXNG_VALUE:
4774 case XML_RELAXNG_LIST:
4775 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004776 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004777 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004778 case XML_RELAXNG_DEF:
4779 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004780 case XML_RELAXNG_ZEROORMORE:
4781 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004782 case XML_RELAXNG_CHOICE:
4783 case XML_RELAXNG_GROUP:
4784 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004785 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004786 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004787 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004788 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004789 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004790 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004791 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004792 if (ctxt->error != NULL)
4793 ctxt->error(ctxt->userData,
4794 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004795 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004796 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004797 case XML_RELAXNG_NOOP:
4798 TODO
4799 if (ctxt->error != NULL)
4800 ctxt->error(ctxt->userData,
4801 "Internal error, noop found\n");
4802 ctxt->nbErrors++;
4803 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004804 }
4805 }
4806 child = child->next;
4807 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004808 if (child != NULL) {
4809 if (ctxt->error != NULL)
4810 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4811 ctxt->nbErrors++;
4812 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004813 ctxt->flags = old_flags;
4814 return(ret);
4815}
4816
4817/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004818 * xmlRelaxNGParseExceptNameClass:
4819 * @ctxt: a Relax-NG parser context
4820 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004821 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004822 *
4823 * parse the content of a RelaxNG nameClass node.
4824 *
4825 * Returns the definition pointer or NULL in case of error.
4826 */
4827static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004828xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4829 xmlNodePtr node, int attr) {
4830 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4831 xmlNodePtr child;
4832
Daniel Veillardd2298792003-02-14 16:54:11 +00004833 if (!IS_RELAXNG(node, "except")) {
4834 if (ctxt->error != NULL)
4835 ctxt->error(ctxt->userData,
4836 "Expecting an except node\n");
4837 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004838 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004839 }
4840 if (node->next != NULL) {
4841 if (ctxt->error != NULL)
4842 ctxt->error(ctxt->userData,
4843 "exceptNameClass allows only a single except node\n");
4844 ctxt->nbErrors++;
4845 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004846 if (node->children == NULL) {
4847 if (ctxt->error != NULL)
4848 ctxt->error(ctxt->userData,
4849 "except has no content\n");
4850 ctxt->nbErrors++;
4851 return(NULL);
4852 }
4853
Daniel Veillardfd573f12003-03-16 17:52:32 +00004854 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004855 if (ret == NULL)
4856 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004857 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004858 child = node->children;
4859 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004860 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004861 if (cur == NULL)
4862 break;
4863 if (attr)
4864 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004865 else
4866 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004867
Daniel Veillard419a7682003-02-03 23:22:49 +00004868 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004869 if (last == NULL) {
4870 ret->content = cur;
4871 } else {
4872 last->next = cur;
4873 }
4874 last = cur;
4875 }
4876 child = child->next;
4877 }
4878
4879 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004880}
4881
4882/**
4883 * xmlRelaxNGParseNameClass:
4884 * @ctxt: a Relax-NG parser context
4885 * @node: the nameClass node
4886 * @def: the current definition
4887 *
4888 * parse the content of a RelaxNG nameClass node.
4889 *
4890 * Returns the definition pointer or NULL in case of error.
4891 */
4892static xmlRelaxNGDefinePtr
4893xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4894 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004895 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004896 xmlChar *val;
4897
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004898 ret = def;
4899 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4900 (IS_RELAXNG(node, "nsName"))) {
4901 if ((def->type != XML_RELAXNG_ELEMENT) &&
4902 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004903 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004904 if (ret == NULL)
4905 return(NULL);
4906 ret->parent = def;
4907 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4908 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004909 else
4910 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004911 }
4912 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004913 if (IS_RELAXNG(node, "name")) {
4914 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004915 xmlRelaxNGNormExtSpace(val);
4916 if (xmlValidateNCName(val, 0)) {
4917 if (ctxt->error != NULL) {
4918 if (node->parent != NULL)
4919 ctxt->error(ctxt->userData,
4920 "Element %s name '%s' is not an NCName\n",
4921 node->parent->name, val);
4922 else
4923 ctxt->error(ctxt->userData,
4924 "name '%s' is not an NCName\n",
4925 val);
4926 }
4927 ctxt->nbErrors++;
4928 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004929 ret->name = val;
4930 val = xmlGetProp(node, BAD_CAST "ns");
4931 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004932 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4933 (val != NULL) &&
4934 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4935 ctxt->error(ctxt->userData,
4936 "Attribute with namespace '%s' is not allowed\n",
4937 val);
4938 ctxt->nbErrors++;
4939 }
4940 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4941 (val != NULL) &&
4942 (val[0] == 0) &&
4943 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4944 ctxt->error(ctxt->userData,
4945 "Attribute with QName 'xmlns' is not allowed\n",
4946 val);
4947 ctxt->nbErrors++;
4948 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004949 } else if (IS_RELAXNG(node, "anyName")) {
4950 ret->name = NULL;
4951 ret->ns = NULL;
4952 if (node->children != NULL) {
4953 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004954 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4955 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004956 }
4957 } else if (IS_RELAXNG(node, "nsName")) {
4958 ret->name = NULL;
4959 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4960 if (ret->ns == NULL) {
4961 if (ctxt->error != NULL)
4962 ctxt->error(ctxt->userData,
4963 "nsName has no ns attribute\n");
4964 ctxt->nbErrors++;
4965 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004966 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4967 (ret->ns != NULL) &&
4968 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4969 ctxt->error(ctxt->userData,
4970 "Attribute with namespace '%s' is not allowed\n",
4971 ret->ns);
4972 ctxt->nbErrors++;
4973 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004974 if (node->children != NULL) {
4975 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004976 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4977 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004978 }
4979 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004980 xmlNodePtr child;
4981 xmlRelaxNGDefinePtr last = NULL;
4982
4983 ret = xmlRelaxNGNewDefine(ctxt, node);
4984 if (ret == NULL)
4985 return(NULL);
4986 ret->parent = def;
4987 ret->type = XML_RELAXNG_CHOICE;
4988
Daniel Veillardd2298792003-02-14 16:54:11 +00004989 if (node->children == NULL) {
4990 if (ctxt->error != NULL)
4991 ctxt->error(ctxt->userData,
4992 "Element choice is empty\n");
4993 ctxt->nbErrors++;
4994 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004995
4996 child = node->children;
4997 while (child != NULL) {
4998 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4999 if (tmp != NULL) {
5000 if (last == NULL) {
5001 last = ret->nameClass = tmp;
5002 } else {
5003 last->next = tmp;
5004 last = tmp;
5005 }
5006 }
5007 child = child->next;
5008 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005009 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005010 } else {
5011 if (ctxt->error != NULL)
5012 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00005013 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005014 node->name);
5015 ctxt->nbErrors++;
5016 return(NULL);
5017 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005018 if (ret != def) {
5019 if (def->nameClass == NULL) {
5020 def->nameClass = ret;
5021 } else {
5022 tmp = def->nameClass;
5023 while (tmp->next != NULL) {
5024 tmp = tmp->next;
5025 }
5026 tmp->next = ret;
5027 }
5028 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005029 return(ret);
5030}
5031
5032/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005033 * xmlRelaxNGParseElement:
5034 * @ctxt: a Relax-NG parser context
5035 * @node: the element node
5036 *
5037 * parse the content of a RelaxNG element node.
5038 *
5039 * Returns the definition pointer or NULL in case of error.
5040 */
5041static xmlRelaxNGDefinePtr
5042xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5043 xmlRelaxNGDefinePtr ret, cur, last;
5044 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005045 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005046
Daniel Veillardfd573f12003-03-16 17:52:32 +00005047 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005048 if (ret == NULL)
5049 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005050 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005051 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005052 child = node->children;
5053 if (child == NULL) {
5054 if (ctxt->error != NULL)
5055 ctxt->error(ctxt->userData,
5056 "xmlRelaxNGParseElement: element has no children\n");
5057 ctxt->nbErrors++;
5058 return(ret);
5059 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005060 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5061 if (cur != NULL)
5062 child = child->next;
5063
Daniel Veillard6eadf632003-01-23 18:29:16 +00005064 if (child == NULL) {
5065 if (ctxt->error != NULL)
5066 ctxt->error(ctxt->userData,
5067 "xmlRelaxNGParseElement: element has no content\n");
5068 ctxt->nbErrors++;
5069 return(ret);
5070 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005071 olddefine = ctxt->define;
5072 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005073 last = NULL;
5074 while (child != NULL) {
5075 cur = xmlRelaxNGParsePattern(ctxt, child);
5076 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005077 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005078 switch (cur->type) {
5079 case XML_RELAXNG_EMPTY:
5080 case XML_RELAXNG_NOT_ALLOWED:
5081 case XML_RELAXNG_TEXT:
5082 case XML_RELAXNG_ELEMENT:
5083 case XML_RELAXNG_DATATYPE:
5084 case XML_RELAXNG_VALUE:
5085 case XML_RELAXNG_LIST:
5086 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00005087 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005088 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005089 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005090 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005091 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005092 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005093 case XML_RELAXNG_CHOICE:
5094 case XML_RELAXNG_GROUP:
5095 case XML_RELAXNG_INTERLEAVE:
5096 if (last == NULL) {
5097 ret->content = last = cur;
5098 } else {
5099 if ((last->type == XML_RELAXNG_ELEMENT) &&
5100 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005101 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005102 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005103 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005104 ret->content->content = last;
5105 } else {
5106 ret->content = last;
5107 }
5108 }
5109 last->next = cur;
5110 last = cur;
5111 }
5112 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005113 case XML_RELAXNG_ATTRIBUTE:
5114 cur->next = ret->attrs;
5115 ret->attrs = cur;
5116 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005117 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00005118 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00005119 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005120 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005121 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005122 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00005123 case XML_RELAXNG_NOOP:
5124 TODO
5125 if (ctxt->error != NULL)
5126 ctxt->error(ctxt->userData,
5127 "Internal error, noop found\n");
5128 ctxt->nbErrors++;
5129 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005130 }
5131 }
5132 child = child->next;
5133 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005134 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005135 return(ret);
5136}
5137
5138/**
5139 * xmlRelaxNGParsePatterns:
5140 * @ctxt: a Relax-NG parser context
5141 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005142 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005143 *
5144 * parse the content of a RelaxNG start node.
5145 *
5146 * Returns the definition pointer or NULL in case of error.
5147 */
5148static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005149xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5150 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005151 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005152
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005153 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005154 while (nodes != NULL) {
5155 if (IS_RELAXNG(nodes, "element")) {
5156 cur = xmlRelaxNGParseElement(ctxt, nodes);
5157 if (def == NULL) {
5158 def = last = cur;
5159 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00005160 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5161 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005162 def = xmlRelaxNGNewDefine(ctxt, nodes);
5163 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005164 def->content = last;
5165 }
5166 last->next = cur;
5167 last = cur;
5168 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005169 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005170 } else {
5171 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00005172 if (cur != NULL) {
5173 if (def == NULL) {
5174 def = last = cur;
5175 } else {
5176 last->next = cur;
5177 last = cur;
5178 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005179 }
5180 }
5181 nodes = nodes->next;
5182 }
5183 return(def);
5184}
5185
5186/**
5187 * xmlRelaxNGParseStart:
5188 * @ctxt: a Relax-NG parser context
5189 * @nodes: start children nodes
5190 *
5191 * parse the content of a RelaxNG start node.
5192 *
5193 * Returns 0 in case of success, -1 in case of error
5194 */
5195static int
5196xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5197 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005198 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005199
Daniel Veillardd2298792003-02-14 16:54:11 +00005200 if (nodes == NULL) {
5201 if (ctxt->error != NULL)
5202 ctxt->error(ctxt->userData,
5203 "start has no children\n");
5204 ctxt->nbErrors++;
5205 return(-1);
5206 }
5207 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005208 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005209 if (def == NULL)
5210 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005211 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00005212 if (nodes->children != NULL) {
5213 if (ctxt->error != NULL)
5214 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005215 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005216 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005217 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005218 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005219 if (def == NULL)
5220 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005221 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00005222 if (nodes->children != NULL) {
5223 if (ctxt->error != NULL)
5224 ctxt->error(ctxt->userData,
5225 "element notAllowed is not empty\n");
5226 ctxt->nbErrors++;
5227 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005228 } else {
5229 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005230 }
5231 if (ctxt->grammar->start != NULL) {
5232 last = ctxt->grammar->start;
5233 while (last->next != NULL)
5234 last = last->next;
5235 last->next = def;
5236 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00005237 ctxt->grammar->start = def;
5238 }
5239 nodes = nodes->next;
5240 if (nodes != NULL) {
5241 if (ctxt->error != NULL)
5242 ctxt->error(ctxt->userData,
5243 "start more than one children\n");
5244 ctxt->nbErrors++;
5245 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005246 }
5247 return(ret);
5248}
5249
5250/**
5251 * xmlRelaxNGParseGrammarContent:
5252 * @ctxt: a Relax-NG parser context
5253 * @nodes: grammar children nodes
5254 *
5255 * parse the content of a RelaxNG grammar node.
5256 *
5257 * Returns 0 in case of success, -1 in case of error
5258 */
5259static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005260xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005261{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005262 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005263
5264 if (nodes == NULL) {
5265 if (ctxt->error != NULL)
5266 ctxt->error(ctxt->userData,
5267 "grammar has no children\n");
5268 ctxt->nbErrors++;
5269 return(-1);
5270 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005271 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005272 if (IS_RELAXNG(nodes, "start")) {
5273 if (nodes->children == NULL) {
5274 if (ctxt->error != NULL)
5275 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00005276 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005277 ctxt->nbErrors++;
5278 } else {
5279 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5280 if (tmp != 0)
5281 ret = -1;
5282 }
5283 } else if (IS_RELAXNG(nodes, "define")) {
5284 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5285 if (tmp != 0)
5286 ret = -1;
5287 } else if (IS_RELAXNG(nodes, "include")) {
5288 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5289 if (tmp != 0)
5290 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005291 } else {
5292 if (ctxt->error != NULL)
5293 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005294 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005295 ctxt->nbErrors++;
5296 ret = -1;
5297 }
5298 nodes = nodes->next;
5299 }
5300 return (ret);
5301}
5302
5303/**
5304 * xmlRelaxNGCheckReference:
5305 * @ref: the ref
5306 * @ctxt: a Relax-NG parser context
5307 * @name: the name associated to the defines
5308 *
5309 * Applies the 4.17. combine attribute rule for all the define
5310 * element of a given grammar using the same name.
5311 */
5312static void
5313xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5314 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5315 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005316 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005317
5318 grammar = ctxt->grammar;
5319 if (grammar == NULL) {
5320 if (ctxt->error != NULL)
5321 ctxt->error(ctxt->userData,
5322 "Internal error: no grammar in CheckReference %s\n",
5323 name);
5324 ctxt->nbErrors++;
5325 return;
5326 }
5327 if (ref->content != NULL) {
5328 if (ctxt->error != NULL)
5329 ctxt->error(ctxt->userData,
5330 "Internal error: reference has content in CheckReference %s\n",
5331 name);
5332 ctxt->nbErrors++;
5333 return;
5334 }
5335 if (grammar->defs != NULL) {
5336 def = xmlHashLookup(grammar->defs, name);
5337 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00005338 cur = ref;
5339 while (cur != NULL) {
5340 cur->content = def;
5341 cur = cur->nextHash;
5342 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005343 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00005344 if (ctxt->error != NULL)
5345 ctxt->error(ctxt->userData,
5346 "Reference %s has no matching definition\n",
5347 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005348 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005349 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005350 } else {
5351 if (ctxt->error != NULL)
5352 ctxt->error(ctxt->userData,
5353 "Reference %s has no matching definition\n",
5354 name);
5355 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005356 }
5357 /*
5358 * TODO: make a closure and verify there is no loop !
5359 */
5360}
5361
5362/**
5363 * xmlRelaxNGCheckCombine:
5364 * @define: the define(s) list
5365 * @ctxt: a Relax-NG parser context
5366 * @name: the name associated to the defines
5367 *
5368 * Applies the 4.17. combine attribute rule for all the define
5369 * element of a given grammar using the same name.
5370 */
5371static void
5372xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5373 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5374 xmlChar *combine;
5375 int choiceOrInterleave = -1;
5376 int missing = 0;
5377 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5378
5379 if (define->nextHash == NULL)
5380 return;
5381 cur = define;
5382 while (cur != NULL) {
5383 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5384 if (combine != NULL) {
5385 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5386 if (choiceOrInterleave == -1)
5387 choiceOrInterleave = 1;
5388 else if (choiceOrInterleave == 0) {
5389 if (ctxt->error != NULL)
5390 ctxt->error(ctxt->userData,
5391 "Defines for %s use both 'choice' and 'interleave'\n",
5392 name);
5393 ctxt->nbErrors++;
5394 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005395 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005396 if (choiceOrInterleave == -1)
5397 choiceOrInterleave = 0;
5398 else if (choiceOrInterleave == 1) {
5399 if (ctxt->error != NULL)
5400 ctxt->error(ctxt->userData,
5401 "Defines for %s use both 'choice' and 'interleave'\n",
5402 name);
5403 ctxt->nbErrors++;
5404 }
5405 } else {
5406 if (ctxt->error != NULL)
5407 ctxt->error(ctxt->userData,
5408 "Defines for %s use unknown combine value '%s''\n",
5409 name, combine);
5410 ctxt->nbErrors++;
5411 }
5412 xmlFree(combine);
5413 } else {
5414 if (missing == 0)
5415 missing = 1;
5416 else {
5417 if (ctxt->error != NULL)
5418 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005419 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005420 name);
5421 ctxt->nbErrors++;
5422 }
5423 }
5424
5425 cur = cur->nextHash;
5426 }
5427#ifdef DEBUG
5428 xmlGenericError(xmlGenericErrorContext,
5429 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5430 name, choiceOrInterleave);
5431#endif
5432 if (choiceOrInterleave == -1)
5433 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005434 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005435 if (cur == NULL)
5436 return;
5437 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005438 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005439 else
5440 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005441 tmp = define;
5442 last = NULL;
5443 while (tmp != NULL) {
5444 if (tmp->content != NULL) {
5445 if (tmp->content->next != NULL) {
5446 /*
5447 * we need first to create a wrapper.
5448 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005449 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005450 if (tmp2 == NULL)
5451 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005452 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005453 tmp2->content = tmp->content;
5454 } else {
5455 tmp2 = tmp->content;
5456 }
5457 if (last == NULL) {
5458 cur->content = tmp2;
5459 } else {
5460 last->next = tmp2;
5461 }
5462 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005463 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005464 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005465 tmp = tmp->nextHash;
5466 }
5467 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005468 if (choiceOrInterleave == 0) {
5469 if (ctxt->interleaves == NULL)
5470 ctxt->interleaves = xmlHashCreate(10);
5471 if (ctxt->interleaves == NULL) {
5472 if (ctxt->error != NULL)
5473 ctxt->error(ctxt->userData,
5474 "Failed to create interleaves hash table\n");
5475 ctxt->nbErrors++;
5476 } else {
5477 char tmpname[32];
5478
5479 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5480 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5481 if (ctxt->error != NULL)
5482 ctxt->error(ctxt->userData,
5483 "Failed to add %s to hash table\n", tmpname);
5484 ctxt->nbErrors++;
5485 }
5486 }
5487 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005488}
5489
5490/**
5491 * xmlRelaxNGCombineStart:
5492 * @ctxt: a Relax-NG parser context
5493 * @grammar: the grammar
5494 *
5495 * Applies the 4.17. combine rule for all the start
5496 * element of a given grammar.
5497 */
5498static void
5499xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5500 xmlRelaxNGGrammarPtr grammar) {
5501 xmlRelaxNGDefinePtr starts;
5502 xmlChar *combine;
5503 int choiceOrInterleave = -1;
5504 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005505 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005506
Daniel Veillard2df2de22003-02-17 23:34:33 +00005507 starts = grammar->start;
5508 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005509 return;
5510 cur = starts;
5511 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005512 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5513 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5514 combine = NULL;
5515 if (ctxt->error != NULL)
5516 ctxt->error(ctxt->userData,
5517 "Internal error: start element not found\n");
5518 ctxt->nbErrors++;
5519 } else {
5520 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5521 }
5522
Daniel Veillard6eadf632003-01-23 18:29:16 +00005523 if (combine != NULL) {
5524 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5525 if (choiceOrInterleave == -1)
5526 choiceOrInterleave = 1;
5527 else if (choiceOrInterleave == 0) {
5528 if (ctxt->error != NULL)
5529 ctxt->error(ctxt->userData,
5530 "<start> use both 'choice' and 'interleave'\n");
5531 ctxt->nbErrors++;
5532 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005533 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005534 if (choiceOrInterleave == -1)
5535 choiceOrInterleave = 0;
5536 else if (choiceOrInterleave == 1) {
5537 if (ctxt->error != NULL)
5538 ctxt->error(ctxt->userData,
5539 "<start> use both 'choice' and 'interleave'\n");
5540 ctxt->nbErrors++;
5541 }
5542 } else {
5543 if (ctxt->error != NULL)
5544 ctxt->error(ctxt->userData,
5545 "<start> uses unknown combine value '%s''\n", combine);
5546 ctxt->nbErrors++;
5547 }
5548 xmlFree(combine);
5549 } else {
5550 if (missing == 0)
5551 missing = 1;
5552 else {
5553 if (ctxt->error != NULL)
5554 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005555 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005556 ctxt->nbErrors++;
5557 }
5558 }
5559
Daniel Veillard2df2de22003-02-17 23:34:33 +00005560 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005561 }
5562#ifdef DEBUG
5563 xmlGenericError(xmlGenericErrorContext,
5564 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5565 choiceOrInterleave);
5566#endif
5567 if (choiceOrInterleave == -1)
5568 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005569 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005570 if (cur == NULL)
5571 return;
5572 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005573 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005574 else
5575 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005576 cur->content = grammar->start;
5577 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005578 if (choiceOrInterleave == 0) {
5579 if (ctxt->interleaves == NULL)
5580 ctxt->interleaves = xmlHashCreate(10);
5581 if (ctxt->interleaves == NULL) {
5582 if (ctxt->error != NULL)
5583 ctxt->error(ctxt->userData,
5584 "Failed to create interleaves hash table\n");
5585 ctxt->nbErrors++;
5586 } else {
5587 char tmpname[32];
5588
5589 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5590 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5591 if (ctxt->error != NULL)
5592 ctxt->error(ctxt->userData,
5593 "Failed to add %s to hash table\n", tmpname);
5594 ctxt->nbErrors++;
5595 }
5596 }
5597 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005598}
5599
5600/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005601 * xmlRelaxNGCheckCycles:
5602 * @ctxt: a Relax-NG parser context
5603 * @nodes: grammar children nodes
5604 * @depth: the counter
5605 *
5606 * Check for cycles.
5607 *
5608 * Returns 0 if check passed, and -1 in case of error
5609 */
5610static int
5611xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5612 xmlRelaxNGDefinePtr cur, int depth) {
5613 int ret = 0;
5614
5615 while ((ret == 0) && (cur != NULL)) {
5616 if ((cur->type == XML_RELAXNG_REF) ||
5617 (cur->type == XML_RELAXNG_PARENTREF)) {
5618 if (cur->depth == -1) {
5619 cur->depth = depth;
5620 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5621 cur->depth = -2;
5622 } else if (depth == cur->depth) {
5623 if (ctxt->error != NULL)
5624 ctxt->error(ctxt->userData,
5625 "Detected a cycle in %s references\n", cur->name);
5626 ctxt->nbErrors++;
5627 return(-1);
5628 }
5629 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5630 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5631 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005632 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005633 }
5634 cur = cur->next;
5635 }
5636 return(ret);
5637}
5638
5639/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005640 * xmlRelaxNGTryUnlink:
5641 * @ctxt: a Relax-NG parser context
5642 * @cur: the definition to unlink
5643 * @parent: the parent definition
5644 * @prev: the previous sibling definition
5645 *
5646 * Try to unlink a definition. If not possble make it a NOOP
5647 *
5648 * Returns the new prev definition
5649 */
5650static xmlRelaxNGDefinePtr
5651xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5652 xmlRelaxNGDefinePtr cur,
5653 xmlRelaxNGDefinePtr parent,
5654 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005655 if (prev != NULL) {
5656 prev->next = cur->next;
5657 } else {
5658 if (parent != NULL) {
5659 if (parent->content == cur)
5660 parent->content = cur->next;
5661 else if (parent->attrs == cur)
5662 parent->attrs = cur->next;
5663 else if (parent->nameClass == cur)
5664 parent->nameClass = cur->next;
5665 } else {
5666 cur->type = XML_RELAXNG_NOOP;
5667 prev = cur;
5668 }
5669 }
5670 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005671}
5672
5673/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005674 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005675 * @ctxt: a Relax-NG parser context
5676 * @nodes: grammar children nodes
5677 *
5678 * Check for simplification of empty and notAllowed
5679 */
5680static void
5681xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5682 xmlRelaxNGDefinePtr cur,
5683 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005684 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005685
Daniel Veillardfd573f12003-03-16 17:52:32 +00005686 while (cur != NULL) {
5687 if ((cur->type == XML_RELAXNG_REF) ||
5688 (cur->type == XML_RELAXNG_PARENTREF)) {
5689 if (cur->depth != -3) {
5690 cur->depth = -3;
5691 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005692 }
5693 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005694 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005695 if ((parent != NULL) &&
5696 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5697 (parent->type == XML_RELAXNG_LIST) ||
5698 (parent->type == XML_RELAXNG_GROUP) ||
5699 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005700 (parent->type == XML_RELAXNG_ONEORMORE) ||
5701 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005702 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005703 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005704 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005705 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005706 (parent->type == XML_RELAXNG_CHOICE)) {
5707 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5708 } else
5709 prev = cur;
5710 } else if (cur->type == XML_RELAXNG_EMPTY){
5711 cur->parent = parent;
5712 if ((parent != NULL) &&
5713 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5714 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005715 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005716 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005717 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005718 if ((parent != NULL) &&
5719 ((parent->type == XML_RELAXNG_GROUP) ||
5720 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5721 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5722 } else
5723 prev = cur;
5724 } else {
5725 cur->parent = parent;
5726 if (cur->content != NULL)
5727 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005728 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
Daniel Veillardfd573f12003-03-16 17:52:32 +00005729 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5730 if (cur->nameClass != NULL)
5731 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5732 /*
5733 * This may result in a simplification
5734 */
5735 if ((cur->type == XML_RELAXNG_GROUP) ||
5736 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5737 if (cur->content == NULL)
5738 cur->type = XML_RELAXNG_EMPTY;
5739 else if (cur->content->next == NULL) {
5740 if ((parent == NULL) && (prev == NULL)) {
5741 cur->type = XML_RELAXNG_NOOP;
5742 } else if (prev == NULL) {
5743 parent->content = cur->content;
5744 cur->content->next = cur->next;
5745 cur = cur->content;
5746 } else {
5747 cur->content->next = cur->next;
5748 prev->next = cur->content;
5749 cur = cur->content;
5750 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005751 }
5752 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005753 /*
5754 * the current node may have been transformed back
5755 */
5756 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5757 (cur->content != NULL) &&
5758 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5759 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5760 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5761 if ((parent != NULL) &&
5762 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5763 (parent->type == XML_RELAXNG_LIST) ||
5764 (parent->type == XML_RELAXNG_GROUP) ||
5765 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5766 (parent->type == XML_RELAXNG_ONEORMORE) ||
5767 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5768 parent->type = XML_RELAXNG_NOT_ALLOWED;
5769 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005770 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005771 if ((parent != NULL) &&
5772 (parent->type == XML_RELAXNG_CHOICE)) {
5773 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5774 } else
5775 prev = cur;
5776 } else if (cur->type == XML_RELAXNG_EMPTY){
5777 if ((parent != NULL) &&
5778 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5779 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5780 parent->type = XML_RELAXNG_EMPTY;
5781 break;
5782 }
5783 if ((parent != NULL) &&
5784 ((parent->type == XML_RELAXNG_GROUP) ||
5785 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5786 (parent->type == XML_RELAXNG_CHOICE))) {
5787 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5788 } else
5789 prev = cur;
5790 } else {
5791 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005792 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005793 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005794 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005795 }
5796}
5797
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005798/**
5799 * xmlRelaxNGGroupContentType:
5800 * @ct1: the first content type
5801 * @ct2: the second content type
5802 *
5803 * Try to group 2 content types
5804 *
5805 * Returns the content type
5806 */
5807static xmlRelaxNGContentType
5808xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5809 xmlRelaxNGContentType ct2) {
5810 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5811 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5812 return(XML_RELAXNG_CONTENT_ERROR);
5813 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5814 return(ct2);
5815 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5816 return(ct1);
5817 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5818 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5819 return(XML_RELAXNG_CONTENT_COMPLEX);
5820 return(XML_RELAXNG_CONTENT_ERROR);
5821}
5822
5823/**
5824 * xmlRelaxNGMaxContentType:
5825 * @ct1: the first content type
5826 * @ct2: the second content type
5827 *
5828 * Compute the max content-type
5829 *
5830 * Returns the content type
5831 */
5832static xmlRelaxNGContentType
5833xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5834 xmlRelaxNGContentType ct2) {
5835 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5836 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5837 return(XML_RELAXNG_CONTENT_ERROR);
5838 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5839 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5840 return(XML_RELAXNG_CONTENT_SIMPLE);
5841 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5842 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5843 return(XML_RELAXNG_CONTENT_COMPLEX);
5844 return(XML_RELAXNG_CONTENT_EMPTY);
5845}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005846
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005847/**
5848 * xmlRelaxNGCheckRules:
5849 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005850 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005851 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005852 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005853 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005854 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005855 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005856 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005857 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005858static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005859xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5860 xmlRelaxNGDefinePtr cur, int flags,
5861 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005862 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005863 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005864
Daniel Veillardfd573f12003-03-16 17:52:32 +00005865 while (cur != NULL) {
5866 ret = XML_RELAXNG_CONTENT_EMPTY;
5867 if ((cur->type == XML_RELAXNG_REF) ||
5868 (cur->type == XML_RELAXNG_PARENTREF)) {
5869 if (flags & XML_RELAXNG_IN_LIST) {
5870 if (ctxt->error != NULL)
5871 ctxt->error(ctxt->userData,
5872 "Found forbidden pattern list//ref\n");
5873 ctxt->nbErrors++;
5874 }
5875 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5876 if (ctxt->error != NULL)
5877 ctxt->error(ctxt->userData,
5878 "Found forbidden pattern data/except//ref\n");
5879 ctxt->nbErrors++;
5880 }
5881 if (cur->depth > -4) {
5882 cur->depth = -4;
5883 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5884 flags, cur->type);
5885 cur->depth = ret - 15 ;
5886 } else if (cur->depth == -4) {
5887 ret = XML_RELAXNG_CONTENT_COMPLEX;
5888 } else {
5889 ret = (xmlRelaxNGContentType) cur->depth + 15;
5890 }
5891 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5892 /*
5893 * The 7.3 Attribute derivation rule for groups is plugged there
5894 */
5895 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5896 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5897 if (ctxt->error != NULL)
5898 ctxt->error(ctxt->userData,
5899 "Found forbidden pattern data/except//element(ref)\n");
5900 ctxt->nbErrors++;
5901 }
5902 if (flags & XML_RELAXNG_IN_LIST) {
5903 if (ctxt->error != NULL)
5904 ctxt->error(ctxt->userData,
5905 "Found forbidden pattern list//element(ref)\n");
5906 ctxt->nbErrors++;
5907 }
5908 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5909 if (ctxt->error != NULL)
5910 ctxt->error(ctxt->userData,
5911 "Found forbidden pattern attribute//element(ref)\n");
5912 ctxt->nbErrors++;
5913 }
5914 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5915 if (ctxt->error != NULL)
5916 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005917 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005918 ctxt->nbErrors++;
5919 }
5920 /*
5921 * reset since in the simple form elements are only child
5922 * of grammar/define
5923 */
5924 nflags = 0;
5925 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5926 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5927 if (ctxt->error != NULL)
5928 ctxt->error(ctxt->userData,
5929 "Element %s attributes have a content type error\n",
5930 cur->name);
5931 ctxt->nbErrors++;
5932 }
5933 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5934 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5935 if (ctxt->error != NULL)
5936 ctxt->error(ctxt->userData,
5937 "Element %s has a content type error\n",
5938 cur->name);
5939 ctxt->nbErrors++;
5940 } else {
5941 ret = XML_RELAXNG_CONTENT_COMPLEX;
5942 }
5943 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5944 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5945 if (ctxt->error != NULL)
5946 ctxt->error(ctxt->userData,
5947 "Found forbidden pattern attribute//attribute\n");
5948 ctxt->nbErrors++;
5949 }
5950 if (flags & XML_RELAXNG_IN_LIST) {
5951 if (ctxt->error != NULL)
5952 ctxt->error(ctxt->userData,
5953 "Found forbidden pattern list//attribute\n");
5954 ctxt->nbErrors++;
5955 }
5956 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5957 if (ctxt->error != NULL)
5958 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005959 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005960 ctxt->nbErrors++;
5961 }
5962 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5963 if (ctxt->error != NULL)
5964 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005965 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005966 ctxt->nbErrors++;
5967 }
5968 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5969 if (ctxt->error != NULL)
5970 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005971 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005972 ctxt->nbErrors++;
5973 }
5974 if (flags & XML_RELAXNG_IN_START) {
5975 if (ctxt->error != NULL)
5976 ctxt->error(ctxt->userData,
5977 "Found forbidden pattern start//attribute\n");
5978 ctxt->nbErrors++;
5979 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005980 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5981 if (cur->ns == NULL) {
5982 if (ctxt->error != NULL)
5983 ctxt->error(ctxt->userData,
5984 "Found anyName attribute without oneOrMore ancestor\n");
5985 ctxt->nbErrors++;
5986 } else {
5987 if (ctxt->error != NULL)
5988 ctxt->error(ctxt->userData,
5989 "Found nsName attribute without oneOrMore ancestor\n");
5990 ctxt->nbErrors++;
5991 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005992 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005993 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5994 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5995 ret = XML_RELAXNG_CONTENT_EMPTY;
5996 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5997 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5998 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5999 if (ctxt->error != NULL)
6000 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006001 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006002 ctxt->nbErrors++;
6003 }
6004 if (flags & XML_RELAXNG_IN_START) {
6005 if (ctxt->error != NULL)
6006 ctxt->error(ctxt->userData,
6007 "Found forbidden pattern start//oneOrMore\n");
6008 ctxt->nbErrors++;
6009 }
6010 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6011 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6012 ret = xmlRelaxNGGroupContentType(ret, ret);
6013 } else if (cur->type == XML_RELAXNG_LIST) {
6014 if (flags & XML_RELAXNG_IN_LIST) {
6015 if (ctxt->error != NULL)
6016 ctxt->error(ctxt->userData,
6017 "Found forbidden pattern list//list\n");
6018 ctxt->nbErrors++;
6019 }
6020 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6021 if (ctxt->error != NULL)
6022 ctxt->error(ctxt->userData,
6023 "Found forbidden pattern data/except//list\n");
6024 ctxt->nbErrors++;
6025 }
6026 if (flags & XML_RELAXNG_IN_START) {
6027 if (ctxt->error != NULL)
6028 ctxt->error(ctxt->userData,
6029 "Found forbidden pattern start//list\n");
6030 ctxt->nbErrors++;
6031 }
6032 nflags = flags | XML_RELAXNG_IN_LIST;
6033 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6034 } else if (cur->type == XML_RELAXNG_GROUP) {
6035 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6036 if (ctxt->error != NULL)
6037 ctxt->error(ctxt->userData,
6038 "Found forbidden pattern data/except//group\n");
6039 ctxt->nbErrors++;
6040 }
6041 if (flags & XML_RELAXNG_IN_START) {
6042 if (ctxt->error != NULL)
6043 ctxt->error(ctxt->userData,
6044 "Found forbidden pattern start//group\n");
6045 ctxt->nbErrors++;
6046 }
6047 if (flags & XML_RELAXNG_IN_ONEORMORE)
6048 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6049 else
6050 nflags = flags;
6051 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6052 /*
6053 * The 7.3 Attribute derivation rule for groups is plugged there
6054 */
6055 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6056 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6057 if (flags & XML_RELAXNG_IN_LIST) {
6058 if (ctxt->error != NULL)
6059 ctxt->error(ctxt->userData,
6060 "Found forbidden pattern list//interleave\n");
6061 ctxt->nbErrors++;
6062 }
6063 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6064 if (ctxt->error != NULL)
6065 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006066 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006067 ctxt->nbErrors++;
6068 }
6069 if (flags & XML_RELAXNG_IN_START) {
6070 if (ctxt->error != NULL)
6071 ctxt->error(ctxt->userData,
6072 "Found forbidden pattern start//interleave\n");
6073 ctxt->nbErrors++;
6074 }
6075 if (flags & XML_RELAXNG_IN_ONEORMORE)
6076 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6077 else
6078 nflags = flags;
6079 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6080 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6081 if ((cur->parent != NULL) &&
6082 (cur->parent->type == XML_RELAXNG_DATATYPE))
6083 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6084 else
6085 nflags = flags;
6086 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6087 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6088 if (flags & XML_RELAXNG_IN_START) {
6089 if (ctxt->error != NULL)
6090 ctxt->error(ctxt->userData,
6091 "Found forbidden pattern start//data\n");
6092 ctxt->nbErrors++;
6093 }
6094 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6095 ret = XML_RELAXNG_CONTENT_SIMPLE;
6096 } else if (cur->type == XML_RELAXNG_VALUE) {
6097 if (flags & XML_RELAXNG_IN_START) {
6098 if (ctxt->error != NULL)
6099 ctxt->error(ctxt->userData,
6100 "Found forbidden pattern start//value\n");
6101 ctxt->nbErrors++;
6102 }
6103 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6104 ret = XML_RELAXNG_CONTENT_SIMPLE;
6105 } else if (cur->type == XML_RELAXNG_TEXT) {
6106 if (flags & XML_RELAXNG_IN_LIST) {
6107 if (ctxt->error != NULL)
6108 ctxt->error(ctxt->userData,
6109 "Found forbidden pattern list//text\n");
6110 ctxt->nbErrors++;
6111 }
6112 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6113 if (ctxt->error != NULL)
6114 ctxt->error(ctxt->userData,
6115 "Found forbidden pattern data/except//text\n");
6116 ctxt->nbErrors++;
6117 }
6118 if (flags & XML_RELAXNG_IN_START) {
6119 if (ctxt->error != NULL)
6120 ctxt->error(ctxt->userData,
6121 "Found forbidden pattern start//text\n");
6122 ctxt->nbErrors++;
6123 }
6124 ret = XML_RELAXNG_CONTENT_COMPLEX;
6125 } else if (cur->type == XML_RELAXNG_EMPTY) {
6126 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6127 if (ctxt->error != NULL)
6128 ctxt->error(ctxt->userData,
6129 "Found forbidden pattern data/except//empty\n");
6130 ctxt->nbErrors++;
6131 }
6132 if (flags & XML_RELAXNG_IN_START) {
6133 if (ctxt->error != NULL)
6134 ctxt->error(ctxt->userData,
6135 "Found forbidden pattern start//empty\n");
6136 ctxt->nbErrors++;
6137 }
6138 ret = XML_RELAXNG_CONTENT_EMPTY;
6139 } else if (cur->type == XML_RELAXNG_CHOICE) {
6140 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6141 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6142 } else {
6143 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6144 }
6145 cur = cur->next;
6146 if (ptype == XML_RELAXNG_GROUP) {
6147 val = xmlRelaxNGGroupContentType(val, ret);
6148 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6149 tmp = xmlRelaxNGGroupContentType(val, ret);
6150 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6151 tmp = xmlRelaxNGMaxContentType(val, ret);
6152 } else if (ptype == XML_RELAXNG_CHOICE) {
6153 val = xmlRelaxNGMaxContentType(val, ret);
6154 } else if (ptype == XML_RELAXNG_LIST) {
6155 val = XML_RELAXNG_CONTENT_SIMPLE;
6156 } else if (ptype == XML_RELAXNG_EXCEPT) {
6157 if (ret == XML_RELAXNG_CONTENT_ERROR)
6158 val = XML_RELAXNG_CONTENT_ERROR;
6159 else
6160 val = XML_RELAXNG_CONTENT_SIMPLE;
6161 } else {
6162 val = xmlRelaxNGGroupContentType(val, ret);
6163 }
6164
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006165 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006166 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006167}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006168
6169/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006170 * xmlRelaxNGParseGrammar:
6171 * @ctxt: a Relax-NG parser context
6172 * @nodes: grammar children nodes
6173 *
6174 * parse a Relax-NG <grammar> node
6175 *
6176 * Returns the internal xmlRelaxNGGrammarPtr built or
6177 * NULL in case of error
6178 */
6179static xmlRelaxNGGrammarPtr
6180xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
6181 xmlRelaxNGGrammarPtr ret, tmp, old;
6182
Daniel Veillardc482e262003-02-26 14:48:48 +00006183#ifdef DEBUG_GRAMMAR
6184 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6185#endif
6186
Daniel Veillard6eadf632003-01-23 18:29:16 +00006187 ret = xmlRelaxNGNewGrammar(ctxt);
6188 if (ret == NULL)
6189 return(NULL);
6190
6191 /*
6192 * Link the new grammar in the tree
6193 */
6194 ret->parent = ctxt->grammar;
6195 if (ctxt->grammar != NULL) {
6196 tmp = ctxt->grammar->children;
6197 if (tmp == NULL) {
6198 ctxt->grammar->children = ret;
6199 } else {
6200 while (tmp->next != NULL)
6201 tmp = tmp->next;
6202 tmp->next = ret;
6203 }
6204 }
6205
6206 old = ctxt->grammar;
6207 ctxt->grammar = ret;
6208 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6209 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006210 if (ctxt->grammar == NULL) {
6211 if (ctxt->error != NULL)
6212 ctxt->error(ctxt->userData,
6213 "Failed to parse <grammar> content\n");
6214 ctxt->nbErrors++;
6215 } else if (ctxt->grammar->start == NULL) {
6216 if (ctxt->error != NULL)
6217 ctxt->error(ctxt->userData,
6218 "Element <grammar> has no <start>\n");
6219 ctxt->nbErrors++;
6220 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006221
6222 /*
6223 * Apply 4.17 mergingd rules to defines and starts
6224 */
6225 xmlRelaxNGCombineStart(ctxt, ret);
6226 if (ret->defs != NULL) {
6227 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6228 ctxt);
6229 }
6230
6231 /*
6232 * link together defines and refs in this grammar
6233 */
6234 if (ret->refs != NULL) {
6235 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6236 ctxt);
6237 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006238
Daniel Veillard6eadf632003-01-23 18:29:16 +00006239 ctxt->grammar = old;
6240 return(ret);
6241}
6242
6243/**
6244 * xmlRelaxNGParseDocument:
6245 * @ctxt: a Relax-NG parser context
6246 * @node: the root node of the RelaxNG schema
6247 *
6248 * parse a Relax-NG definition resource and build an internal
6249 * xmlRelaxNG struture which can be used to validate instances.
6250 *
6251 * Returns the internal XML RelaxNG structure built or
6252 * NULL in case of error
6253 */
6254static xmlRelaxNGPtr
6255xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6256 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006257 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006258 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006259
6260 if ((ctxt == NULL) || (node == NULL))
6261 return (NULL);
6262
6263 schema = xmlRelaxNGNewRelaxNG(ctxt);
6264 if (schema == NULL)
6265 return(NULL);
6266
Daniel Veillard276be4a2003-01-24 01:03:34 +00006267 olddefine = ctxt->define;
6268 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006269 if (IS_RELAXNG(node, "grammar")) {
6270 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6271 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00006272 xmlRelaxNGGrammarPtr tmp, ret;
6273
6274 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006275 if (schema->topgrammar == NULL) {
6276 return(schema);
6277 }
Daniel Veillardc482e262003-02-26 14:48:48 +00006278 /*
6279 * Link the new grammar in the tree
6280 */
6281 ret->parent = ctxt->grammar;
6282 if (ctxt->grammar != NULL) {
6283 tmp = ctxt->grammar->children;
6284 if (tmp == NULL) {
6285 ctxt->grammar->children = ret;
6286 } else {
6287 while (tmp->next != NULL)
6288 tmp = tmp->next;
6289 tmp->next = ret;
6290 }
6291 }
Daniel Veillarde431a272003-01-29 23:02:33 +00006292 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00006293 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006294 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00006295 if (old != NULL)
6296 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006297 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006298 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006299 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006300 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006301 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006302 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6303 while ((schema->topgrammar->start != NULL) &&
6304 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6305 (schema->topgrammar->start->next != NULL))
6306 schema->topgrammar->start = schema->topgrammar->start->content;
6307 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6308 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006309 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006310 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006311
6312#ifdef DEBUG
6313 if (schema == NULL)
6314 xmlGenericError(xmlGenericErrorContext,
6315 "xmlRelaxNGParseDocument() failed\n");
6316#endif
6317
6318 return (schema);
6319}
6320
6321/************************************************************************
6322 * *
6323 * Reading RelaxNGs *
6324 * *
6325 ************************************************************************/
6326
6327/**
6328 * xmlRelaxNGNewParserCtxt:
6329 * @URL: the location of the schema
6330 *
6331 * Create an XML RelaxNGs parse context for that file/resource expected
6332 * to contain an XML RelaxNGs file.
6333 *
6334 * Returns the parser context or NULL in case of error
6335 */
6336xmlRelaxNGParserCtxtPtr
6337xmlRelaxNGNewParserCtxt(const char *URL) {
6338 xmlRelaxNGParserCtxtPtr ret;
6339
6340 if (URL == NULL)
6341 return(NULL);
6342
6343 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6344 if (ret == NULL) {
6345 xmlGenericError(xmlGenericErrorContext,
6346 "Failed to allocate new schama parser context for %s\n", URL);
6347 return (NULL);
6348 }
6349 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6350 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006351 ret->error = xmlGenericError;
6352 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006353 return (ret);
6354}
6355
6356/**
6357 * xmlRelaxNGNewMemParserCtxt:
6358 * @buffer: a pointer to a char array containing the schemas
6359 * @size: the size of the array
6360 *
6361 * Create an XML RelaxNGs parse context for that memory buffer expected
6362 * to contain an XML RelaxNGs file.
6363 *
6364 * Returns the parser context or NULL in case of error
6365 */
6366xmlRelaxNGParserCtxtPtr
6367xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6368 xmlRelaxNGParserCtxtPtr ret;
6369
6370 if ((buffer == NULL) || (size <= 0))
6371 return(NULL);
6372
6373 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6374 if (ret == NULL) {
6375 xmlGenericError(xmlGenericErrorContext,
6376 "Failed to allocate new schama parser context\n");
6377 return (NULL);
6378 }
6379 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6380 ret->buffer = buffer;
6381 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006382 ret->error = xmlGenericError;
6383 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006384 return (ret);
6385}
6386
6387/**
6388 * xmlRelaxNGFreeParserCtxt:
6389 * @ctxt: the schema parser context
6390 *
6391 * Free the resources associated to the schema parser context
6392 */
6393void
6394xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6395 if (ctxt == NULL)
6396 return;
6397 if (ctxt->URL != NULL)
6398 xmlFree(ctxt->URL);
6399 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006400 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006401 if (ctxt->interleaves != NULL)
6402 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006403 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006404 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006405 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006406 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006407 if (ctxt->docTab != NULL)
6408 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006409 if (ctxt->incTab != NULL)
6410 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006411 if (ctxt->defTab != NULL) {
6412 int i;
6413
6414 for (i = 0;i < ctxt->defNr;i++)
6415 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6416 xmlFree(ctxt->defTab);
6417 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006418 xmlFree(ctxt);
6419}
6420
Daniel Veillard6eadf632003-01-23 18:29:16 +00006421/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006422 * xmlRelaxNGNormExtSpace:
6423 * @value: a value
6424 *
6425 * Removes the leading and ending spaces of the value
6426 * The string is modified "in situ"
6427 */
6428static void
6429xmlRelaxNGNormExtSpace(xmlChar *value) {
6430 xmlChar *start = value;
6431 xmlChar *cur = value;
6432 if (value == NULL)
6433 return;
6434
6435 while (IS_BLANK(*cur)) cur++;
6436 if (cur == start) {
6437 do {
6438 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6439 if (*cur == 0)
6440 return;
6441 start = cur;
6442 while (IS_BLANK(*cur)) cur++;
6443 if (*cur == 0) {
6444 *start = 0;
6445 return;
6446 }
6447 } while (1);
6448 } else {
6449 do {
6450 while ((*cur != 0) && (!IS_BLANK(*cur)))
6451 *start++ = *cur++;
6452 if (*cur == 0) {
6453 *start = 0;
6454 return;
6455 }
6456 /* don't try to normalize the inner spaces */
6457 while (IS_BLANK(*cur)) cur++;
6458 *start++ = *cur++;
6459 if (*cur == 0) {
6460 *start = 0;
6461 return;
6462 }
6463 } while (1);
6464 }
6465}
6466
6467/**
6468 * xmlRelaxNGCheckAttributes:
6469 * @ctxt: a Relax-NG parser context
6470 * @node: a Relax-NG node
6471 *
6472 * Check all the attributes on the given node
6473 */
6474static void
6475xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6476 xmlAttrPtr cur, next;
6477
6478 cur = node->properties;
6479 while (cur != NULL) {
6480 next = cur->next;
6481 if ((cur->ns == NULL) ||
6482 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6483 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6484 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6485 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6486 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6487 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006488 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006489 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6490 if (ctxt->error != NULL)
6491 ctxt->error(ctxt->userData,
6492 "Attribute %s is not allowed on %s\n",
6493 cur->name, node->name);
6494 ctxt->nbErrors++;
6495 }
6496 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6497 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6498 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6499 if (ctxt->error != NULL)
6500 ctxt->error(ctxt->userData,
6501 "Attribute %s is not allowed on %s\n",
6502 cur->name, node->name);
6503 ctxt->nbErrors++;
6504 }
6505 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6506 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6507 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6508 if (ctxt->error != NULL)
6509 ctxt->error(ctxt->userData,
6510 "Attribute %s is not allowed on %s\n",
6511 cur->name, node->name);
6512 ctxt->nbErrors++;
6513 }
6514 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6515 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6516 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6517 if (ctxt->error != NULL)
6518 ctxt->error(ctxt->userData,
6519 "Attribute %s is not allowed on %s\n",
6520 cur->name, node->name);
6521 ctxt->nbErrors++;
6522 }
6523 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6524 xmlChar *val;
6525 xmlURIPtr uri;
6526
6527 val = xmlNodeListGetString(node->doc, cur->children, 1);
6528 if (val != NULL) {
6529 if (val[0] != 0) {
6530 uri = xmlParseURI((const char *) val);
6531 if (uri == NULL) {
6532 if (ctxt->error != NULL)
6533 ctxt->error(ctxt->userData,
6534 "Attribute %s contains invalid URI %s\n",
6535 cur->name, val);
6536 ctxt->nbErrors++;
6537 } else {
6538 if (uri->scheme == NULL) {
6539 if (ctxt->error != NULL)
6540 ctxt->error(ctxt->userData,
6541 "Attribute %s URI %s is not absolute\n",
6542 cur->name, val);
6543 ctxt->nbErrors++;
6544 }
6545 if (uri->fragment != NULL) {
6546 if (ctxt->error != NULL)
6547 ctxt->error(ctxt->userData,
6548 "Attribute %s URI %s has a fragment ID\n",
6549 cur->name, val);
6550 ctxt->nbErrors++;
6551 }
6552 xmlFreeURI(uri);
6553 }
6554 }
6555 xmlFree(val);
6556 }
6557 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6558 if (ctxt->error != NULL)
6559 ctxt->error(ctxt->userData,
6560 "Unknown attribute %s on %s\n",
6561 cur->name, node->name);
6562 ctxt->nbErrors++;
6563 }
6564 }
6565 cur = next;
6566 }
6567}
6568
6569/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006570 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006571 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006572 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006573 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006574 * Cleanup the subtree from unwanted nodes for parsing, resolve
6575 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006576 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006577static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006578xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006579 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006580
Daniel Veillard6eadf632003-01-23 18:29:16 +00006581 delete = NULL;
6582 cur = root;
6583 while (cur != NULL) {
6584 if (delete != NULL) {
6585 xmlUnlinkNode(delete);
6586 xmlFreeNode(delete);
6587 delete = NULL;
6588 }
6589 if (cur->type == XML_ELEMENT_NODE) {
6590 /*
6591 * Simplification 4.1. Annotations
6592 */
6593 if ((cur->ns == NULL) ||
6594 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006595 if ((cur->parent != NULL) &&
6596 (cur->parent->type == XML_ELEMENT_NODE) &&
6597 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6598 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6599 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6600 if (ctxt->error != NULL)
6601 ctxt->error(ctxt->userData,
6602 "element %s doesn't allow foreign elements\n",
6603 cur->parent->name);
6604 ctxt->nbErrors++;
6605 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006606 delete = cur;
6607 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006608 } else {
6609 xmlRelaxNGCleanupAttributes(ctxt, cur);
6610 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6611 xmlChar *href, *ns, *base, *URL;
6612 xmlRelaxNGDocumentPtr docu;
6613 xmlNodePtr tmp;
6614
6615 ns = xmlGetProp(cur, BAD_CAST "ns");
6616 if (ns == NULL) {
6617 tmp = cur->parent;
6618 while ((tmp != NULL) &&
6619 (tmp->type == XML_ELEMENT_NODE)) {
6620 ns = xmlGetProp(tmp, BAD_CAST "ns");
6621 if (ns != NULL)
6622 break;
6623 tmp = tmp->parent;
6624 }
6625 }
6626 href = xmlGetProp(cur, BAD_CAST "href");
6627 if (href == NULL) {
6628 if (ctxt->error != NULL)
6629 ctxt->error(ctxt->userData,
6630 "xmlRelaxNGParse: externalRef has no href attribute\n");
6631 ctxt->nbErrors++;
6632 delete = cur;
6633 goto skip_children;
6634 }
6635 base = xmlNodeGetBase(cur->doc, cur);
6636 URL = xmlBuildURI(href, base);
6637 if (URL == NULL) {
6638 if (ctxt->error != NULL)
6639 ctxt->error(ctxt->userData,
6640 "Failed to compute URL for externalRef %s\n", href);
6641 ctxt->nbErrors++;
6642 if (href != NULL)
6643 xmlFree(href);
6644 if (base != NULL)
6645 xmlFree(base);
6646 delete = cur;
6647 goto skip_children;
6648 }
6649 if (href != NULL)
6650 xmlFree(href);
6651 if (base != NULL)
6652 xmlFree(base);
6653 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6654 if (docu == NULL) {
6655 if (ctxt->error != NULL)
6656 ctxt->error(ctxt->userData,
6657 "Failed to load externalRef %s\n", URL);
6658 ctxt->nbErrors++;
6659 xmlFree(URL);
6660 delete = cur;
6661 goto skip_children;
6662 }
6663 if (ns != NULL)
6664 xmlFree(ns);
6665 xmlFree(URL);
6666 cur->_private = docu;
6667 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6668 xmlChar *href, *ns, *base, *URL;
6669 xmlRelaxNGIncludePtr incl;
6670 xmlNodePtr tmp;
6671
6672 href = xmlGetProp(cur, BAD_CAST "href");
6673 if (href == NULL) {
6674 if (ctxt->error != NULL)
6675 ctxt->error(ctxt->userData,
6676 "xmlRelaxNGParse: include has no href attribute\n");
6677 ctxt->nbErrors++;
6678 delete = cur;
6679 goto skip_children;
6680 }
6681 base = xmlNodeGetBase(cur->doc, cur);
6682 URL = xmlBuildURI(href, base);
6683 if (URL == NULL) {
6684 if (ctxt->error != NULL)
6685 ctxt->error(ctxt->userData,
6686 "Failed to compute URL for include %s\n", href);
6687 ctxt->nbErrors++;
6688 if (href != NULL)
6689 xmlFree(href);
6690 if (base != NULL)
6691 xmlFree(base);
6692 delete = cur;
6693 goto skip_children;
6694 }
6695 if (href != NULL)
6696 xmlFree(href);
6697 if (base != NULL)
6698 xmlFree(base);
6699 ns = xmlGetProp(cur, BAD_CAST "ns");
6700 if (ns == NULL) {
6701 tmp = cur->parent;
6702 while ((tmp != NULL) &&
6703 (tmp->type == XML_ELEMENT_NODE)) {
6704 ns = xmlGetProp(tmp, BAD_CAST "ns");
6705 if (ns != NULL)
6706 break;
6707 tmp = tmp->parent;
6708 }
6709 }
6710 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6711 if (ns != NULL)
6712 xmlFree(ns);
6713 if (incl == NULL) {
6714 if (ctxt->error != NULL)
6715 ctxt->error(ctxt->userData,
6716 "Failed to load include %s\n", URL);
6717 ctxt->nbErrors++;
6718 xmlFree(URL);
6719 delete = cur;
6720 goto skip_children;
6721 }
6722 xmlFree(URL);
6723 cur->_private = incl;
6724 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6725 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6726 xmlChar *name, *ns;
6727 xmlNodePtr text = NULL;
6728
6729 /*
6730 * Simplification 4.8. name attribute of element
6731 * and attribute elements
6732 */
6733 name = xmlGetProp(cur, BAD_CAST "name");
6734 if (name != NULL) {
6735 if (cur->children == NULL) {
6736 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6737 name);
6738 } else {
6739 xmlNodePtr node;
6740 node = xmlNewNode(cur->ns, BAD_CAST "name");
6741 if (node != NULL) {
6742 xmlAddPrevSibling(cur->children, node);
6743 text = xmlNewText(name);
6744 xmlAddChild(node, text);
6745 text = node;
6746 }
6747 }
6748 if (text == NULL) {
6749 if (ctxt->error != NULL)
6750 ctxt->error(ctxt->userData,
6751 "Failed to create a name %s element\n", name);
6752 ctxt->nbErrors++;
6753 }
6754 xmlUnsetProp(cur, BAD_CAST "name");
6755 xmlFree(name);
6756 ns = xmlGetProp(cur, BAD_CAST "ns");
6757 if (ns != NULL) {
6758 if (text != NULL) {
6759 xmlSetProp(text, BAD_CAST "ns", ns);
6760 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6761 }
6762 xmlFree(ns);
6763 } else if (xmlStrEqual(cur->name,
6764 BAD_CAST "attribute")) {
6765 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6766 }
6767 }
6768 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6769 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6770 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6771 /*
6772 * Simplification 4.8. name attribute of element
6773 * and attribute elements
6774 */
6775 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6776 xmlNodePtr node;
6777 xmlChar *ns = NULL;
6778
6779 node = cur->parent;
6780 while ((node != NULL) &&
6781 (node->type == XML_ELEMENT_NODE)) {
6782 ns = xmlGetProp(node, BAD_CAST "ns");
6783 if (ns != NULL) {
6784 break;
6785 }
6786 node = node->parent;
6787 }
6788 if (ns == NULL) {
6789 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6790 } else {
6791 xmlSetProp(cur, BAD_CAST "ns", ns);
6792 xmlFree(ns);
6793 }
6794 }
6795 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6796 xmlChar *name, *local, *prefix;
6797
6798 /*
6799 * Simplification: 4.10. QNames
6800 */
6801 name = xmlNodeGetContent(cur);
6802 if (name != NULL) {
6803 local = xmlSplitQName2(name, &prefix);
6804 if (local != NULL) {
6805 xmlNsPtr ns;
6806
6807 ns = xmlSearchNs(cur->doc, cur, prefix);
6808 if (ns == NULL) {
6809 if (ctxt->error != NULL)
6810 ctxt->error(ctxt->userData,
6811 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6812 ctxt->nbErrors++;
6813 } else {
6814 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6815 xmlNodeSetContent(cur, local);
6816 }
6817 xmlFree(local);
6818 xmlFree(prefix);
6819 }
6820 xmlFree(name);
6821 }
6822 }
6823 /*
6824 * 4.16
6825 */
6826 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6827 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6828 if (ctxt->error != NULL)
6829 ctxt->error(ctxt->userData,
6830 "Found nsName/except//nsName forbidden construct\n");
6831 ctxt->nbErrors++;
6832 }
6833 }
6834 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6835 (cur != root)) {
6836 int oldflags = ctxt->flags;
6837
6838 /*
6839 * 4.16
6840 */
6841 if ((cur->parent != NULL) &&
6842 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6843 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6844 xmlRelaxNGCleanupTree(ctxt, cur);
6845 ctxt->flags = oldflags;
6846 goto skip_children;
6847 } else if ((cur->parent != NULL) &&
6848 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6849 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6850 xmlRelaxNGCleanupTree(ctxt, cur);
6851 ctxt->flags = oldflags;
6852 goto skip_children;
6853 }
6854 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6855 /*
6856 * 4.16
6857 */
6858 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6859 if (ctxt->error != NULL)
6860 ctxt->error(ctxt->userData,
6861 "Found anyName/except//anyName forbidden construct\n");
6862 ctxt->nbErrors++;
6863 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6864 if (ctxt->error != NULL)
6865 ctxt->error(ctxt->userData,
6866 "Found nsName/except//anyName forbidden construct\n");
6867 ctxt->nbErrors++;
6868 }
6869 }
6870 /*
6871 * Thisd is not an else since "include" is transformed
6872 * into a div
6873 */
6874 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6875 xmlChar *ns;
6876 xmlNodePtr child, ins, tmp;
6877
6878 /*
6879 * implements rule 4.11
6880 */
6881
6882 ns = xmlGetProp(cur, BAD_CAST "ns");
6883
6884 child = cur->children;
6885 ins = cur;
6886 while (child != NULL) {
6887 if (ns != NULL) {
6888 if (!xmlHasProp(child, BAD_CAST "ns")) {
6889 xmlSetProp(child, BAD_CAST "ns", ns);
6890 }
6891 }
6892 tmp = child->next;
6893 xmlUnlinkNode(child);
6894 ins = xmlAddNextSibling(ins, child);
6895 child = tmp;
6896 }
6897 if (ns != NULL)
6898 xmlFree(ns);
6899 delete = cur;
6900 goto skip_children;
6901 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006902 }
6903 }
6904 /*
6905 * Simplification 4.2 whitespaces
6906 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006907 else if ((cur->type == XML_TEXT_NODE) ||
6908 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006909 if (IS_BLANK_NODE(cur)) {
6910 if (cur->parent->type == XML_ELEMENT_NODE) {
6911 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6912 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6913 delete = cur;
6914 } else {
6915 delete = cur;
6916 goto skip_children;
6917 }
6918 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006919 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006920 delete = cur;
6921 goto skip_children;
6922 }
6923
6924 /*
6925 * Skip to next node
6926 */
6927 if (cur->children != NULL) {
6928 if ((cur->children->type != XML_ENTITY_DECL) &&
6929 (cur->children->type != XML_ENTITY_REF_NODE) &&
6930 (cur->children->type != XML_ENTITY_NODE)) {
6931 cur = cur->children;
6932 continue;
6933 }
6934 }
6935skip_children:
6936 if (cur->next != NULL) {
6937 cur = cur->next;
6938 continue;
6939 }
6940
6941 do {
6942 cur = cur->parent;
6943 if (cur == NULL)
6944 break;
6945 if (cur == root) {
6946 cur = NULL;
6947 break;
6948 }
6949 if (cur->next != NULL) {
6950 cur = cur->next;
6951 break;
6952 }
6953 } while (cur != NULL);
6954 }
6955 if (delete != NULL) {
6956 xmlUnlinkNode(delete);
6957 xmlFreeNode(delete);
6958 delete = NULL;
6959 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006960}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006961
Daniel Veillardc5312d72003-02-21 17:14:10 +00006962/**
6963 * xmlRelaxNGCleanupDoc:
6964 * @ctxt: a Relax-NG parser context
6965 * @doc: an xmldocPtr document pointer
6966 *
6967 * Cleanup the document from unwanted nodes for parsing, resolve
6968 * Include and externalRef lookups.
6969 *
6970 * Returns the cleaned up document or NULL in case of error
6971 */
6972static xmlDocPtr
6973xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6974 xmlNodePtr root;
6975
6976 /*
6977 * Extract the root
6978 */
6979 root = xmlDocGetRootElement(doc);
6980 if (root == NULL) {
6981 if (ctxt->error != NULL)
6982 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6983 ctxt->URL);
6984 ctxt->nbErrors++;
6985 return (NULL);
6986 }
6987 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006988 return(doc);
6989}
6990
6991/**
6992 * xmlRelaxNGParse:
6993 * @ctxt: a Relax-NG parser context
6994 *
6995 * parse a schema definition resource and build an internal
6996 * XML Shema struture which can be used to validate instances.
6997 * *WARNING* this interface is highly subject to change
6998 *
6999 * Returns the internal XML RelaxNG structure built from the resource or
7000 * NULL in case of error
7001 */
7002xmlRelaxNGPtr
7003xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7004{
7005 xmlRelaxNGPtr ret = NULL;
7006 xmlDocPtr doc;
7007 xmlNodePtr root;
7008
7009 xmlRelaxNGInitTypes();
7010
7011 if (ctxt == NULL)
7012 return (NULL);
7013
7014 /*
7015 * First step is to parse the input document into an DOM/Infoset
7016 */
7017 if (ctxt->URL != NULL) {
7018 doc = xmlParseFile((const char *) ctxt->URL);
7019 if (doc == NULL) {
7020 if (ctxt->error != NULL)
7021 ctxt->error(ctxt->userData,
7022 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
7023 ctxt->nbErrors++;
7024 return (NULL);
7025 }
7026 } else if (ctxt->buffer != NULL) {
7027 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
7028 if (doc == NULL) {
7029 if (ctxt->error != NULL)
7030 ctxt->error(ctxt->userData,
7031 "xmlRelaxNGParse: could not parse schemas\n");
7032 ctxt->nbErrors++;
7033 return (NULL);
7034 }
7035 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7036 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7037 } else {
7038 if (ctxt->error != NULL)
7039 ctxt->error(ctxt->userData,
7040 "xmlRelaxNGParse: nothing to parse\n");
7041 ctxt->nbErrors++;
7042 return (NULL);
7043 }
7044 ctxt->document = doc;
7045
7046 /*
7047 * Some preprocessing of the document content
7048 */
7049 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7050 if (doc == NULL) {
7051 xmlFreeDoc(ctxt->document);
7052 ctxt->document = NULL;
7053 return(NULL);
7054 }
7055
Daniel Veillard6eadf632003-01-23 18:29:16 +00007056 /*
7057 * Then do the parsing for good
7058 */
7059 root = xmlDocGetRootElement(doc);
7060 if (root == NULL) {
7061 if (ctxt->error != NULL)
7062 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7063 ctxt->URL);
7064 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007065 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007066 return (NULL);
7067 }
7068 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007069 if (ret == NULL) {
7070 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007071 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007072 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007073
7074 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007075 * Check the ref/defines links
7076 */
7077 /*
7078 * try to preprocess interleaves
7079 */
7080 if (ctxt->interleaves != NULL) {
7081 xmlHashScan(ctxt->interleaves,
7082 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
7083 }
7084
7085 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007086 * if there was a parsing error return NULL
7087 */
7088 if (ctxt->nbErrors > 0) {
7089 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007090 ctxt->document = NULL;
7091 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007092 return(NULL);
7093 }
7094
7095 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007096 * try to compile (parts of) the schemas
7097 */
7098 if (ctxt->grammar != NULL)
7099 xmlRelaxNGTryCompile(ctxt, ctxt->grammar->start);
7100
7101 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007102 * Transfer the pointer for cleanup at the schema level.
7103 */
7104 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007105 ctxt->document = NULL;
7106 ret->documents = ctxt->documents;
7107 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007108
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007109 ret->includes = ctxt->includes;
7110 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007111 ret->defNr = ctxt->defNr;
7112 ret->defTab = ctxt->defTab;
7113 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007114 if (ctxt->idref == 1)
7115 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007116
7117 return (ret);
7118}
7119
7120/**
7121 * xmlRelaxNGSetParserErrors:
7122 * @ctxt: a Relax-NG validation context
7123 * @err: the error callback
7124 * @warn: the warning callback
7125 * @ctx: contextual data for the callbacks
7126 *
7127 * Set the callback functions used to handle errors for a validation context
7128 */
7129void
7130xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7131 xmlRelaxNGValidityErrorFunc err,
7132 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7133 if (ctxt == NULL)
7134 return;
7135 ctxt->error = err;
7136 ctxt->warning = warn;
7137 ctxt->userData = ctx;
7138}
7139/************************************************************************
7140 * *
7141 * Dump back a compiled form *
7142 * *
7143 ************************************************************************/
7144static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
7145
7146/**
7147 * xmlRelaxNGDumpDefines:
7148 * @output: the file output
7149 * @defines: a list of define structures
7150 *
7151 * Dump a RelaxNG structure back
7152 */
7153static void
7154xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
7155 while (defines != NULL) {
7156 xmlRelaxNGDumpDefine(output, defines);
7157 defines = defines->next;
7158 }
7159}
7160
7161/**
7162 * xmlRelaxNGDumpDefine:
7163 * @output: the file output
7164 * @define: a define structure
7165 *
7166 * Dump a RelaxNG structure back
7167 */
7168static void
7169xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
7170 if (define == NULL)
7171 return;
7172 switch(define->type) {
7173 case XML_RELAXNG_EMPTY:
7174 fprintf(output, "<empty/>\n");
7175 break;
7176 case XML_RELAXNG_NOT_ALLOWED:
7177 fprintf(output, "<notAllowed/>\n");
7178 break;
7179 case XML_RELAXNG_TEXT:
7180 fprintf(output, "<text/>\n");
7181 break;
7182 case XML_RELAXNG_ELEMENT:
7183 fprintf(output, "<element>\n");
7184 if (define->name != NULL) {
7185 fprintf(output, "<name");
7186 if (define->ns != NULL)
7187 fprintf(output, " ns=\"%s\"", define->ns);
7188 fprintf(output, ">%s</name>\n", define->name);
7189 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007190 xmlRelaxNGDumpDefines(output, define->attrs);
7191 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007192 fprintf(output, "</element>\n");
7193 break;
7194 case XML_RELAXNG_LIST:
7195 fprintf(output, "<list>\n");
7196 xmlRelaxNGDumpDefines(output, define->content);
7197 fprintf(output, "</list>\n");
7198 break;
7199 case XML_RELAXNG_ONEORMORE:
7200 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007201 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007202 fprintf(output, "</oneOrMore>\n");
7203 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007204 case XML_RELAXNG_ZEROORMORE:
7205 fprintf(output, "<zeroOrMore>\n");
7206 xmlRelaxNGDumpDefines(output, define->content);
7207 fprintf(output, "</zeroOrMore>\n");
7208 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007209 case XML_RELAXNG_CHOICE:
7210 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007211 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007212 fprintf(output, "</choice>\n");
7213 break;
7214 case XML_RELAXNG_GROUP:
7215 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007216 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007217 fprintf(output, "</group>\n");
7218 break;
7219 case XML_RELAXNG_INTERLEAVE:
7220 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007221 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007222 fprintf(output, "</interleave>\n");
7223 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007224 case XML_RELAXNG_OPTIONAL:
7225 fprintf(output, "<optional>\n");
7226 xmlRelaxNGDumpDefines(output, define->content);
7227 fprintf(output, "</optional>\n");
7228 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007229 case XML_RELAXNG_ATTRIBUTE:
7230 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007231 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007232 fprintf(output, "</attribute>\n");
7233 break;
7234 case XML_RELAXNG_DEF:
7235 fprintf(output, "<define");
7236 if (define->name != NULL)
7237 fprintf(output, " name=\"%s\"", define->name);
7238 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007239 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007240 fprintf(output, "</define>\n");
7241 break;
7242 case XML_RELAXNG_REF:
7243 fprintf(output, "<ref");
7244 if (define->name != NULL)
7245 fprintf(output, " name=\"%s\"", define->name);
7246 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007247 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007248 fprintf(output, "</ref>\n");
7249 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007250 case XML_RELAXNG_PARENTREF:
7251 fprintf(output, "<parentRef");
7252 if (define->name != NULL)
7253 fprintf(output, " name=\"%s\"", define->name);
7254 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007255 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00007256 fprintf(output, "</parentRef>\n");
7257 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007258 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00007259 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007260 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00007261 fprintf(output, "</externalRef>\n");
7262 break;
7263 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007264 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007265 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00007266 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007267 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007268 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00007269 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007270 TODO
7271 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00007272 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007273 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00007274 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007275 }
7276}
7277
7278/**
7279 * xmlRelaxNGDumpGrammar:
7280 * @output: the file output
7281 * @grammar: a grammar structure
7282 * @top: is this a top grammar
7283 *
7284 * Dump a RelaxNG structure back
7285 */
7286static void
7287xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7288{
7289 if (grammar == NULL)
7290 return;
7291
7292 fprintf(output, "<grammar");
7293 if (top)
7294 fprintf(output,
7295 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7296 switch(grammar->combine) {
7297 case XML_RELAXNG_COMBINE_UNDEFINED:
7298 break;
7299 case XML_RELAXNG_COMBINE_CHOICE:
7300 fprintf(output, " combine=\"choice\"");
7301 break;
7302 case XML_RELAXNG_COMBINE_INTERLEAVE:
7303 fprintf(output, " combine=\"interleave\"");
7304 break;
7305 default:
7306 fprintf(output, " <!-- invalid combine value -->");
7307 }
7308 fprintf(output, ">\n");
7309 if (grammar->start == NULL) {
7310 fprintf(output, " <!-- grammar had no start -->");
7311 } else {
7312 fprintf(output, "<start>\n");
7313 xmlRelaxNGDumpDefine(output, grammar->start);
7314 fprintf(output, "</start>\n");
7315 }
7316 /* TODO ? Dump the defines ? */
7317 fprintf(output, "</grammar>\n");
7318}
7319
7320/**
7321 * xmlRelaxNGDump:
7322 * @output: the file output
7323 * @schema: a schema structure
7324 *
7325 * Dump a RelaxNG structure back
7326 */
7327void
7328xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7329{
7330 if (schema == NULL) {
7331 fprintf(output, "RelaxNG empty or failed to compile\n");
7332 return;
7333 }
7334 fprintf(output, "RelaxNG: ");
7335 if (schema->doc == NULL) {
7336 fprintf(output, "no document\n");
7337 } else if (schema->doc->URL != NULL) {
7338 fprintf(output, "%s\n", schema->doc->URL);
7339 } else {
7340 fprintf(output, "\n");
7341 }
7342 if (schema->topgrammar == NULL) {
7343 fprintf(output, "RelaxNG has no top grammar\n");
7344 return;
7345 }
7346 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7347}
7348
Daniel Veillardfebcca42003-02-16 15:44:18 +00007349/**
7350 * xmlRelaxNGDumpTree:
7351 * @output: the file output
7352 * @schema: a schema structure
7353 *
7354 * Dump the transformed RelaxNG tree.
7355 */
7356void
7357xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7358{
7359 if (schema == NULL) {
7360 fprintf(output, "RelaxNG empty or failed to compile\n");
7361 return;
7362 }
7363 if (schema->doc == NULL) {
7364 fprintf(output, "no document\n");
7365 } else {
7366 xmlDocDump(output, schema->doc);
7367 }
7368}
7369
Daniel Veillard6eadf632003-01-23 18:29:16 +00007370/************************************************************************
7371 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007372 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007373 * *
7374 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00007375static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7376 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007377
7378/**
7379 * xmlRelaxNGValidateCompiledCallback:
7380 * @exec: the regular expression instance
7381 * @token: the token which matched
7382 * @transdata: callback data, the define for the subelement if available
7383 @ @inputdata: callback data, the Relax NG validation context
7384 *
7385 * Handle the callback and if needed validate the element children.
7386 */
7387static void
7388xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7389 const xmlChar *token,
7390 void *transdata,
7391 void *inputdata) {
7392 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7393 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7394 int ret;
7395
7396#ifdef DEBUG_COMPILE
7397 xmlGenericError(xmlGenericErrorContext,
7398 "Compiled callback for: '%s'\n", token);
7399#endif
7400 if (ctxt == NULL) {
7401 fprintf(stderr, "callback on %s missing context\n", token);
7402 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7403 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7404 return;
7405 }
7406 if (define == NULL) {
7407 if (token[0] == '#')
7408 return;
7409 fprintf(stderr, "callback on %s missing define\n", token);
7410 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7411 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7412 return;
7413 }
7414 if ((ctxt == NULL) || (define == NULL)) {
7415 fprintf(stderr, "callback on %s missing info\n", token);
7416 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7417 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7418 return;
7419 } else if (define->type != XML_RELAXNG_ELEMENT) {
7420 fprintf(stderr, "callback on %s define is not element\n", token);
7421 if (ctxt->errNo == XML_RELAXNG_OK)
7422 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7423 return;
7424 }
7425 ret = xmlRelaxNGValidateDefinition(ctxt, define);
7426}
7427
7428/**
7429 * xmlRelaxNGValidateCompiledContent:
7430 * @ctxt: the RelaxNG validation context
7431 * @regexp: the regular expression as compiled
7432 * @content: list of children to test against the regexp
7433 *
7434 * Validate the content model of an element or start using the regexp
7435 *
7436 * Returns 0 in case of success, -1 in case of error.
7437 */
7438static int
7439xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7440 xmlRegexpPtr regexp, xmlNodePtr content) {
7441 xmlRegExecCtxtPtr exec;
7442 xmlNodePtr cur;
7443 int ret;
7444
7445 if ((ctxt == NULL) || (regexp == NULL))
7446 return(-1);
7447 exec = xmlRegNewExecCtxt(regexp,
7448 xmlRelaxNGValidateCompiledCallback, ctxt);
7449 cur = content;
7450 while (cur != NULL) {
7451 ctxt->state->seq = cur;
7452 switch (cur->type) {
7453 case XML_TEXT_NODE:
7454 case XML_CDATA_SECTION_NODE:
7455 if (xmlIsBlankNode(cur))
7456 break;
7457 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7458 if (ret < 0) {
7459 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, cur->parent->name);
7460 }
7461 break;
7462 case XML_ELEMENT_NODE:
7463 if (cur->ns != NULL) {
7464 ret = xmlRegExecPushString2(exec, cur->name,
7465 cur->ns->href, ctxt);
7466 } else {
7467 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7468 }
7469 if (ret < 0) {
7470 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7471 }
7472 break;
7473 default:
7474 break;
7475 }
7476 if (ret < 0) break;
7477 /*
7478 * Switch to next element
7479 */
7480 cur = cur->next;
7481 }
7482 ret = xmlRegExecPushString(exec, NULL, NULL);
7483 if (ret == 1) {
7484 ret = 0;
7485 ctxt->state->seq = NULL;
7486 } else if (ret == 0) {
7487 /*
7488 * TODO: get soem of the names needed to exit the current state of exec
7489 */
7490 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7491 ret = -1;
7492 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7493 xmlRelaxNGDumpValidError(ctxt);
7494 } else {
7495 ret = -1;
7496 }
7497 xmlRegFreeExecCtxt(exec);
7498 return(ret);
7499}
7500
7501/************************************************************************
7502 * *
7503 * Progressive validation of when possible *
7504 * *
7505 ************************************************************************/
7506/************************************************************************
7507 * *
7508 * Generic interpreted validation implementation *
7509 * *
7510 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007511static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7512 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007513
7514/**
7515 * xmlRelaxNGSkipIgnored:
7516 * @ctxt: a schema validation context
7517 * @node: the top node.
7518 *
7519 * Skip ignorable nodes in that context
7520 *
7521 * Returns the new sibling or NULL in case of error.
7522 */
7523static xmlNodePtr
7524xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
7525 xmlNodePtr node) {
7526 /*
7527 * TODO complete and handle entities
7528 */
7529 while ((node != NULL) &&
7530 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007531 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007532 (((node->type == XML_TEXT_NODE) ||
7533 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007534 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
7535 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007536 node = node->next;
7537 }
7538 return(node);
7539}
7540
7541/**
Daniel Veillardedc91922003-01-26 00:52:04 +00007542 * xmlRelaxNGNormalize:
7543 * @ctxt: a schema validation context
7544 * @str: the string to normalize
7545 *
7546 * Implements the normalizeWhiteSpace( s ) function from
7547 * section 6.2.9 of the spec
7548 *
7549 * Returns the new string or NULL in case of error.
7550 */
7551static xmlChar *
7552xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
7553 xmlChar *ret, *p;
7554 const xmlChar *tmp;
7555 int len;
7556
7557 if (str == NULL)
7558 return(NULL);
7559 tmp = str;
7560 while (*tmp != 0) tmp++;
7561 len = tmp - str;
7562
7563 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
7564 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007565 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007566 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007567 } else {
7568 xmlGenericError(xmlGenericErrorContext,
7569 "xmlRelaxNGNormalize: out of memory\n");
7570 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007571 return(NULL);
7572 }
7573 p = ret;
7574 while (IS_BLANK(*str)) str++;
7575 while (*str != 0) {
7576 if (IS_BLANK(*str)) {
7577 while (IS_BLANK(*str)) str++;
7578 if (*str == 0)
7579 break;
7580 *p++ = ' ';
7581 } else
7582 *p++ = *str++;
7583 }
7584 *p = 0;
7585 return(ret);
7586}
7587
7588/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007589 * xmlRelaxNGValidateDatatype:
7590 * @ctxt: a Relax-NG validation context
7591 * @value: the string value
7592 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007593 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007594 *
7595 * Validate the given value against the dataype
7596 *
7597 * Returns 0 if the validation succeeded or an error code.
7598 */
7599static int
7600xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007601 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007602 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007603 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007604 void *result = NULL;
7605 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007606
7607 if ((define == NULL) || (define->data == NULL)) {
7608 return(-1);
7609 }
7610 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007611 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007612 if ((define->attrs != NULL) &&
7613 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007614 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007615 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007616 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007617 }
7618 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007619 ret = -1;
7620 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007621 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007622 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7623 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007624 return(-1);
7625 } else if (ret == 1) {
7626 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007627 } else if (ret == 2) {
7628 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007629 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007630 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007631 ret = -1;
7632 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007633 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007634 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
7635 if (lib->facet != NULL) {
7636 tmp = lib->facet(lib->data, define->name, cur->name,
7637 cur->value, value, result);
7638 if (tmp != 0)
7639 ret = -1;
7640 }
7641 cur = cur->next;
7642 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007643 if ((ret == 0) && (define->content != NULL)) {
7644 const xmlChar *oldvalue, *oldendvalue;
7645
7646 oldvalue = ctxt->state->value;
7647 oldendvalue = ctxt->state->endvalue;
7648 ctxt->state->value = (xmlChar *) value;
7649 ctxt->state->endvalue = NULL;
7650 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7651 ctxt->state->value = (xmlChar *) oldvalue;
7652 ctxt->state->endvalue = (xmlChar *) oldendvalue;
7653 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007654 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7655 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007656 return(ret);
7657}
7658
7659/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007660 * xmlRelaxNGNextValue:
7661 * @ctxt: a Relax-NG validation context
7662 *
7663 * Skip to the next value when validating within a list
7664 *
7665 * Returns 0 if the operation succeeded or an error code.
7666 */
7667static int
7668xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
7669 xmlChar *cur;
7670
7671 cur = ctxt->state->value;
7672 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
7673 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007674 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007675 return(0);
7676 }
7677 while (*cur != 0) cur++;
7678 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
7679 if (cur == ctxt->state->endvalue)
7680 ctxt->state->value = NULL;
7681 else
7682 ctxt->state->value = cur;
7683 return(0);
7684}
7685
7686/**
7687 * xmlRelaxNGValidateValueList:
7688 * @ctxt: a Relax-NG validation context
7689 * @defines: the list of definitions to verify
7690 *
7691 * Validate the given set of definitions for the current value
7692 *
7693 * Returns 0 if the validation succeeded or an error code.
7694 */
7695static int
7696xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
7697 xmlRelaxNGDefinePtr defines) {
7698 int ret = 0;
7699
7700 while (defines != NULL) {
7701 ret = xmlRelaxNGValidateValue(ctxt, defines);
7702 if (ret != 0)
7703 break;
7704 defines = defines->next;
7705 }
7706 return(ret);
7707}
7708
7709/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007710 * xmlRelaxNGValidateValue:
7711 * @ctxt: a Relax-NG validation context
7712 * @define: the definition to verify
7713 *
7714 * Validate the given definition for the current value
7715 *
7716 * Returns 0 if the validation succeeded or an error code.
7717 */
7718static int
7719xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7720 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00007721 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007722 xmlChar *value;
7723
7724 value = ctxt->state->value;
7725 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007726 case XML_RELAXNG_EMPTY: {
7727 if ((value != NULL) && (value[0] != 0)) {
7728 int idx = 0;
7729
7730 while (IS_BLANK(value[idx]))
7731 idx++;
7732 if (value[idx] != 0)
7733 ret = -1;
7734 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007735 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00007736 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007737 case XML_RELAXNG_TEXT:
7738 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00007739 case XML_RELAXNG_VALUE: {
7740 if (!xmlStrEqual(value, define->value)) {
7741 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007742 xmlRelaxNGTypeLibraryPtr lib;
7743
7744 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00007745 if ((lib != NULL) && (lib->comp != NULL)) {
7746 ret = lib->comp(lib->data, define->name,
7747 define->value, define->node,
7748 (void *) define->attrs,
7749 value, ctxt->state->node);
7750 } else
Daniel Veillardea3f3982003-01-26 19:45:18 +00007751 ret = -1;
7752 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007753 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007754 return(-1);
7755 } else if (ret == 1) {
7756 ret = 0;
7757 } else {
7758 ret = -1;
7759 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007760 } else {
7761 xmlChar *nval, *nvalue;
7762
7763 /*
7764 * TODO: trivial optimizations are possible by
7765 * computing at compile-time
7766 */
7767 nval = xmlRelaxNGNormalize(ctxt, define->value);
7768 nvalue = xmlRelaxNGNormalize(ctxt, value);
7769
Daniel Veillardea3f3982003-01-26 19:45:18 +00007770 if ((nval == NULL) || (nvalue == NULL) ||
7771 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00007772 ret = -1;
7773 if (nval != NULL)
7774 xmlFree(nval);
7775 if (nvalue != NULL)
7776 xmlFree(nvalue);
7777 }
7778 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007779 if (ret == 0)
7780 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00007781 break;
7782 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007783 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007784 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
7785 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007786 if (ret == 0)
7787 xmlRelaxNGNextValue(ctxt);
7788
7789 break;
7790 }
7791 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007792 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007793 xmlChar *oldvalue;
7794
7795 oldflags = ctxt->flags;
7796 ctxt->flags |= FLAGS_IGNORABLE;
7797
7798 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007799 while (list != NULL) {
7800 ret = xmlRelaxNGValidateValue(ctxt, list);
7801 if (ret == 0) {
7802 break;
7803 }
7804 ctxt->state->value = oldvalue;
7805 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007806 }
7807 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007808 if (ret != 0) {
7809 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7810 xmlRelaxNGDumpValidError(ctxt);
7811 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007812 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007813 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007814 if (ret == 0)
7815 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007816 break;
7817 }
7818 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007819 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007820 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00007821#ifdef DEBUG_LIST
7822 int nb_values = 0;
7823#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007824
7825 oldvalue = ctxt->state->value;
7826 oldend = ctxt->state->endvalue;
7827
7828 val = xmlStrdup(oldvalue);
7829 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007830 val = xmlStrdup(BAD_CAST "");
7831 }
7832 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007833 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007834 return(-1);
7835 }
7836 cur = val;
7837 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007838 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007839 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007840 cur++;
7841#ifdef DEBUG_LIST
7842 nb_values++;
7843#endif
7844 while (IS_BLANK(*cur))
7845 *cur++ = 0;
7846 } else
7847 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007848 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007849#ifdef DEBUG_LIST
7850 xmlGenericError(xmlGenericErrorContext,
7851 "list value: '%s' found %d items\n", oldvalue, nb_values);
7852 nb_values = 0;
7853#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007854 ctxt->state->endvalue = cur;
7855 cur = val;
7856 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007857
Daniel Veillardfd573f12003-03-16 17:52:32 +00007858 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007859
Daniel Veillardfd573f12003-03-16 17:52:32 +00007860 while (list != NULL) {
7861 if (ctxt->state->value == ctxt->state->endvalue)
7862 ctxt->state->value = NULL;
7863 ret = xmlRelaxNGValidateValue(ctxt, list);
7864 if (ret != 0) {
7865#ifdef DEBUG_LIST
7866 xmlGenericError(xmlGenericErrorContext,
7867 "Failed to validate value: '%s' with %d rule\n",
7868 ctxt->state->value, nb_values);
7869#endif
7870 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007871 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007872#ifdef DEBUG_LIST
7873 nb_values++;
7874#endif
7875 list = list->next;
7876 }
7877
7878 if ((ret == 0) && (ctxt->state->value != NULL) &&
7879 (ctxt->state->value != ctxt->state->endvalue)) {
7880 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7881 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007882 }
7883 xmlFree(val);
7884 ctxt->state->value = oldvalue;
7885 ctxt->state->endvalue = oldend;
7886 break;
7887 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007888 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007889 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7890 if (ret != 0) {
7891 break;
7892 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007893 /* no break on purpose */
7894 case XML_RELAXNG_ZEROORMORE: {
7895 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007896
7897 oldflags = ctxt->flags;
7898 ctxt->flags |= FLAGS_IGNORABLE;
7899 cur = ctxt->state->value;
7900 temp = NULL;
7901 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7902 (temp != cur)) {
7903 temp = cur;
7904 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7905 if (ret != 0) {
7906 ctxt->state->value = temp;
7907 ret = 0;
7908 break;
7909 }
7910 cur = ctxt->state->value;
7911 }
7912 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007913 if (ret != 0) {
7914 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7915 xmlRelaxNGDumpValidError(ctxt);
7916 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007917 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007918 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007919 break;
7920 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007921 case XML_RELAXNG_EXCEPT: {
7922 xmlRelaxNGDefinePtr list;
7923
7924 list = define->content;
7925 while (list != NULL) {
7926 ret = xmlRelaxNGValidateValue(ctxt, list);
7927 if (ret == 0) {
7928 ret = -1;
7929 break;
7930 } else
7931 ret = 0;
7932 list = list->next;
7933 }
7934 break;
7935 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007936 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007937 case XML_RELAXNG_GROUP: {
7938 xmlRelaxNGDefinePtr list;
7939
7940 list = define->content;
7941 while (list != NULL) {
7942 ret = xmlRelaxNGValidateValue(ctxt, list);
7943 if (ret != 0) {
7944 ret = -1;
7945 break;
7946 } else
7947 ret = 0;
7948 list = list->next;
7949 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007950 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007951 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007952 case XML_RELAXNG_REF:
7953 case XML_RELAXNG_PARENTREF:
7954 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7955 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007956 default:
7957 TODO
7958 ret = -1;
7959 }
7960 return(ret);
7961}
7962
7963/**
7964 * xmlRelaxNGValidateValueContent:
7965 * @ctxt: a Relax-NG validation context
7966 * @defines: the list of definitions to verify
7967 *
7968 * Validate the given definitions for the current value
7969 *
7970 * Returns 0 if the validation succeeded or an error code.
7971 */
7972static int
7973xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7974 xmlRelaxNGDefinePtr defines) {
7975 int ret = 0;
7976
7977 while (defines != NULL) {
7978 ret = xmlRelaxNGValidateValue(ctxt, defines);
7979 if (ret != 0)
7980 break;
7981 defines = defines->next;
7982 }
7983 return(ret);
7984}
7985
7986/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007987 * xmlRelaxNGAttributeMatch:
7988 * @ctxt: a Relax-NG validation context
7989 * @define: the definition to check
7990 * @prop: the attribute
7991 *
7992 * Check if the attribute matches the definition nameClass
7993 *
7994 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7995 */
7996static int
7997xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7998 xmlRelaxNGDefinePtr define,
7999 xmlAttrPtr prop) {
8000 int ret;
8001
8002 if (define->name != NULL) {
8003 if (!xmlStrEqual(define->name, prop->name))
8004 return(0);
8005 }
8006 if (define->ns != NULL) {
8007 if (define->ns[0] == 0) {
8008 if (prop->ns != NULL)
8009 return(0);
8010 } else {
8011 if ((prop->ns == NULL) ||
8012 (!xmlStrEqual(define->ns, prop->ns->href)))
8013 return(0);
8014 }
8015 }
8016 if (define->nameClass == NULL)
8017 return(1);
8018 define = define->nameClass;
8019 if (define->type == XML_RELAXNG_EXCEPT) {
8020 xmlRelaxNGDefinePtr list;
8021
8022 list = define->content;
8023 while (list != NULL) {
8024 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8025 if (ret == 1)
8026 return(0);
8027 if (ret < 0)
8028 return(ret);
8029 list = list->next;
8030 }
8031 } else {
8032 TODO
8033 }
8034 return(1);
8035}
8036
8037/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008038 * xmlRelaxNGValidateAttribute:
8039 * @ctxt: a Relax-NG validation context
8040 * @define: the definition to verify
8041 *
8042 * Validate the given attribute definition for that node
8043 *
8044 * Returns 0 if the validation succeeded or an error code.
8045 */
8046static int
8047xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8048 xmlRelaxNGDefinePtr define) {
8049 int ret = 0, i;
8050 xmlChar *value, *oldvalue;
8051 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008052 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008053
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008054 if (ctxt->state->nbAttrLeft <= 0)
8055 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008056 if (define->name != NULL) {
8057 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8058 tmp = ctxt->state->attrs[i];
8059 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8060 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8061 (tmp->ns == NULL)) ||
8062 ((tmp->ns != NULL) &&
8063 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8064 prop = tmp;
8065 break;
8066 }
8067 }
8068 }
8069 if (prop != NULL) {
8070 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8071 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008072 oldseq = ctxt->state->seq;
8073 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008074 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00008075 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008076 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008077 if (ctxt->state->value != NULL)
8078 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008079 if (value != NULL)
8080 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008081 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008082 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008083 if (ret == 0) {
8084 /*
8085 * flag the attribute as processed
8086 */
8087 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008088 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008089 }
8090 } else {
8091 ret = -1;
8092 }
8093#ifdef DEBUG
8094 xmlGenericError(xmlGenericErrorContext,
8095 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
8096#endif
8097 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008098 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8099 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00008100 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00008101 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008102 prop = tmp;
8103 break;
8104 }
8105 }
8106 if (prop != NULL) {
8107 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8108 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008109 oldseq = ctxt->state->seq;
8110 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008111 ctxt->state->value = value;
8112 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008113 if (ctxt->state->value != NULL)
8114 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008115 if (value != NULL)
8116 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008117 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008118 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008119 if (ret == 0) {
8120 /*
8121 * flag the attribute as processed
8122 */
8123 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008124 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008125 }
8126 } else {
8127 ret = -1;
8128 }
8129#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00008130 if (define->ns != NULL) {
8131 xmlGenericError(xmlGenericErrorContext,
8132 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8133 define->ns, ret);
8134 } else {
8135 xmlGenericError(xmlGenericErrorContext,
8136 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8137 ret);
8138 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008139#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008140 }
8141
8142 return(ret);
8143}
8144
8145/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008146 * xmlRelaxNGValidateAttributeList:
8147 * @ctxt: a Relax-NG validation context
8148 * @define: the list of definition to verify
8149 *
8150 * Validate the given node against the list of attribute definitions
8151 *
8152 * Returns 0 if the validation succeeded or an error code.
8153 */
8154static int
8155xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8156 xmlRelaxNGDefinePtr defines) {
8157 int ret = 0;
8158 while (defines != NULL) {
8159 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
8160 ret = -1;
8161 defines = defines->next;
8162 }
8163 return(ret);
8164}
8165
8166/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008167 * xmlRelaxNGNodeMatchesList:
8168 * @node: the node
8169 * @list: a NULL terminated array of definitions
8170 *
8171 * Check if a node can be matched by one of the definitions
8172 *
8173 * Returns 1 if matches 0 otherwise
8174 */
8175static int
8176xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
8177 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008178 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008179
8180 if ((node == NULL) || (list == NULL))
8181 return(0);
8182
8183 cur = list[i++];
8184 while (cur != NULL) {
8185 if ((node->type == XML_ELEMENT_NODE) &&
8186 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008187 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
8188 if (tmp == 1)
8189 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008190 } else if (((node->type == XML_TEXT_NODE) ||
8191 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008192 (cur->type == XML_RELAXNG_TEXT)) {
8193 return(1);
8194 }
8195 cur = list[i++];
8196 }
8197 return(0);
8198}
8199
8200/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008201 * xmlRelaxNGValidateInterleave:
8202 * @ctxt: a Relax-NG validation context
8203 * @define: the definition to verify
8204 *
8205 * Validate an interleave definition for a node.
8206 *
8207 * Returns 0 if the validation succeeded or an error code.
8208 */
8209static int
8210xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
8211 xmlRelaxNGDefinePtr define) {
8212 int ret = 0, i, nbgroups, left;
8213 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008214 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008215
8216 xmlRelaxNGValidStatePtr oldstate;
8217 xmlRelaxNGPartitionPtr partitions;
8218 xmlRelaxNGInterleaveGroupPtr group = NULL;
8219 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
8220 xmlNodePtr *list = NULL, *lasts = NULL;
8221
8222 if (define->data != NULL) {
8223 partitions = (xmlRelaxNGPartitionPtr) define->data;
8224 nbgroups = partitions->nbgroups;
8225 left = nbgroups;
8226 } else {
8227 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
8228 return(-1);
8229 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008230 /*
8231 * Optimizations for MIXED
8232 */
8233 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00008234 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008235 ctxt->flags |= FLAGS_MIXED_CONTENT;
8236 if (nbgroups == 2) {
8237 /*
8238 * this is a pure <mixed> case
8239 */
8240 if (ctxt->state != NULL)
8241 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8242 ctxt->state->seq);
8243 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
8244 ret = xmlRelaxNGValidateDefinition(ctxt,
8245 partitions->groups[1]->rule);
8246 else
8247 ret = xmlRelaxNGValidateDefinition(ctxt,
8248 partitions->groups[0]->rule);
8249 if (ret == 0) {
8250 if (ctxt->state != NULL)
8251 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8252 ctxt->state->seq);
8253 }
8254 ctxt->flags = oldflags;
8255 return(ret);
8256 }
8257 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008258
8259 /*
8260 * Build arrays to store the first and last node of the chain
8261 * pertaining to each group
8262 */
8263 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8264 if (list == NULL) {
8265 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8266 return(-1);
8267 }
8268 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
8269 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8270 if (lasts == NULL) {
8271 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8272 return(-1);
8273 }
8274 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
8275
8276 /*
8277 * Walk the sequence of children finding the right group and
8278 * sorting them in sequences.
8279 */
8280 cur = ctxt->state->seq;
8281 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8282 start = cur;
8283 while (cur != NULL) {
8284 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008285 if ((partitions->triage != NULL) &&
8286 (partitions->flags & IS_DETERMINIST)) {
8287 void *tmp = NULL;
8288
8289 if ((cur->type == XML_TEXT_NODE) ||
8290 (cur->type == XML_CDATA_SECTION_NODE)) {
8291 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
8292 NULL);
8293 } else if (cur->type == XML_ELEMENT_NODE) {
8294 if (cur->ns != NULL) {
8295 tmp = xmlHashLookup2(partitions->triage, cur->name,
8296 cur->ns->href);
8297 if (tmp == NULL)
8298 tmp = xmlHashLookup2(partitions->triage,
8299 BAD_CAST "#any", cur->ns->href);
8300 } else
8301 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
8302 if (tmp == NULL)
8303 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
8304 NULL);
8305 }
8306
8307 if (tmp == NULL) {
8308 i = nbgroups;
8309 } else {
8310 i = ((long) tmp) - 1;
8311 if (partitions->flags & IS_NEEDCHECK) {
8312 group = partitions->groups[i];
8313 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
8314 i = nbgroups;
8315 }
8316 }
8317 } else {
8318 for (i = 0;i < nbgroups;i++) {
8319 group = partitions->groups[i];
8320 if (group == NULL)
8321 continue;
8322 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
8323 break;
8324 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008325 }
8326 /*
8327 * We break as soon as an element not matched is found
8328 */
8329 if (i >= nbgroups) {
8330 break;
8331 }
8332 if (lasts[i] != NULL) {
8333 lasts[i]->next = cur;
8334 lasts[i] = cur;
8335 } else {
8336 list[i] = cur;
8337 lasts[i] = cur;
8338 }
8339 if (cur->next != NULL)
8340 lastchg = cur->next;
8341 else
8342 lastchg = cur;
8343 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
8344 }
8345 if (ret != 0) {
8346 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
8347 ret = -1;
8348 goto done;
8349 }
8350 lastelem = cur;
8351 oldstate = ctxt->state;
8352 for (i = 0;i < nbgroups;i++) {
8353 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
8354 group = partitions->groups[i];
8355 if (lasts[i] != NULL) {
8356 last = lasts[i]->next;
8357 lasts[i]->next = NULL;
8358 }
8359 ctxt->state->seq = list[i];
8360 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
8361 if (ret != 0)
8362 break;
8363 if (ctxt->state != NULL) {
8364 cur = ctxt->state->seq;
8365 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00008366 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008367 oldstate = ctxt->state;
8368 ctxt->state = NULL;
8369 if (cur != NULL) {
8370 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
8371 ret = -1;
8372 ctxt->state = oldstate;
8373 goto done;
8374 }
8375 } else if (ctxt->states != NULL) {
8376 int j;
8377 int found = 0;
8378
8379 for (j = 0;j < ctxt->states->nbState;j++) {
8380 cur = ctxt->states->tabState[j]->seq;
8381 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8382 if (cur == NULL) {
8383 found = 1;
8384 break;
8385 }
8386 }
8387 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008388 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008389 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
8390 }
8391 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008392 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008393 }
8394 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8395 ctxt->states = NULL;
8396 if (found == 0) {
8397 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
8398 ret = -1;
8399 ctxt->state = oldstate;
8400 goto done;
8401 }
8402 } else {
8403 ret = -1;
8404 break;
8405 }
8406 if (lasts[i] != NULL) {
8407 lasts[i]->next = last;
8408 }
8409 }
8410 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008411 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008412 ctxt->state = oldstate;
8413 ctxt->state->seq = lastelem;
8414 if (ret != 0) {
8415 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
8416 ret = -1;
8417 goto done;
8418 }
8419
8420done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008421 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008422 /*
8423 * builds the next links chain from the prev one
8424 */
8425 cur = lastchg;
8426 while (cur != NULL) {
8427 if ((cur == start) || (cur->prev == NULL))
8428 break;
8429 cur->prev->next = cur;
8430 cur = cur->prev;
8431 }
8432 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008433 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008434 }
8435
8436 xmlFree(list);
8437 xmlFree(lasts);
8438 return(ret);
8439}
8440
8441/**
8442 * xmlRelaxNGValidateDefinitionList:
8443 * @ctxt: a Relax-NG validation context
8444 * @define: the list of definition to verify
8445 *
8446 * Validate the given node content against the (list) of definitions
8447 *
8448 * Returns 0 if the validation succeeded or an error code.
8449 */
8450static int
8451xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
8452 xmlRelaxNGDefinePtr defines) {
8453 int ret = 0, res;
8454
8455
Daniel Veillard952379b2003-03-17 15:37:12 +00008456 if (defines == NULL) {
8457 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
8458 return(-1);
8459 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008460 while (defines != NULL) {
8461 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8462 res = xmlRelaxNGValidateDefinition(ctxt, defines);
8463 if (res < 0)
8464 ret = -1;
8465 } else {
8466 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8467 return(-1);
8468 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008469 if (res == -1) /* continues on -2 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00008470 break;
8471 defines = defines->next;
8472 }
8473
8474 return(ret);
8475}
8476
8477/**
8478 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00008479 * @ctxt: a Relax-NG validation context
8480 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00008481 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00008482 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008483 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00008484 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008485 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00008486 */
8487static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008488xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
8489 xmlRelaxNGDefinePtr define,
8490 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008491 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008492
Daniel Veillardfd573f12003-03-16 17:52:32 +00008493 if (define->name != NULL) {
8494 if (!xmlStrEqual(elem->name, define->name)) {
8495 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
8496 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008497 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008498 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008499 if ((define->ns != NULL) && (define->ns[0] != 0)) {
8500 if (elem->ns == NULL) {
8501 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
8502 elem->name);
8503 return(0);
8504 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
8505 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
8506 elem->name, define->ns);
8507 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008508 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008509 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
8510 (define->name == NULL)) {
8511 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8512 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008513 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008514 } else if ((elem->ns != NULL) && (define->name != NULL)) {
8515 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8516 define->name);
8517 return(0);
8518 }
8519
8520 if (define->nameClass == NULL)
8521 return(1);
8522
8523 define = define->nameClass;
8524 if (define->type == XML_RELAXNG_EXCEPT) {
8525 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008526 if (ctxt != NULL) {
8527 oldflags = ctxt->flags;
8528 ctxt->flags |= FLAGS_IGNORABLE;
8529 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008530
8531 list = define->content;
8532 while (list != NULL) {
8533 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8534 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008535 if (ctxt != NULL)
8536 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008537 return(0);
8538 }
8539 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008540 if (ctxt != NULL)
8541 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008542 return(ret);
8543 }
8544 list = list->next;
8545 }
8546 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008547 if (ctxt != NULL) {
8548 ctxt->flags = oldflags;
8549 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008550 } else if (define->type == XML_RELAXNG_CHOICE) {
8551 xmlRelaxNGDefinePtr list;
8552
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008553 if (ctxt != NULL) {
8554 oldflags = ctxt->flags;
8555 ctxt->flags |= FLAGS_IGNORABLE;
8556 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008557
8558 list = define->nameClass;
8559 while (list != NULL) {
8560 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8561 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008562 if (ctxt != NULL)
8563 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008564 return(1);
8565 }
8566 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008567 if (ctxt != NULL)
8568 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008569 return(ret);
8570 }
8571 list = list->next;
8572 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008573 if (ctxt != NULL) {
8574 if (ret != 0) {
8575 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8576 xmlRelaxNGDumpValidError(ctxt);
8577 } else {
8578 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8579 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008580 }
8581 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008582 if (ctxt != NULL) {
8583 ctxt->flags = oldflags;
8584 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008585 } else {
8586 TODO
8587 ret = -1;
8588 }
8589 return(ret);
8590}
8591
8592/**
8593 * xmlRelaxNGValidateElementEnd:
8594 * @ctxt: a Relax-NG validation context
8595 *
8596 * Validate the end of the element, implements check that
8597 * there is nothing left not consumed in the element content
8598 * or in the attribute list.
8599 *
8600 * Returns 0 if the validation succeeded or an error code.
8601 */
8602static int
8603xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
8604 int ret = 0, i;
8605 xmlRelaxNGValidStatePtr state;
8606
8607 state = ctxt->state;
8608 if (state->seq != NULL) {
8609 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
8610 if (state->seq != NULL) {
8611 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
8612 state->node->name, state->seq->name);
8613 ret = -1;
8614 }
8615 }
8616 for (i = 0;i < state->nbAttrs;i++) {
8617 if (state->attrs[i] != NULL) {
8618 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
8619 state->attrs[i]->name, state->node->name);
8620 ret = -1;
8621 }
8622 }
8623 return(ret);
8624}
8625
8626/**
8627 * xmlRelaxNGValidateState:
8628 * @ctxt: a Relax-NG validation context
8629 * @define: the definition to verify
8630 *
8631 * Validate the current state against the definition
8632 *
8633 * Returns 0 if the validation succeeded or an error code.
8634 */
8635static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008636xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
8637 xmlRelaxNGDefinePtr define)
8638{
Daniel Veillardfd573f12003-03-16 17:52:32 +00008639 xmlNodePtr node;
8640 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008641 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008642
8643 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008644 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8645 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008646 }
8647
8648 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008649 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008650 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008651 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008652 }
8653#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008654 for (i = 0; i < ctxt->depth; i++)
8655 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00008656 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008657 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00008658 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008659 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008660 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008661 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008662 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008663 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00008664#endif
8665 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008666 switch (define->type) {
8667 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008668 node = xmlRelaxNGSkipIgnored(ctxt, node);
8669 ret = 0;
8670 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008671 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008672 ret = -1;
8673 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008674 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008675 while ((node != NULL) &&
8676 ((node->type == XML_TEXT_NODE) ||
8677 (node->type == XML_COMMENT_NODE) ||
8678 (node->type == XML_PI_NODE) ||
8679 (node->type == XML_CDATA_SECTION_NODE)))
8680 node = node->next;
8681 ctxt->state->seq = node;
8682 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008683 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008684 errNr = ctxt->errNr;
8685 node = xmlRelaxNGSkipIgnored(ctxt, node);
8686 if (node == NULL) {
8687 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
8688 ret = -1;
8689 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8690 xmlRelaxNGDumpValidError(ctxt);
8691 break;
8692 }
8693 if (node->type != XML_ELEMENT_NODE) {
8694 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8695 ret = -1;
8696 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8697 xmlRelaxNGDumpValidError(ctxt);
8698 break;
8699 }
8700 /*
8701 * This node was already validated successfully against
8702 * this definition.
8703 */
8704 if (node->_private == define) {
8705 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
8706 if (ctxt->errNr > errNr)
8707 xmlRelaxNGPopErrors(ctxt, errNr);
8708 if (ctxt->errNr != 0) {
8709 while ((ctxt->err != NULL) &&
8710 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
8711 && (xmlStrEqual(ctxt->err->arg2, node->name)))
8712 ||
8713 ((ctxt->err->err ==
8714 XML_RELAXNG_ERR_ELEMEXTRANS)
8715 && (xmlStrEqual(ctxt->err->arg1, node->name)))
8716 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
8717 || (ctxt->err->err ==
8718 XML_RELAXNG_ERR_NOTELEM)))
8719 xmlRelaxNGValidErrorPop(ctxt);
8720 }
8721 break;
8722 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008723
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008724 ret = xmlRelaxNGElementMatch(ctxt, define, node);
8725 if (ret <= 0) {
8726 ret = -1;
8727 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8728 xmlRelaxNGDumpValidError(ctxt);
8729 break;
8730 }
8731 ret = 0;
8732 if (ctxt->errNr != 0) {
8733 if (ctxt->errNr > errNr)
8734 xmlRelaxNGPopErrors(ctxt, errNr);
8735 while ((ctxt->err != NULL) &&
8736 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8737 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
8738 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8739 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
8740 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8741 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8742 xmlRelaxNGValidErrorPop(ctxt);
8743 }
8744 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008745
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008746 oldflags = ctxt->flags;
8747 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
8748 ctxt->flags -= FLAGS_MIXED_CONTENT;
8749 }
8750 state = xmlRelaxNGNewValidState(ctxt, node);
8751 if (state == NULL) {
8752 ret = -1;
8753 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8754 xmlRelaxNGDumpValidError(ctxt);
8755 break;
8756 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00008757
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008758 oldstate = ctxt->state;
8759 ctxt->state = state;
8760 if (define->attrs != NULL) {
8761 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8762 if (tmp != 0) {
8763 ret = -1;
8764 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8765 }
8766 }
8767 if (define->contModel != NULL) {
8768 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
8769 define->contModel,
8770 ctxt->state->seq);
8771#ifdef DEBUG_COMPILE
8772 xmlGenericError(xmlGenericErrorContext,
8773 "Validating content of '%s' : %d\n", define->name, tmp);
8774#endif
8775 state = ctxt->state;
8776 if (tmp == 0) {
8777 tmp = xmlRelaxNGValidateElementEnd(ctxt);
8778 if (tmp != 0)
8779 ret = -1;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008780 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008781 ret = -1;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008782 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008783 xmlRelaxNGFreeValidState(ctxt, state);
8784 } else {
8785 if (define->content != NULL) {
8786 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
8787 define->content);
8788 if (tmp != 0) {
8789 ret = -1;
8790 if (ctxt->state == NULL) {
8791 ctxt->state = oldstate;
8792 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
8793 node->name);
8794 ctxt->state = NULL;
8795 } else {
8796 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
8797 node->name);
8798 }
8799
8800 }
8801 }
8802 if (ctxt->states != NULL) {
8803 tmp = -1;
8804
8805 ctxt->flags |= FLAGS_IGNORABLE;
8806
8807 for (i = 0; i < ctxt->states->nbState; i++) {
8808 state = ctxt->states->tabState[i];
8809 ctxt->state = state;
8810
8811 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
8812 tmp = 0;
8813 xmlRelaxNGFreeValidState(ctxt, state);
8814 }
8815 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8816 ctxt->flags = oldflags;
8817 ctxt->states = NULL;
8818 if ((ret == 0) && (tmp == -1))
8819 ret = -1;
8820 } else {
8821 state = ctxt->state;
8822 if (ret == 0)
8823 ret = xmlRelaxNGValidateElementEnd(ctxt);
8824 xmlRelaxNGFreeValidState(ctxt, state);
8825 }
8826 }
8827 if (ret == 0) {
8828 node->_private = define;
8829 }
8830 ctxt->flags = oldflags;
8831 ctxt->state = oldstate;
8832 if (oldstate != NULL)
8833 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
8834 if (ret != 0) {
8835 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
8836 xmlRelaxNGDumpValidError(ctxt);
8837 ret = 0;
8838 } else {
8839 ret = -2;
8840 }
8841 } else {
8842 if (ctxt->errNr > errNr)
8843 xmlRelaxNGPopErrors(ctxt, errNr);
8844 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008845
8846#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008847 xmlGenericError(xmlGenericErrorContext,
8848 "xmlRelaxNGValidateDefinition(): validated %s : %d",
8849 node->name, ret);
8850 if (oldstate == NULL)
8851 xmlGenericError(xmlGenericErrorContext, ": no state\n");
8852 else if (oldstate->seq == NULL)
8853 xmlGenericError(xmlGenericErrorContext, ": done\n");
8854 else if (oldstate->seq->type == XML_ELEMENT_NODE)
8855 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
8856 oldstate->seq->name);
8857 else
8858 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
8859 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008860#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008861 break;
8862 case XML_RELAXNG_OPTIONAL:{
8863 errNr = ctxt->errNr;
8864 oldflags = ctxt->flags;
8865 ctxt->flags |= FLAGS_IGNORABLE;
8866 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8867 ret =
8868 xmlRelaxNGValidateDefinitionList(ctxt,
8869 define->content);
8870 if (ret != 0) {
8871 if (ctxt->state != NULL)
8872 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8873 ctxt->state = oldstate;
8874 ctxt->flags = oldflags;
8875 ret = 0;
8876 if (ctxt->errNr > errNr)
8877 xmlRelaxNGPopErrors(ctxt, errNr);
8878 break;
8879 }
8880 if (ctxt->states != NULL) {
8881 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8882 } else {
8883 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
8884 if (ctxt->states == NULL) {
8885 xmlRelaxNGFreeValidState(ctxt, oldstate);
8886 ctxt->flags = oldflags;
8887 ret = -1;
8888 if (ctxt->errNr > errNr)
8889 xmlRelaxNGPopErrors(ctxt, errNr);
8890 break;
8891 }
8892 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8893 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
8894 ctxt->state = NULL;
8895 }
8896 ctxt->flags = oldflags;
8897 ret = 0;
8898 if (ctxt->errNr > errNr)
8899 xmlRelaxNGPopErrors(ctxt, errNr);
8900 break;
8901 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008902 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008903 errNr = ctxt->errNr;
8904 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8905 if (ret != 0) {
8906 break;
8907 }
8908 if (ctxt->errNr > errNr)
8909 xmlRelaxNGPopErrors(ctxt, errNr);
8910 /* no break on purpose */
8911 case XML_RELAXNG_ZEROORMORE:{
8912 int progress;
8913 xmlRelaxNGStatesPtr states = NULL, res = NULL;
8914 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008915
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008916 errNr = ctxt->errNr;
8917 res = xmlRelaxNGNewStates(ctxt, 1);
8918 if (res == NULL) {
8919 ret = -1;
8920 break;
8921 }
8922 /*
8923 * All the input states are also exit states
8924 */
8925 if (ctxt->state != NULL) {
8926 xmlRelaxNGAddStates(ctxt, res,
8927 xmlRelaxNGCopyValidState(ctxt,
8928 ctxt->
8929 state));
8930 } else {
8931 for (j = 0; j < ctxt->states->nbState; j++) {
8932 xmlRelaxNGAddStates(ctxt, res,
8933 xmlRelaxNGCopyValidState(ctxt,
8934 ctxt->
8935 states->
8936 tabState
8937 [j]));
8938 }
8939 }
8940 oldflags = ctxt->flags;
8941 ctxt->flags |= FLAGS_IGNORABLE;
8942 do {
8943 progress = 0;
8944 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008945
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008946 if (ctxt->states != NULL) {
8947 states = ctxt->states;
8948 for (i = 0; i < states->nbState; i++) {
8949 ctxt->state = states->tabState[i];
8950 ctxt->states = NULL;
8951 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8952 define->
8953 content);
8954 if (ret == 0) {
8955 if (ctxt->state != NULL) {
8956 tmp = xmlRelaxNGAddStates(ctxt, res,
8957 ctxt->state);
8958 ctxt->state = NULL;
8959 if (tmp == 1)
8960 progress = 1;
8961 } else if (ctxt->states != NULL) {
8962 for (j = 0; j < ctxt->states->nbState;
8963 j++) {
8964 tmp =
8965 xmlRelaxNGAddStates(ctxt, res,
8966 ctxt->
8967 states->
8968 tabState
8969 [j]);
8970 if (tmp == 1)
8971 progress = 1;
8972 }
8973 xmlRelaxNGFreeStates(ctxt,
8974 ctxt->states);
8975 ctxt->states = NULL;
8976 }
8977 } else {
8978 if (ctxt->state != NULL) {
8979 xmlRelaxNGFreeValidState(ctxt,
8980 ctxt->state);
8981 ctxt->state = NULL;
8982 }
8983 }
8984 }
8985 } else {
8986 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8987 define->
8988 content);
8989 if (ret != 0) {
8990 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
8991 ctxt->state = NULL;
8992 } else {
8993 base = res->nbState;
8994 if (ctxt->state != NULL) {
8995 tmp = xmlRelaxNGAddStates(ctxt, res,
8996 ctxt->state);
8997 ctxt->state = NULL;
8998 if (tmp == 1)
8999 progress = 1;
9000 } else if (ctxt->states != NULL) {
9001 for (j = 0; j < ctxt->states->nbState; j++) {
9002 tmp = xmlRelaxNGAddStates(ctxt, res,
9003 ctxt->
9004 states->
9005 tabState[j]);
9006 if (tmp == 1)
9007 progress = 1;
9008 }
9009 if (states == NULL) {
9010 states = ctxt->states;
9011 } else {
9012 xmlRelaxNGFreeStates(ctxt,
9013 ctxt->states);
9014 }
9015 ctxt->states = NULL;
9016 }
9017 }
9018 }
9019 if (progress) {
9020 /*
9021 * Collect all the new nodes added at that step
9022 * and make them the new node set
9023 */
9024 if (res->nbState - base == 1) {
9025 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9026 res->
9027 tabState
9028 [base]);
9029 } else {
9030 if (states == NULL) {
9031 xmlRelaxNGNewStates(ctxt,
9032 res->nbState - base);
9033 }
9034 states->nbState = 0;
9035 for (i = base; i < res->nbState; i++)
9036 xmlRelaxNGAddStates(ctxt, states,
9037 xmlRelaxNGCopyValidState
9038 (ctxt,
9039 res->tabState[i]));
9040 ctxt->states = states;
9041 }
9042 }
9043 } while (progress == 1);
9044 if (states != NULL) {
9045 xmlRelaxNGFreeStates(ctxt, states);
9046 }
9047 ctxt->states = res;
9048 ctxt->flags = oldflags;
9049 if (ctxt->errNr > errNr)
9050 xmlRelaxNGPopErrors(ctxt, errNr);
9051 ret = 0;
9052 break;
9053 }
9054 case XML_RELAXNG_CHOICE:{
9055 xmlRelaxNGDefinePtr list = NULL;
9056 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009057
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009058 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009059
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009060 errNr = ctxt->errNr;
9061 if ((define->dflags & IS_TRIABLE)
9062 && (define->data != NULL)) {
9063 xmlHashTablePtr triage =
9064 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +00009065
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009066 /*
9067 * Something we can optimize cleanly there is only one
9068 * possble branch out !
9069 */
9070 if (node == NULL) {
9071 ret = -1;
9072 break;
9073 }
9074 if ((node->type == XML_TEXT_NODE) ||
9075 (node->type == XML_CDATA_SECTION_NODE)) {
9076 list =
9077 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
9078 } else if (node->type == XML_ELEMENT_NODE) {
9079 if (node->ns != NULL) {
9080 list = xmlHashLookup2(triage, node->name,
9081 node->ns->href);
9082 if (list == NULL)
9083 list =
9084 xmlHashLookup2(triage, BAD_CAST "#any",
9085 node->ns->href);
9086 } else
9087 list =
9088 xmlHashLookup2(triage, node->name, NULL);
9089 if (list == NULL)
9090 list =
9091 xmlHashLookup2(triage, BAD_CAST "#any",
9092 NULL);
9093 }
9094 if (list == NULL) {
9095 ret = -1;
9096 break;
9097 }
9098 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9099 if (ret == 0) {
9100 }
9101 break;
9102 }
Daniel Veillarde063f482003-03-21 16:53:17 +00009103
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009104 list = define->content;
9105 oldflags = ctxt->flags;
9106 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009107
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009108 while (list != NULL) {
9109 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9110 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9111 if (ret == 0) {
9112 if (states == NULL) {
9113 states = xmlRelaxNGNewStates(ctxt, 1);
9114 }
9115 if (ctxt->state != NULL) {
9116 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
9117 } else if (ctxt->states != NULL) {
9118 for (i = 0; i < ctxt->states->nbState; i++) {
9119 xmlRelaxNGAddStates(ctxt, states,
9120 ctxt->states->
9121 tabState[i]);
9122 }
9123 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9124 ctxt->states = NULL;
9125 }
9126 } else {
9127 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9128 }
9129 ctxt->state = oldstate;
9130 list = list->next;
9131 }
9132 if (states != NULL) {
9133 xmlRelaxNGFreeValidState(ctxt, oldstate);
9134 ctxt->states = states;
9135 ctxt->state = NULL;
9136 ret = 0;
9137 } else {
9138 ctxt->states = NULL;
9139 }
9140 ctxt->flags = oldflags;
9141 if (ret != 0) {
9142 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9143 xmlRelaxNGDumpValidError(ctxt);
9144 }
9145 } else {
9146 if (ctxt->errNr > errNr)
9147 xmlRelaxNGPopErrors(ctxt, errNr);
9148 }
9149 break;
9150 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009151 case XML_RELAXNG_DEF:
9152 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009153 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9154 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009155 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009156 ret = xmlRelaxNGValidateInterleave(ctxt, define);
9157 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009158 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009159 ret = xmlRelaxNGValidateAttribute(ctxt, define);
9160 break;
9161 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00009162 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009163 case XML_RELAXNG_EXTERNALREF:
9164 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
9165 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00009166 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009167 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
9168 break;
9169 case XML_RELAXNG_DATATYPE:{
9170 xmlNodePtr child;
9171 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009172
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009173 child = node;
9174 while (child != NULL) {
9175 if (child->type == XML_ELEMENT_NODE) {
9176 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
9177 node->parent->name);
9178 ret = -1;
9179 break;
9180 } else if ((child->type == XML_TEXT_NODE) ||
9181 (child->type == XML_CDATA_SECTION_NODE)) {
9182 content = xmlStrcat(content, child->content);
9183 }
9184 /* TODO: handle entities ... */
9185 child = child->next;
9186 }
9187 if (ret == -1) {
9188 if (content != NULL)
9189 xmlFree(content);
9190 break;
9191 }
9192 if (content == NULL) {
9193 content = xmlStrdup(BAD_CAST "");
9194 if (content == NULL) {
9195 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9196 ret = -1;
9197 break;
9198 }
9199 }
9200 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
9201 ctxt->state->seq);
9202 if (ret == -1) {
9203 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
9204 } else if (ret == 0) {
9205 ctxt->state->seq = NULL;
9206 }
9207 if (content != NULL)
9208 xmlFree(content);
9209 break;
9210 }
9211 case XML_RELAXNG_VALUE:{
9212 xmlChar *content = NULL;
9213 xmlChar *oldvalue;
9214 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009215
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009216 child = node;
9217 while (child != NULL) {
9218 if (child->type == XML_ELEMENT_NODE) {
9219 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
9220 node->parent->name);
9221 ret = -1;
9222 break;
9223 } else if ((child->type == XML_TEXT_NODE) ||
9224 (child->type == XML_CDATA_SECTION_NODE)) {
9225 content = xmlStrcat(content, child->content);
9226 }
9227 /* TODO: handle entities ... */
9228 child = child->next;
9229 }
9230 if (ret == -1) {
9231 if (content != NULL)
9232 xmlFree(content);
9233 break;
9234 }
9235 if (content == NULL) {
9236 content = xmlStrdup(BAD_CAST "");
9237 if (content == NULL) {
9238 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9239 ret = -1;
9240 break;
9241 }
9242 }
9243 oldvalue = ctxt->state->value;
9244 ctxt->state->value = content;
9245 ret = xmlRelaxNGValidateValue(ctxt, define);
9246 ctxt->state->value = oldvalue;
9247 if (ret == -1) {
9248 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
9249 } else if (ret == 0) {
9250 ctxt->state->seq = NULL;
9251 }
9252 if (content != NULL)
9253 xmlFree(content);
9254 break;
9255 }
9256 case XML_RELAXNG_LIST:{
9257 xmlChar *content;
9258 xmlNodePtr child;
9259 xmlChar *oldvalue, *oldendvalue;
9260 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009261
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009262 /*
9263 * Make sure it's only text nodes
9264 */
9265
9266 content = NULL;
9267 child = node;
9268 while (child != NULL) {
9269 if (child->type == XML_ELEMENT_NODE) {
9270 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
9271 node->parent->name);
9272 ret = -1;
9273 break;
9274 } else if ((child->type == XML_TEXT_NODE) ||
9275 (child->type == XML_CDATA_SECTION_NODE)) {
9276 content = xmlStrcat(content, child->content);
9277 }
9278 /* TODO: handle entities ... */
9279 child = child->next;
9280 }
9281 if (ret == -1) {
9282 if (content != NULL)
9283 xmlFree(content);
9284 break;
9285 }
9286 if (content == NULL) {
9287 content = xmlStrdup(BAD_CAST "");
9288 if (content == NULL) {
9289 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9290 ret = -1;
9291 break;
9292 }
9293 }
9294 len = xmlStrlen(content);
9295 oldvalue = ctxt->state->value;
9296 oldendvalue = ctxt->state->endvalue;
9297 ctxt->state->value = content;
9298 ctxt->state->endvalue = content + len;
9299 ret = xmlRelaxNGValidateValue(ctxt, define);
9300 ctxt->state->value = oldvalue;
9301 ctxt->state->endvalue = oldendvalue;
9302 if (ret == -1) {
9303 VALID_ERR(XML_RELAXNG_ERR_LIST);
9304 } else if ((ret == 0) && (node != NULL)) {
9305 ctxt->state->seq = node->next;
9306 }
9307 if (content != NULL)
9308 xmlFree(content);
9309 break;
9310 }
9311 case XML_RELAXNG_START:
9312 case XML_RELAXNG_EXCEPT:
9313 case XML_RELAXNG_PARAM:
9314 TODO ret = -1;
9315 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009316 }
9317 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009318#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009319 for (i = 0; i < ctxt->depth; i++)
9320 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009321 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009322 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009323 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009324 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009325 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009326 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009327 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009328 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009329#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009330 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009331}
9332
9333/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009334 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009335 * @ctxt: a Relax-NG validation context
9336 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009337 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009338 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009339 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009340 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009341 */
9342static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00009343xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
9344 xmlRelaxNGDefinePtr define) {
9345 xmlRelaxNGStatesPtr states, res;
9346 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009347
Daniel Veillardfd573f12003-03-16 17:52:32 +00009348 /*
9349 * We should NOT have both ctxt->state and ctxt->states
9350 */
9351 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9352 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009353 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009354 ctxt->state = NULL;
9355 }
9356
9357 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
9358 if (ctxt->states != NULL) {
9359 ctxt->state = ctxt->states->tabState[0];
9360 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9361 ctxt->states = NULL;
9362 }
9363 ret = xmlRelaxNGValidateState(ctxt, define);
9364 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9365 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009366 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009367 ctxt->state = NULL;
9368 }
9369 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
9370 ctxt->state = ctxt->states->tabState[0];
9371 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9372 ctxt->states = NULL;
9373 }
9374 return(ret);
9375 }
9376
9377 states = ctxt->states;
9378 ctxt->states = NULL;
9379 res = NULL;
9380 j = 0;
9381 oldflags = ctxt->flags;
9382 ctxt->flags |= FLAGS_IGNORABLE;
9383 for (i = 0;i < states->nbState;i++) {
9384 ctxt->state = states->tabState[i];
9385 ctxt->states = NULL;
9386 ret = xmlRelaxNGValidateState(ctxt, define);
9387 /*
9388 * We should NOT have both ctxt->state and ctxt->states
9389 */
9390 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9391 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009392 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009393 ctxt->state = NULL;
9394 }
9395 if (ret == 0) {
9396 if (ctxt->states == NULL) {
9397 if (res != NULL) {
9398 /* add the state to the container */
9399 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
9400 ctxt->state = NULL;
9401 } else {
9402 /* add the state directly in states */
9403 states->tabState[j++] = ctxt->state;
9404 ctxt->state = NULL;
9405 }
9406 } else {
9407 if (res == NULL) {
9408 /* make it the new container and copy other results */
9409 res = ctxt->states;
9410 ctxt->states = NULL;
9411 for (k = 0;k < j;k++)
9412 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
9413 } else {
9414 /* add all the new results to res and reff the container */
9415 for (k = 0;k < ctxt->states->nbState;k++)
9416 xmlRelaxNGAddStates(ctxt, res,
9417 ctxt->states->tabState[k]);
9418 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9419 ctxt->states = NULL;
9420 }
9421 }
9422 } else {
9423 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009424 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009425 ctxt->state = NULL;
9426 } else if (ctxt->states != NULL) {
9427 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00009428 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009429 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9430 ctxt->states = NULL;
9431 }
9432 }
9433 }
9434 ctxt->flags = oldflags;
9435 if (res != NULL) {
9436 xmlRelaxNGFreeStates(ctxt, states);
9437 ctxt->states = res;
9438 ret = 0;
9439 } else if (j > 1) {
9440 states->nbState = j;
9441 ctxt->states = states;
9442 ret =0;
9443 } else if (j == 1) {
9444 ctxt->state = states->tabState[0];
9445 xmlRelaxNGFreeStates(ctxt, states);
9446 ret = 0;
9447 } else {
9448 ret = -1;
9449 xmlRelaxNGFreeStates(ctxt, states);
9450 if (ctxt->states != NULL) {
9451 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9452 ctxt->states = NULL;
9453 }
9454 }
9455 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9456 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009457 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009458 ctxt->state = NULL;
9459 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009460 return(ret);
9461}
9462
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009463/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00009464 * xmlRelaxNGValidateDocument:
9465 * @ctxt: a Relax-NG validation context
9466 * @doc: the document
9467 *
9468 * Validate the given document
9469 *
9470 * Returns 0 if the validation succeeded or an error code.
9471 */
9472static int
9473xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
9474 int ret;
9475 xmlRelaxNGPtr schema;
9476 xmlRelaxNGGrammarPtr grammar;
9477 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009478 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009479
9480 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
9481 return(-1);
9482
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009483 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009484 schema = ctxt->schema;
9485 grammar = schema->topgrammar;
9486 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00009487 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009488 return(-1);
9489 }
9490 state = xmlRelaxNGNewValidState(ctxt, NULL);
9491 ctxt->state = state;
9492 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009493 if ((ctxt->state != NULL) && (state->seq != NULL)) {
9494 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009495 node = state->seq;
9496 node = xmlRelaxNGSkipIgnored(ctxt, node);
9497 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00009498 if (ret != -1) {
9499 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
9500 ret = -1;
9501 }
9502 }
9503 } else if (ctxt->states != NULL) {
9504 int i;
9505 int tmp = -1;
9506
9507 for (i = 0;i < ctxt->states->nbState;i++) {
9508 state = ctxt->states->tabState[i];
9509 node = state->seq;
9510 node = xmlRelaxNGSkipIgnored(ctxt, node);
9511 if (node == NULL)
9512 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00009513 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009514 }
9515 if (tmp == -1) {
9516 if (ret != -1) {
9517 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
9518 ret = -1;
9519 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009520 }
9521 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009522 if (ctxt->state != NULL) {
9523 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9524 ctxt->state = NULL;
9525 }
Daniel Veillard580ced82003-03-21 21:22:48 +00009526 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +00009527 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +00009528#ifdef DEBUG
9529 else if (ctxt->errNr != 0) {
9530 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
9531 ctxt->errNr);
9532 xmlRelaxNGDumpValidError(ctxt);
9533 }
9534#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +00009535 if (ctxt->idref == 1) {
9536 xmlValidCtxt vctxt;
9537
9538 memset(&vctxt, 0, sizeof(xmlValidCtxt));
9539 vctxt.valid = 1;
9540 vctxt.error = ctxt->error;
9541 vctxt.warning = ctxt->warning;
9542 vctxt.userData = ctxt->userData;
9543
9544 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
9545 ret = -1;
9546 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009547 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
9548 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009549
9550 return(ret);
9551}
9552
Daniel Veillardfd573f12003-03-16 17:52:32 +00009553/************************************************************************
9554 * *
9555 * Validation interfaces *
9556 * *
9557 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00009558/**
9559 * xmlRelaxNGNewValidCtxt:
9560 * @schema: a precompiled XML RelaxNGs
9561 *
9562 * Create an XML RelaxNGs validation context based on the given schema
9563 *
9564 * Returns the validation context or NULL in case of error
9565 */
9566xmlRelaxNGValidCtxtPtr
9567xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
9568 xmlRelaxNGValidCtxtPtr ret;
9569
9570 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
9571 if (ret == NULL) {
9572 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00009573 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00009574 return (NULL);
9575 }
9576 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
9577 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00009578 ret->error = xmlGenericError;
9579 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00009580 ret->errNr = 0;
9581 ret->errMax = 0;
9582 ret->err = NULL;
9583 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00009584 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00009585 ret->states = NULL;
9586 ret->freeState = NULL;
9587 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009588 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009589 return (ret);
9590}
9591
9592/**
9593 * xmlRelaxNGFreeValidCtxt:
9594 * @ctxt: the schema validation context
9595 *
9596 * Free the resources associated to the schema validation context
9597 */
9598void
9599xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009600 int k;
9601
Daniel Veillard6eadf632003-01-23 18:29:16 +00009602 if (ctxt == NULL)
9603 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009604 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00009605 xmlRelaxNGFreeStates(NULL, ctxt->states);
9606 if (ctxt->freeState != NULL) {
9607 for (k = 0;k < ctxt->freeState->nbState;k++) {
9608 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
9609 }
9610 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
9611 }
Daniel Veillard798024a2003-03-19 10:36:09 +00009612 if (ctxt->freeStates != NULL) {
9613 for (k = 0;k < ctxt->freeStatesNr;k++) {
9614 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
9615 }
9616 xmlFree(ctxt->freeStates);
9617 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00009618 if (ctxt->errTab != NULL)
9619 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009620 xmlFree(ctxt);
9621}
9622
9623/**
9624 * xmlRelaxNGSetValidErrors:
9625 * @ctxt: a Relax-NG validation context
9626 * @err: the error function
9627 * @warn: the warning function
9628 * @ctx: the functions context
9629 *
9630 * Set the error and warning callback informations
9631 */
9632void
9633xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
9634 xmlRelaxNGValidityErrorFunc err,
9635 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
9636 if (ctxt == NULL)
9637 return;
9638 ctxt->error = err;
9639 ctxt->warning = warn;
9640 ctxt->userData = ctx;
9641}
9642
9643/**
9644 * xmlRelaxNGValidateDoc:
9645 * @ctxt: a Relax-NG validation context
9646 * @doc: a parsed document tree
9647 *
9648 * Validate a document tree in memory.
9649 *
9650 * Returns 0 if the document is valid, a positive error code
9651 * number otherwise and -1 in case of internal or API error.
9652 */
9653int
9654xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
9655 int ret;
9656
9657 if ((ctxt == NULL) || (doc == NULL))
9658 return(-1);
9659
9660 ctxt->doc = doc;
9661
9662 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00009663 /*
9664 * TODO: build error codes
9665 */
9666 if (ret == -1)
9667 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009668 return(ret);
9669}
9670
9671#endif /* LIBXML_SCHEMAS_ENABLED */
9672