blob: 99ff9e9206cd507e2687219807be791a6c42f753 [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 Veillardf4b4f982003-02-13 11:02:08 +000011 * - add support for DTD compatibility spec
12 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
Daniel Veillardac297932003-04-17 12:55:35 +000013 * - report better mem allocations pbms at runtime and abort immediately.
Daniel Veillardd41f4f42003-01-29 21:07:52 +000014 */
15
Daniel Veillard6eadf632003-01-23 18:29:16 +000016#define IN_LIBXML
17#include "libxml.h"
18
19#ifdef LIBXML_SCHEMAS_ENABLED
20
21#include <string.h>
22#include <stdio.h>
23#include <libxml/xmlmemory.h>
24#include <libxml/parser.h>
25#include <libxml/parserInternals.h>
26#include <libxml/hash.h>
27#include <libxml/uri.h>
28
29#include <libxml/relaxng.h>
30
31#include <libxml/xmlschemastypes.h>
32#include <libxml/xmlautomata.h>
33#include <libxml/xmlregexp.h>
Daniel Veillardc6e997c2003-01-27 12:35:42 +000034#include <libxml/xmlschemastypes.h>
Daniel Veillard6eadf632003-01-23 18:29:16 +000035
36/*
37 * The Relax-NG namespace
38 */
39static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
40 "http://relaxng.org/ns/structure/1.0";
41
42#define IS_RELAXNG(node, type) \
43 ((node != NULL) && (node->ns != NULL) && \
44 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
45 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
46
47
Daniel Veillard952379b2003-03-17 15:37:12 +000048/* #define DEBUG 1 */
Daniel Veillardc482e262003-02-26 14:48:48 +000049/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard71531f32003-02-05 13:19:53 +000050/* #define DEBUG_CONTENT 1 */
51/* #define DEBUG_TYPE 1 */
52/* #define DEBUG_VALID 1 */
Daniel Veillarde5b110b2003-02-04 14:43:39 +000053/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard416589a2003-02-17 17:25:42 +000054/* #define DEBUG_LIST 1 */
Daniel Veillard5add8682003-03-10 13:13:58 +000055/* #define DEBUG_INCLUDE */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000056/* #define DEBUG_ERROR 1 */
Daniel Veillardc58f4ef2003-04-14 16:11:26 +000057/* #define DEBUG_COMPILE 1 */
Daniel Veillardf4e55762003-04-15 23:32:22 +000058/* #define DEBUG_PROGRESSIVE 1 */
Daniel Veillard6eadf632003-01-23 18:29:16 +000059
Daniel Veillard5f1946a2003-03-31 16:38:16 +000060#define MAX_ERROR 5
61
Daniel Veillard6eadf632003-01-23 18:29:16 +000062#define TODO \
63 xmlGenericError(xmlGenericErrorContext, \
64 "Unimplemented block at %s:%d\n", \
65 __FILE__, __LINE__);
66
67typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
68typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
69
70typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
71typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
72
Daniel Veillardd41f4f42003-01-29 21:07:52 +000073typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
74typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
75
Daniel Veillarda9d912d2003-02-01 17:43:10 +000076typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
77typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
78
Daniel Veillard6eadf632003-01-23 18:29:16 +000079typedef enum {
80 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
81 XML_RELAXNG_COMBINE_CHOICE, /* choice */
82 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
83} xmlRelaxNGCombine;
84
Daniel Veillard4c5cf702003-02-21 15:40:34 +000085typedef enum {
86 XML_RELAXNG_CONTENT_ERROR = -1,
87 XML_RELAXNG_CONTENT_EMPTY = 0,
88 XML_RELAXNG_CONTENT_SIMPLE,
89 XML_RELAXNG_CONTENT_COMPLEX
90} xmlRelaxNGContentType;
91
Daniel Veillard6eadf632003-01-23 18:29:16 +000092typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
93typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
94
95struct _xmlRelaxNGGrammar {
96 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
97 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
98 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
99 xmlRelaxNGDefinePtr start; /* <start> content */
100 xmlRelaxNGCombine combine; /* the default combine value */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000101 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000102 xmlHashTablePtr defs; /* define* */
103 xmlHashTablePtr refs; /* references */
104};
105
106
Daniel Veillard6eadf632003-01-23 18:29:16 +0000107typedef enum {
Daniel Veillard77648bb2003-02-20 15:03:22 +0000108 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000109 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
110 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000111 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000112 XML_RELAXNG_TEXT, /* textual content */
113 XML_RELAXNG_ELEMENT, /* an element */
114 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000115 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000116 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
117 XML_RELAXNG_LIST, /* a list of patterns */
118 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
119 XML_RELAXNG_DEF, /* a definition */
120 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000121 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000122 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000123 XML_RELAXNG_OPTIONAL, /* optional patterns */
124 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000125 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
126 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
127 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000128 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000129 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000130} xmlRelaxNGType;
131
Daniel Veillard52b48c72003-04-13 19:53:42 +0000132#define IS_NULLABLE (1 << 0)
133#define IS_NOT_NULLABLE (1 << 1)
134#define IS_INDETERMINIST (1 << 2)
135#define IS_MIXED (1 << 3)
136#define IS_TRIABLE (1 << 4)
137#define IS_PROCESSED (1 << 5)
138#define IS_COMPILABLE (1 << 6)
139#define IS_NOT_COMPILABLE (1 << 7)
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000140
Daniel Veillard6eadf632003-01-23 18:29:16 +0000141struct _xmlRelaxNGDefine {
142 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000143 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000144 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000145 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000146 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000147 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000148 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000149 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000150 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000151 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000152 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000153 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000154 short depth; /* used for the cycle detection */
Daniel Veillarde063f482003-03-21 16:53:17 +0000155 short dflags; /* define related flags */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000156 xmlRegexpPtr contModel; /* a compiled content model if available */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000157};
158
159/**
160 * _xmlRelaxNG:
161 *
162 * A RelaxNGs definition
163 */
164struct _xmlRelaxNG {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000165 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000166 xmlRelaxNGGrammarPtr topgrammar;
167 xmlDocPtr doc;
168
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000169 int idref; /* requires idref checking */
170
Daniel Veillard6eadf632003-01-23 18:29:16 +0000171 xmlHashTablePtr defs; /* define */
172 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000173 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
174 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000175 int defNr; /* number of defines used */
176 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000177
Daniel Veillard6eadf632003-01-23 18:29:16 +0000178};
179
Daniel Veillard77648bb2003-02-20 15:03:22 +0000180#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
181#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
182#define XML_RELAXNG_IN_LIST (1 << 2)
183#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
184#define XML_RELAXNG_IN_START (1 << 4)
185#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
186#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
187#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000188#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
189#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000190
191struct _xmlRelaxNGParserCtxt {
192 void *userData; /* user specific data block */
193 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
194 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000195 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000196
197 xmlRelaxNGPtr schema; /* The schema in use */
198 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000199 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000200 int flags; /* parser flags */
201 int nbErrors; /* number of errors at parse time */
202 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000203 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000204 xmlRelaxNGDefinePtr def; /* the current define */
205
206 int nbInterleaves;
207 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000208
Daniel Veillardc482e262003-02-26 14:48:48 +0000209 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
210 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000211 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000212 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000213
Daniel Veillard419a7682003-02-03 23:22:49 +0000214 int defNr; /* number of defines used */
215 int defMax; /* number of defines aloocated */
216 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
217
Daniel Veillard6eadf632003-01-23 18:29:16 +0000218 const char *buffer;
219 int size;
220
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000221 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000222 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000223 int docNr; /* Depth of the parsing stack */
224 int docMax; /* Max depth of the parsing stack */
225 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000226
227 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000228 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000229 int incNr; /* Depth of the include parsing stack */
230 int incMax; /* Max depth of the parsing stack */
231 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000232
233 int idref; /* requires idref checking */
Daniel Veillard52b48c72003-04-13 19:53:42 +0000234
235 /* used to compile content models */
236 xmlAutomataPtr am; /* the automata */
237 xmlAutomataStatePtr state; /* used to build the automata */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000238};
239
240#define FLAGS_IGNORABLE 1
241#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000242#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000243
244/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000245 * xmlRelaxNGInterleaveGroup:
246 *
247 * A RelaxNGs partition set associated to lists of definitions
248 */
249typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
250typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
251struct _xmlRelaxNGInterleaveGroup {
252 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
253 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000254 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000255};
256
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000257#define IS_DETERMINIST 1
258#define IS_NEEDCHECK 2
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000259/**
260 * xmlRelaxNGPartitions:
261 *
262 * A RelaxNGs partition associated to an interleave group
263 */
264typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
265typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
266struct _xmlRelaxNGPartition {
267 int nbgroups; /* number of groups in the partitions */
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000268 xmlHashTablePtr triage; /* hash table used to direct nodes to the
269 right group when possible */
270 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000271 xmlRelaxNGInterleaveGroupPtr *groups;
272};
273
274/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000275 * xmlRelaxNGValidState:
276 *
277 * A RelaxNGs validation state
278 */
279#define MAX_ATTR 20
280typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
281typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
282struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000283 xmlNodePtr node; /* the current node */
284 xmlNodePtr seq; /* the sequence of children left to validate */
285 int nbAttrs; /* the number of attributes */
Daniel Veillard798024a2003-03-19 10:36:09 +0000286 int maxAttrs; /* the size of attrs */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000287 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000288 xmlChar *value; /* the value when operating on string */
289 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard798024a2003-03-19 10:36:09 +0000290 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000291};
292
293/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000294 * xmlRelaxNGStates:
295 *
296 * A RelaxNGs container for validation state
297 */
298typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
299typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
300struct _xmlRelaxNGStates {
301 int nbState; /* the number of states */
302 int maxState; /* the size of the array */
303 xmlRelaxNGValidStatePtr *tabState;
304};
305
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000306#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000307/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000308 * xmlRelaxNGValidError:
309 *
310 * A RelaxNGs validation error
311 */
312typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
313typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
314struct _xmlRelaxNGValidError {
315 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000316 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000317 xmlNodePtr node; /* the current node */
318 xmlNodePtr seq; /* the current child */
319 const xmlChar * arg1; /* first arg */
320 const xmlChar * arg2; /* second arg */
321};
322
323/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000324 * xmlRelaxNGValidCtxt:
325 *
326 * A RelaxNGs validation context
327 */
328
329struct _xmlRelaxNGValidCtxt {
330 void *userData; /* user specific data block */
331 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
332 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
333
334 xmlRelaxNGPtr schema; /* The schema in use */
335 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000336 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000337 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000338 int idref; /* requires idref checking */
Daniel Veillarda507fbf2003-03-31 16:09:37 +0000339 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000340
341 /*
342 * Errors accumulated in branches may have to be stacked to be
343 * provided back when it's sure they affect validation.
344 */
345 xmlRelaxNGValidErrorPtr err; /* Last error */
346 int errNr; /* Depth of the error stack */
347 int errMax; /* Max depth of the error stack */
348 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000349
Daniel Veillardfd573f12003-03-16 17:52:32 +0000350 xmlRelaxNGValidStatePtr state; /* the current validation state */
351 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000352
353 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
354 int freeStatesNr;
355 int freeStatesMax;
356 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillardf4e55762003-04-15 23:32:22 +0000357
358 /*
359 * This is used for "progressive" validation
360 */
361 xmlRegExecCtxtPtr elem; /* the current element regexp */
362 int elemNr; /* the number of element validated */
363 int elemMax; /* the max depth of elements */
364 xmlRegExecCtxtPtr *elemTab; /* the stack of regexp runtime */
365 int pstate; /* progressive state */
366 xmlNodePtr pnode; /* the current node */
367 xmlRelaxNGDefinePtr pdef; /* the non-streamable definition */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000368};
369
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000370/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000371 * xmlRelaxNGInclude:
372 *
373 * Structure associated to a RelaxNGs document element
374 */
375struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000376 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000377 xmlChar *href; /* the normalized href value */
378 xmlDocPtr doc; /* the associated XML document */
379 xmlRelaxNGDefinePtr content;/* the definitions */
380 xmlRelaxNGPtr schema; /* the schema */
381};
382
383/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000384 * xmlRelaxNGDocument:
385 *
386 * Structure associated to a RelaxNGs document element
387 */
388struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000389 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000390 xmlChar *href; /* the normalized href value */
391 xmlDocPtr doc; /* the associated XML document */
392 xmlRelaxNGDefinePtr content;/* the definitions */
393 xmlRelaxNGPtr schema; /* the schema */
394};
395
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000396
Daniel Veillard6eadf632003-01-23 18:29:16 +0000397/************************************************************************
398 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000399 * Preliminary type checking interfaces *
400 * *
401 ************************************************************************/
402/**
403 * xmlRelaxNGTypeHave:
404 * @data: data needed for the library
405 * @type: the type name
406 * @value: the value to check
407 *
408 * Function provided by a type library to check if a type is exported
409 *
410 * Returns 1 if yes, 0 if no and -1 in case of error.
411 */
412typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
413
414/**
415 * xmlRelaxNGTypeCheck:
416 * @data: data needed for the library
417 * @type: the type name
418 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000419 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000420 *
421 * Function provided by a type library to check if a value match a type
422 *
423 * Returns 1 if yes, 0 if no and -1 in case of error.
424 */
425typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000426 const xmlChar *value, void **result,
427 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000428
429/**
430 * xmlRelaxNGFacetCheck:
431 * @data: data needed for the library
432 * @type: the type name
433 * @facet: the facet name
434 * @val: the facet value
435 * @strval: the string value
436 * @value: the value to check
437 *
438 * Function provided by a type library to check a value facet
439 *
440 * Returns 1 if yes, 0 if no and -1 in case of error.
441 */
442typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
443 const xmlChar *facet, const xmlChar *val,
444 const xmlChar *strval, void *value);
445
446/**
447 * xmlRelaxNGTypeFree:
448 * @data: data needed for the library
449 * @result: the value to free
450 *
451 * Function provided by a type library to free a returned result
452 */
453typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000454
455/**
456 * xmlRelaxNGTypeCompare:
457 * @data: data needed for the library
458 * @type: the type name
459 * @value1: the first value
460 * @value2: the second value
461 *
462 * Function provided by a type library to compare two values accordingly
463 * to a type.
464 *
465 * Returns 1 if yes, 0 if no and -1 in case of error.
466 */
467typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
468 const xmlChar *value1,
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000469 xmlNodePtr ctxt1,
470 void *comp1,
471 const xmlChar *value2,
472 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000473typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
474typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
475struct _xmlRelaxNGTypeLibrary {
476 const xmlChar *namespace; /* the datatypeLibrary value */
477 void *data; /* data needed for the library */
478 xmlRelaxNGTypeHave have; /* the export function */
479 xmlRelaxNGTypeCheck check; /* the checking function */
480 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000481 xmlRelaxNGFacetCheck facet; /* the facet check function */
482 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000483};
484
485/************************************************************************
486 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000487 * Allocation functions *
488 * *
489 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000490static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
491static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000492static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000493static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000494static int xmlRelaxNGEqualValidState(
495 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
496 xmlRelaxNGValidStatePtr state1,
497 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000498static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
499 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000500
501/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000502 * xmlRelaxNGFreeDocument:
503 * @docu: a document structure
504 *
505 * Deallocate a RelaxNG document structure.
506 */
507static void
508xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
509{
510 if (docu == NULL)
511 return;
512
513 if (docu->href != NULL)
514 xmlFree(docu->href);
515 if (docu->doc != NULL)
516 xmlFreeDoc(docu->doc);
517 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000518 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000519 xmlFree(docu);
520}
521
522/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000523 * xmlRelaxNGFreeDocumentList:
524 * @docu: a list of document structure
525 *
526 * Deallocate a RelaxNG document structures.
527 */
528static void
529xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
530{
531 xmlRelaxNGDocumentPtr next;
532 while (docu != NULL) {
533 next = docu->next;
534 xmlRelaxNGFreeDocument(docu);
535 docu = next;
536 }
537}
538
539/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000540 * xmlRelaxNGFreeInclude:
541 * @incl: a include structure
542 *
543 * Deallocate a RelaxNG include structure.
544 */
545static void
546xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
547{
548 if (incl == NULL)
549 return;
550
551 if (incl->href != NULL)
552 xmlFree(incl->href);
553 if (incl->doc != NULL)
554 xmlFreeDoc(incl->doc);
555 if (incl->schema != NULL)
556 xmlRelaxNGFree(incl->schema);
557 xmlFree(incl);
558}
559
560/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000561 * xmlRelaxNGFreeIncludeList:
562 * @incl: a include structure list
563 *
564 * Deallocate a RelaxNG include structure.
565 */
566static void
567xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
568{
569 xmlRelaxNGIncludePtr next;
570 while (incl != NULL) {
571 next = incl->next;
572 xmlRelaxNGFreeInclude(incl);
573 incl = next;
574 }
575}
576
577/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000578 * xmlRelaxNGNewRelaxNG:
579 * @ctxt: a Relax-NG validation context (optional)
580 *
581 * Allocate a new RelaxNG structure.
582 *
583 * Returns the newly allocated structure or NULL in case or error
584 */
585static xmlRelaxNGPtr
586xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
587{
588 xmlRelaxNGPtr ret;
589
590 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
591 if (ret == NULL) {
592 if ((ctxt != NULL) && (ctxt->error != NULL))
593 ctxt->error(ctxt->userData, "Out of memory\n");
594 ctxt->nbErrors++;
595 return (NULL);
596 }
597 memset(ret, 0, sizeof(xmlRelaxNG));
598
599 return (ret);
600}
601
602/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000603 * xmlRelaxNGFreeInnerSchema:
604 * @schema: a schema structure
605 *
606 * Deallocate a RelaxNG schema structure.
607 */
608static void
609xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
610{
611 if (schema == NULL)
612 return;
613
614 if (schema->doc != NULL)
615 xmlFreeDoc(schema->doc);
616 if (schema->defTab != NULL) {
617 int i;
618
619 for (i = 0;i < schema->defNr;i++)
620 xmlRelaxNGFreeDefine(schema->defTab[i]);
621 xmlFree(schema->defTab);
622 }
623
624 xmlFree(schema);
625}
626
627/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000628 * xmlRelaxNGFree:
629 * @schema: a schema structure
630 *
631 * Deallocate a RelaxNG structure.
632 */
633void
634xmlRelaxNGFree(xmlRelaxNGPtr schema)
635{
636 if (schema == NULL)
637 return;
638
Daniel Veillard6eadf632003-01-23 18:29:16 +0000639 if (schema->topgrammar != NULL)
640 xmlRelaxNGFreeGrammar(schema->topgrammar);
641 if (schema->doc != NULL)
642 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000643 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000644 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000645 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000646 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000647 if (schema->defTab != NULL) {
648 int i;
649
650 for (i = 0;i < schema->defNr;i++)
651 xmlRelaxNGFreeDefine(schema->defTab[i]);
652 xmlFree(schema->defTab);
653 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000654
655 xmlFree(schema);
656}
657
658/**
659 * xmlRelaxNGNewGrammar:
660 * @ctxt: a Relax-NG validation context (optional)
661 *
662 * Allocate a new RelaxNG grammar.
663 *
664 * Returns the newly allocated structure or NULL in case or error
665 */
666static xmlRelaxNGGrammarPtr
667xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
668{
669 xmlRelaxNGGrammarPtr ret;
670
671 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
672 if (ret == NULL) {
673 if ((ctxt != NULL) && (ctxt->error != NULL))
674 ctxt->error(ctxt->userData, "Out of memory\n");
675 ctxt->nbErrors++;
676 return (NULL);
677 }
678 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
679
680 return (ret);
681}
682
683/**
684 * xmlRelaxNGFreeGrammar:
685 * @grammar: a grammar structure
686 *
687 * Deallocate a RelaxNG grammar structure.
688 */
689static void
690xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
691{
692 if (grammar == NULL)
693 return;
694
Daniel Veillardc482e262003-02-26 14:48:48 +0000695 if (grammar->children != NULL) {
696 xmlRelaxNGFreeGrammar(grammar->children);
697 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000698 if (grammar->next != NULL) {
699 xmlRelaxNGFreeGrammar(grammar->next);
700 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000701 if (grammar->refs != NULL) {
702 xmlHashFree(grammar->refs, NULL);
703 }
704 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000705 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000706 }
707
708 xmlFree(grammar);
709}
710
711/**
712 * xmlRelaxNGNewDefine:
713 * @ctxt: a Relax-NG validation context
714 * @node: the node in the input document.
715 *
716 * Allocate a new RelaxNG define.
717 *
718 * Returns the newly allocated structure or NULL in case or error
719 */
720static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000721xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000722{
723 xmlRelaxNGDefinePtr ret;
724
Daniel Veillard419a7682003-02-03 23:22:49 +0000725 if (ctxt->defMax == 0) {
726 ctxt->defMax = 16;
727 ctxt->defNr = 0;
728 ctxt->defTab = (xmlRelaxNGDefinePtr *)
729 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
730 if (ctxt->defTab == NULL) {
731 if ((ctxt != NULL) && (ctxt->error != NULL))
732 ctxt->error(ctxt->userData, "Out of memory\n");
733 ctxt->nbErrors++;
734 return (NULL);
735 }
736 } else if (ctxt->defMax <= ctxt->defNr) {
737 xmlRelaxNGDefinePtr *tmp;
738 ctxt->defMax *= 2;
739 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
740 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
741 if (tmp == NULL) {
742 if ((ctxt != NULL) && (ctxt->error != NULL))
743 ctxt->error(ctxt->userData, "Out of memory\n");
744 ctxt->nbErrors++;
745 return (NULL);
746 }
747 ctxt->defTab = tmp;
748 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000749 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
750 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000751 if ((ctxt != NULL) && (ctxt->error != NULL))
752 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000753 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000754 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000755 }
756 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000757 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000758 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000759 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000760 return (ret);
761}
762
763/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000764 * xmlRelaxNGFreePartition:
765 * @partitions: a partition set structure
766 *
767 * Deallocate RelaxNG partition set structures.
768 */
769static void
770xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
771 xmlRelaxNGInterleaveGroupPtr group;
772 int j;
773
774 if (partitions != NULL) {
775 if (partitions->groups != NULL) {
776 for (j = 0;j < partitions->nbgroups;j++) {
777 group = partitions->groups[j];
778 if (group != NULL) {
779 if (group->defs != NULL)
780 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000781 if (group->attrs != NULL)
782 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000783 xmlFree(group);
784 }
785 }
786 xmlFree(partitions->groups);
787 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000788 if (partitions->triage != NULL) {
789 xmlHashFree(partitions->triage, NULL);
790 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000791 xmlFree(partitions);
792 }
793}
794/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000795 * xmlRelaxNGFreeDefine:
796 * @define: a define structure
797 *
798 * Deallocate a RelaxNG define structure.
799 */
800static void
801xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
802{
803 if (define == NULL)
804 return;
805
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000806 if ((define->type == XML_RELAXNG_VALUE) &&
807 (define->attrs != NULL)) {
808 xmlRelaxNGTypeLibraryPtr lib;
809
810 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
811 if ((lib != NULL) && (lib->freef != NULL))
812 lib->freef(lib->data, (void *) define->attrs);
813 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000814 if ((define->data != NULL) &&
815 (define->type == XML_RELAXNG_INTERLEAVE))
816 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillarde063f482003-03-21 16:53:17 +0000817 if ((define->data != NULL) &&
818 (define->type == XML_RELAXNG_CHOICE))
819 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000820 if (define->name != NULL)
821 xmlFree(define->name);
822 if (define->ns != NULL)
823 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000824 if (define->value != NULL)
825 xmlFree(define->value);
Daniel Veillard52b48c72003-04-13 19:53:42 +0000826 if (define->contModel != NULL)
827 xmlRegFreeRegexp(define->contModel);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000828 xmlFree(define);
829}
830
831/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000832 * xmlRelaxNGNewStates:
833 * @ctxt: a Relax-NG validation context
834 * @size: the default size for the container
835 *
836 * Allocate a new RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000837 *
838 * Returns the newly allocated structure or NULL in case or error
839 */
840static xmlRelaxNGStatesPtr
841xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
842{
843 xmlRelaxNGStatesPtr ret;
844
Daniel Veillard798024a2003-03-19 10:36:09 +0000845 if ((ctxt != NULL) &&
846 (ctxt->freeState != NULL) &&
847 (ctxt->freeStatesNr > 0)) {
848 ctxt->freeStatesNr--;
849 ret = ctxt->freeStates[ctxt->freeStatesNr];
850 ret->nbState = 0;
851 return(ret);
852 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000853 if (size < 16) size = 16;
854
855 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
856 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
857 if (ret == NULL) {
858 if ((ctxt != NULL) && (ctxt->error != NULL))
859 ctxt->error(ctxt->userData, "Out of memory\n");
860 return (NULL);
861 }
862 ret->nbState = 0;
863 ret->maxState = size;
864 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
865 (size) * sizeof(xmlRelaxNGValidStatePtr));
866 if (ret->tabState == NULL) {
867 if ((ctxt != NULL) && (ctxt->error != NULL))
868 ctxt->error(ctxt->userData, "Out of memory\n");
869 xmlFree(ret->tabState);
870 return (NULL);
871 }
872 return(ret);
873}
874
875/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000876 * xmlRelaxNGAddStateUniq:
877 * @ctxt: a Relax-NG validation context
878 * @states: the states container
879 * @state: the validation state
880 *
881 * Add a RelaxNG validation state to the container without checking
882 * for unicity.
883 *
884 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
885 */
886static int
887xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
888 xmlRelaxNGStatesPtr states,
889 xmlRelaxNGValidStatePtr state)
890{
891 if (state == NULL) {
892 return(-1);
893 }
894 if (states->nbState >= states->maxState) {
895 xmlRelaxNGValidStatePtr *tmp;
896 int size;
897
898 size = states->maxState * 2;
899 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
900 (size) * sizeof(xmlRelaxNGValidStatePtr));
901 if (tmp == NULL) {
902 if ((ctxt != NULL) && (ctxt->error != NULL))
903 ctxt->error(ctxt->userData, "Out of memory\n");
904 return(-1);
905 }
906 states->tabState = tmp;
907 states->maxState = size;
908 }
909 states->tabState[states->nbState++] = state;
910 return(1);
911}
912
913/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000914 * xmlRelaxNGAddState:
915 * @ctxt: a Relax-NG validation context
916 * @states: the states container
917 * @state: the validation state
918 *
919 * Add a RelaxNG validation state to the container
920 *
921 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
922 */
923static int
924xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
925 xmlRelaxNGValidStatePtr state)
926{
927 int i;
928
929 if (state == NULL) {
930 return(-1);
931 }
932 if (states->nbState >= states->maxState) {
933 xmlRelaxNGValidStatePtr *tmp;
934 int size;
935
936 size = states->maxState * 2;
937 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
938 (size) * sizeof(xmlRelaxNGValidStatePtr));
939 if (tmp == NULL) {
940 if ((ctxt != NULL) && (ctxt->error != NULL))
941 ctxt->error(ctxt->userData, "Out of memory\n");
942 return(-1);
943 }
944 states->tabState = tmp;
945 states->maxState = size;
946 }
947 for (i = 0;i < states->nbState;i++) {
948 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000949 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000950 return(0);
951 }
952 }
953 states->tabState[states->nbState++] = state;
954 return(1);
955}
956
957/**
958 * xmlRelaxNGFreeStates:
959 * @ctxt: a Relax-NG validation context
960 * @states: teh container
961 *
962 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000963 */
964static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000965xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000966 xmlRelaxNGStatesPtr states)
967{
Daniel Veillard798024a2003-03-19 10:36:09 +0000968 if (states == NULL)
969 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000970 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
971 ctxt->freeStatesMax = 40;
972 ctxt->freeStatesNr = 0;
973 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
974 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
975 if (ctxt->freeStates == NULL) {
976 if ((ctxt != NULL) && (ctxt->error != NULL))
977 ctxt->error(ctxt->userData, "Out of memory\n");
978 }
979 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
980 xmlRelaxNGStatesPtr *tmp;
981
982 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
983 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
984 if (tmp == NULL) {
985 if ((ctxt != NULL) && (ctxt->error != NULL))
986 ctxt->error(ctxt->userData, "Out of memory\n");
987 xmlFree(states->tabState);
988 xmlFree(states);
989 return;
990 }
991 ctxt->freeStates = tmp;
992 ctxt->freeStatesMax *= 2;
993 }
994 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000995 xmlFree(states->tabState);
996 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +0000997 } else {
998 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000999 }
1000}
1001
1002/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001003 * xmlRelaxNGNewValidState:
1004 * @ctxt: a Relax-NG validation context
1005 * @node: the current node or NULL for the document
1006 *
1007 * Allocate a new RelaxNG validation state
1008 *
1009 * Returns the newly allocated structure or NULL in case or error
1010 */
1011static xmlRelaxNGValidStatePtr
1012xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
1013{
1014 xmlRelaxNGValidStatePtr ret;
1015 xmlAttrPtr attr;
1016 xmlAttrPtr attrs[MAX_ATTR];
1017 int nbAttrs = 0;
1018 xmlNodePtr root = NULL;
1019
1020 if (node == NULL) {
1021 root = xmlDocGetRootElement(ctxt->doc);
1022 if (root == NULL)
1023 return(NULL);
1024 } else {
1025 attr = node->properties;
1026 while (attr != NULL) {
1027 if (nbAttrs < MAX_ATTR)
1028 attrs[nbAttrs++] = attr;
1029 else
1030 nbAttrs++;
1031 attr = attr->next;
1032 }
1033 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001034 if ((ctxt->freeState != NULL) &&
1035 (ctxt->freeState->nbState > 0)) {
1036 ctxt->freeState->nbState--;
1037 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1038 } else {
1039 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1040 if (ret == NULL) {
1041 if ((ctxt != NULL) && (ctxt->error != NULL))
1042 ctxt->error(ctxt->userData, "Out of memory\n");
1043 return (NULL);
1044 }
1045 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001046 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001047 ret->value = NULL;
1048 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001049 if (node == NULL) {
1050 ret->node = (xmlNodePtr) ctxt->doc;
1051 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001052 } else {
1053 ret->node = node;
1054 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001055 }
1056 ret->nbAttrs = 0;
1057 if (nbAttrs > 0) {
1058 if (ret->attrs == NULL) {
1059 if (nbAttrs < 4) ret->maxAttrs = 4;
1060 else ret->maxAttrs = nbAttrs;
1061 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1062 sizeof(xmlAttrPtr));
1063 if (ret->attrs == NULL) {
1064 if ((ctxt != NULL) && (ctxt->error != NULL))
1065 ctxt->error(ctxt->userData, "Out of memory\n");
1066 return (ret);
1067 }
1068 } else if (ret->maxAttrs < nbAttrs) {
1069 xmlAttrPtr *tmp;
1070
1071 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1072 sizeof(xmlAttrPtr));
1073 if (tmp == NULL) {
1074 if ((ctxt != NULL) && (ctxt->error != NULL))
1075 ctxt->error(ctxt->userData, "Out of memory\n");
1076 return (ret);
1077 }
1078 ret->attrs = tmp;
1079 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001080 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001081 if (nbAttrs < MAX_ATTR) {
1082 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1083 } else {
1084 attr = node->properties;
1085 nbAttrs = 0;
1086 while (attr != NULL) {
1087 ret->attrs[nbAttrs++] = attr;
1088 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001089 }
1090 }
1091 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001092 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001093 return (ret);
1094}
1095
1096/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001097 * xmlRelaxNGCopyValidState:
1098 * @ctxt: a Relax-NG validation context
1099 * @state: a validation state
1100 *
1101 * Copy the validation state
1102 *
1103 * Returns the newly allocated structure or NULL in case or error
1104 */
1105static xmlRelaxNGValidStatePtr
1106xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1107 xmlRelaxNGValidStatePtr state)
1108{
1109 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001110 unsigned int maxAttrs;
1111 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001112
1113 if (state == NULL)
1114 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001115 if ((ctxt->freeState != NULL) &&
1116 (ctxt->freeState->nbState > 0)) {
1117 ctxt->freeState->nbState--;
1118 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1119 } else {
1120 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1121 if (ret == NULL) {
1122 if ((ctxt != NULL) && (ctxt->error != NULL))
1123 ctxt->error(ctxt->userData, "Out of memory\n");
1124 return (NULL);
1125 }
1126 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001127 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001128 attrs = ret->attrs;
1129 maxAttrs = ret->maxAttrs;
1130 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1131 ret->attrs = attrs;
1132 ret->maxAttrs = maxAttrs;
1133 if (state->nbAttrs > 0) {
1134 if (ret->attrs == NULL) {
1135 ret->maxAttrs = state->maxAttrs;
1136 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1137 sizeof(xmlAttrPtr));
1138 if (ret->attrs == NULL) {
1139 if ((ctxt != NULL) && (ctxt->error != NULL))
1140 ctxt->error(ctxt->userData, "Out of memory\n");
1141 ret->nbAttrs = 0;
1142 return (ret);
1143 }
1144 } else if (ret->maxAttrs < state->nbAttrs) {
1145 xmlAttrPtr *tmp;
1146
1147 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1148 sizeof(xmlAttrPtr));
1149 if (tmp == NULL) {
1150 if ((ctxt != NULL) && (ctxt->error != NULL))
1151 ctxt->error(ctxt->userData, "Out of memory\n");
1152 ret->nbAttrs = 0;
1153 return (ret);
1154 }
1155 ret->maxAttrs = state->maxAttrs;
1156 }
1157 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1158 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001159 return(ret);
1160}
1161
1162/**
1163 * xmlRelaxNGEqualValidState:
1164 * @ctxt: a Relax-NG validation context
1165 * @state1: a validation state
1166 * @state2: a validation state
1167 *
1168 * Compare the validation states for equality
1169 *
1170 * Returns 1 if equald, 0 otherwise
1171 */
1172static int
1173xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1174 xmlRelaxNGValidStatePtr state1,
1175 xmlRelaxNGValidStatePtr state2)
1176{
1177 int i;
1178
1179 if ((state1 == NULL) || (state2 == NULL))
1180 return(0);
1181 if (state1 == state2)
1182 return(1);
1183 if (state1->node != state2->node)
1184 return(0);
1185 if (state1->seq != state2->seq)
1186 return(0);
1187 if (state1->nbAttrLeft != state2->nbAttrLeft)
1188 return(0);
1189 if (state1->nbAttrs != state2->nbAttrs)
1190 return(0);
1191 if (state1->endvalue != state2->endvalue)
1192 return(0);
1193 if ((state1->value != state2->value) &&
1194 (!xmlStrEqual(state1->value, state2->value)))
1195 return(0);
1196 for (i = 0;i < state1->nbAttrs;i++) {
1197 if (state1->attrs[i] != state2->attrs[i])
1198 return(0);
1199 }
1200 return(1);
1201}
1202
1203/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001204 * xmlRelaxNGFreeValidState:
1205 * @state: a validation state structure
1206 *
1207 * Deallocate a RelaxNG validation state structure.
1208 */
1209static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001210xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1211 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001212{
1213 if (state == NULL)
1214 return;
1215
Daniel Veillard798024a2003-03-19 10:36:09 +00001216 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1217 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1218 }
1219 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1220 if (state->attrs != NULL)
1221 xmlFree(state->attrs);
1222 xmlFree(state);
1223 } else {
1224 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1225 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001226}
1227
1228/************************************************************************
1229 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001230 * Document functions *
1231 * *
1232 ************************************************************************/
1233static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1234 xmlDocPtr doc);
1235
1236/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001237 * xmlRelaxNGIncludePush:
1238 * @ctxt: the parser context
1239 * @value: the element doc
1240 *
1241 * Pushes a new include on top of the include stack
1242 *
1243 * Returns 0 in case of error, the index in the stack otherwise
1244 */
1245static int
1246xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1247 xmlRelaxNGIncludePtr value)
1248{
1249 if (ctxt->incTab == NULL) {
1250 ctxt->incMax = 4;
1251 ctxt->incNr = 0;
1252 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1253 ctxt->incMax * sizeof(ctxt->incTab[0]));
1254 if (ctxt->incTab == NULL) {
1255 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1256 return (0);
1257 }
1258 }
1259 if (ctxt->incNr >= ctxt->incMax) {
1260 ctxt->incMax *= 2;
1261 ctxt->incTab =
1262 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1263 ctxt->incMax *
1264 sizeof(ctxt->incTab[0]));
1265 if (ctxt->incTab == NULL) {
1266 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1267 return (0);
1268 }
1269 }
1270 ctxt->incTab[ctxt->incNr] = value;
1271 ctxt->inc = value;
1272 return (ctxt->incNr++);
1273}
1274
1275/**
1276 * xmlRelaxNGIncludePop:
1277 * @ctxt: the parser context
1278 *
1279 * Pops the top include from the include stack
1280 *
1281 * Returns the include just removed
1282 */
1283static xmlRelaxNGIncludePtr
1284xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1285{
1286 xmlRelaxNGIncludePtr ret;
1287
1288 if (ctxt->incNr <= 0)
1289 return (0);
1290 ctxt->incNr--;
1291 if (ctxt->incNr > 0)
1292 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1293 else
1294 ctxt->inc = NULL;
1295 ret = ctxt->incTab[ctxt->incNr];
1296 ctxt->incTab[ctxt->incNr] = 0;
1297 return (ret);
1298}
1299
1300/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001301 * xmlRelaxNGRemoveRedefine:
1302 * @ctxt: the parser context
1303 * @URL: the normalized URL
1304 * @target: the included target
1305 * @name: the define name to eliminate
1306 *
1307 * Applies the elimination algorithm of 4.7
1308 *
1309 * Returns 0 in case of error, 1 in case of success.
1310 */
1311static int
1312xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1313 const xmlChar *URL ATTRIBUTE_UNUSED,
1314 xmlNodePtr target, const xmlChar *name) {
1315 int found = 0;
1316 xmlNodePtr tmp, tmp2;
1317 xmlChar *name2;
1318
1319#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001320 if (name == NULL)
1321 xmlGenericError(xmlGenericErrorContext,
1322 "Elimination of <include> start from %s\n", URL);
1323 else
1324 xmlGenericError(xmlGenericErrorContext,
1325 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001326#endif
1327 tmp = target;
1328 while (tmp != NULL) {
1329 tmp2 = tmp->next;
1330 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1331 found = 1;
1332 xmlUnlinkNode(tmp);
1333 xmlFreeNode(tmp);
1334 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1335 name2 = xmlGetProp(tmp, BAD_CAST "name");
1336 xmlRelaxNGNormExtSpace(name2);
1337 if (name2 != NULL) {
1338 if (xmlStrEqual(name, name2)) {
1339 found = 1;
1340 xmlUnlinkNode(tmp);
1341 xmlFreeNode(tmp);
1342 }
1343 xmlFree(name2);
1344 }
1345 } else if (IS_RELAXNG(tmp, "include")) {
1346 xmlChar *href = NULL;
1347 xmlRelaxNGDocumentPtr inc = tmp->_private;
1348
1349 if ((inc != NULL) && (inc->doc != NULL) &&
1350 (inc->doc->children != NULL)) {
1351
1352 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1353#ifdef DEBUG_INCLUDE
1354 href = xmlGetProp(tmp, BAD_CAST "href");
1355#endif
1356 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1357 inc->doc->children->children, name) == 1) {
1358 found = 1;
1359 }
1360 if (href != NULL)
1361 xmlFree(href);
1362 }
1363 }
1364 }
1365 tmp = tmp2;
1366 }
1367 return(found);
1368}
1369
1370/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001371 * xmlRelaxNGLoadInclude:
1372 * @ctxt: the parser context
1373 * @URL: the normalized URL
1374 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001375 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001376 *
1377 * First lookup if the document is already loaded into the parser context,
1378 * check against recursion. If not found the resource is loaded and
1379 * the content is preprocessed before being returned back to the caller.
1380 *
1381 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1382 */
1383static xmlRelaxNGIncludePtr
1384xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001385 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001386 xmlRelaxNGIncludePtr ret = NULL;
1387 xmlDocPtr doc;
1388 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001389 xmlNodePtr root, cur;
1390
1391#ifdef DEBUG_INCLUDE
1392 xmlGenericError(xmlGenericErrorContext,
1393 "xmlRelaxNGLoadInclude(%s)\n", URL);
1394#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001395
1396 /*
1397 * check against recursion in the stack
1398 */
1399 for (i = 0;i < ctxt->incNr;i++) {
1400 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1401 if (ctxt->error != NULL)
1402 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001403 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001404 URL);
1405 ctxt->nbErrors++;
1406 return(NULL);
1407 }
1408 }
1409
1410 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001411 * load the document
1412 */
1413 doc = xmlParseFile((const char *) URL);
1414 if (doc == NULL) {
1415 if (ctxt->error != NULL)
1416 ctxt->error(ctxt->userData,
1417 "xmlRelaxNG: could not load %s\n", URL);
1418 ctxt->nbErrors++;
1419 return (NULL);
1420 }
1421
Daniel Veillard5add8682003-03-10 13:13:58 +00001422#ifdef DEBUG_INCLUDE
1423 xmlGenericError(xmlGenericErrorContext,
1424 "Parsed %s Okay\n", URL);
1425#endif
1426
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001427 /*
1428 * Allocate the document structures and register it first.
1429 */
1430 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1431 if (ret == NULL) {
1432 if (ctxt->error != NULL)
1433 ctxt->error(ctxt->userData,
1434 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1435 ctxt->nbErrors++;
1436 xmlFreeDoc(doc);
1437 return (NULL);
1438 }
1439 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1440 ret->doc = doc;
1441 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001442 ret->next = ctxt->includes;
1443 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001444
1445 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001446 * transmit the ns if needed
1447 */
1448 if (ns != NULL) {
1449 root = xmlDocGetRootElement(doc);
1450 if (root != NULL) {
1451 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1452 xmlSetProp(root, BAD_CAST"ns", ns);
1453 }
1454 }
1455 }
1456
1457 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001458 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001459 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001460 xmlRelaxNGIncludePush(ctxt, ret);
1461
1462 /*
1463 * Some preprocessing of the document content, this include recursing
1464 * in the include stack.
1465 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001466#ifdef DEBUG_INCLUDE
1467 xmlGenericError(xmlGenericErrorContext,
1468 "cleanup of %s\n", URL);
1469#endif
1470
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001471 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1472 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001473 ctxt->inc = NULL;
1474 return(NULL);
1475 }
1476
1477 /*
1478 * Pop up the include from the stack
1479 */
1480 xmlRelaxNGIncludePop(ctxt);
1481
Daniel Veillard5add8682003-03-10 13:13:58 +00001482#ifdef DEBUG_INCLUDE
1483 xmlGenericError(xmlGenericErrorContext,
1484 "Checking of %s\n", URL);
1485#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001486 /*
1487 * Check that the top element is a grammar
1488 */
1489 root = xmlDocGetRootElement(doc);
1490 if (root == NULL) {
1491 if (ctxt->error != NULL)
1492 ctxt->error(ctxt->userData,
1493 "xmlRelaxNG: included document is empty %s\n", URL);
1494 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001495 return (NULL);
1496 }
1497 if (!IS_RELAXNG(root, "grammar")) {
1498 if (ctxt->error != NULL)
1499 ctxt->error(ctxt->userData,
1500 "xmlRelaxNG: included document %s root is not a grammar\n",
1501 URL);
1502 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001503 return (NULL);
1504 }
1505
1506 /*
1507 * Elimination of redefined rules in the include.
1508 */
1509 cur = node->children;
1510 while (cur != NULL) {
1511 if (IS_RELAXNG(cur, "start")) {
1512 int found = 0;
1513
Daniel Veillard5add8682003-03-10 13:13:58 +00001514 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001515 if (!found) {
1516 if (ctxt->error != NULL)
1517 ctxt->error(ctxt->userData,
1518 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1519 URL);
1520 ctxt->nbErrors++;
1521 }
1522 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001523 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001524
1525 name = xmlGetProp(cur, BAD_CAST "name");
1526 if (name == NULL) {
1527 if (ctxt->error != NULL)
1528 ctxt->error(ctxt->userData,
1529 "xmlRelaxNG: include %s has define without name\n",
1530 URL);
1531 ctxt->nbErrors++;
1532 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001533 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001534
Daniel Veillardd2298792003-02-14 16:54:11 +00001535 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001536 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1537 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001538 if (!found) {
1539 if (ctxt->error != NULL)
1540 ctxt->error(ctxt->userData,
1541 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1542 URL, name);
1543 ctxt->nbErrors++;
1544 }
1545 xmlFree(name);
1546 }
1547 }
1548 cur = cur->next;
1549 }
1550
1551
1552 return(ret);
1553}
1554
1555/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001556 * xmlRelaxNGValidErrorPush:
1557 * @ctxt: the validation context
1558 * @err: the error code
1559 * @arg1: the first string argument
1560 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001561 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001562 *
1563 * Pushes a new error on top of the error stack
1564 *
1565 * Returns 0 in case of error, the index in the stack otherwise
1566 */
1567static int
1568xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001569 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001570{
1571 xmlRelaxNGValidErrorPtr cur;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001572#ifdef DEBUG_ERROR
1573 xmlGenericError(xmlGenericErrorContext,
1574 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1575#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001576 if (ctxt->errTab == NULL) {
1577 ctxt->errMax = 8;
1578 ctxt->errNr = 0;
1579 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1580 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1581 if (ctxt->errTab == NULL) {
1582 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1583 return (0);
1584 }
Daniel Veillard20863822003-03-22 17:51:47 +00001585 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001586 }
1587 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard20863822003-03-22 17:51:47 +00001588 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001589 ctxt->errTab =
1590 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard20863822003-03-22 17:51:47 +00001591 ctxt->errMax * sizeof(xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001592 if (ctxt->errTab == NULL) {
1593 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1594 return (0);
1595 }
Daniel Veillard20863822003-03-22 17:51:47 +00001596 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001597 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001598 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001599 (ctxt->err->node == ctxt->state->node) &&
1600 (ctxt->err->err == err))
1601 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001602 cur = &ctxt->errTab[ctxt->errNr];
1603 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001604 if (dup) {
1605 cur->arg1 = xmlStrdup(arg1);
1606 cur->arg2 = xmlStrdup(arg2);
1607 cur->flags = ERROR_IS_DUP;
1608 } else {
1609 cur->arg1 = arg1;
1610 cur->arg2 = arg2;
1611 cur->flags = 0;
1612 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001613 if (ctxt->state != NULL) {
1614 cur->node = ctxt->state->node;
1615 cur->seq = ctxt->state->seq;
1616 } else {
1617 cur->node = NULL;
1618 cur->seq = NULL;
1619 }
1620 ctxt->err = cur;
1621 return (ctxt->errNr++);
1622}
1623
1624/**
1625 * xmlRelaxNGValidErrorPop:
1626 * @ctxt: the validation context
1627 *
1628 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001629 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001630static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001631xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1632{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001633 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001634
Daniel Veillard580ced82003-03-21 21:22:48 +00001635 if (ctxt->errNr <= 0) {
1636 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001637 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001638 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001639 ctxt->errNr--;
1640 if (ctxt->errNr > 0)
1641 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1642 else
1643 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001644 cur = &ctxt->errTab[ctxt->errNr];
1645 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001646 if (cur->arg1 != NULL)
1647 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001648 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001649 if (cur->arg2 != NULL)
1650 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001651 cur->arg2 = NULL;
1652 cur->flags = 0;
1653 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001654}
1655
Daniel Veillard42f12e92003-03-07 18:32:59 +00001656/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001657 * xmlRelaxNGDocumentPush:
1658 * @ctxt: the parser context
1659 * @value: the element doc
1660 *
1661 * Pushes a new doc on top of the doc stack
1662 *
1663 * Returns 0 in case of error, the index in the stack otherwise
1664 */
1665static int
1666xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1667 xmlRelaxNGDocumentPtr value)
1668{
1669 if (ctxt->docTab == NULL) {
1670 ctxt->docMax = 4;
1671 ctxt->docNr = 0;
1672 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1673 ctxt->docMax * sizeof(ctxt->docTab[0]));
1674 if (ctxt->docTab == NULL) {
1675 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1676 return (0);
1677 }
1678 }
1679 if (ctxt->docNr >= ctxt->docMax) {
1680 ctxt->docMax *= 2;
1681 ctxt->docTab =
1682 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1683 ctxt->docMax *
1684 sizeof(ctxt->docTab[0]));
1685 if (ctxt->docTab == NULL) {
1686 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1687 return (0);
1688 }
1689 }
1690 ctxt->docTab[ctxt->docNr] = value;
1691 ctxt->doc = value;
1692 return (ctxt->docNr++);
1693}
1694
1695/**
1696 * xmlRelaxNGDocumentPop:
1697 * @ctxt: the parser context
1698 *
1699 * Pops the top doc from the doc stack
1700 *
1701 * Returns the doc just removed
1702 */
1703static xmlRelaxNGDocumentPtr
1704xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1705{
1706 xmlRelaxNGDocumentPtr ret;
1707
1708 if (ctxt->docNr <= 0)
1709 return (0);
1710 ctxt->docNr--;
1711 if (ctxt->docNr > 0)
1712 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1713 else
1714 ctxt->doc = NULL;
1715 ret = ctxt->docTab[ctxt->docNr];
1716 ctxt->docTab[ctxt->docNr] = 0;
1717 return (ret);
1718}
1719
1720/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001721 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001722 * @ctxt: the parser context
1723 * @URL: the normalized URL
1724 * @ns: the inherited ns if any
1725 *
1726 * First lookup if the document is already loaded into the parser context,
1727 * check against recursion. If not found the resource is loaded and
1728 * the content is preprocessed before being returned back to the caller.
1729 *
1730 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1731 */
1732static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001733xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001734 const xmlChar *ns) {
1735 xmlRelaxNGDocumentPtr ret = NULL;
1736 xmlDocPtr doc;
1737 xmlNodePtr root;
1738 int i;
1739
1740 /*
1741 * check against recursion in the stack
1742 */
1743 for (i = 0;i < ctxt->docNr;i++) {
1744 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1745 if (ctxt->error != NULL)
1746 ctxt->error(ctxt->userData,
1747 "Detected an externalRef recursion for %s\n",
1748 URL);
1749 ctxt->nbErrors++;
1750 return(NULL);
1751 }
1752 }
1753
1754 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001755 * load the document
1756 */
1757 doc = xmlParseFile((const char *) URL);
1758 if (doc == NULL) {
1759 if (ctxt->error != NULL)
1760 ctxt->error(ctxt->userData,
1761 "xmlRelaxNG: could not load %s\n", URL);
1762 ctxt->nbErrors++;
1763 return (NULL);
1764 }
1765
1766 /*
1767 * Allocate the document structures and register it first.
1768 */
1769 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1770 if (ret == NULL) {
1771 if (ctxt->error != NULL)
1772 ctxt->error(ctxt->userData,
1773 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1774 ctxt->nbErrors++;
1775 xmlFreeDoc(doc);
1776 return (NULL);
1777 }
1778 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1779 ret->doc = doc;
1780 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001781 ret->next = ctxt->documents;
1782 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001783
1784 /*
1785 * transmit the ns if needed
1786 */
1787 if (ns != NULL) {
1788 root = xmlDocGetRootElement(doc);
1789 if (root != NULL) {
1790 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1791 xmlSetProp(root, BAD_CAST"ns", ns);
1792 }
1793 }
1794 }
1795
1796 /*
1797 * push it on the stack and register it in the hash table
1798 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001799 xmlRelaxNGDocumentPush(ctxt, ret);
1800
1801 /*
1802 * Some preprocessing of the document content
1803 */
1804 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1805 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001806 ctxt->doc = NULL;
1807 return(NULL);
1808 }
1809
1810 xmlRelaxNGDocumentPop(ctxt);
1811
1812 return(ret);
1813}
1814
1815/************************************************************************
1816 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001817 * Error functions *
1818 * *
1819 ************************************************************************/
1820
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001821#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1822#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1823#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1824#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1825#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001826
Daniel Veillard231d7912003-02-09 14:22:17 +00001827static const char *
1828xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1829 if (def == NULL)
1830 return("none");
1831 switch(def->type) {
1832 case XML_RELAXNG_EMPTY: return("empty");
1833 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1834 case XML_RELAXNG_EXCEPT: return("except");
1835 case XML_RELAXNG_TEXT: return("text");
1836 case XML_RELAXNG_ELEMENT: return("element");
1837 case XML_RELAXNG_DATATYPE: return("datatype");
1838 case XML_RELAXNG_VALUE: return("value");
1839 case XML_RELAXNG_LIST: return("list");
1840 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1841 case XML_RELAXNG_DEF: return("def");
1842 case XML_RELAXNG_REF: return("ref");
1843 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1844 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001845 case XML_RELAXNG_OPTIONAL: return("optional");
1846 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001847 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1848 case XML_RELAXNG_CHOICE: return("choice");
1849 case XML_RELAXNG_GROUP: return("group");
1850 case XML_RELAXNG_INTERLEAVE: return("interleave");
1851 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001852 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001853 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001854 }
1855 return("unknown");
1856}
Daniel Veillardd2298792003-02-14 16:54:11 +00001857
Daniel Veillard6eadf632003-01-23 18:29:16 +00001858/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001859 * xmlRelaxNGGetErrorString:
1860 * @err: the error code
1861 * @arg1: the first string argument
1862 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001863 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001864 * computes a formatted error string for the given error code and args
1865 *
1866 * Returns the error string, it must be deallocated by the caller
1867 */
1868static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001869xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1870 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001871 char msg[1000];
1872
1873 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001874 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001875 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001876 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001877
1878 msg[0] = 0;
1879 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001880 case XML_RELAXNG_OK:
1881 return(NULL);
1882 case XML_RELAXNG_ERR_MEMORY:
1883 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001884 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001885 snprintf(msg, 1000, "failed to validate type %s", arg1);
1886 break;
1887 case XML_RELAXNG_ERR_TYPEVAL:
Daniel Veillardc4c21552003-03-29 10:53:38 +00001888 snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001889 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001890 case XML_RELAXNG_ERR_DUPID:
1891 snprintf(msg, 1000, "ID %s redefined", arg1);
1892 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001893 case XML_RELAXNG_ERR_TYPECMP:
1894 snprintf(msg, 1000, "failed to compare type %s", arg1);
1895 break;
1896 case XML_RELAXNG_ERR_NOSTATE:
1897 return(xmlCharStrdup("Internal error: no state"));
1898 case XML_RELAXNG_ERR_NODEFINE:
1899 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001900 case XML_RELAXNG_ERR_INTERNAL:
1901 snprintf(msg, 1000, "Internal error: %s", arg1);
1902 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001903 case XML_RELAXNG_ERR_LISTEXTRA:
1904 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1905 break;
1906 case XML_RELAXNG_ERR_INTERNODATA:
1907 return(xmlCharStrdup("Internal: interleave block has no data"));
1908 case XML_RELAXNG_ERR_INTERSEQ:
1909 return(xmlCharStrdup("Invalid sequence in interleave"));
1910 case XML_RELAXNG_ERR_INTEREXTRA:
1911 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1912 break;
1913 case XML_RELAXNG_ERR_ELEMNAME:
1914 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1915 break;
1916 case XML_RELAXNG_ERR_ELEMNONS:
1917 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1918 break;
1919 case XML_RELAXNG_ERR_ELEMWRONGNS:
1920 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1921 arg1, arg2);
1922 break;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00001923 case XML_RELAXNG_ERR_ELEMWRONG:
1924 snprintf(msg, 1000, "Did not expect element %s there",
1925 arg1);
1926 break;
1927 case XML_RELAXNG_ERR_TEXTWRONG:
1928 snprintf(msg, 1000, "Did not expect text in element %s content",
1929 arg1);
1930 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001931 case XML_RELAXNG_ERR_ELEMEXTRANS:
1932 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1933 break;
1934 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1935 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1936 break;
1937 case XML_RELAXNG_ERR_NOELEM:
1938 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1939 break;
1940 case XML_RELAXNG_ERR_NOTELEM:
1941 return(xmlCharStrdup("Expecting an element got text"));
1942 case XML_RELAXNG_ERR_ATTRVALID:
1943 snprintf(msg, 1000, "Element %s failed to validate attributes",
1944 arg1);
1945 break;
1946 case XML_RELAXNG_ERR_CONTENTVALID:
1947 snprintf(msg, 1000, "Element %s failed to validate content",
1948 arg1);
1949 break;
1950 case XML_RELAXNG_ERR_EXTRACONTENT:
1951 snprintf(msg, 1000, "Element %s has extra content: %s",
1952 arg1, arg2);
1953 break;
1954 case XML_RELAXNG_ERR_INVALIDATTR:
1955 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1956 arg1, arg2);
1957 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +00001958 case XML_RELAXNG_ERR_LACKDATA:
1959 snprintf(msg, 1000, "Datatype element %s contains no data",
1960 arg1);
1961 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001962 case XML_RELAXNG_ERR_DATAELEM:
1963 snprintf(msg, 1000, "Datatype element %s has child elements",
1964 arg1);
1965 break;
1966 case XML_RELAXNG_ERR_VALELEM:
1967 snprintf(msg, 1000, "Value element %s has child elements",
1968 arg1);
1969 break;
1970 case XML_RELAXNG_ERR_LISTELEM:
1971 snprintf(msg, 1000, "List element %s has child elements",
1972 arg1);
1973 break;
1974 case XML_RELAXNG_ERR_DATATYPE:
1975 snprintf(msg, 1000, "Error validating datatype %s",
1976 arg1);
1977 break;
1978 case XML_RELAXNG_ERR_VALUE:
1979 snprintf(msg, 1000, "Error validating value %s",
1980 arg1);
1981 break;
1982 case XML_RELAXNG_ERR_LIST:
1983 return(xmlCharStrdup("Error validating list"));
1984 case XML_RELAXNG_ERR_NOGRAMMAR:
1985 return(xmlCharStrdup("No top grammar defined"));
1986 case XML_RELAXNG_ERR_EXTRADATA:
1987 return(xmlCharStrdup("Extra data in the document"));
1988 default:
Daniel Veillardac297932003-04-17 12:55:35 +00001989 return(xmlCharStrdup("Unknown error !"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001990 }
1991 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001992 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001993 }
Daniel Veillardadbb0e62003-05-10 20:02:45 +00001994 msg[1000 - 1] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001995 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001996}
1997
1998/**
1999 * xmlRelaxNGValidErrorContext:
2000 * @ctxt: the validation context
2001 * @node: the node
2002 * @child: the node child generating the problem.
2003 *
2004 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00002005 */
2006static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00002007xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
2008 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00002009{
2010 int line = 0;
2011 const xmlChar *file = NULL;
2012 const xmlChar *name = NULL;
2013 const char *type = "error";
2014
2015 if ((ctxt == NULL) || (ctxt->error == NULL))
2016 return;
2017
2018 if (child != NULL)
2019 node = child;
2020
2021 if (node != NULL) {
2022 if ((node->type == XML_DOCUMENT_NODE) ||
2023 (node->type == XML_HTML_DOCUMENT_NODE)) {
2024 xmlDocPtr doc = (xmlDocPtr) node;
2025
2026 file = doc->URL;
2027 } else {
2028 /*
2029 * Try to find contextual informations to report
2030 */
2031 if (node->type == XML_ELEMENT_NODE) {
2032 line = (int) node->content;
2033 } else if ((node->prev != NULL) &&
2034 (node->prev->type == XML_ELEMENT_NODE)) {
2035 line = (int) node->prev->content;
2036 } else if ((node->parent != NULL) &&
2037 (node->parent->type == XML_ELEMENT_NODE)) {
2038 line = (int) node->parent->content;
2039 }
2040 if ((node->doc != NULL) && (node->doc->URL != NULL))
2041 file = node->doc->URL;
2042 if (node->name != NULL)
2043 name = node->name;
2044 }
2045 }
2046
Daniel Veillard42f12e92003-03-07 18:32:59 +00002047 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002048
2049 if ((file != NULL) && (line != 0) && (name != NULL))
2050 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2051 type, file, line, name);
2052 else if ((file != NULL) && (name != NULL))
2053 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2054 type, file, name);
2055 else if ((file != NULL) && (line != 0))
2056 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2057 else if (file != NULL)
2058 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2059 else if (name != NULL)
2060 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2061 else
2062 ctxt->error(ctxt->userData, "%s\n", type);
2063}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002064
2065/**
2066 * xmlRelaxNGShowValidError:
2067 * @ctxt: the validation context
2068 * @err: the error number
2069 * @node: the node
2070 * @child: the node child generating the problem.
2071 * @arg1: the first argument
2072 * @arg2: the second argument
2073 *
2074 * Show a validation error.
2075 */
2076static void
2077xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2078 xmlNodePtr node, xmlNodePtr child,
2079 const xmlChar *arg1, const xmlChar *arg2)
2080{
2081 xmlChar *msg;
2082
2083 if (ctxt->error == NULL)
2084 return;
2085
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002086#ifdef DEBUG_ERROR
2087 xmlGenericError(xmlGenericErrorContext,
2088 "Show error %d\n", err);
2089#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002090 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2091 if (msg == NULL)
2092 return;
2093
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002094 if (ctxt->errNo == XML_RELAXNG_OK)
2095 ctxt->errNo = err;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002096 xmlRelaxNGValidErrorContext(ctxt, node, child);
2097 ctxt->error(ctxt->userData, "%s\n", msg);
2098 xmlFree(msg);
2099}
2100
2101/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002102 * xmlRelaxNGPopErrors:
2103 * @ctxt: the validation context
2104 * @level: the error level in the stack
2105 *
2106 * pop and discard all errors until the given level is reached
2107 */
2108static void
2109xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2110 int i;
2111 xmlRelaxNGValidErrorPtr err;
2112
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002113#ifdef DEBUG_ERROR
2114 xmlGenericError(xmlGenericErrorContext,
2115 "Pop errors till level %d\n", level);
2116#endif
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002117 for (i = level;i < ctxt->errNr;i++) {
2118 err = &ctxt->errTab[i];
2119 if (err->flags & ERROR_IS_DUP) {
2120 if (err->arg1 != NULL)
2121 xmlFree((xmlChar *)err->arg1);
2122 err->arg1 = NULL;
2123 if (err->arg2 != NULL)
2124 xmlFree((xmlChar *)err->arg2);
2125 err->arg2 = NULL;
2126 err->flags = 0;
2127 }
2128 }
2129 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002130 if (ctxt->errNr <= 0)
2131 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002132}
2133/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002134 * xmlRelaxNGDumpValidError:
2135 * @ctxt: the validation context
2136 *
2137 * Show all validation error over a given index.
2138 */
2139static void
2140xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002141 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002142 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002143
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002144#ifdef DEBUG_ERROR
2145 xmlGenericError(xmlGenericErrorContext,
2146 "Dumping error stack %d errors\n", ctxt->errNr);
2147#endif
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002148 for (i = 0, k = 0;i < ctxt->errNr;i++) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00002149 err = &ctxt->errTab[i];
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002150 if (k < MAX_ERROR) {
2151 for (j = 0;j < i;j++) {
2152 dup = &ctxt->errTab[j];
2153 if ((err->err == dup->err) && (err->node == dup->node) &&
2154 (xmlStrEqual(err->arg1, dup->arg1)) &&
2155 (xmlStrEqual(err->arg2, dup->arg2))) {
2156 goto skip;
2157 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002158 }
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002159 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2160 err->arg1, err->arg2);
2161 k++;
Daniel Veillard580ced82003-03-21 21:22:48 +00002162 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002163skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002164 if (err->flags & ERROR_IS_DUP) {
2165 if (err->arg1 != NULL)
2166 xmlFree((xmlChar *)err->arg1);
2167 err->arg1 = NULL;
2168 if (err->arg2 != NULL)
2169 xmlFree((xmlChar *)err->arg2);
2170 err->arg2 = NULL;
2171 err->flags = 0;
2172 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002173 }
2174 ctxt->errNr = 0;
2175}
2176/**
2177 * xmlRelaxNGAddValidError:
2178 * @ctxt: the validation context
2179 * @err: the error number
2180 * @arg1: the first argument
2181 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002182 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002183 *
2184 * Register a validation error, either generating it if it's sure
2185 * or stacking it for later handling if unsure.
2186 */
2187static void
2188xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002189 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002190{
2191 if ((ctxt == NULL) || (ctxt->error == NULL))
2192 return;
2193
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002194#ifdef DEBUG_ERROR
2195 xmlGenericError(xmlGenericErrorContext,
2196 "Adding error %d\n", err);
2197#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002198 /*
2199 * generate the error directly
2200 */
2201 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2202 xmlNodePtr node, seq;
2203 /*
2204 * Flush first any stacked error which might be the
2205 * real cause of the problem.
2206 */
2207 if (ctxt->errNr != 0)
2208 xmlRelaxNGDumpValidError(ctxt);
2209 if (ctxt->state != NULL) {
2210 node = ctxt->state->node;
2211 seq = ctxt->state->seq;
2212 } else {
2213 node = seq = NULL;
2214 }
2215 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2216 }
2217 /*
2218 * Stack the error for later processing if needed
2219 */
2220 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002221 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002222 }
2223}
2224
Daniel Veillard6eadf632003-01-23 18:29:16 +00002225
2226/************************************************************************
2227 * *
2228 * Type library hooks *
2229 * *
2230 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002231static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2232 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002233
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002234/**
2235 * xmlRelaxNGSchemaTypeHave:
2236 * @data: data needed for the library
2237 * @type: the type name
2238 *
2239 * Check if the given type is provided by
2240 * the W3C XMLSchema Datatype library.
2241 *
2242 * Returns 1 if yes, 0 if no and -1 in case of error.
2243 */
2244static int
2245xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002246 const xmlChar *type) {
2247 xmlSchemaTypePtr typ;
2248
2249 if (type == NULL)
2250 return(-1);
2251 typ = xmlSchemaGetPredefinedType(type,
2252 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2253 if (typ == NULL)
2254 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002255 return(1);
2256}
2257
2258/**
2259 * xmlRelaxNGSchemaTypeCheck:
2260 * @data: data needed for the library
2261 * @type: the type name
2262 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002263 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002264 *
2265 * Check if the given type and value are validated by
2266 * the W3C XMLSchema Datatype library.
2267 *
2268 * Returns 1 if yes, 0 if no and -1 in case of error.
2269 */
2270static int
2271xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002272 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002273 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002274 void **result,
2275 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002276 xmlSchemaTypePtr typ;
2277 int ret;
2278
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002279 if ((type == NULL) || (value == NULL))
2280 return(-1);
2281 typ = xmlSchemaGetPredefinedType(type,
2282 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2283 if (typ == NULL)
2284 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002285 ret = xmlSchemaValPredefTypeNode(typ, value,
2286 (xmlSchemaValPtr *) result, node);
2287 if (ret == 2) /* special ID error code */
2288 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002289 if (ret == 0)
2290 return(1);
2291 if (ret > 0)
2292 return(0);
2293 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002294}
2295
2296/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002297 * xmlRelaxNGSchemaFacetCheck:
2298 * @data: data needed for the library
2299 * @type: the type name
2300 * @facet: the facet name
2301 * @val: the facet value
2302 * @strval: the string value
2303 * @value: the value to check
2304 *
2305 * Function provided by a type library to check a value facet
2306 *
2307 * Returns 1 if yes, 0 if no and -1 in case of error.
2308 */
2309static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002310xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002311 const xmlChar *facetname, const xmlChar *val,
2312 const xmlChar *strval, void *value) {
2313 xmlSchemaFacetPtr facet;
2314 xmlSchemaTypePtr typ;
2315 int ret;
2316
2317 if ((type == NULL) || (strval == NULL))
2318 return(-1);
2319 typ = xmlSchemaGetPredefinedType(type,
2320 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2321 if (typ == NULL)
2322 return(-1);
2323
2324 facet = xmlSchemaNewFacet();
2325 if (facet == NULL)
2326 return(-1);
2327
2328 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2329 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2330 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2331 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2332 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2333 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2334 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2335 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2336 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2337 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2338 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2339 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2340 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2341 facet->type = XML_SCHEMA_FACET_PATTERN;
2342 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2343 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2344 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2345 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2346 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2347 facet->type = XML_SCHEMA_FACET_LENGTH;
2348 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2349 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2350 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2351 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2352 } else {
2353 xmlSchemaFreeFacet(facet);
2354 return(-1);
2355 }
2356 facet->value = xmlStrdup(val);
2357 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2358 if (ret != 0) {
2359 xmlSchemaFreeFacet(facet);
2360 return(-1);
2361 }
2362 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2363 xmlSchemaFreeFacet(facet);
2364 if (ret != 0)
2365 return(-1);
2366 return(0);
2367}
2368
2369/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002370 * xmlRelaxNGSchemaFreeValue:
2371 * @data: data needed for the library
2372 * @value: the value to free
2373 *
2374 * Function provided by a type library to free a Schemas value
2375 *
2376 * Returns 1 if yes, 0 if no and -1 in case of error.
2377 */
2378static void
2379xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2380 xmlSchemaFreeValue(value);
2381}
2382
2383/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002384 * xmlRelaxNGSchemaTypeCompare:
2385 * @data: data needed for the library
2386 * @type: the type name
2387 * @value1: the first value
2388 * @value2: the second value
2389 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002390 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002391 * Datatype library.
2392 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002393 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002394 */
2395static int
2396xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002397 const xmlChar *type,
2398 const xmlChar *value1,
2399 xmlNodePtr ctxt1,
2400 void *comp1,
2401 const xmlChar *value2,
2402 xmlNodePtr ctxt2) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002403 int ret;
2404 xmlSchemaTypePtr typ;
2405 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2406
2407 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2408 return(-1);
2409 typ = xmlSchemaGetPredefinedType(type,
2410 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2411 if (typ == NULL)
2412 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002413 if (comp1 == NULL) {
2414 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2415 if (ret != 0)
2416 return(-1);
2417 if (res1 == NULL)
2418 return(-1);
2419 } else {
2420 res1 = (xmlSchemaValPtr) comp1;
2421 }
2422 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002423 if (ret != 0) {
2424 xmlSchemaFreeValue(res1);
2425 return(-1);
2426 }
2427 if (res1 == NULL) {
2428 xmlSchemaFreeValue(res1);
2429 return(-1);
2430 }
2431 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002432 if (res1 != (xmlSchemaValPtr) comp1)
2433 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002434 xmlSchemaFreeValue(res2);
2435 if (ret == -2)
2436 return(-1);
2437 if (ret == 0)
2438 return(1);
2439 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002440}
2441
2442/**
2443 * xmlRelaxNGDefaultTypeHave:
2444 * @data: data needed for the library
2445 * @type: the type name
2446 *
2447 * Check if the given type is provided by
2448 * the default datatype library.
2449 *
2450 * Returns 1 if yes, 0 if no and -1 in case of error.
2451 */
2452static int
2453xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2454 if (type == NULL)
2455 return(-1);
2456 if (xmlStrEqual(type, BAD_CAST "string"))
2457 return(1);
2458 if (xmlStrEqual(type, BAD_CAST "token"))
2459 return(1);
2460 return(0);
2461}
2462
2463/**
2464 * xmlRelaxNGDefaultTypeCheck:
2465 * @data: data needed for the library
2466 * @type: the type name
2467 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002468 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002469 *
2470 * Check if the given type and value are validated by
2471 * the default datatype library.
2472 *
2473 * Returns 1 if yes, 0 if no and -1 in case of error.
2474 */
2475static int
2476xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2477 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002478 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002479 void **result ATTRIBUTE_UNUSED,
2480 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002481 if (value == NULL)
2482 return(-1);
2483 if (xmlStrEqual(type, BAD_CAST "string"))
2484 return(1);
2485 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002486 return(1);
2487 }
2488
2489 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002490}
2491
2492/**
2493 * xmlRelaxNGDefaultTypeCompare:
2494 * @data: data needed for the library
2495 * @type: the type name
2496 * @value1: the first value
2497 * @value2: the second value
2498 *
2499 * Compare two values accordingly a type from the default
2500 * datatype library.
2501 *
2502 * Returns 1 if yes, 0 if no and -1 in case of error.
2503 */
2504static int
2505xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002506 const xmlChar *type,
2507 const xmlChar *value1,
2508 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2509 void *comp1 ATTRIBUTE_UNUSED,
2510 const xmlChar *value2,
2511 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002512 int ret = -1;
2513
2514 if (xmlStrEqual(type, BAD_CAST "string")) {
2515 ret = xmlStrEqual(value1, value2);
2516 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2517 if (!xmlStrEqual(value1, value2)) {
2518 xmlChar *nval, *nvalue;
2519
2520 /*
2521 * TODO: trivial optimizations are possible by
2522 * computing at compile-time
2523 */
2524 nval = xmlRelaxNGNormalize(NULL, value1);
2525 nvalue = xmlRelaxNGNormalize(NULL, value2);
2526
Daniel Veillardd4310742003-02-18 21:12:46 +00002527 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002528 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002529 else if (xmlStrEqual(nval, nvalue))
2530 ret = 1;
2531 else
2532 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002533 if (nval != NULL)
2534 xmlFree(nval);
2535 if (nvalue != NULL)
2536 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002537 } else
2538 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002539 }
2540 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002541}
2542
2543static int xmlRelaxNGTypeInitialized = 0;
2544static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2545
2546/**
2547 * xmlRelaxNGFreeTypeLibrary:
2548 * @lib: the type library structure
2549 * @namespace: the URI bound to the library
2550 *
2551 * Free the structure associated to the type library
2552 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002553static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002554xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2555 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2556 if (lib == NULL)
2557 return;
2558 if (lib->namespace != NULL)
2559 xmlFree((xmlChar *)lib->namespace);
2560 xmlFree(lib);
2561}
2562
2563/**
2564 * xmlRelaxNGRegisterTypeLibrary:
2565 * @namespace: the URI bound to the library
2566 * @data: data associated to the library
2567 * @have: the provide function
2568 * @check: the checking function
2569 * @comp: the comparison function
2570 *
2571 * Register a new type library
2572 *
2573 * Returns 0 in case of success and -1 in case of error.
2574 */
2575static int
2576xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2577 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002578 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2579 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002580 xmlRelaxNGTypeLibraryPtr lib;
2581 int ret;
2582
2583 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2584 (check == NULL) || (comp == NULL))
2585 return(-1);
2586 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2587 xmlGenericError(xmlGenericErrorContext,
2588 "Relax-NG types library '%s' already registered\n",
2589 namespace);
2590 return(-1);
2591 }
2592 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2593 if (lib == NULL) {
2594 xmlGenericError(xmlGenericErrorContext,
2595 "Relax-NG types library '%s' malloc() failed\n",
2596 namespace);
2597 return (-1);
2598 }
2599 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2600 lib->namespace = xmlStrdup(namespace);
2601 lib->data = data;
2602 lib->have = have;
2603 lib->comp = comp;
2604 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002605 lib->facet = facet;
2606 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002607 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2608 if (ret < 0) {
2609 xmlGenericError(xmlGenericErrorContext,
2610 "Relax-NG types library failed to register '%s'\n",
2611 namespace);
2612 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2613 return(-1);
2614 }
2615 return(0);
2616}
2617
2618/**
2619 * xmlRelaxNGInitTypes:
2620 *
2621 * Initilize the default type libraries.
2622 *
2623 * Returns 0 in case of success and -1 in case of error.
2624 */
2625static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002626xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002627 if (xmlRelaxNGTypeInitialized != 0)
2628 return(0);
2629 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2630 if (xmlRelaxNGRegisteredTypes == NULL) {
2631 xmlGenericError(xmlGenericErrorContext,
2632 "Failed to allocate sh table for Relax-NG types\n");
2633 return(-1);
2634 }
2635 xmlRelaxNGRegisterTypeLibrary(
2636 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2637 NULL,
2638 xmlRelaxNGSchemaTypeHave,
2639 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002640 xmlRelaxNGSchemaTypeCompare,
2641 xmlRelaxNGSchemaFacetCheck,
Daniel Veillard80b19092003-03-28 13:29:53 +00002642 xmlRelaxNGSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002643 xmlRelaxNGRegisterTypeLibrary(
2644 xmlRelaxNGNs,
2645 NULL,
2646 xmlRelaxNGDefaultTypeHave,
2647 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002648 xmlRelaxNGDefaultTypeCompare,
2649 NULL,
2650 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002651 xmlRelaxNGTypeInitialized = 1;
2652 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002653}
2654
2655/**
2656 * xmlRelaxNGCleanupTypes:
2657 *
2658 * Cleanup the default Schemas type library associated to RelaxNG
2659 */
2660void
2661xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002662 if (xmlRelaxNGTypeInitialized == 0)
2663 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002664 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002665 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2666 xmlRelaxNGFreeTypeLibrary);
2667 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002668}
2669
2670/************************************************************************
2671 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002672 * Compiling element content into regexp *
2673 * *
2674 * Sometime the element content can be compiled into a pure regexp, *
2675 * This allows a faster execution and streamability at that level *
2676 * *
2677 ************************************************************************/
2678
Daniel Veillard52b48c72003-04-13 19:53:42 +00002679static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
2680 xmlRelaxNGDefinePtr def);
2681
Daniel Veillard952379b2003-03-17 15:37:12 +00002682/**
2683 * xmlRelaxNGIsCompileable:
2684 * @define: the definition to check
2685 *
2686 * Check if a definition is nullable.
2687 *
2688 * Returns 1 if yes, 0 if no and -1 in case of error
2689 */
2690static int
2691xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
Daniel Veillard52b48c72003-04-13 19:53:42 +00002692 int ret = -1;
2693
Daniel Veillard952379b2003-03-17 15:37:12 +00002694 if (def == NULL) {
2695 return(-1);
2696 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002697 if ((def->type != XML_RELAXNG_ELEMENT) &&
2698 (def->dflags & IS_COMPILABLE))
2699 return(1);
2700 if ((def->type != XML_RELAXNG_ELEMENT) &&
2701 (def->dflags & IS_NOT_COMPILABLE))
2702 return(0);
Daniel Veillard952379b2003-03-17 15:37:12 +00002703 switch(def->type) {
2704 case XML_RELAXNG_REF:
2705 case XML_RELAXNG_EXTERNALREF:
2706 case XML_RELAXNG_PARENTREF:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002707 if (def->depth == -20) {
2708 return(1);
2709 } else {
2710 def->depth = -20;
2711 ret = xmlRelaxNGIsCompileable(def->content);
2712 }
2713 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002714 case XML_RELAXNG_NOOP:
2715 case XML_RELAXNG_START:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002716 ret = xmlRelaxNGIsCompileable(def->content);
2717 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002718 case XML_RELAXNG_TEXT:
Daniel Veillard952379b2003-03-17 15:37:12 +00002719 case XML_RELAXNG_EMPTY:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002720 ret = 1;
2721 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002722 case XML_RELAXNG_ELEMENT:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002723 if (((def->dflags & IS_NOT_COMPILABLE) == 0) &&
2724 ((def->dflags & IS_COMPILABLE) == 0)) {
2725 ret = xmlRelaxNGIsCompileable(def->content);
2726 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2727 if (ret == 1) def->dflags |= IS_COMPILABLE;
2728 }
2729 if ((def->nameClass != NULL) || (def->name == NULL))
2730 return(0);
2731 else
2732 return(1);
2733 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002734 case XML_RELAXNG_OPTIONAL:
2735 case XML_RELAXNG_ZEROORMORE:
2736 case XML_RELAXNG_ONEORMORE:
2737 case XML_RELAXNG_CHOICE:
2738 case XML_RELAXNG_GROUP:
2739 case XML_RELAXNG_DEF: {
2740 xmlRelaxNGDefinePtr list;
Daniel Veillard952379b2003-03-17 15:37:12 +00002741
2742 list = def->content;
2743 while (list != NULL) {
2744 ret = xmlRelaxNGIsCompileable(list);
2745 if (ret != 1)
Daniel Veillard52b48c72003-04-13 19:53:42 +00002746 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002747 list = list->next;
2748 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002749 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002750 }
2751 case XML_RELAXNG_EXCEPT:
2752 case XML_RELAXNG_ATTRIBUTE:
2753 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002754 case XML_RELAXNG_DATATYPE:
2755 case XML_RELAXNG_LIST:
2756 case XML_RELAXNG_PARAM:
2757 case XML_RELAXNG_VALUE:
2758 ret = 0;
2759 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002760 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillard52b48c72003-04-13 19:53:42 +00002761 ret = -1;
2762 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00002763 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002764 if (ret == 0) def->dflags |= IS_NOT_COMPILABLE;
2765 if (ret == 1) def->dflags |= IS_COMPILABLE;
2766 return(ret);
2767}
2768
2769/**
2770 * xmlRelaxNGCompile:
2771 * ctxt: the RelaxNG parser context
2772 * @define: the definition tree to compile
2773 *
2774 * Compile the set of definitions, it works recursively, till the
2775 * element boundaries, where it tries to compile the content if possible
2776 *
2777 * Returns 0 if success and -1 in case of error
2778 */
2779static int
2780xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2781 int ret = 0;
2782 xmlRelaxNGDefinePtr list;
2783
2784 if ((ctxt == NULL) || (def == NULL)) return(-1);
2785
2786 switch(def->type) {
2787 case XML_RELAXNG_START:
2788 if ((xmlRelaxNGIsCompileable(def) == 1) && (def->depth != -25)) {
2789 xmlAutomataPtr oldam = ctxt->am;
2790 xmlAutomataStatePtr oldstate = ctxt->state;
2791
2792 def->depth = -25;
2793
2794 list = def->content;
2795 ctxt->am = xmlNewAutomata();
2796 if (ctxt->am == NULL)
2797 return(-1);
2798 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2799 while (list != NULL) {
2800 xmlRelaxNGCompile(ctxt, list);
2801 list = list->next;
2802 }
2803 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2804 def->contModel = xmlAutomataCompile(ctxt->am);
2805 xmlRegexpIsDeterminist(def->contModel);
2806
2807 xmlFreeAutomata(ctxt->am);
2808 ctxt->state = oldstate;
2809 ctxt->am = oldam;
2810 }
2811 break;
2812 case XML_RELAXNG_ELEMENT:
2813 if ((ctxt->am != NULL) && (def->name != NULL)) {
2814 ctxt->state = xmlAutomataNewTransition2(ctxt->am,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002815 ctxt->state, NULL, def->name, def->ns, def);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002816 }
2817 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2818 xmlAutomataPtr oldam = ctxt->am;
2819 xmlAutomataStatePtr oldstate = ctxt->state;
2820
2821 def->depth = -25;
2822
2823 list = def->content;
2824 ctxt->am = xmlNewAutomata();
2825 if (ctxt->am == NULL)
2826 return(-1);
2827 ctxt->state = xmlAutomataGetInitState(ctxt->am);
2828 while (list != NULL) {
2829 xmlRelaxNGCompile(ctxt, list);
2830 list = list->next;
2831 }
2832 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
2833 def->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002834 if (!xmlRegexpIsDeterminist(def->contModel)) {
2835 /*
2836 * we can only use the automata if it is determinist
2837 */
2838 xmlRegFreeRegexp(def->contModel);
2839 def->contModel = NULL;
2840 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002841 xmlFreeAutomata(ctxt->am);
2842 ctxt->state = oldstate;
2843 ctxt->am = oldam;
2844 } else {
2845 xmlAutomataPtr oldam = ctxt->am;
2846
2847 /*
2848 * we can't build the content model for this element content
2849 * but it still might be possible to build it for some of its
2850 * children, recurse.
2851 */
2852 ret = xmlRelaxNGTryCompile(ctxt, def);
2853 ctxt->am = oldam;
2854 }
2855 break;
2856 case XML_RELAXNG_REF:
2857 case XML_RELAXNG_EXTERNALREF:
2858 case XML_RELAXNG_PARENTREF:
2859 case XML_RELAXNG_NOOP:
2860 ret = xmlRelaxNGCompile(ctxt, def->content);
2861 break;
2862 case XML_RELAXNG_OPTIONAL: {
2863 xmlAutomataStatePtr oldstate = ctxt->state;
2864
2865 xmlRelaxNGCompile(ctxt, def->content);
2866 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
2867 break;
2868 }
2869 case XML_RELAXNG_ZEROORMORE: {
2870 xmlAutomataStatePtr oldstate;
2871
2872 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2873 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002874 list = def->content;
2875 while (list != NULL) {
2876 xmlRelaxNGCompile(ctxt, list);
2877 list = list->next;
2878 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002879 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2880 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2881 break;
2882 }
2883 case XML_RELAXNG_ONEORMORE: {
2884 xmlAutomataStatePtr oldstate;
2885
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002886 list = def->content;
2887 while (list != NULL) {
2888 xmlRelaxNGCompile(ctxt, list);
2889 list = list->next;
2890 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002891 oldstate = ctxt->state;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002892 list = def->content;
2893 while (list != NULL) {
2894 xmlRelaxNGCompile(ctxt, list);
2895 list = list->next;
2896 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00002897 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldstate);
2898 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2899 break;
2900 }
2901 case XML_RELAXNG_CHOICE: {
2902 xmlAutomataStatePtr target = NULL;
2903 xmlAutomataStatePtr oldstate = ctxt->state;
2904
2905 list = def->content;
2906 while (list != NULL) {
2907 ctxt->state = oldstate;
2908 xmlRelaxNGCompile(ctxt, list);
2909 if (target == NULL)
2910 target = ctxt->state;
2911 else {
2912 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, target);
2913 }
2914 list = list->next;
2915 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002916 ctxt->state = target;
Daniel Veillard52b48c72003-04-13 19:53:42 +00002917
2918 break;
2919 }
2920 case XML_RELAXNG_GROUP:
2921 case XML_RELAXNG_DEF:
2922 list = def->content;
2923 while (list != NULL) {
2924 xmlRelaxNGCompile(ctxt, list);
2925 list = list->next;
2926 }
2927 break;
2928 case XML_RELAXNG_TEXT: {
2929 xmlAutomataStatePtr oldstate;
2930
2931 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
2932 oldstate = ctxt->state;
2933 xmlRelaxNGCompile(ctxt, def->content);
2934 xmlAutomataNewTransition(ctxt->am, ctxt->state, ctxt->state,
2935 BAD_CAST "#text", NULL);
2936 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
2937 break;
2938 }
2939 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00002940 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
Daniel Veillard52b48c72003-04-13 19:53:42 +00002941 break;
2942 case XML_RELAXNG_EXCEPT:
2943 case XML_RELAXNG_ATTRIBUTE:
2944 case XML_RELAXNG_INTERLEAVE:
2945 case XML_RELAXNG_NOT_ALLOWED:
2946 case XML_RELAXNG_DATATYPE:
2947 case XML_RELAXNG_LIST:
2948 case XML_RELAXNG_PARAM:
2949 case XML_RELAXNG_VALUE:
Daniel Veillardac297932003-04-17 12:55:35 +00002950 /* This should not happen and generate an internal error */
2951 fprintf(stderr, "RNG internal error trying to compile %s\n",
2952 xmlRelaxNGDefName(def));
Daniel Veillard52b48c72003-04-13 19:53:42 +00002953 break;
2954 }
2955 return(ret);
2956}
2957
2958/**
2959 * xmlRelaxNGTryCompile:
2960 * ctxt: the RelaxNG parser context
2961 * @define: the definition tree to compile
2962 *
2963 * Try to compile the set of definitions, it works recursively,
2964 * possibly ignoring parts which cannot be compiled.
2965 *
2966 * Returns 0 if success and -1 in case of error
2967 */
2968static int
2969xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGDefinePtr def) {
2970 int ret = 0;
2971 xmlRelaxNGDefinePtr list;
2972
2973 if ((ctxt == NULL) || (def == NULL)) return(-1);
2974
2975 if ((def->type == XML_RELAXNG_START) ||
2976 (def->type == XML_RELAXNG_ELEMENT)) {
2977 ret = xmlRelaxNGIsCompileable(def);
2978 if ((def->dflags & IS_COMPILABLE) && (def->depth != -25)) {
2979 ctxt->am = NULL;
2980 ret = xmlRelaxNGCompile(ctxt, def);
2981 return(ret);
2982 }
2983 }
2984 switch(def->type) {
2985 case XML_RELAXNG_REF:
2986 case XML_RELAXNG_EXTERNALREF:
2987 case XML_RELAXNG_PARENTREF:
2988 case XML_RELAXNG_NOOP:
2989 case XML_RELAXNG_START:
2990 ret = xmlRelaxNGTryCompile(ctxt, def->content);
2991 break;
2992 case XML_RELAXNG_TEXT:
2993 case XML_RELAXNG_DATATYPE:
2994 case XML_RELAXNG_LIST:
2995 case XML_RELAXNG_PARAM:
2996 case XML_RELAXNG_VALUE:
2997 case XML_RELAXNG_EMPTY:
2998 case XML_RELAXNG_ELEMENT:
2999 ret = 0;
3000 break;
3001 case XML_RELAXNG_OPTIONAL:
3002 case XML_RELAXNG_ZEROORMORE:
3003 case XML_RELAXNG_ONEORMORE:
3004 case XML_RELAXNG_CHOICE:
3005 case XML_RELAXNG_GROUP:
3006 case XML_RELAXNG_DEF:
3007 list = def->content;
3008 while (list != NULL) {
3009 ret = xmlRelaxNGTryCompile(ctxt, list);
3010 if (ret != 0)
3011 break;
3012 list = list->next;
3013 }
3014 break;
3015 case XML_RELAXNG_EXCEPT:
3016 case XML_RELAXNG_ATTRIBUTE:
3017 case XML_RELAXNG_INTERLEAVE:
3018 case XML_RELAXNG_NOT_ALLOWED:
3019 ret = 0;
3020 break;
3021 }
3022 return(ret);
Daniel Veillard952379b2003-03-17 15:37:12 +00003023}
3024
3025/************************************************************************
3026 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00003027 * Parsing functions *
3028 * *
3029 ************************************************************************/
3030
3031static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
3032 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3033static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
3034 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
3035static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00003036 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003037static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
3038 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00003039static xmlRelaxNGPtr xmlRelaxNGParseDocument(
3040 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003041static int xmlRelaxNGParseGrammarContent(
3042 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00003043static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
3044 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3045 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00003046static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
3047 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003048static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
3049 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003050
3051
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003052#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00003053
3054/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003055 * xmlRelaxNGIsNullable:
3056 * @define: the definition to verify
3057 *
3058 * Check if a definition is nullable.
3059 *
3060 * Returns 1 if yes, 0 if no and -1 in case of error
3061 */
3062static int
3063xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
3064 int ret;
3065 if (define == NULL)
3066 return(-1);
3067
Daniel Veillarde063f482003-03-21 16:53:17 +00003068 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003069 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00003070 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00003071 return(0);
3072 switch (define->type) {
3073 case XML_RELAXNG_EMPTY:
3074 case XML_RELAXNG_TEXT:
3075 ret = 1; break;
3076 case XML_RELAXNG_NOOP:
3077 case XML_RELAXNG_DEF:
3078 case XML_RELAXNG_REF:
3079 case XML_RELAXNG_EXTERNALREF:
3080 case XML_RELAXNG_PARENTREF:
3081 case XML_RELAXNG_ONEORMORE:
3082 ret = xmlRelaxNGIsNullable(define->content);
3083 break;
3084 case XML_RELAXNG_EXCEPT:
3085 case XML_RELAXNG_NOT_ALLOWED:
3086 case XML_RELAXNG_ELEMENT:
3087 case XML_RELAXNG_DATATYPE:
3088 case XML_RELAXNG_PARAM:
3089 case XML_RELAXNG_VALUE:
3090 case XML_RELAXNG_LIST:
3091 case XML_RELAXNG_ATTRIBUTE:
3092 ret = 0; break;
3093 case XML_RELAXNG_CHOICE: {
3094 xmlRelaxNGDefinePtr list = define->content;
3095
3096 while (list != NULL) {
3097 ret = xmlRelaxNGIsNullable(list);
3098 if (ret != 0)
3099 goto done;
3100 list = list->next;
3101 }
3102 ret = 0; break;
3103 }
3104 case XML_RELAXNG_START:
3105 case XML_RELAXNG_INTERLEAVE:
3106 case XML_RELAXNG_GROUP: {
3107 xmlRelaxNGDefinePtr list = define->content;
3108
3109 while (list != NULL) {
3110 ret = xmlRelaxNGIsNullable(list);
3111 if (ret != 1)
3112 goto done;
3113 list = list->next;
3114 }
3115 return(1);
3116 }
3117 default:
3118 return(-1);
3119 }
3120done:
3121 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003122 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003123 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00003124 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003125 return(ret);
3126}
3127
3128/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00003129 * xmlRelaxNGIsBlank:
3130 * @str: a string
3131 *
3132 * Check if a string is ignorable c.f. 4.2. Whitespace
3133 *
3134 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3135 */
3136static int
3137xmlRelaxNGIsBlank(xmlChar *str) {
3138 if (str == NULL)
3139 return(1);
3140 while (*str != 0) {
3141 if (!(IS_BLANK(*str))) return(0);
3142 str++;
3143 }
3144 return(1);
3145}
3146
Daniel Veillard6eadf632003-01-23 18:29:16 +00003147/**
3148 * xmlRelaxNGGetDataTypeLibrary:
3149 * @ctxt: a Relax-NG parser context
3150 * @node: the current data or value element
3151 *
3152 * Applies algorithm from 4.3. datatypeLibrary attribute
3153 *
3154 * Returns the datatypeLibary value or NULL if not found
3155 */
3156static xmlChar *
3157xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3158 xmlNodePtr node) {
3159 xmlChar *ret, *escape;
3160
Daniel Veillard6eadf632003-01-23 18:29:16 +00003161 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
3162 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3163 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003164 if (ret[0] == 0) {
3165 xmlFree(ret);
3166 return(NULL);
3167 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003168 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00003169 if (escape == NULL) {
3170 return(ret);
3171 }
3172 xmlFree(ret);
3173 return(escape);
3174 }
3175 }
3176 node = node->parent;
3177 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003178 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
3179 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003180 if (ret[0] == 0) {
3181 xmlFree(ret);
3182 return(NULL);
3183 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003184 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
3185 if (escape == NULL) {
3186 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003187 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00003188 xmlFree(ret);
3189 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00003190 }
3191 node = node->parent;
3192 }
3193 return(NULL);
3194}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003195
3196/**
Daniel Veillardedc91922003-01-26 00:52:04 +00003197 * xmlRelaxNGParseValue:
3198 * @ctxt: a Relax-NG parser context
3199 * @node: the data node.
3200 *
3201 * parse the content of a RelaxNG value node.
3202 *
3203 * Returns the definition pointer or NULL in case of error
3204 */
3205static xmlRelaxNGDefinePtr
3206xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3207 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00003208 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00003209 xmlChar *type;
3210 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003211 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00003212
Daniel Veillardfd573f12003-03-16 17:52:32 +00003213 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00003214 if (def == NULL)
3215 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003216 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00003217
3218 type = xmlGetProp(node, BAD_CAST "type");
3219 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00003220 xmlRelaxNGNormExtSpace(type);
3221 if (xmlValidateNCName(type, 0)) {
3222 if (ctxt->error != NULL)
3223 ctxt->error(ctxt->userData,
3224 "value type '%s' is not an NCName\n",
3225 type);
3226 ctxt->nbErrors++;
3227 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003228 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3229 if (library == NULL)
3230 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3231
3232 def->name = type;
3233 def->ns = library;
3234
3235 lib = (xmlRelaxNGTypeLibraryPtr)
3236 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3237 if (lib == NULL) {
3238 if (ctxt->error != NULL)
3239 ctxt->error(ctxt->userData,
3240 "Use of unregistered type library '%s'\n",
3241 library);
3242 ctxt->nbErrors++;
3243 def->data = NULL;
3244 } else {
3245 def->data = lib;
3246 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003247 if (ctxt->error != NULL)
3248 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003249 "Internal error with type library '%s': no 'have'\n",
3250 library);
3251 ctxt->nbErrors++;
3252 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003253 success = lib->have(lib->data, def->name);
3254 if (success != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003255 if (ctxt->error != NULL)
3256 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00003257 "Error type '%s' is not exported by type library '%s'\n",
3258 def->name, library);
3259 ctxt->nbErrors++;
3260 }
3261 }
3262 }
3263 }
3264 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00003265 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00003266 } else if (((node->children->type != XML_TEXT_NODE) &&
3267 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00003268 (node->children->next != NULL)) {
3269 if (ctxt->error != NULL)
3270 ctxt->error(ctxt->userData,
3271 "Expecting a single text value for <value>content\n");
3272 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003273 } else if (def != NULL) {
Daniel Veillardedc91922003-01-26 00:52:04 +00003274 def->value = xmlNodeGetContent(node);
3275 if (def->value == NULL) {
3276 if (ctxt->error != NULL)
3277 ctxt->error(ctxt->userData,
3278 "Element <value> has no content\n");
3279 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003280 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
3281 void *val = NULL;
3282
3283 success = lib->check(lib->data, def->name, def->value, &val, node);
3284 if (success != 1) {
3285 if (ctxt->error != NULL)
3286 ctxt->error(ctxt->userData,
3287 "Value '%s' is not acceptable for type '%s'\n",
3288 def->value, def->name);
3289 ctxt->nbErrors++;
3290 } else {
3291 if (val != NULL)
3292 def->attrs = val;
3293 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003294 }
3295 }
Daniel Veillardedc91922003-01-26 00:52:04 +00003296 return(def);
3297}
3298
3299/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003300 * xmlRelaxNGParseData:
3301 * @ctxt: a Relax-NG parser context
3302 * @node: the data node.
3303 *
3304 * parse the content of a RelaxNG data node.
3305 *
3306 * Returns the definition pointer or NULL in case of error
3307 */
3308static xmlRelaxNGDefinePtr
3309xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003310 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003311 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003312 xmlRelaxNGTypeLibraryPtr lib;
3313 xmlChar *type;
3314 xmlChar *library;
3315 xmlNodePtr content;
3316 int tmp;
3317
3318 type = xmlGetProp(node, BAD_CAST "type");
3319 if (type == NULL) {
3320 if (ctxt->error != NULL)
3321 ctxt->error(ctxt->userData,
3322 "data has no type\n");
3323 ctxt->nbErrors++;
3324 return(NULL);
3325 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003326 xmlRelaxNGNormExtSpace(type);
3327 if (xmlValidateNCName(type, 0)) {
3328 if (ctxt->error != NULL)
3329 ctxt->error(ctxt->userData,
3330 "data type '%s' is not an NCName\n",
3331 type);
3332 ctxt->nbErrors++;
3333 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003334 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3335 if (library == NULL)
3336 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3337
Daniel Veillardfd573f12003-03-16 17:52:32 +00003338 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003339 if (def == NULL) {
3340 xmlFree(type);
3341 return(NULL);
3342 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003343 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003344 def->name = type;
3345 def->ns = library;
3346
3347 lib = (xmlRelaxNGTypeLibraryPtr)
3348 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3349 if (lib == NULL) {
3350 if (ctxt->error != NULL)
3351 ctxt->error(ctxt->userData,
3352 "Use of unregistered type library '%s'\n",
3353 library);
3354 ctxt->nbErrors++;
3355 def->data = NULL;
3356 } else {
3357 def->data = lib;
3358 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003359 if (ctxt->error != NULL)
3360 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003361 "Internal error with type library '%s': no 'have'\n",
3362 library);
3363 ctxt->nbErrors++;
3364 } else {
3365 tmp = lib->have(lib->data, def->name);
3366 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003367 if (ctxt->error != NULL)
3368 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003369 "Error type '%s' is not exported by type library '%s'\n",
3370 def->name, library);
3371 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003372 } else if ((xmlStrEqual(library, BAD_CAST
3373 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3374 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3375 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3376 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003377 }
3378 }
3379 }
3380 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003381
3382 /*
3383 * Handle optional params
3384 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003385 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003386 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3387 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003388 if (xmlStrEqual(library,
3389 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3390 if (ctxt->error != NULL)
3391 ctxt->error(ctxt->userData,
3392 "Type library '%s' does not allow type parameters\n",
3393 library);
3394 ctxt->nbErrors++;
3395 content = content->next;
3396 while ((content != NULL) &&
3397 (xmlStrEqual(content->name, BAD_CAST "param")))
3398 content = content->next;
3399 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003400 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003401 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003402 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003403 param->name = xmlGetProp(content, BAD_CAST "name");
3404 if (param->name == NULL) {
3405 if (ctxt->error != NULL)
3406 ctxt->error(ctxt->userData,
3407 "param has no name\n");
3408 ctxt->nbErrors++;
3409 }
3410 param->value = xmlNodeGetContent(content);
3411 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003412 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003413 } else {
3414 lastparam->next = param;
3415 lastparam = param;
3416 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003417 if (lib != NULL) {
3418 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003419 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003420 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003421 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003422 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003423 /*
3424 * Handle optional except
3425 */
3426 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3427 xmlNodePtr child;
3428 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3429
Daniel Veillardfd573f12003-03-16 17:52:32 +00003430 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003431 if (except == NULL) {
3432 return(def);
3433 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003434 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003435 child = content->children;
3436 if (last == NULL) {
3437 def->content = except;
3438 } else {
3439 last->next = except;
3440 }
3441 if (child == NULL) {
3442 if (ctxt->error != NULL)
3443 ctxt->error(ctxt->userData,
3444 "except has no content\n");
3445 ctxt->nbErrors++;
3446 }
3447 while (child != NULL) {
3448 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3449 if (tmp2 != NULL) {
3450 if (last2 == NULL) {
3451 except->content = last2 = tmp2;
3452 } else {
3453 last2->next = tmp2;
3454 last2 = tmp2;
3455 }
3456 }
3457 child = child->next;
3458 }
3459 content = content->next;
3460 }
3461 /*
3462 * Check there is no unhandled data
3463 */
3464 if (content != NULL) {
3465 if (ctxt->error != NULL)
3466 ctxt->error(ctxt->userData,
3467 "Element data has unexpected content %s\n", content->name);
3468 ctxt->nbErrors++;
3469 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003470
3471 return(def);
3472}
3473
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003474static const xmlChar *invalidName = BAD_CAST "\1";
3475
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003476/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003477 * xmlRelaxNGCompareNameClasses:
3478 * @defs1: the first element/attribute defs
3479 * @defs2: the second element/attribute defs
3480 * @name: the restriction on the name
3481 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003482 *
3483 * Compare the 2 lists of element definitions. The comparison is
3484 * that if both lists do not accept the same QNames, it returns 1
3485 * If the 2 lists can accept the same QName the comparison returns 0
3486 *
3487 * Returns 1 disttinct, 0 if equal
3488 */
3489static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003490xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3491 xmlRelaxNGDefinePtr def2) {
3492 int ret = 1;
3493 xmlNode node;
3494 xmlNs ns;
3495 xmlRelaxNGValidCtxt ctxt;
3496 ctxt.flags = FLAGS_IGNORABLE;
3497
Daniel Veillard42f12e92003-03-07 18:32:59 +00003498 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3499
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003500 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3501 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3502 if (def2->type == XML_RELAXNG_TEXT)
3503 return(1);
3504 if (def1->name != NULL) {
3505 node.name = def1->name;
3506 } else {
3507 node.name = invalidName;
3508 }
3509 node.ns = &ns;
3510 if (def1->ns != NULL) {
3511 if (def1->ns[0] == 0) {
3512 node.ns = NULL;
3513 } else {
3514 ns.href = def1->ns;
3515 }
3516 } else {
3517 ns.href = invalidName;
3518 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003519 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003520 if (def1->nameClass != NULL) {
3521 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3522 } else {
3523 ret = 0;
3524 }
3525 } else {
3526 ret = 1;
3527 }
3528 } else if (def1->type == XML_RELAXNG_TEXT) {
3529 if (def2->type == XML_RELAXNG_TEXT)
3530 return(0);
3531 return(1);
3532 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003533 TODO
3534 ret = 0;
3535 } else {
3536 TODO
3537 ret = 0;
3538 }
3539 if (ret == 0)
3540 return(ret);
3541 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3542 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3543 if (def2->name != NULL) {
3544 node.name = def2->name;
3545 } else {
3546 node.name = invalidName;
3547 }
3548 node.ns = &ns;
3549 if (def2->ns != NULL) {
3550 if (def2->ns[0] == 0) {
3551 node.ns = NULL;
3552 } else {
3553 ns.href = def2->ns;
3554 }
3555 } else {
3556 ns.href = invalidName;
3557 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003558 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003559 if (def2->nameClass != NULL) {
3560 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3561 } else {
3562 ret = 0;
3563 }
3564 } else {
3565 ret = 1;
3566 }
3567 } else {
3568 TODO
3569 ret = 0;
3570 }
3571
3572 return(ret);
3573}
3574
3575/**
3576 * xmlRelaxNGCompareElemDefLists:
3577 * @ctxt: a Relax-NG parser context
3578 * @defs1: the first list of element/attribute defs
3579 * @defs2: the second list of element/attribute defs
3580 *
3581 * Compare the 2 lists of element or attribute definitions. The comparison
3582 * is that if both lists do not accept the same QNames, it returns 1
3583 * If the 2 lists can accept the same QName the comparison returns 0
3584 *
3585 * Returns 1 disttinct, 0 if equal
3586 */
3587static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003588xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3589 xmlRelaxNGDefinePtr *def1,
3590 xmlRelaxNGDefinePtr *def2) {
3591 xmlRelaxNGDefinePtr *basedef2 = def2;
3592
Daniel Veillard154877e2003-01-30 12:17:05 +00003593 if ((def1 == NULL) || (def2 == NULL))
3594 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003595 if ((*def1 == NULL) || (*def2 == NULL))
3596 return(1);
3597 while (*def1 != NULL) {
3598 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003599 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3600 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003601 def2++;
3602 }
3603 def2 = basedef2;
3604 def1++;
3605 }
3606 return(1);
3607}
3608
3609/**
Daniel Veillardce192eb2003-04-16 15:58:05 +00003610 * xmlRelaxNGGenerateAttributes:
3611 * @ctxt: a Relax-NG parser context
3612 * @def: the definition definition
3613 *
3614 * Check if the definition can only generate attributes
3615 *
3616 * Returns 1 if yes, 0 if no and -1 in case of error.
3617 */
3618static int
3619xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
3620 xmlRelaxNGDefinePtr def) {
3621 xmlRelaxNGDefinePtr parent, cur, tmp;
3622
3623 /*
3624 * Don't run that check in case of error. Infinite recursion
3625 * becomes possible.
3626 */
3627 if (ctxt->nbErrors != 0)
3628 return(-1);
3629
3630 parent = NULL;
3631 cur = def;
3632 while (cur != NULL) {
3633 if ((cur->type == XML_RELAXNG_ELEMENT) ||
3634 (cur->type == XML_RELAXNG_TEXT) ||
3635 (cur->type == XML_RELAXNG_DATATYPE) ||
3636 (cur->type == XML_RELAXNG_PARAM) ||
3637 (cur->type == XML_RELAXNG_LIST) ||
3638 (cur->type == XML_RELAXNG_VALUE) ||
3639 (cur->type == XML_RELAXNG_EMPTY))
3640 return(0);
3641 if ((cur->type == XML_RELAXNG_CHOICE) ||
3642 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3643 (cur->type == XML_RELAXNG_GROUP) ||
3644 (cur->type == XML_RELAXNG_ONEORMORE) ||
3645 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3646 (cur->type == XML_RELAXNG_OPTIONAL) ||
3647 (cur->type == XML_RELAXNG_PARENTREF) ||
3648 (cur->type == XML_RELAXNG_EXTERNALREF) ||
3649 (cur->type == XML_RELAXNG_REF) ||
3650 (cur->type == XML_RELAXNG_DEF)) {
3651 if (cur->content != NULL) {
3652 parent = cur;
3653 cur = cur->content;
3654 tmp = cur;
3655 while (tmp != NULL) {
3656 tmp->parent = parent;
3657 tmp = tmp->next;
3658 }
3659 continue;
3660 }
3661 }
3662 if (cur == def)
3663 break;
3664 if (cur->next != NULL) {
3665 cur = cur->next;
3666 continue;
3667 }
3668 do {
3669 cur = cur->parent;
3670 if (cur == NULL) break;
3671 if (cur == def) return(1);
3672 if (cur->next != NULL) {
3673 cur = cur->next;
3674 break;
3675 }
3676 } while (cur != NULL);
3677 }
3678 return(1);
3679}
3680
3681/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003682 * xmlRelaxNGGetElements:
3683 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003684 * @def: the definition definition
3685 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003686 *
3687 * Compute the list of top elements a definition can generate
3688 *
3689 * Returns a list of elements or NULL if none was found.
3690 */
3691static xmlRelaxNGDefinePtr *
3692xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003693 xmlRelaxNGDefinePtr def,
3694 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003695 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003696 int len = 0;
3697 int max = 0;
3698
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003699 /*
3700 * Don't run that check in case of error. Infinite recursion
3701 * becomes possible.
3702 */
3703 if (ctxt->nbErrors != 0)
3704 return(NULL);
3705
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003706 parent = NULL;
3707 cur = def;
3708 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003709 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3710 (cur->type == XML_RELAXNG_TEXT))) ||
3711 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003712 if (ret == NULL) {
3713 max = 10;
3714 ret = (xmlRelaxNGDefinePtr *)
3715 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3716 if (ret == NULL) {
3717 if (ctxt->error != NULL)
3718 ctxt->error(ctxt->userData,
3719 "Out of memory in element search\n");
3720 ctxt->nbErrors++;
3721 return(NULL);
3722 }
3723 } else if (max <= len) {
3724 max *= 2;
3725 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3726 if (ret == NULL) {
3727 if (ctxt->error != NULL)
3728 ctxt->error(ctxt->userData,
3729 "Out of memory in element search\n");
3730 ctxt->nbErrors++;
3731 return(NULL);
3732 }
3733 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003734 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003735 ret[len] = NULL;
3736 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3737 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3738 (cur->type == XML_RELAXNG_GROUP) ||
3739 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003740 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3741 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003742 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003743 (cur->type == XML_RELAXNG_REF) ||
3744 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003745 /*
3746 * Don't go within elements or attributes or string values.
3747 * Just gather the element top list
3748 */
3749 if (cur->content != NULL) {
3750 parent = cur;
3751 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003752 tmp = cur;
3753 while (tmp != NULL) {
3754 tmp->parent = parent;
3755 tmp = tmp->next;
3756 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003757 continue;
3758 }
3759 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003760 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003761 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003762 if (cur->next != NULL) {
3763 cur = cur->next;
3764 continue;
3765 }
3766 do {
3767 cur = cur->parent;
3768 if (cur == NULL) break;
3769 if (cur == def) return(ret);
3770 if (cur->next != NULL) {
3771 cur = cur->next;
3772 break;
3773 }
3774 } while (cur != NULL);
3775 }
3776 return(ret);
3777}
3778
3779/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003780 * xmlRelaxNGCheckChoiceDeterminism:
3781 * @ctxt: a Relax-NG parser context
3782 * @def: the choice definition
3783 *
3784 * Also used to find indeterministic pattern in choice
3785 */
3786static void
3787xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3788 xmlRelaxNGDefinePtr def) {
3789 xmlRelaxNGDefinePtr **list;
3790 xmlRelaxNGDefinePtr cur;
3791 int nbchild = 0, i, j, ret;
3792 int is_nullable = 0;
3793 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003794 xmlHashTablePtr triage = NULL;
3795 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003796
3797 if ((def == NULL) ||
3798 (def->type != XML_RELAXNG_CHOICE))
3799 return;
3800
Daniel Veillarde063f482003-03-21 16:53:17 +00003801 if (def->dflags & IS_PROCESSED)
3802 return;
3803
Daniel Veillardfd573f12003-03-16 17:52:32 +00003804 /*
3805 * Don't run that check in case of error. Infinite recursion
3806 * becomes possible.
3807 */
3808 if (ctxt->nbErrors != 0)
3809 return;
3810
3811 is_nullable = xmlRelaxNGIsNullable(def);
3812
3813 cur = def->content;
3814 while (cur != NULL) {
3815 nbchild++;
3816 cur = cur->next;
3817 }
3818
3819 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3820 sizeof(xmlRelaxNGDefinePtr *));
3821 if (list == NULL) {
3822 if (ctxt->error != NULL)
3823 ctxt->error(ctxt->userData,
3824 "Out of memory in choice computation\n");
3825 ctxt->nbErrors++;
3826 return;
3827 }
3828 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003829 /*
3830 * a bit strong but safe
3831 */
3832 if (is_nullable == 0) {
3833 triage = xmlHashCreate(10);
3834 } else {
3835 is_triable = 0;
3836 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003837 cur = def->content;
3838 while (cur != NULL) {
3839 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003840 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3841 is_triable = 0;
3842 } else if (is_triable == 1) {
3843 xmlRelaxNGDefinePtr *tmp;
3844 int res;
3845
3846 tmp = list[i];
3847 while ((*tmp != NULL) && (is_triable == 1)) {
3848 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3849 res = xmlHashAddEntry2(triage,
3850 BAD_CAST "#text", NULL,
3851 (void *)cur);
3852 if (res != 0)
3853 is_triable = -1;
3854 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3855 ((*tmp)->name != NULL)) {
3856 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3857 res = xmlHashAddEntry2(triage,
3858 (*tmp)->name, NULL,
3859 (void *)cur);
3860 else
3861 res = xmlHashAddEntry2(triage,
3862 (*tmp)->name, (*tmp)->ns,
3863 (void *)cur);
3864 if (res != 0)
3865 is_triable = -1;
3866 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3867 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3868 res = xmlHashAddEntry2(triage,
3869 BAD_CAST "#any", NULL,
3870 (void *)cur);
3871 else
3872 res = xmlHashAddEntry2(triage,
3873 BAD_CAST "#any", (*tmp)->ns,
3874 (void *)cur);
3875 if (res != 0)
3876 is_triable = -1;
3877 } else {
3878 is_triable = -1;
3879 }
3880 tmp++;
3881 }
3882 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003883 i++;
3884 cur = cur->next;
3885 }
3886
3887 for (i = 0;i < nbchild;i++) {
3888 if (list[i] == NULL)
3889 continue;
3890 for (j = 0;j < i;j++) {
3891 if (list[j] == NULL)
3892 continue;
3893 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3894 if (ret == 0) {
3895 is_indeterminist = 1;
3896 }
3897 }
3898 }
3899 for (i = 0;i < nbchild;i++) {
3900 if (list[i] != NULL)
3901 xmlFree(list[i]);
3902 }
3903
3904 xmlFree(list);
3905 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003906 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003907 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003908 if (is_triable == 1) {
3909 def->dflags |= IS_TRIABLE;
3910 def->data = triage;
3911 } else if (triage != NULL) {
3912 xmlHashFree(triage, NULL);
3913 }
3914 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003915}
3916
3917/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003918 * xmlRelaxNGCheckGroupAttrs:
3919 * @ctxt: a Relax-NG parser context
3920 * @def: the group definition
3921 *
3922 * Detects violations of rule 7.3
3923 */
3924static void
3925xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3926 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003927 xmlRelaxNGDefinePtr **list;
3928 xmlRelaxNGDefinePtr cur;
3929 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003930
3931 if ((def == NULL) ||
3932 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003933 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003934 return;
3935
Daniel Veillarde063f482003-03-21 16:53:17 +00003936 if (def->dflags & IS_PROCESSED)
3937 return;
3938
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003939 /*
3940 * Don't run that check in case of error. Infinite recursion
3941 * becomes possible.
3942 */
3943 if (ctxt->nbErrors != 0)
3944 return;
3945
Daniel Veillardfd573f12003-03-16 17:52:32 +00003946 cur = def->attrs;
3947 while (cur != NULL) {
3948 nbchild++;
3949 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003950 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003951 cur = def->content;
3952 while (cur != NULL) {
3953 nbchild++;
3954 cur = cur->next;
3955 }
3956
3957 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3958 sizeof(xmlRelaxNGDefinePtr *));
3959 if (list == NULL) {
3960 if (ctxt->error != NULL)
3961 ctxt->error(ctxt->userData,
3962 "Out of memory in group computation\n");
3963 ctxt->nbErrors++;
3964 return;
3965 }
3966 i = 0;
3967 cur = def->attrs;
3968 while (cur != NULL) {
3969 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3970 i++;
3971 cur = cur->next;
3972 }
3973 cur = def->content;
3974 while (cur != NULL) {
3975 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3976 i++;
3977 cur = cur->next;
3978 }
3979
3980 for (i = 0;i < nbchild;i++) {
3981 if (list[i] == NULL)
3982 continue;
3983 for (j = 0;j < i;j++) {
3984 if (list[j] == NULL)
3985 continue;
3986 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3987 if (ret == 0) {
3988 if (ctxt->error != NULL)
3989 ctxt->error(ctxt->userData,
3990 "Attributes conflicts in group\n");
3991 ctxt->nbErrors++;
3992 }
3993 }
3994 }
3995 for (i = 0;i < nbchild;i++) {
3996 if (list[i] != NULL)
3997 xmlFree(list[i]);
3998 }
3999
4000 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00004001 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004002}
4003
4004/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00004005 * xmlRelaxNGComputeInterleaves:
4006 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004007 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00004008 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004009 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00004010 * A lot of work for preprocessing interleave definitions
4011 * is potentially needed to get a decent execution speed at runtime
4012 * - trying to get a total order on the element nodes generated
4013 * by the interleaves, order the list of interleave definitions
4014 * following that order.
4015 * - if <text/> is used to handle mixed content, it is better to
4016 * flag this in the define and simplify the runtime checking
4017 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004018 */
4019static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00004020xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
4021 xmlRelaxNGParserCtxtPtr ctxt,
4022 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004023 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004024
Daniel Veillardfd573f12003-03-16 17:52:32 +00004025 xmlRelaxNGPartitionPtr partitions = NULL;
4026 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
4027 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004028 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004029 int nbgroups = 0;
4030 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004031 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004032 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004033
Daniel Veillard44e1dd02003-02-21 23:23:28 +00004034 /*
4035 * Don't run that check in case of error. Infinite recursion
4036 * becomes possible.
4037 */
4038 if (ctxt->nbErrors != 0)
4039 return;
4040
Daniel Veillardfd573f12003-03-16 17:52:32 +00004041#ifdef DEBUG_INTERLEAVE
4042 xmlGenericError(xmlGenericErrorContext,
4043 "xmlRelaxNGComputeInterleaves(%s)\n",
4044 name);
4045#endif
4046 cur = def->content;
4047 while (cur != NULL) {
4048 nbchild++;
4049 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004050 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004051
4052#ifdef DEBUG_INTERLEAVE
4053 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
4054#endif
4055 groups = (xmlRelaxNGInterleaveGroupPtr *)
4056 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
4057 if (groups == NULL)
4058 goto error;
4059 cur = def->content;
4060 while (cur != NULL) {
4061 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
4062 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
4063 if (groups[nbgroups] == NULL)
4064 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004065 if (cur->type == XML_RELAXNG_TEXT)
4066 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004067 groups[nbgroups]->rule = cur;
4068 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
4069 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
4070 nbgroups++;
4071 cur = cur->next;
4072 }
4073#ifdef DEBUG_INTERLEAVE
4074 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
4075#endif
4076
4077 /*
4078 * Let's check that all rules makes a partitions according to 7.4
4079 */
4080 partitions = (xmlRelaxNGPartitionPtr)
4081 xmlMalloc(sizeof(xmlRelaxNGPartition));
4082 if (partitions == NULL)
4083 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00004084 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00004085 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004086 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004087 for (i = 0;i < nbgroups;i++) {
4088 group = groups[i];
4089 for (j = i+1;j < nbgroups;j++) {
4090 if (groups[j] == NULL)
4091 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004092
Daniel Veillardfd573f12003-03-16 17:52:32 +00004093 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
4094 groups[j]->defs);
4095 if (ret == 0) {
4096 if (ctxt->error != NULL)
4097 ctxt->error(ctxt->userData,
4098 "Element or text conflicts in interleave\n");
4099 ctxt->nbErrors++;
4100 }
4101 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
4102 groups[j]->attrs);
4103 if (ret == 0) {
4104 if (ctxt->error != NULL)
4105 ctxt->error(ctxt->userData,
4106 "Attributes conflicts in interleave\n");
4107 ctxt->nbErrors++;
4108 }
4109 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004110 tmp = group->defs;
4111 if ((tmp != NULL) && (*tmp != NULL)) {
4112 while (*tmp != NULL) {
4113 if ((*tmp)->type == XML_RELAXNG_TEXT) {
4114 res = xmlHashAddEntry2(partitions->triage,
4115 BAD_CAST "#text", NULL,
4116 (void *)(i + 1));
4117 if (res != 0)
4118 is_determinist = -1;
4119 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
4120 ((*tmp)->name != NULL)) {
4121 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4122 res = xmlHashAddEntry2(partitions->triage,
4123 (*tmp)->name, NULL,
4124 (void *)(i + 1));
4125 else
4126 res = xmlHashAddEntry2(partitions->triage,
4127 (*tmp)->name, (*tmp)->ns,
4128 (void *)(i + 1));
4129 if (res != 0)
4130 is_determinist = -1;
4131 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
4132 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
4133 res = xmlHashAddEntry2(partitions->triage,
4134 BAD_CAST "#any", NULL,
4135 (void *)(i + 1));
4136 else
4137 res = xmlHashAddEntry2(partitions->triage,
4138 BAD_CAST "#any", (*tmp)->ns,
4139 (void *)(i + 1));
4140 if ((*tmp)->nameClass != NULL)
4141 is_determinist = 2;
4142 if (res != 0)
4143 is_determinist = -1;
4144 } else {
4145 is_determinist = -1;
4146 }
4147 tmp++;
4148 }
4149 } else {
4150 is_determinist = 0;
4151 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004152 }
4153 partitions->groups = groups;
4154
4155 /*
4156 * and save the partition list back in the def
4157 */
4158 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00004159 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00004160 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00004161 if (is_determinist == 1)
4162 partitions->flags = IS_DETERMINIST;
4163 if (is_determinist == 2)
4164 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004165 return;
4166
4167error:
4168 if (ctxt->error != NULL)
4169 ctxt->error(ctxt->userData,
4170 "Out of memory in interleave computation\n");
4171 ctxt->nbErrors++;
4172 if (groups != NULL) {
4173 for (i = 0;i < nbgroups;i++)
4174 if (groups[i] != NULL) {
4175 if (groups[i]->defs != NULL)
4176 xmlFree(groups[i]->defs);
4177 xmlFree(groups[i]);
4178 }
4179 xmlFree(groups);
4180 }
4181 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004182}
4183
4184/**
4185 * xmlRelaxNGParseInterleave:
4186 * @ctxt: a Relax-NG parser context
4187 * @node: the data node.
4188 *
4189 * parse the content of a RelaxNG interleave node.
4190 *
4191 * Returns the definition pointer or NULL in case of error
4192 */
4193static xmlRelaxNGDefinePtr
4194xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4195 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004196 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004197 xmlNodePtr child;
4198
Daniel Veillardfd573f12003-03-16 17:52:32 +00004199 def = xmlRelaxNGNewDefine(ctxt, node);
4200 if (def == NULL) {
4201 return(NULL);
4202 }
4203 def->type = XML_RELAXNG_INTERLEAVE;
4204
4205 if (ctxt->interleaves == NULL)
4206 ctxt->interleaves = xmlHashCreate(10);
4207 if (ctxt->interleaves == NULL) {
4208 if (ctxt->error != NULL)
4209 ctxt->error(ctxt->userData,
4210 "Failed to create interleaves hash table\n");
4211 ctxt->nbErrors++;
4212 } else {
4213 char name[32];
4214
4215 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
4216 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
4217 if (ctxt->error != NULL)
4218 ctxt->error(ctxt->userData,
4219 "Failed to add %s to hash table\n", name);
4220 ctxt->nbErrors++;
4221 }
4222 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004223 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00004224 if (child == NULL) {
4225 if (ctxt->error != NULL)
4226 ctxt->error(ctxt->userData, "Element interleave is empty\n");
4227 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00004228 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004229 while (child != NULL) {
4230 if (IS_RELAXNG(child, "element")) {
4231 cur = xmlRelaxNGParseElement(ctxt, child);
4232 } else {
4233 cur = xmlRelaxNGParsePattern(ctxt, child);
4234 }
4235 if (cur != NULL) {
4236 cur->parent = def;
4237 if (last == NULL) {
4238 def->content = last = cur;
4239 } else {
4240 last->next = cur;
4241 last = cur;
4242 }
4243 }
4244 child = child->next;
4245 }
4246
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004247 return(def);
4248}
Daniel Veillard6eadf632003-01-23 18:29:16 +00004249
4250/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004251 * xmlRelaxNGParseInclude:
4252 * @ctxt: a Relax-NG parser context
4253 * @node: the include node
4254 *
4255 * Integrate the content of an include node in the current grammar
4256 *
4257 * Returns 0 in case of success or -1 in case of error
4258 */
4259static int
4260xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4261 xmlRelaxNGIncludePtr incl;
4262 xmlNodePtr root;
4263 int ret = 0, tmp;
4264
4265 incl = node->_private;
4266 if (incl == NULL) {
4267 if (ctxt->error != NULL)
4268 ctxt->error(ctxt->userData,
4269 "Include node has no data\n");
4270 ctxt->nbErrors++;
4271 return(-1);
4272 }
4273 root = xmlDocGetRootElement(incl->doc);
4274 if (root == NULL) {
4275 if (ctxt->error != NULL)
4276 ctxt->error(ctxt->userData,
4277 "Include document is empty\n");
4278 ctxt->nbErrors++;
4279 return(-1);
4280 }
4281 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
4282 if (ctxt->error != NULL)
4283 ctxt->error(ctxt->userData,
4284 "Include document root is not a grammar\n");
4285 ctxt->nbErrors++;
4286 return(-1);
4287 }
4288
4289 /*
4290 * Merge the definition from both the include and the internal list
4291 */
4292 if (root->children != NULL) {
4293 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
4294 if (tmp != 0)
4295 ret = -1;
4296 }
4297 if (node->children != NULL) {
4298 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
4299 if (tmp != 0)
4300 ret = -1;
4301 }
4302 return(ret);
4303}
4304
4305/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00004306 * xmlRelaxNGParseDefine:
4307 * @ctxt: a Relax-NG parser context
4308 * @node: the define node
4309 *
4310 * parse the content of a RelaxNG define element node.
4311 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004312 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00004313 */
4314static int
4315xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4316 xmlChar *name;
4317 int ret = 0, tmp;
4318 xmlRelaxNGDefinePtr def;
4319 const xmlChar *olddefine;
4320
4321 name = xmlGetProp(node, BAD_CAST "name");
4322 if (name == NULL) {
4323 if (ctxt->error != NULL)
4324 ctxt->error(ctxt->userData,
4325 "define has no name\n");
4326 ctxt->nbErrors++;
4327 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004328 xmlRelaxNGNormExtSpace(name);
4329 if (xmlValidateNCName(name, 0)) {
4330 if (ctxt->error != NULL)
4331 ctxt->error(ctxt->userData,
4332 "define name '%s' is not an NCName\n",
4333 name);
4334 ctxt->nbErrors++;
4335 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004336 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004337 if (def == NULL) {
4338 xmlFree(name);
4339 return(-1);
4340 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004341 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004342 def->name = name;
4343 if (node->children == NULL) {
4344 if (ctxt->error != NULL)
4345 ctxt->error(ctxt->userData,
4346 "define has no children\n");
4347 ctxt->nbErrors++;
4348 } else {
4349 olddefine = ctxt->define;
4350 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00004351 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00004352 ctxt->define = olddefine;
4353 }
4354 if (ctxt->grammar->defs == NULL)
4355 ctxt->grammar->defs = xmlHashCreate(10);
4356 if (ctxt->grammar->defs == NULL) {
4357 if (ctxt->error != NULL)
4358 ctxt->error(ctxt->userData,
4359 "Could not create definition hash\n");
4360 ctxt->nbErrors++;
4361 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004362 } else {
4363 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
4364 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00004365 xmlRelaxNGDefinePtr prev;
4366
4367 prev = xmlHashLookup(ctxt->grammar->defs, name);
4368 if (prev == NULL) {
4369 if (ctxt->error != NULL)
4370 ctxt->error(ctxt->userData,
4371 "Internal error on define aggregation of %s\n",
4372 name);
4373 ctxt->nbErrors++;
4374 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00004375 } else {
4376 while (prev->nextHash != NULL)
4377 prev = prev->nextHash;
4378 prev->nextHash = def;
4379 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004380 }
4381 }
4382 }
4383 return(ret);
4384}
4385
4386/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004387 * xmlRelaxNGProcessExternalRef:
4388 * @ctxt: the parser context
4389 * @node: the externlRef node
4390 *
4391 * Process and compile an externlRef node
4392 *
4393 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4394 */
4395static xmlRelaxNGDefinePtr
4396xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4397 xmlRelaxNGDocumentPtr docu;
4398 xmlNodePtr root, tmp;
4399 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004400 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004401 xmlRelaxNGDefinePtr def;
4402
4403 docu = node->_private;
4404 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004405 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004406 if (def == NULL)
4407 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004408 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004409
4410 if (docu->content == NULL) {
4411 /*
4412 * Then do the parsing for good
4413 */
4414 root = xmlDocGetRootElement(docu->doc);
4415 if (root == NULL) {
4416 if (ctxt->error != NULL)
4417 ctxt->error(ctxt->userData,
4418 "xmlRelaxNGParse: %s is empty\n",
4419 ctxt->URL);
4420 ctxt->nbErrors++;
4421 return (NULL);
4422 }
4423 /*
4424 * ns transmission rules
4425 */
4426 ns = xmlGetProp(root, BAD_CAST "ns");
4427 if (ns == NULL) {
4428 tmp = node;
4429 while ((tmp != NULL) &&
4430 (tmp->type == XML_ELEMENT_NODE)) {
4431 ns = xmlGetProp(tmp, BAD_CAST "ns");
4432 if (ns != NULL) {
4433 break;
4434 }
4435 tmp = tmp->parent;
4436 }
4437 if (ns != NULL) {
4438 xmlSetProp(root, BAD_CAST "ns", ns);
4439 newNs = 1;
4440 xmlFree(ns);
4441 }
4442 } else {
4443 xmlFree(ns);
4444 }
4445
4446 /*
4447 * Parsing to get a precompiled schemas.
4448 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004449 oldflags = ctxt->flags;
4450 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004451 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004452 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004453 if ((docu->schema != NULL) &&
4454 (docu->schema->topgrammar != NULL)) {
4455 docu->content = docu->schema->topgrammar->start;
4456 }
4457
4458 /*
4459 * the externalRef may be reused in a different ns context
4460 */
4461 if (newNs == 1) {
4462 xmlUnsetProp(root, BAD_CAST "ns");
4463 }
4464 }
4465 def->content = docu->content;
4466 } else {
4467 def = NULL;
4468 }
4469 return(def);
4470}
4471
4472/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004473 * xmlRelaxNGParsePattern:
4474 * @ctxt: a Relax-NG parser context
4475 * @node: the pattern node.
4476 *
4477 * parse the content of a RelaxNG pattern node.
4478 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004479 * Returns the definition pointer or NULL in case of error or if no
4480 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004481 */
4482static xmlRelaxNGDefinePtr
4483xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4484 xmlRelaxNGDefinePtr def = NULL;
4485
Daniel Veillardd2298792003-02-14 16:54:11 +00004486 if (node == NULL) {
4487 return(NULL);
4488 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004489 if (IS_RELAXNG(node, "element")) {
4490 def = xmlRelaxNGParseElement(ctxt, node);
4491 } else if (IS_RELAXNG(node, "attribute")) {
4492 def = xmlRelaxNGParseAttribute(ctxt, node);
4493 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004494 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004495 if (def == NULL)
4496 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004497 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004498 if (node->children != NULL) {
4499 if (ctxt->error != NULL)
4500 ctxt->error(ctxt->userData, "empty: had a child node\n");
4501 ctxt->nbErrors++;
4502 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004503 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004504 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004505 if (def == NULL)
4506 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004507 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004508 if (node->children != NULL) {
4509 if (ctxt->error != NULL)
4510 ctxt->error(ctxt->userData, "text: had a child node\n");
4511 ctxt->nbErrors++;
4512 }
4513 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004514 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004515 if (def == NULL)
4516 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004517 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004518 if (node->children == NULL) {
4519 if (ctxt->error != NULL)
4520 ctxt->error(ctxt->userData,
4521 "Element %s is empty\n", node->name);
4522 ctxt->nbErrors++;
4523 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004524 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004525 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004526 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004527 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004528 if (def == NULL)
4529 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004530 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004531 if (node->children == NULL) {
4532 if (ctxt->error != NULL)
4533 ctxt->error(ctxt->userData,
4534 "Element %s is empty\n", node->name);
4535 ctxt->nbErrors++;
4536 } else {
4537 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4538 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004539 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004540 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004541 if (def == NULL)
4542 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004543 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004544 if (node->children == NULL) {
4545 if (ctxt->error != NULL)
4546 ctxt->error(ctxt->userData,
4547 "Element %s is empty\n", node->name);
4548 ctxt->nbErrors++;
4549 } else {
4550 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4551 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004552 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004553 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004554 if (def == NULL)
4555 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004556 def->type = XML_RELAXNG_CHOICE;
4557 if (node->children == NULL) {
4558 if (ctxt->error != NULL)
4559 ctxt->error(ctxt->userData,
4560 "Element %s is empty\n", node->name);
4561 ctxt->nbErrors++;
4562 } else {
4563 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4564 }
4565 } else if (IS_RELAXNG(node, "group")) {
4566 def = xmlRelaxNGNewDefine(ctxt, node);
4567 if (def == NULL)
4568 return(NULL);
4569 def->type = XML_RELAXNG_GROUP;
4570 if (node->children == NULL) {
4571 if (ctxt->error != NULL)
4572 ctxt->error(ctxt->userData,
4573 "Element %s is empty\n", node->name);
4574 ctxt->nbErrors++;
4575 } else {
4576 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4577 }
4578 } else if (IS_RELAXNG(node, "ref")) {
4579 def = xmlRelaxNGNewDefine(ctxt, node);
4580 if (def == NULL)
4581 return(NULL);
4582 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004583 def->name = xmlGetProp(node, BAD_CAST "name");
4584 if (def->name == NULL) {
4585 if (ctxt->error != NULL)
4586 ctxt->error(ctxt->userData,
4587 "ref has no name\n");
4588 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004589 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004590 xmlRelaxNGNormExtSpace(def->name);
4591 if (xmlValidateNCName(def->name, 0)) {
4592 if (ctxt->error != NULL)
4593 ctxt->error(ctxt->userData,
4594 "ref name '%s' is not an NCName\n",
4595 def->name);
4596 ctxt->nbErrors++;
4597 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004598 }
4599 if (node->children != NULL) {
4600 if (ctxt->error != NULL)
4601 ctxt->error(ctxt->userData,
4602 "ref is not empty\n");
4603 ctxt->nbErrors++;
4604 }
4605 if (ctxt->grammar->refs == NULL)
4606 ctxt->grammar->refs = xmlHashCreate(10);
4607 if (ctxt->grammar->refs == NULL) {
4608 if (ctxt->error != NULL)
4609 ctxt->error(ctxt->userData,
4610 "Could not create references hash\n");
4611 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004612 def = NULL;
4613 } else {
4614 int tmp;
4615
4616 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4617 if (tmp < 0) {
4618 xmlRelaxNGDefinePtr prev;
4619
4620 prev = (xmlRelaxNGDefinePtr)
4621 xmlHashLookup(ctxt->grammar->refs, def->name);
4622 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004623 if (def->name != NULL) {
4624 if (ctxt->error != NULL)
4625 ctxt->error(ctxt->userData,
4626 "Error refs definitions '%s'\n",
4627 def->name);
4628 } else {
4629 if (ctxt->error != NULL)
4630 ctxt->error(ctxt->userData,
4631 "Error refs definitions\n");
4632 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004633 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004634 def = NULL;
4635 } else {
4636 def->nextHash = prev->nextHash;
4637 prev->nextHash = def;
4638 }
4639 }
4640 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004641 } else if (IS_RELAXNG(node, "data")) {
4642 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004643 } else if (IS_RELAXNG(node, "value")) {
4644 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004645 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004646 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004647 if (def == NULL)
4648 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004649 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004650 if (node->children == NULL) {
4651 if (ctxt->error != NULL)
4652 ctxt->error(ctxt->userData,
4653 "Element %s is empty\n", node->name);
4654 ctxt->nbErrors++;
4655 } else {
4656 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4657 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004658 } else if (IS_RELAXNG(node, "interleave")) {
4659 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004660 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004661 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004662 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004663 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004664 if (def == NULL)
4665 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004666 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004667 if (node->children != NULL) {
4668 if (ctxt->error != NULL)
4669 ctxt->error(ctxt->userData,
4670 "xmlRelaxNGParse: notAllowed element is not empty\n");
4671 ctxt->nbErrors++;
4672 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004673 } else if (IS_RELAXNG(node, "grammar")) {
4674 xmlRelaxNGGrammarPtr grammar, old;
4675 xmlRelaxNGGrammarPtr oldparent;
4676
Daniel Veillardc482e262003-02-26 14:48:48 +00004677#ifdef DEBUG_GRAMMAR
4678 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4679#endif
4680
Daniel Veillard419a7682003-02-03 23:22:49 +00004681 oldparent = ctxt->parentgrammar;
4682 old = ctxt->grammar;
4683 ctxt->parentgrammar = old;
4684 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4685 if (old != NULL) {
4686 ctxt->grammar = old;
4687 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004688#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004689 if (grammar != NULL) {
4690 grammar->next = old->next;
4691 old->next = grammar;
4692 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004693#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004694 }
4695 if (grammar != NULL)
4696 def = grammar->start;
4697 else
4698 def = NULL;
4699 } else if (IS_RELAXNG(node, "parentRef")) {
4700 if (ctxt->parentgrammar == NULL) {
4701 if (ctxt->error != NULL)
4702 ctxt->error(ctxt->userData,
4703 "Use of parentRef without a parent grammar\n");
4704 ctxt->nbErrors++;
4705 return(NULL);
4706 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004707 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004708 if (def == NULL)
4709 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004710 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004711 def->name = xmlGetProp(node, BAD_CAST "name");
4712 if (def->name == NULL) {
4713 if (ctxt->error != NULL)
4714 ctxt->error(ctxt->userData,
4715 "parentRef has no name\n");
4716 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004717 } else {
4718 xmlRelaxNGNormExtSpace(def->name);
4719 if (xmlValidateNCName(def->name, 0)) {
4720 if (ctxt->error != NULL)
4721 ctxt->error(ctxt->userData,
4722 "parentRef name '%s' is not an NCName\n",
4723 def->name);
4724 ctxt->nbErrors++;
4725 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004726 }
4727 if (node->children != NULL) {
4728 if (ctxt->error != NULL)
4729 ctxt->error(ctxt->userData,
4730 "parentRef is not empty\n");
4731 ctxt->nbErrors++;
4732 }
4733 if (ctxt->parentgrammar->refs == NULL)
4734 ctxt->parentgrammar->refs = xmlHashCreate(10);
4735 if (ctxt->parentgrammar->refs == NULL) {
4736 if (ctxt->error != NULL)
4737 ctxt->error(ctxt->userData,
4738 "Could not create references hash\n");
4739 ctxt->nbErrors++;
4740 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004741 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004742 int tmp;
4743
4744 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4745 if (tmp < 0) {
4746 xmlRelaxNGDefinePtr prev;
4747
4748 prev = (xmlRelaxNGDefinePtr)
4749 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4750 if (prev == NULL) {
4751 if (ctxt->error != NULL)
4752 ctxt->error(ctxt->userData,
4753 "Internal error parentRef definitions '%s'\n",
4754 def->name);
4755 ctxt->nbErrors++;
4756 def = NULL;
4757 } else {
4758 def->nextHash = prev->nextHash;
4759 prev->nextHash = def;
4760 }
4761 }
4762 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004763 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004764 if (node->children == NULL) {
4765 if (ctxt->error != NULL)
4766 ctxt->error(ctxt->userData,
4767 "Mixed is empty\n");
4768 ctxt->nbErrors++;
4769 def = NULL;
4770 } else {
4771 def = xmlRelaxNGParseInterleave(ctxt, node);
4772 if (def != NULL) {
4773 xmlRelaxNGDefinePtr tmp;
4774
4775 if ((def->content != NULL) && (def->content->next != NULL)) {
4776 tmp = xmlRelaxNGNewDefine(ctxt, node);
4777 if (tmp != NULL) {
4778 tmp->type = XML_RELAXNG_GROUP;
4779 tmp->content = def->content;
4780 def->content = tmp;
4781 }
4782 }
4783
4784 tmp = xmlRelaxNGNewDefine(ctxt, node);
4785 if (tmp == NULL)
4786 return(def);
4787 tmp->type = XML_RELAXNG_TEXT;
4788 tmp->next = def->content;
4789 def->content = tmp;
4790 }
4791 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004792 } else {
4793 if (ctxt->error != NULL)
4794 ctxt->error(ctxt->userData,
4795 "Unexpected node %s is not a pattern\n",
4796 node->name);
4797 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004798 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004799 }
4800 return(def);
4801}
4802
4803/**
4804 * xmlRelaxNGParseAttribute:
4805 * @ctxt: a Relax-NG parser context
4806 * @node: the element node
4807 *
4808 * parse the content of a RelaxNG attribute node.
4809 *
4810 * Returns the definition pointer or NULL in case of error.
4811 */
4812static xmlRelaxNGDefinePtr
4813xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004814 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004815 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004816 int old_flags;
4817
Daniel Veillardfd573f12003-03-16 17:52:32 +00004818 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004819 if (ret == NULL)
4820 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004821 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004822 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004823 child = node->children;
4824 if (child == NULL) {
4825 if (ctxt->error != NULL)
4826 ctxt->error(ctxt->userData,
4827 "xmlRelaxNGParseattribute: attribute has no children\n");
4828 ctxt->nbErrors++;
4829 return(ret);
4830 }
4831 old_flags = ctxt->flags;
4832 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004833 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4834 if (cur != NULL)
4835 child = child->next;
4836
Daniel Veillardd2298792003-02-14 16:54:11 +00004837 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004838 cur = xmlRelaxNGParsePattern(ctxt, child);
4839 if (cur != NULL) {
4840 switch (cur->type) {
4841 case XML_RELAXNG_EMPTY:
4842 case XML_RELAXNG_NOT_ALLOWED:
4843 case XML_RELAXNG_TEXT:
4844 case XML_RELAXNG_ELEMENT:
4845 case XML_RELAXNG_DATATYPE:
4846 case XML_RELAXNG_VALUE:
4847 case XML_RELAXNG_LIST:
4848 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004849 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004850 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004851 case XML_RELAXNG_DEF:
4852 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004853 case XML_RELAXNG_ZEROORMORE:
4854 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004855 case XML_RELAXNG_CHOICE:
4856 case XML_RELAXNG_GROUP:
4857 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004858 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004859 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004860 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004861 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004862 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004863 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004864 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004865 if (ctxt->error != NULL)
4866 ctxt->error(ctxt->userData,
4867 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004868 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004869 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004870 case XML_RELAXNG_NOOP:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004871 if (ctxt->error != NULL)
4872 ctxt->error(ctxt->userData,
Daniel Veillardac297932003-04-17 12:55:35 +00004873 "RNG Internal error, noop found in attribute\n");
Daniel Veillard77648bb2003-02-20 15:03:22 +00004874 ctxt->nbErrors++;
4875 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004876 }
4877 }
4878 child = child->next;
4879 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004880 if (child != NULL) {
4881 if (ctxt->error != NULL)
4882 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4883 ctxt->nbErrors++;
4884 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004885 ctxt->flags = old_flags;
4886 return(ret);
4887}
4888
4889/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004890 * xmlRelaxNGParseExceptNameClass:
4891 * @ctxt: a Relax-NG parser context
4892 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004893 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004894 *
4895 * parse the content of a RelaxNG nameClass node.
4896 *
4897 * Returns the definition pointer or NULL in case of error.
4898 */
4899static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004900xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4901 xmlNodePtr node, int attr) {
4902 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4903 xmlNodePtr child;
4904
Daniel Veillardd2298792003-02-14 16:54:11 +00004905 if (!IS_RELAXNG(node, "except")) {
4906 if (ctxt->error != NULL)
4907 ctxt->error(ctxt->userData,
4908 "Expecting an except node\n");
4909 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004910 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004911 }
4912 if (node->next != NULL) {
4913 if (ctxt->error != NULL)
4914 ctxt->error(ctxt->userData,
4915 "exceptNameClass allows only a single except node\n");
4916 ctxt->nbErrors++;
4917 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004918 if (node->children == NULL) {
4919 if (ctxt->error != NULL)
4920 ctxt->error(ctxt->userData,
4921 "except has no content\n");
4922 ctxt->nbErrors++;
4923 return(NULL);
4924 }
4925
Daniel Veillardfd573f12003-03-16 17:52:32 +00004926 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004927 if (ret == NULL)
4928 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004929 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004930 child = node->children;
4931 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004932 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004933 if (cur == NULL)
4934 break;
4935 if (attr)
4936 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004937 else
4938 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004939
Daniel Veillard419a7682003-02-03 23:22:49 +00004940 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004941 if (last == NULL) {
4942 ret->content = cur;
4943 } else {
4944 last->next = cur;
4945 }
4946 last = cur;
4947 }
4948 child = child->next;
4949 }
4950
4951 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004952}
4953
4954/**
4955 * xmlRelaxNGParseNameClass:
4956 * @ctxt: a Relax-NG parser context
4957 * @node: the nameClass node
4958 * @def: the current definition
4959 *
4960 * parse the content of a RelaxNG nameClass node.
4961 *
4962 * Returns the definition pointer or NULL in case of error.
4963 */
4964static xmlRelaxNGDefinePtr
4965xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4966 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004967 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004968 xmlChar *val;
4969
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004970 ret = def;
4971 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4972 (IS_RELAXNG(node, "nsName"))) {
4973 if ((def->type != XML_RELAXNG_ELEMENT) &&
4974 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004975 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004976 if (ret == NULL)
4977 return(NULL);
4978 ret->parent = def;
4979 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4980 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004981 else
4982 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004983 }
4984 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004985 if (IS_RELAXNG(node, "name")) {
4986 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004987 xmlRelaxNGNormExtSpace(val);
4988 if (xmlValidateNCName(val, 0)) {
4989 if (ctxt->error != NULL) {
4990 if (node->parent != NULL)
4991 ctxt->error(ctxt->userData,
4992 "Element %s name '%s' is not an NCName\n",
4993 node->parent->name, val);
4994 else
4995 ctxt->error(ctxt->userData,
4996 "name '%s' is not an NCName\n",
4997 val);
4998 }
4999 ctxt->nbErrors++;
5000 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005001 ret->name = val;
5002 val = xmlGetProp(node, BAD_CAST "ns");
5003 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00005004 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5005 (val != NULL) &&
5006 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5007 ctxt->error(ctxt->userData,
5008 "Attribute with namespace '%s' is not allowed\n",
5009 val);
5010 ctxt->nbErrors++;
5011 }
5012 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5013 (val != NULL) &&
5014 (val[0] == 0) &&
5015 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
5016 ctxt->error(ctxt->userData,
5017 "Attribute with QName 'xmlns' is not allowed\n",
5018 val);
5019 ctxt->nbErrors++;
5020 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005021 } else if (IS_RELAXNG(node, "anyName")) {
5022 ret->name = NULL;
5023 ret->ns = NULL;
5024 if (node->children != NULL) {
5025 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00005026 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5027 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005028 }
5029 } else if (IS_RELAXNG(node, "nsName")) {
5030 ret->name = NULL;
5031 ret->ns = xmlGetProp(node, BAD_CAST "ns");
5032 if (ret->ns == NULL) {
5033 if (ctxt->error != NULL)
5034 ctxt->error(ctxt->userData,
5035 "nsName has no ns attribute\n");
5036 ctxt->nbErrors++;
5037 }
Daniel Veillard416589a2003-02-17 17:25:42 +00005038 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
5039 (ret->ns != NULL) &&
5040 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
5041 ctxt->error(ctxt->userData,
5042 "Attribute with namespace '%s' is not allowed\n",
5043 ret->ns);
5044 ctxt->nbErrors++;
5045 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005046 if (node->children != NULL) {
5047 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00005048 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
5049 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005050 }
5051 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005052 xmlNodePtr child;
5053 xmlRelaxNGDefinePtr last = NULL;
5054
5055 ret = xmlRelaxNGNewDefine(ctxt, node);
5056 if (ret == NULL)
5057 return(NULL);
5058 ret->parent = def;
5059 ret->type = XML_RELAXNG_CHOICE;
5060
Daniel Veillardd2298792003-02-14 16:54:11 +00005061 if (node->children == NULL) {
5062 if (ctxt->error != NULL)
5063 ctxt->error(ctxt->userData,
5064 "Element choice is empty\n");
5065 ctxt->nbErrors++;
5066 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005067
5068 child = node->children;
5069 while (child != NULL) {
5070 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
5071 if (tmp != NULL) {
5072 if (last == NULL) {
5073 last = ret->nameClass = tmp;
5074 } else {
5075 last->next = tmp;
5076 last = tmp;
5077 }
5078 }
5079 child = child->next;
5080 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005081 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005082 } else {
5083 if (ctxt->error != NULL)
5084 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00005085 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005086 node->name);
5087 ctxt->nbErrors++;
5088 return(NULL);
5089 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00005090 if (ret != def) {
5091 if (def->nameClass == NULL) {
5092 def->nameClass = ret;
5093 } else {
5094 tmp = def->nameClass;
5095 while (tmp->next != NULL) {
5096 tmp = tmp->next;
5097 }
5098 tmp->next = ret;
5099 }
5100 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005101 return(ret);
5102}
5103
5104/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005105 * xmlRelaxNGParseElement:
5106 * @ctxt: a Relax-NG parser context
5107 * @node: the element node
5108 *
5109 * parse the content of a RelaxNG element node.
5110 *
5111 * Returns the definition pointer or NULL in case of error.
5112 */
5113static xmlRelaxNGDefinePtr
5114xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5115 xmlRelaxNGDefinePtr ret, cur, last;
5116 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005117 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005118
Daniel Veillardfd573f12003-03-16 17:52:32 +00005119 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005120 if (ret == NULL)
5121 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005122 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005123 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005124 child = node->children;
5125 if (child == NULL) {
5126 if (ctxt->error != NULL)
5127 ctxt->error(ctxt->userData,
5128 "xmlRelaxNGParseElement: element has no children\n");
5129 ctxt->nbErrors++;
5130 return(ret);
5131 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00005132 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
5133 if (cur != NULL)
5134 child = child->next;
5135
Daniel Veillard6eadf632003-01-23 18:29:16 +00005136 if (child == NULL) {
5137 if (ctxt->error != NULL)
5138 ctxt->error(ctxt->userData,
5139 "xmlRelaxNGParseElement: element has no content\n");
5140 ctxt->nbErrors++;
5141 return(ret);
5142 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005143 olddefine = ctxt->define;
5144 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005145 last = NULL;
5146 while (child != NULL) {
5147 cur = xmlRelaxNGParsePattern(ctxt, child);
5148 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005149 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005150 switch (cur->type) {
5151 case XML_RELAXNG_EMPTY:
5152 case XML_RELAXNG_NOT_ALLOWED:
5153 case XML_RELAXNG_TEXT:
5154 case XML_RELAXNG_ELEMENT:
5155 case XML_RELAXNG_DATATYPE:
5156 case XML_RELAXNG_VALUE:
5157 case XML_RELAXNG_LIST:
5158 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00005159 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005160 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005161 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005162 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005163 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00005164 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00005165 case XML_RELAXNG_CHOICE:
5166 case XML_RELAXNG_GROUP:
5167 case XML_RELAXNG_INTERLEAVE:
5168 if (last == NULL) {
5169 ret->content = last = cur;
5170 } else {
5171 if ((last->type == XML_RELAXNG_ELEMENT) &&
5172 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005173 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005174 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005175 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005176 ret->content->content = last;
5177 } else {
5178 ret->content = last;
5179 }
5180 }
5181 last->next = cur;
5182 last = cur;
5183 }
5184 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005185 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardce192eb2003-04-16 15:58:05 +00005186 /* HERE !!! */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005187 cur->next = ret->attrs;
5188 ret->attrs = cur;
5189 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005190 case XML_RELAXNG_START:
Daniel Veillardac297932003-04-17 12:55:35 +00005191 if (ctxt->error != NULL)
5192 ctxt->error(ctxt->userData,
5193 "RNG Internal error, start found in element\n");
5194 ctxt->nbErrors++;
5195 break;
Daniel Veillard8fe98712003-02-19 00:19:14 +00005196 case XML_RELAXNG_PARAM:
Daniel Veillardac297932003-04-17 12:55:35 +00005197 if (ctxt->error != NULL)
5198 ctxt->error(ctxt->userData,
5199 "RNG Internal error, param found in element\n");
5200 ctxt->nbErrors++;
5201 break;
Daniel Veillard144fae12003-02-03 13:17:57 +00005202 case XML_RELAXNG_EXCEPT:
Daniel Veillardac297932003-04-17 12:55:35 +00005203 if (ctxt->error != NULL)
5204 ctxt->error(ctxt->userData,
5205 "RNG Internal error, except found in element\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005206 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00005207 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00005208 case XML_RELAXNG_NOOP:
Daniel Veillard77648bb2003-02-20 15:03:22 +00005209 if (ctxt->error != NULL)
5210 ctxt->error(ctxt->userData,
Daniel Veillardac297932003-04-17 12:55:35 +00005211 "RNG Internal error, noop found in element\n");
Daniel Veillard77648bb2003-02-20 15:03:22 +00005212 ctxt->nbErrors++;
5213 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005214 }
5215 }
5216 child = child->next;
5217 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005218 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005219 return(ret);
5220}
5221
5222/**
5223 * xmlRelaxNGParsePatterns:
5224 * @ctxt: a Relax-NG parser context
5225 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00005226 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00005227 *
5228 * parse the content of a RelaxNG start node.
5229 *
5230 * Returns the definition pointer or NULL in case of error.
5231 */
5232static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00005233xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
5234 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005235 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005236
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005237 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005238 while (nodes != NULL) {
5239 if (IS_RELAXNG(nodes, "element")) {
5240 cur = xmlRelaxNGParseElement(ctxt, nodes);
5241 if (def == NULL) {
5242 def = last = cur;
5243 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00005244 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
5245 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005246 def = xmlRelaxNGNewDefine(ctxt, nodes);
5247 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005248 def->content = last;
5249 }
5250 last->next = cur;
5251 last = cur;
5252 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00005253 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005254 } else {
5255 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00005256 if (cur != NULL) {
5257 if (def == NULL) {
5258 def = last = cur;
5259 } else {
5260 last->next = cur;
5261 last = cur;
5262 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005263 }
5264 }
5265 nodes = nodes->next;
5266 }
5267 return(def);
5268}
5269
5270/**
5271 * xmlRelaxNGParseStart:
5272 * @ctxt: a Relax-NG parser context
5273 * @nodes: start children nodes
5274 *
5275 * parse the content of a RelaxNG start node.
5276 *
5277 * Returns 0 in case of success, -1 in case of error
5278 */
5279static int
5280xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5281 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005282 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005283
Daniel Veillardd2298792003-02-14 16:54:11 +00005284 if (nodes == NULL) {
5285 if (ctxt->error != NULL)
5286 ctxt->error(ctxt->userData,
5287 "start has no children\n");
5288 ctxt->nbErrors++;
5289 return(-1);
5290 }
5291 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005292 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005293 if (def == NULL)
5294 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005295 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00005296 if (nodes->children != NULL) {
5297 if (ctxt->error != NULL)
5298 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005299 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005300 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005301 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005302 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00005303 if (def == NULL)
5304 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00005305 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00005306 if (nodes->children != NULL) {
5307 if (ctxt->error != NULL)
5308 ctxt->error(ctxt->userData,
5309 "element notAllowed is not empty\n");
5310 ctxt->nbErrors++;
5311 }
Daniel Veillardd2298792003-02-14 16:54:11 +00005312 } else {
5313 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00005314 }
5315 if (ctxt->grammar->start != NULL) {
5316 last = ctxt->grammar->start;
5317 while (last->next != NULL)
5318 last = last->next;
5319 last->next = def;
5320 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00005321 ctxt->grammar->start = def;
5322 }
5323 nodes = nodes->next;
5324 if (nodes != NULL) {
5325 if (ctxt->error != NULL)
5326 ctxt->error(ctxt->userData,
5327 "start more than one children\n");
5328 ctxt->nbErrors++;
5329 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005330 }
5331 return(ret);
5332}
5333
5334/**
5335 * xmlRelaxNGParseGrammarContent:
5336 * @ctxt: a Relax-NG parser context
5337 * @nodes: grammar children nodes
5338 *
5339 * parse the content of a RelaxNG grammar node.
5340 *
5341 * Returns 0 in case of success, -1 in case of error
5342 */
5343static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005344xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005345{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005346 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005347
5348 if (nodes == NULL) {
5349 if (ctxt->error != NULL)
5350 ctxt->error(ctxt->userData,
5351 "grammar has no children\n");
5352 ctxt->nbErrors++;
5353 return(-1);
5354 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005355 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005356 if (IS_RELAXNG(nodes, "start")) {
5357 if (nodes->children == NULL) {
5358 if (ctxt->error != NULL)
5359 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00005360 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005361 ctxt->nbErrors++;
5362 } else {
5363 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
5364 if (tmp != 0)
5365 ret = -1;
5366 }
5367 } else if (IS_RELAXNG(nodes, "define")) {
5368 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
5369 if (tmp != 0)
5370 ret = -1;
5371 } else if (IS_RELAXNG(nodes, "include")) {
5372 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
5373 if (tmp != 0)
5374 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005375 } else {
5376 if (ctxt->error != NULL)
5377 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00005378 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005379 ctxt->nbErrors++;
5380 ret = -1;
5381 }
5382 nodes = nodes->next;
5383 }
5384 return (ret);
5385}
5386
5387/**
5388 * xmlRelaxNGCheckReference:
5389 * @ref: the ref
5390 * @ctxt: a Relax-NG parser context
5391 * @name: the name associated to the defines
5392 *
5393 * Applies the 4.17. combine attribute rule for all the define
5394 * element of a given grammar using the same name.
5395 */
5396static void
5397xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5398 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5399 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005400 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005401
5402 grammar = ctxt->grammar;
5403 if (grammar == NULL) {
5404 if (ctxt->error != NULL)
5405 ctxt->error(ctxt->userData,
5406 "Internal error: no grammar in CheckReference %s\n",
5407 name);
5408 ctxt->nbErrors++;
5409 return;
5410 }
5411 if (ref->content != NULL) {
5412 if (ctxt->error != NULL)
5413 ctxt->error(ctxt->userData,
5414 "Internal error: reference has content in CheckReference %s\n",
5415 name);
5416 ctxt->nbErrors++;
5417 return;
5418 }
5419 if (grammar->defs != NULL) {
5420 def = xmlHashLookup(grammar->defs, name);
5421 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00005422 cur = ref;
5423 while (cur != NULL) {
5424 cur->content = def;
5425 cur = cur->nextHash;
5426 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005427 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00005428 if (ctxt->error != NULL)
5429 ctxt->error(ctxt->userData,
5430 "Reference %s has no matching definition\n",
5431 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005432 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005433 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005434 } else {
5435 if (ctxt->error != NULL)
5436 ctxt->error(ctxt->userData,
5437 "Reference %s has no matching definition\n",
5438 name);
5439 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005440 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005441}
5442
5443/**
5444 * xmlRelaxNGCheckCombine:
5445 * @define: the define(s) list
5446 * @ctxt: a Relax-NG parser context
5447 * @name: the name associated to the defines
5448 *
5449 * Applies the 4.17. combine attribute rule for all the define
5450 * element of a given grammar using the same name.
5451 */
5452static void
5453xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5454 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5455 xmlChar *combine;
5456 int choiceOrInterleave = -1;
5457 int missing = 0;
5458 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5459
5460 if (define->nextHash == NULL)
5461 return;
5462 cur = define;
5463 while (cur != NULL) {
5464 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5465 if (combine != NULL) {
5466 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5467 if (choiceOrInterleave == -1)
5468 choiceOrInterleave = 1;
5469 else if (choiceOrInterleave == 0) {
5470 if (ctxt->error != NULL)
5471 ctxt->error(ctxt->userData,
5472 "Defines for %s use both 'choice' and 'interleave'\n",
5473 name);
5474 ctxt->nbErrors++;
5475 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005476 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005477 if (choiceOrInterleave == -1)
5478 choiceOrInterleave = 0;
5479 else if (choiceOrInterleave == 1) {
5480 if (ctxt->error != NULL)
5481 ctxt->error(ctxt->userData,
5482 "Defines for %s use both 'choice' and 'interleave'\n",
5483 name);
5484 ctxt->nbErrors++;
5485 }
5486 } else {
5487 if (ctxt->error != NULL)
5488 ctxt->error(ctxt->userData,
5489 "Defines for %s use unknown combine value '%s''\n",
5490 name, combine);
5491 ctxt->nbErrors++;
5492 }
5493 xmlFree(combine);
5494 } else {
5495 if (missing == 0)
5496 missing = 1;
5497 else {
5498 if (ctxt->error != NULL)
5499 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005500 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005501 name);
5502 ctxt->nbErrors++;
5503 }
5504 }
5505
5506 cur = cur->nextHash;
5507 }
5508#ifdef DEBUG
5509 xmlGenericError(xmlGenericErrorContext,
5510 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5511 name, choiceOrInterleave);
5512#endif
5513 if (choiceOrInterleave == -1)
5514 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005515 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005516 if (cur == NULL)
5517 return;
5518 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005519 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005520 else
5521 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005522 tmp = define;
5523 last = NULL;
5524 while (tmp != NULL) {
5525 if (tmp->content != NULL) {
5526 if (tmp->content->next != NULL) {
5527 /*
5528 * we need first to create a wrapper.
5529 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005530 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005531 if (tmp2 == NULL)
5532 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005533 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005534 tmp2->content = tmp->content;
5535 } else {
5536 tmp2 = tmp->content;
5537 }
5538 if (last == NULL) {
5539 cur->content = tmp2;
5540 } else {
5541 last->next = tmp2;
5542 }
5543 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005544 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005545 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005546 tmp = tmp->nextHash;
5547 }
5548 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005549 if (choiceOrInterleave == 0) {
5550 if (ctxt->interleaves == NULL)
5551 ctxt->interleaves = xmlHashCreate(10);
5552 if (ctxt->interleaves == NULL) {
5553 if (ctxt->error != NULL)
5554 ctxt->error(ctxt->userData,
5555 "Failed to create interleaves hash table\n");
5556 ctxt->nbErrors++;
5557 } else {
5558 char tmpname[32];
5559
5560 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5561 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5562 if (ctxt->error != NULL)
5563 ctxt->error(ctxt->userData,
5564 "Failed to add %s to hash table\n", tmpname);
5565 ctxt->nbErrors++;
5566 }
5567 }
5568 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005569}
5570
5571/**
5572 * xmlRelaxNGCombineStart:
5573 * @ctxt: a Relax-NG parser context
5574 * @grammar: the grammar
5575 *
5576 * Applies the 4.17. combine rule for all the start
5577 * element of a given grammar.
5578 */
5579static void
5580xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5581 xmlRelaxNGGrammarPtr grammar) {
5582 xmlRelaxNGDefinePtr starts;
5583 xmlChar *combine;
5584 int choiceOrInterleave = -1;
5585 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005586 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005587
Daniel Veillard2df2de22003-02-17 23:34:33 +00005588 starts = grammar->start;
5589 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005590 return;
5591 cur = starts;
5592 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005593 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5594 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5595 combine = NULL;
5596 if (ctxt->error != NULL)
5597 ctxt->error(ctxt->userData,
5598 "Internal error: start element not found\n");
5599 ctxt->nbErrors++;
5600 } else {
5601 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5602 }
5603
Daniel Veillard6eadf632003-01-23 18:29:16 +00005604 if (combine != NULL) {
5605 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5606 if (choiceOrInterleave == -1)
5607 choiceOrInterleave = 1;
5608 else if (choiceOrInterleave == 0) {
5609 if (ctxt->error != NULL)
5610 ctxt->error(ctxt->userData,
5611 "<start> use both 'choice' and 'interleave'\n");
5612 ctxt->nbErrors++;
5613 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005614 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005615 if (choiceOrInterleave == -1)
5616 choiceOrInterleave = 0;
5617 else if (choiceOrInterleave == 1) {
5618 if (ctxt->error != NULL)
5619 ctxt->error(ctxt->userData,
5620 "<start> use both 'choice' and 'interleave'\n");
5621 ctxt->nbErrors++;
5622 }
5623 } else {
5624 if (ctxt->error != NULL)
5625 ctxt->error(ctxt->userData,
5626 "<start> uses unknown combine value '%s''\n", combine);
5627 ctxt->nbErrors++;
5628 }
5629 xmlFree(combine);
5630 } else {
5631 if (missing == 0)
5632 missing = 1;
5633 else {
5634 if (ctxt->error != NULL)
5635 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005636 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005637 ctxt->nbErrors++;
5638 }
5639 }
5640
Daniel Veillard2df2de22003-02-17 23:34:33 +00005641 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005642 }
5643#ifdef DEBUG
5644 xmlGenericError(xmlGenericErrorContext,
5645 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5646 choiceOrInterleave);
5647#endif
5648 if (choiceOrInterleave == -1)
5649 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005650 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005651 if (cur == NULL)
5652 return;
5653 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005654 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005655 else
5656 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005657 cur->content = grammar->start;
5658 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005659 if (choiceOrInterleave == 0) {
5660 if (ctxt->interleaves == NULL)
5661 ctxt->interleaves = xmlHashCreate(10);
5662 if (ctxt->interleaves == NULL) {
5663 if (ctxt->error != NULL)
5664 ctxt->error(ctxt->userData,
5665 "Failed to create interleaves hash table\n");
5666 ctxt->nbErrors++;
5667 } else {
5668 char tmpname[32];
5669
5670 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5671 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5672 if (ctxt->error != NULL)
5673 ctxt->error(ctxt->userData,
5674 "Failed to add %s to hash table\n", tmpname);
5675 ctxt->nbErrors++;
5676 }
5677 }
5678 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005679}
5680
5681/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005682 * xmlRelaxNGCheckCycles:
5683 * @ctxt: a Relax-NG parser context
5684 * @nodes: grammar children nodes
5685 * @depth: the counter
5686 *
5687 * Check for cycles.
5688 *
5689 * Returns 0 if check passed, and -1 in case of error
5690 */
5691static int
5692xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5693 xmlRelaxNGDefinePtr cur, int depth) {
5694 int ret = 0;
5695
5696 while ((ret == 0) && (cur != NULL)) {
5697 if ((cur->type == XML_RELAXNG_REF) ||
5698 (cur->type == XML_RELAXNG_PARENTREF)) {
5699 if (cur->depth == -1) {
5700 cur->depth = depth;
5701 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5702 cur->depth = -2;
5703 } else if (depth == cur->depth) {
5704 if (ctxt->error != NULL)
5705 ctxt->error(ctxt->userData,
5706 "Detected a cycle in %s references\n", cur->name);
5707 ctxt->nbErrors++;
5708 return(-1);
5709 }
5710 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5711 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5712 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005713 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005714 }
5715 cur = cur->next;
5716 }
5717 return(ret);
5718}
5719
5720/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005721 * xmlRelaxNGTryUnlink:
5722 * @ctxt: a Relax-NG parser context
5723 * @cur: the definition to unlink
5724 * @parent: the parent definition
5725 * @prev: the previous sibling definition
5726 *
5727 * Try to unlink a definition. If not possble make it a NOOP
5728 *
5729 * Returns the new prev definition
5730 */
5731static xmlRelaxNGDefinePtr
5732xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5733 xmlRelaxNGDefinePtr cur,
5734 xmlRelaxNGDefinePtr parent,
5735 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005736 if (prev != NULL) {
5737 prev->next = cur->next;
5738 } else {
5739 if (parent != NULL) {
5740 if (parent->content == cur)
5741 parent->content = cur->next;
5742 else if (parent->attrs == cur)
5743 parent->attrs = cur->next;
5744 else if (parent->nameClass == cur)
5745 parent->nameClass = cur->next;
5746 } else {
5747 cur->type = XML_RELAXNG_NOOP;
5748 prev = cur;
5749 }
5750 }
5751 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005752}
5753
5754/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005755 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005756 * @ctxt: a Relax-NG parser context
5757 * @nodes: grammar children nodes
5758 *
5759 * Check for simplification of empty and notAllowed
5760 */
5761static void
5762xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5763 xmlRelaxNGDefinePtr cur,
5764 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005765 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005766
Daniel Veillardfd573f12003-03-16 17:52:32 +00005767 while (cur != NULL) {
5768 if ((cur->type == XML_RELAXNG_REF) ||
5769 (cur->type == XML_RELAXNG_PARENTREF)) {
5770 if (cur->depth != -3) {
5771 cur->depth = -3;
5772 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005773 }
5774 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005775 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005776 if ((parent != NULL) &&
5777 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5778 (parent->type == XML_RELAXNG_LIST) ||
5779 (parent->type == XML_RELAXNG_GROUP) ||
5780 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005781 (parent->type == XML_RELAXNG_ONEORMORE) ||
5782 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005783 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005784 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005785 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005786 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005787 (parent->type == XML_RELAXNG_CHOICE)) {
5788 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5789 } else
5790 prev = cur;
5791 } else if (cur->type == XML_RELAXNG_EMPTY){
5792 cur->parent = parent;
5793 if ((parent != NULL) &&
5794 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5795 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005796 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005797 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005798 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005799 if ((parent != NULL) &&
5800 ((parent->type == XML_RELAXNG_GROUP) ||
5801 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5802 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5803 } else
5804 prev = cur;
5805 } else {
5806 cur->parent = parent;
5807 if (cur->content != NULL)
5808 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005809 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
Daniel Veillardfd573f12003-03-16 17:52:32 +00005810 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5811 if (cur->nameClass != NULL)
5812 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5813 /*
Daniel Veillardce192eb2003-04-16 15:58:05 +00005814 * On Elements, try to move attribute only generating rules on
5815 * the attrs rules.
5816 */
5817 if (cur->type == XML_RELAXNG_ELEMENT) {
5818 int attronly;
5819 xmlRelaxNGDefinePtr tmp, pre;
5820
5821 while (cur->content != NULL) {
5822 attronly = xmlRelaxNGGenerateAttributes(ctxt, cur->content);
5823 if (attronly == 1) {
5824 /*
5825 * migrate cur->content to attrs
5826 */
5827 tmp = cur->content;
5828 cur->content = tmp->next;
5829 tmp->next = cur->attrs;
5830 cur->attrs = tmp;
5831 } else {
5832 /*
5833 * cur->content can generate elements or text
5834 */
5835 break;
5836 }
5837 }
5838 pre = cur->content;
5839 while ((pre != NULL) && (pre->next != NULL)) {
5840 tmp = pre->next;
5841 attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
5842 if (attronly == 1) {
5843 /*
5844 * migrate tmp to attrs
5845 */
5846 pre->next = tmp->next;
5847 tmp->next = cur->attrs;
5848 cur->attrs = tmp;
5849 } else {
5850 pre = tmp;
5851 }
5852 }
5853 }
5854 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00005855 * This may result in a simplification
5856 */
5857 if ((cur->type == XML_RELAXNG_GROUP) ||
5858 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5859 if (cur->content == NULL)
5860 cur->type = XML_RELAXNG_EMPTY;
5861 else if (cur->content->next == NULL) {
5862 if ((parent == NULL) && (prev == NULL)) {
5863 cur->type = XML_RELAXNG_NOOP;
5864 } else if (prev == NULL) {
5865 parent->content = cur->content;
5866 cur->content->next = cur->next;
5867 cur = cur->content;
5868 } else {
5869 cur->content->next = cur->next;
5870 prev->next = cur->content;
5871 cur = cur->content;
5872 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005873 }
5874 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005875 /*
5876 * the current node may have been transformed back
5877 */
5878 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5879 (cur->content != NULL) &&
5880 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5881 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5882 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5883 if ((parent != NULL) &&
5884 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5885 (parent->type == XML_RELAXNG_LIST) ||
5886 (parent->type == XML_RELAXNG_GROUP) ||
5887 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5888 (parent->type == XML_RELAXNG_ONEORMORE) ||
5889 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5890 parent->type = XML_RELAXNG_NOT_ALLOWED;
5891 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005892 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005893 if ((parent != NULL) &&
5894 (parent->type == XML_RELAXNG_CHOICE)) {
5895 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5896 } else
5897 prev = cur;
5898 } else if (cur->type == XML_RELAXNG_EMPTY){
5899 if ((parent != NULL) &&
5900 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5901 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5902 parent->type = XML_RELAXNG_EMPTY;
5903 break;
5904 }
5905 if ((parent != NULL) &&
5906 ((parent->type == XML_RELAXNG_GROUP) ||
5907 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5908 (parent->type == XML_RELAXNG_CHOICE))) {
5909 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5910 } else
5911 prev = cur;
5912 } else {
5913 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005914 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005915 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005916 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005917 }
5918}
5919
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005920/**
5921 * xmlRelaxNGGroupContentType:
5922 * @ct1: the first content type
5923 * @ct2: the second content type
5924 *
5925 * Try to group 2 content types
5926 *
5927 * Returns the content type
5928 */
5929static xmlRelaxNGContentType
5930xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5931 xmlRelaxNGContentType ct2) {
5932 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5933 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5934 return(XML_RELAXNG_CONTENT_ERROR);
5935 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5936 return(ct2);
5937 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5938 return(ct1);
5939 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5940 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5941 return(XML_RELAXNG_CONTENT_COMPLEX);
5942 return(XML_RELAXNG_CONTENT_ERROR);
5943}
5944
5945/**
5946 * xmlRelaxNGMaxContentType:
5947 * @ct1: the first content type
5948 * @ct2: the second content type
5949 *
5950 * Compute the max content-type
5951 *
5952 * Returns the content type
5953 */
5954static xmlRelaxNGContentType
5955xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5956 xmlRelaxNGContentType ct2) {
5957 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5958 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5959 return(XML_RELAXNG_CONTENT_ERROR);
5960 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5961 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5962 return(XML_RELAXNG_CONTENT_SIMPLE);
5963 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5964 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5965 return(XML_RELAXNG_CONTENT_COMPLEX);
5966 return(XML_RELAXNG_CONTENT_EMPTY);
5967}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005968
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005969/**
5970 * xmlRelaxNGCheckRules:
5971 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005972 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005973 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005974 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005975 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005976 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005977 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005978 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005979 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005980static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005981xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5982 xmlRelaxNGDefinePtr cur, int flags,
5983 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005984 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005985 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005986
Daniel Veillardfd573f12003-03-16 17:52:32 +00005987 while (cur != NULL) {
5988 ret = XML_RELAXNG_CONTENT_EMPTY;
5989 if ((cur->type == XML_RELAXNG_REF) ||
5990 (cur->type == XML_RELAXNG_PARENTREF)) {
5991 if (flags & XML_RELAXNG_IN_LIST) {
5992 if (ctxt->error != NULL)
5993 ctxt->error(ctxt->userData,
5994 "Found forbidden pattern list//ref\n");
5995 ctxt->nbErrors++;
5996 }
5997 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5998 if (ctxt->error != NULL)
5999 ctxt->error(ctxt->userData,
6000 "Found forbidden pattern data/except//ref\n");
6001 ctxt->nbErrors++;
6002 }
6003 if (cur->depth > -4) {
6004 cur->depth = -4;
6005 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
6006 flags, cur->type);
6007 cur->depth = ret - 15 ;
6008 } else if (cur->depth == -4) {
6009 ret = XML_RELAXNG_CONTENT_COMPLEX;
6010 } else {
6011 ret = (xmlRelaxNGContentType) cur->depth + 15;
6012 }
6013 } else if (cur->type == XML_RELAXNG_ELEMENT) {
6014 /*
6015 * The 7.3 Attribute derivation rule for groups is plugged there
6016 */
6017 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6018 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6019 if (ctxt->error != NULL)
6020 ctxt->error(ctxt->userData,
6021 "Found forbidden pattern data/except//element(ref)\n");
6022 ctxt->nbErrors++;
6023 }
6024 if (flags & XML_RELAXNG_IN_LIST) {
6025 if (ctxt->error != NULL)
6026 ctxt->error(ctxt->userData,
6027 "Found forbidden pattern list//element(ref)\n");
6028 ctxt->nbErrors++;
6029 }
6030 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6031 if (ctxt->error != NULL)
6032 ctxt->error(ctxt->userData,
6033 "Found forbidden pattern attribute//element(ref)\n");
6034 ctxt->nbErrors++;
6035 }
6036 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6037 if (ctxt->error != NULL)
6038 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00006039 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006040 ctxt->nbErrors++;
6041 }
6042 /*
6043 * reset since in the simple form elements are only child
6044 * of grammar/define
6045 */
6046 nflags = 0;
6047 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
6048 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
6049 if (ctxt->error != NULL)
6050 ctxt->error(ctxt->userData,
6051 "Element %s attributes have a content type error\n",
6052 cur->name);
6053 ctxt->nbErrors++;
6054 }
6055 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6056 if (ret == XML_RELAXNG_CONTENT_ERROR) {
6057 if (ctxt->error != NULL)
6058 ctxt->error(ctxt->userData,
6059 "Element %s has a content type error\n",
6060 cur->name);
6061 ctxt->nbErrors++;
6062 } else {
6063 ret = XML_RELAXNG_CONTENT_COMPLEX;
6064 }
6065 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
6066 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
6067 if (ctxt->error != NULL)
6068 ctxt->error(ctxt->userData,
6069 "Found forbidden pattern attribute//attribute\n");
6070 ctxt->nbErrors++;
6071 }
6072 if (flags & XML_RELAXNG_IN_LIST) {
6073 if (ctxt->error != NULL)
6074 ctxt->error(ctxt->userData,
6075 "Found forbidden pattern list//attribute\n");
6076 ctxt->nbErrors++;
6077 }
6078 if (flags & XML_RELAXNG_IN_OOMGROUP) {
6079 if (ctxt->error != NULL)
6080 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006081 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006082 ctxt->nbErrors++;
6083 }
6084 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
6085 if (ctxt->error != NULL)
6086 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006087 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006088 ctxt->nbErrors++;
6089 }
6090 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6091 if (ctxt->error != NULL)
6092 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006093 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006094 ctxt->nbErrors++;
6095 }
6096 if (flags & XML_RELAXNG_IN_START) {
6097 if (ctxt->error != NULL)
6098 ctxt->error(ctxt->userData,
6099 "Found forbidden pattern start//attribute\n");
6100 ctxt->nbErrors++;
6101 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00006102 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
6103 if (cur->ns == NULL) {
6104 if (ctxt->error != NULL)
6105 ctxt->error(ctxt->userData,
6106 "Found anyName attribute without oneOrMore ancestor\n");
6107 ctxt->nbErrors++;
6108 } else {
6109 if (ctxt->error != NULL)
6110 ctxt->error(ctxt->userData,
6111 "Found nsName attribute without oneOrMore ancestor\n");
6112 ctxt->nbErrors++;
6113 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00006114 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006115 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
6116 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6117 ret = XML_RELAXNG_CONTENT_EMPTY;
6118 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
6119 (cur->type == XML_RELAXNG_ZEROORMORE)) {
6120 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6121 if (ctxt->error != NULL)
6122 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006123 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006124 ctxt->nbErrors++;
6125 }
6126 if (flags & XML_RELAXNG_IN_START) {
6127 if (ctxt->error != NULL)
6128 ctxt->error(ctxt->userData,
6129 "Found forbidden pattern start//oneOrMore\n");
6130 ctxt->nbErrors++;
6131 }
6132 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
6133 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6134 ret = xmlRelaxNGGroupContentType(ret, ret);
6135 } else if (cur->type == XML_RELAXNG_LIST) {
6136 if (flags & XML_RELAXNG_IN_LIST) {
6137 if (ctxt->error != NULL)
6138 ctxt->error(ctxt->userData,
6139 "Found forbidden pattern list//list\n");
6140 ctxt->nbErrors++;
6141 }
6142 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6143 if (ctxt->error != NULL)
6144 ctxt->error(ctxt->userData,
6145 "Found forbidden pattern data/except//list\n");
6146 ctxt->nbErrors++;
6147 }
6148 if (flags & XML_RELAXNG_IN_START) {
6149 if (ctxt->error != NULL)
6150 ctxt->error(ctxt->userData,
6151 "Found forbidden pattern start//list\n");
6152 ctxt->nbErrors++;
6153 }
6154 nflags = flags | XML_RELAXNG_IN_LIST;
6155 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6156 } else if (cur->type == XML_RELAXNG_GROUP) {
6157 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6158 if (ctxt->error != NULL)
6159 ctxt->error(ctxt->userData,
6160 "Found forbidden pattern data/except//group\n");
6161 ctxt->nbErrors++;
6162 }
6163 if (flags & XML_RELAXNG_IN_START) {
6164 if (ctxt->error != NULL)
6165 ctxt->error(ctxt->userData,
6166 "Found forbidden pattern start//group\n");
6167 ctxt->nbErrors++;
6168 }
6169 if (flags & XML_RELAXNG_IN_ONEORMORE)
6170 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
6171 else
6172 nflags = flags;
6173 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6174 /*
6175 * The 7.3 Attribute derivation rule for groups is plugged there
6176 */
6177 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
6178 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
6179 if (flags & XML_RELAXNG_IN_LIST) {
6180 if (ctxt->error != NULL)
6181 ctxt->error(ctxt->userData,
6182 "Found forbidden pattern list//interleave\n");
6183 ctxt->nbErrors++;
6184 }
6185 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6186 if (ctxt->error != NULL)
6187 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00006188 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006189 ctxt->nbErrors++;
6190 }
6191 if (flags & XML_RELAXNG_IN_START) {
6192 if (ctxt->error != NULL)
6193 ctxt->error(ctxt->userData,
6194 "Found forbidden pattern start//interleave\n");
6195 ctxt->nbErrors++;
6196 }
6197 if (flags & XML_RELAXNG_IN_ONEORMORE)
6198 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
6199 else
6200 nflags = flags;
6201 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6202 } else if (cur->type == XML_RELAXNG_EXCEPT) {
6203 if ((cur->parent != NULL) &&
6204 (cur->parent->type == XML_RELAXNG_DATATYPE))
6205 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
6206 else
6207 nflags = flags;
6208 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
6209 } else if (cur->type == XML_RELAXNG_DATATYPE) {
6210 if (flags & XML_RELAXNG_IN_START) {
6211 if (ctxt->error != NULL)
6212 ctxt->error(ctxt->userData,
6213 "Found forbidden pattern start//data\n");
6214 ctxt->nbErrors++;
6215 }
6216 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6217 ret = XML_RELAXNG_CONTENT_SIMPLE;
6218 } else if (cur->type == XML_RELAXNG_VALUE) {
6219 if (flags & XML_RELAXNG_IN_START) {
6220 if (ctxt->error != NULL)
6221 ctxt->error(ctxt->userData,
6222 "Found forbidden pattern start//value\n");
6223 ctxt->nbErrors++;
6224 }
6225 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6226 ret = XML_RELAXNG_CONTENT_SIMPLE;
6227 } else if (cur->type == XML_RELAXNG_TEXT) {
6228 if (flags & XML_RELAXNG_IN_LIST) {
6229 if (ctxt->error != NULL)
6230 ctxt->error(ctxt->userData,
6231 "Found forbidden pattern list//text\n");
6232 ctxt->nbErrors++;
6233 }
6234 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6235 if (ctxt->error != NULL)
6236 ctxt->error(ctxt->userData,
6237 "Found forbidden pattern data/except//text\n");
6238 ctxt->nbErrors++;
6239 }
6240 if (flags & XML_RELAXNG_IN_START) {
6241 if (ctxt->error != NULL)
6242 ctxt->error(ctxt->userData,
6243 "Found forbidden pattern start//text\n");
6244 ctxt->nbErrors++;
6245 }
6246 ret = XML_RELAXNG_CONTENT_COMPLEX;
6247 } else if (cur->type == XML_RELAXNG_EMPTY) {
6248 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
6249 if (ctxt->error != NULL)
6250 ctxt->error(ctxt->userData,
6251 "Found forbidden pattern data/except//empty\n");
6252 ctxt->nbErrors++;
6253 }
6254 if (flags & XML_RELAXNG_IN_START) {
6255 if (ctxt->error != NULL)
6256 ctxt->error(ctxt->userData,
6257 "Found forbidden pattern start//empty\n");
6258 ctxt->nbErrors++;
6259 }
6260 ret = XML_RELAXNG_CONTENT_EMPTY;
6261 } else if (cur->type == XML_RELAXNG_CHOICE) {
6262 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
6263 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6264 } else {
6265 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
6266 }
6267 cur = cur->next;
6268 if (ptype == XML_RELAXNG_GROUP) {
6269 val = xmlRelaxNGGroupContentType(val, ret);
6270 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
6271 tmp = xmlRelaxNGGroupContentType(val, ret);
6272 if (tmp != XML_RELAXNG_CONTENT_ERROR)
6273 tmp = xmlRelaxNGMaxContentType(val, ret);
6274 } else if (ptype == XML_RELAXNG_CHOICE) {
6275 val = xmlRelaxNGMaxContentType(val, ret);
6276 } else if (ptype == XML_RELAXNG_LIST) {
6277 val = XML_RELAXNG_CONTENT_SIMPLE;
6278 } else if (ptype == XML_RELAXNG_EXCEPT) {
6279 if (ret == XML_RELAXNG_CONTENT_ERROR)
6280 val = XML_RELAXNG_CONTENT_ERROR;
6281 else
6282 val = XML_RELAXNG_CONTENT_SIMPLE;
6283 } else {
6284 val = xmlRelaxNGGroupContentType(val, ret);
6285 }
6286
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006287 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006288 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006289}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00006290
6291/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006292 * xmlRelaxNGParseGrammar:
6293 * @ctxt: a Relax-NG parser context
6294 * @nodes: grammar children nodes
6295 *
6296 * parse a Relax-NG <grammar> node
6297 *
6298 * Returns the internal xmlRelaxNGGrammarPtr built or
6299 * NULL in case of error
6300 */
6301static xmlRelaxNGGrammarPtr
6302xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
6303 xmlRelaxNGGrammarPtr ret, tmp, old;
6304
Daniel Veillardc482e262003-02-26 14:48:48 +00006305#ifdef DEBUG_GRAMMAR
6306 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
6307#endif
6308
Daniel Veillard6eadf632003-01-23 18:29:16 +00006309 ret = xmlRelaxNGNewGrammar(ctxt);
6310 if (ret == NULL)
6311 return(NULL);
6312
6313 /*
6314 * Link the new grammar in the tree
6315 */
6316 ret->parent = ctxt->grammar;
6317 if (ctxt->grammar != NULL) {
6318 tmp = ctxt->grammar->children;
6319 if (tmp == NULL) {
6320 ctxt->grammar->children = ret;
6321 } else {
6322 while (tmp->next != NULL)
6323 tmp = tmp->next;
6324 tmp->next = ret;
6325 }
6326 }
6327
6328 old = ctxt->grammar;
6329 ctxt->grammar = ret;
6330 xmlRelaxNGParseGrammarContent(ctxt, nodes);
6331 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00006332 if (ctxt->grammar == NULL) {
6333 if (ctxt->error != NULL)
6334 ctxt->error(ctxt->userData,
6335 "Failed to parse <grammar> content\n");
6336 ctxt->nbErrors++;
6337 } else if (ctxt->grammar->start == NULL) {
6338 if (ctxt->error != NULL)
6339 ctxt->error(ctxt->userData,
6340 "Element <grammar> has no <start>\n");
6341 ctxt->nbErrors++;
6342 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006343
6344 /*
6345 * Apply 4.17 mergingd rules to defines and starts
6346 */
6347 xmlRelaxNGCombineStart(ctxt, ret);
6348 if (ret->defs != NULL) {
6349 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
6350 ctxt);
6351 }
6352
6353 /*
6354 * link together defines and refs in this grammar
6355 */
6356 if (ret->refs != NULL) {
6357 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
6358 ctxt);
6359 }
Daniel Veillard952379b2003-03-17 15:37:12 +00006360
Daniel Veillard6eadf632003-01-23 18:29:16 +00006361 ctxt->grammar = old;
6362 return(ret);
6363}
6364
6365/**
6366 * xmlRelaxNGParseDocument:
6367 * @ctxt: a Relax-NG parser context
6368 * @node: the root node of the RelaxNG schema
6369 *
6370 * parse a Relax-NG definition resource and build an internal
6371 * xmlRelaxNG struture which can be used to validate instances.
6372 *
6373 * Returns the internal XML RelaxNG structure built or
6374 * NULL in case of error
6375 */
6376static xmlRelaxNGPtr
6377xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6378 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00006379 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00006380 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006381
6382 if ((ctxt == NULL) || (node == NULL))
6383 return (NULL);
6384
6385 schema = xmlRelaxNGNewRelaxNG(ctxt);
6386 if (schema == NULL)
6387 return(NULL);
6388
Daniel Veillard276be4a2003-01-24 01:03:34 +00006389 olddefine = ctxt->define;
6390 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006391 if (IS_RELAXNG(node, "grammar")) {
6392 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
6393 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00006394 xmlRelaxNGGrammarPtr tmp, ret;
6395
6396 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006397 if (schema->topgrammar == NULL) {
6398 return(schema);
6399 }
Daniel Veillardc482e262003-02-26 14:48:48 +00006400 /*
6401 * Link the new grammar in the tree
6402 */
6403 ret->parent = ctxt->grammar;
6404 if (ctxt->grammar != NULL) {
6405 tmp = ctxt->grammar->children;
6406 if (tmp == NULL) {
6407 ctxt->grammar->children = ret;
6408 } else {
6409 while (tmp->next != NULL)
6410 tmp = tmp->next;
6411 tmp->next = ret;
6412 }
6413 }
Daniel Veillarde431a272003-01-29 23:02:33 +00006414 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00006415 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006416 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00006417 if (old != NULL)
6418 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006419 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00006420 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00006421 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006422 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006423 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00006424 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
6425 while ((schema->topgrammar->start != NULL) &&
6426 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6427 (schema->topgrammar->start->next != NULL))
6428 schema->topgrammar->start = schema->topgrammar->start->content;
6429 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6430 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006431 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006432 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006433
6434#ifdef DEBUG
6435 if (schema == NULL)
6436 xmlGenericError(xmlGenericErrorContext,
6437 "xmlRelaxNGParseDocument() failed\n");
6438#endif
6439
6440 return (schema);
6441}
6442
6443/************************************************************************
6444 * *
6445 * Reading RelaxNGs *
6446 * *
6447 ************************************************************************/
6448
6449/**
6450 * xmlRelaxNGNewParserCtxt:
6451 * @URL: the location of the schema
6452 *
6453 * Create an XML RelaxNGs parse context for that file/resource expected
6454 * to contain an XML RelaxNGs file.
6455 *
6456 * Returns the parser context or NULL in case of error
6457 */
6458xmlRelaxNGParserCtxtPtr
6459xmlRelaxNGNewParserCtxt(const char *URL) {
6460 xmlRelaxNGParserCtxtPtr ret;
6461
6462 if (URL == NULL)
6463 return(NULL);
6464
6465 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6466 if (ret == NULL) {
6467 xmlGenericError(xmlGenericErrorContext,
6468 "Failed to allocate new schama parser context for %s\n", URL);
6469 return (NULL);
6470 }
6471 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6472 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006473 ret->error = xmlGenericError;
6474 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006475 return (ret);
6476}
6477
6478/**
6479 * xmlRelaxNGNewMemParserCtxt:
6480 * @buffer: a pointer to a char array containing the schemas
6481 * @size: the size of the array
6482 *
6483 * Create an XML RelaxNGs parse context for that memory buffer expected
6484 * to contain an XML RelaxNGs file.
6485 *
6486 * Returns the parser context or NULL in case of error
6487 */
6488xmlRelaxNGParserCtxtPtr
6489xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6490 xmlRelaxNGParserCtxtPtr ret;
6491
6492 if ((buffer == NULL) || (size <= 0))
6493 return(NULL);
6494
6495 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6496 if (ret == NULL) {
6497 xmlGenericError(xmlGenericErrorContext,
6498 "Failed to allocate new schama parser context\n");
6499 return (NULL);
6500 }
6501 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6502 ret->buffer = buffer;
6503 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006504 ret->error = xmlGenericError;
6505 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006506 return (ret);
6507}
6508
6509/**
Daniel Veillard33300b42003-04-17 09:09:19 +00006510 * xmlRelaxNGNewDocParserCtxt:
6511 * @doc: a preparsed document tree
6512 *
6513 * Create an XML RelaxNGs parser context for that document.
6514 * Note: since the process of compiling a RelaxNG schemas modifies the
6515 * document, the @doc parameter is duplicated internally.
6516 *
6517 * Returns the parser context or NULL in case of error
6518 */
6519xmlRelaxNGParserCtxtPtr
6520xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc) {
6521 xmlRelaxNGParserCtxtPtr ret;
6522 xmlDocPtr copy;
6523
6524 if (doc == NULL)
6525 return(NULL);
6526 copy = xmlCopyDoc(doc, 1);
6527 if (copy == NULL)
6528 return(NULL);
6529
6530 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6531 if (ret == NULL) {
6532 xmlGenericError(xmlGenericErrorContext,
6533 "Failed to allocate new schama parser context\n");
6534 return (NULL);
6535 }
6536 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6537 ret->document = copy;
6538 ret->userData = xmlGenericErrorContext;
6539 return (ret);
6540}
6541
6542/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00006543 * xmlRelaxNGFreeParserCtxt:
6544 * @ctxt: the schema parser context
6545 *
6546 * Free the resources associated to the schema parser context
6547 */
6548void
6549xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6550 if (ctxt == NULL)
6551 return;
6552 if (ctxt->URL != NULL)
6553 xmlFree(ctxt->URL);
6554 if (ctxt->doc != NULL)
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00006555 xmlRelaxNGFreeDocument(ctxt->doc);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006556 if (ctxt->interleaves != NULL)
6557 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006558 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006559 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006560 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006561 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006562 if (ctxt->docTab != NULL)
6563 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006564 if (ctxt->incTab != NULL)
6565 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006566 if (ctxt->defTab != NULL) {
6567 int i;
6568
6569 for (i = 0;i < ctxt->defNr;i++)
6570 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6571 xmlFree(ctxt->defTab);
6572 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006573 xmlFree(ctxt);
6574}
6575
Daniel Veillard6eadf632003-01-23 18:29:16 +00006576/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006577 * xmlRelaxNGNormExtSpace:
6578 * @value: a value
6579 *
6580 * Removes the leading and ending spaces of the value
6581 * The string is modified "in situ"
6582 */
6583static void
6584xmlRelaxNGNormExtSpace(xmlChar *value) {
6585 xmlChar *start = value;
6586 xmlChar *cur = value;
6587 if (value == NULL)
6588 return;
6589
6590 while (IS_BLANK(*cur)) cur++;
6591 if (cur == start) {
6592 do {
6593 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6594 if (*cur == 0)
6595 return;
6596 start = cur;
6597 while (IS_BLANK(*cur)) cur++;
6598 if (*cur == 0) {
6599 *start = 0;
6600 return;
6601 }
6602 } while (1);
6603 } else {
6604 do {
6605 while ((*cur != 0) && (!IS_BLANK(*cur)))
6606 *start++ = *cur++;
6607 if (*cur == 0) {
6608 *start = 0;
6609 return;
6610 }
6611 /* don't try to normalize the inner spaces */
6612 while (IS_BLANK(*cur)) cur++;
6613 *start++ = *cur++;
6614 if (*cur == 0) {
6615 *start = 0;
6616 return;
6617 }
6618 } while (1);
6619 }
6620}
6621
6622/**
6623 * xmlRelaxNGCheckAttributes:
6624 * @ctxt: a Relax-NG parser context
6625 * @node: a Relax-NG node
6626 *
6627 * Check all the attributes on the given node
6628 */
6629static void
6630xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6631 xmlAttrPtr cur, next;
6632
6633 cur = node->properties;
6634 while (cur != NULL) {
6635 next = cur->next;
6636 if ((cur->ns == NULL) ||
6637 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6638 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6639 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6640 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6641 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6642 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006643 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006644 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6645 if (ctxt->error != NULL)
6646 ctxt->error(ctxt->userData,
6647 "Attribute %s is not allowed on %s\n",
6648 cur->name, node->name);
6649 ctxt->nbErrors++;
6650 }
6651 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6652 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6653 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6654 if (ctxt->error != NULL)
6655 ctxt->error(ctxt->userData,
6656 "Attribute %s is not allowed on %s\n",
6657 cur->name, node->name);
6658 ctxt->nbErrors++;
6659 }
6660 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6661 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6662 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6663 if (ctxt->error != NULL)
6664 ctxt->error(ctxt->userData,
6665 "Attribute %s is not allowed on %s\n",
6666 cur->name, node->name);
6667 ctxt->nbErrors++;
6668 }
6669 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6670 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6671 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6672 if (ctxt->error != NULL)
6673 ctxt->error(ctxt->userData,
6674 "Attribute %s is not allowed on %s\n",
6675 cur->name, node->name);
6676 ctxt->nbErrors++;
6677 }
6678 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6679 xmlChar *val;
6680 xmlURIPtr uri;
6681
6682 val = xmlNodeListGetString(node->doc, cur->children, 1);
6683 if (val != NULL) {
6684 if (val[0] != 0) {
6685 uri = xmlParseURI((const char *) val);
6686 if (uri == NULL) {
6687 if (ctxt->error != NULL)
6688 ctxt->error(ctxt->userData,
6689 "Attribute %s contains invalid URI %s\n",
6690 cur->name, val);
6691 ctxt->nbErrors++;
6692 } else {
6693 if (uri->scheme == NULL) {
6694 if (ctxt->error != NULL)
6695 ctxt->error(ctxt->userData,
6696 "Attribute %s URI %s is not absolute\n",
6697 cur->name, val);
6698 ctxt->nbErrors++;
6699 }
6700 if (uri->fragment != NULL) {
6701 if (ctxt->error != NULL)
6702 ctxt->error(ctxt->userData,
6703 "Attribute %s URI %s has a fragment ID\n",
6704 cur->name, val);
6705 ctxt->nbErrors++;
6706 }
6707 xmlFreeURI(uri);
6708 }
6709 }
6710 xmlFree(val);
6711 }
6712 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6713 if (ctxt->error != NULL)
6714 ctxt->error(ctxt->userData,
6715 "Unknown attribute %s on %s\n",
6716 cur->name, node->name);
6717 ctxt->nbErrors++;
6718 }
6719 }
6720 cur = next;
6721 }
6722}
6723
6724/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006725 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006726 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006727 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006728 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006729 * Cleanup the subtree from unwanted nodes for parsing, resolve
6730 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006731 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006732static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006733xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006734 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006735
Daniel Veillard6eadf632003-01-23 18:29:16 +00006736 delete = NULL;
6737 cur = root;
6738 while (cur != NULL) {
6739 if (delete != NULL) {
6740 xmlUnlinkNode(delete);
6741 xmlFreeNode(delete);
6742 delete = NULL;
6743 }
6744 if (cur->type == XML_ELEMENT_NODE) {
6745 /*
6746 * Simplification 4.1. Annotations
6747 */
6748 if ((cur->ns == NULL) ||
6749 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006750 if ((cur->parent != NULL) &&
6751 (cur->parent->type == XML_ELEMENT_NODE) &&
6752 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6753 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6754 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6755 if (ctxt->error != NULL)
6756 ctxt->error(ctxt->userData,
6757 "element %s doesn't allow foreign elements\n",
6758 cur->parent->name);
6759 ctxt->nbErrors++;
6760 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006761 delete = cur;
6762 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006763 } else {
6764 xmlRelaxNGCleanupAttributes(ctxt, cur);
6765 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6766 xmlChar *href, *ns, *base, *URL;
6767 xmlRelaxNGDocumentPtr docu;
6768 xmlNodePtr tmp;
6769
6770 ns = xmlGetProp(cur, BAD_CAST "ns");
6771 if (ns == NULL) {
6772 tmp = cur->parent;
6773 while ((tmp != NULL) &&
6774 (tmp->type == XML_ELEMENT_NODE)) {
6775 ns = xmlGetProp(tmp, BAD_CAST "ns");
6776 if (ns != NULL)
6777 break;
6778 tmp = tmp->parent;
6779 }
6780 }
6781 href = xmlGetProp(cur, BAD_CAST "href");
6782 if (href == NULL) {
6783 if (ctxt->error != NULL)
6784 ctxt->error(ctxt->userData,
6785 "xmlRelaxNGParse: externalRef has no href attribute\n");
6786 ctxt->nbErrors++;
6787 delete = cur;
6788 goto skip_children;
6789 }
6790 base = xmlNodeGetBase(cur->doc, cur);
6791 URL = xmlBuildURI(href, base);
6792 if (URL == NULL) {
6793 if (ctxt->error != NULL)
6794 ctxt->error(ctxt->userData,
6795 "Failed to compute URL for externalRef %s\n", href);
6796 ctxt->nbErrors++;
6797 if (href != NULL)
6798 xmlFree(href);
6799 if (base != NULL)
6800 xmlFree(base);
6801 delete = cur;
6802 goto skip_children;
6803 }
6804 if (href != NULL)
6805 xmlFree(href);
6806 if (base != NULL)
6807 xmlFree(base);
6808 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6809 if (docu == NULL) {
6810 if (ctxt->error != NULL)
6811 ctxt->error(ctxt->userData,
6812 "Failed to load externalRef %s\n", URL);
6813 ctxt->nbErrors++;
6814 xmlFree(URL);
6815 delete = cur;
6816 goto skip_children;
6817 }
6818 if (ns != NULL)
6819 xmlFree(ns);
6820 xmlFree(URL);
6821 cur->_private = docu;
6822 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6823 xmlChar *href, *ns, *base, *URL;
6824 xmlRelaxNGIncludePtr incl;
6825 xmlNodePtr tmp;
6826
6827 href = xmlGetProp(cur, BAD_CAST "href");
6828 if (href == NULL) {
6829 if (ctxt->error != NULL)
6830 ctxt->error(ctxt->userData,
6831 "xmlRelaxNGParse: include has no href attribute\n");
6832 ctxt->nbErrors++;
6833 delete = cur;
6834 goto skip_children;
6835 }
6836 base = xmlNodeGetBase(cur->doc, cur);
6837 URL = xmlBuildURI(href, base);
6838 if (URL == NULL) {
6839 if (ctxt->error != NULL)
6840 ctxt->error(ctxt->userData,
6841 "Failed to compute URL for include %s\n", href);
6842 ctxt->nbErrors++;
6843 if (href != NULL)
6844 xmlFree(href);
6845 if (base != NULL)
6846 xmlFree(base);
6847 delete = cur;
6848 goto skip_children;
6849 }
6850 if (href != NULL)
6851 xmlFree(href);
6852 if (base != NULL)
6853 xmlFree(base);
6854 ns = xmlGetProp(cur, BAD_CAST "ns");
6855 if (ns == NULL) {
6856 tmp = cur->parent;
6857 while ((tmp != NULL) &&
6858 (tmp->type == XML_ELEMENT_NODE)) {
6859 ns = xmlGetProp(tmp, BAD_CAST "ns");
6860 if (ns != NULL)
6861 break;
6862 tmp = tmp->parent;
6863 }
6864 }
6865 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6866 if (ns != NULL)
6867 xmlFree(ns);
6868 if (incl == NULL) {
6869 if (ctxt->error != NULL)
6870 ctxt->error(ctxt->userData,
6871 "Failed to load include %s\n", URL);
6872 ctxt->nbErrors++;
6873 xmlFree(URL);
6874 delete = cur;
6875 goto skip_children;
6876 }
6877 xmlFree(URL);
6878 cur->_private = incl;
6879 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6880 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6881 xmlChar *name, *ns;
6882 xmlNodePtr text = NULL;
6883
6884 /*
6885 * Simplification 4.8. name attribute of element
6886 * and attribute elements
6887 */
6888 name = xmlGetProp(cur, BAD_CAST "name");
6889 if (name != NULL) {
6890 if (cur->children == NULL) {
6891 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6892 name);
6893 } else {
6894 xmlNodePtr node;
6895 node = xmlNewNode(cur->ns, BAD_CAST "name");
6896 if (node != NULL) {
6897 xmlAddPrevSibling(cur->children, node);
6898 text = xmlNewText(name);
6899 xmlAddChild(node, text);
6900 text = node;
6901 }
6902 }
6903 if (text == NULL) {
6904 if (ctxt->error != NULL)
6905 ctxt->error(ctxt->userData,
6906 "Failed to create a name %s element\n", name);
6907 ctxt->nbErrors++;
6908 }
6909 xmlUnsetProp(cur, BAD_CAST "name");
6910 xmlFree(name);
6911 ns = xmlGetProp(cur, BAD_CAST "ns");
6912 if (ns != NULL) {
6913 if (text != NULL) {
6914 xmlSetProp(text, BAD_CAST "ns", ns);
6915 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6916 }
6917 xmlFree(ns);
6918 } else if (xmlStrEqual(cur->name,
6919 BAD_CAST "attribute")) {
6920 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6921 }
6922 }
6923 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6924 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6925 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6926 /*
6927 * Simplification 4.8. name attribute of element
6928 * and attribute elements
6929 */
6930 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6931 xmlNodePtr node;
6932 xmlChar *ns = NULL;
6933
6934 node = cur->parent;
6935 while ((node != NULL) &&
6936 (node->type == XML_ELEMENT_NODE)) {
6937 ns = xmlGetProp(node, BAD_CAST "ns");
6938 if (ns != NULL) {
6939 break;
6940 }
6941 node = node->parent;
6942 }
6943 if (ns == NULL) {
6944 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6945 } else {
6946 xmlSetProp(cur, BAD_CAST "ns", ns);
6947 xmlFree(ns);
6948 }
6949 }
6950 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6951 xmlChar *name, *local, *prefix;
6952
6953 /*
6954 * Simplification: 4.10. QNames
6955 */
6956 name = xmlNodeGetContent(cur);
6957 if (name != NULL) {
6958 local = xmlSplitQName2(name, &prefix);
6959 if (local != NULL) {
6960 xmlNsPtr ns;
6961
6962 ns = xmlSearchNs(cur->doc, cur, prefix);
6963 if (ns == NULL) {
6964 if (ctxt->error != NULL)
6965 ctxt->error(ctxt->userData,
6966 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6967 ctxt->nbErrors++;
6968 } else {
6969 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6970 xmlNodeSetContent(cur, local);
6971 }
6972 xmlFree(local);
6973 xmlFree(prefix);
6974 }
6975 xmlFree(name);
6976 }
6977 }
6978 /*
6979 * 4.16
6980 */
6981 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6982 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6983 if (ctxt->error != NULL)
6984 ctxt->error(ctxt->userData,
6985 "Found nsName/except//nsName forbidden construct\n");
6986 ctxt->nbErrors++;
6987 }
6988 }
6989 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6990 (cur != root)) {
6991 int oldflags = ctxt->flags;
6992
6993 /*
6994 * 4.16
6995 */
6996 if ((cur->parent != NULL) &&
6997 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6998 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6999 xmlRelaxNGCleanupTree(ctxt, cur);
7000 ctxt->flags = oldflags;
7001 goto skip_children;
7002 } else if ((cur->parent != NULL) &&
7003 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
7004 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
7005 xmlRelaxNGCleanupTree(ctxt, cur);
7006 ctxt->flags = oldflags;
7007 goto skip_children;
7008 }
7009 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
7010 /*
7011 * 4.16
7012 */
7013 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
7014 if (ctxt->error != NULL)
7015 ctxt->error(ctxt->userData,
7016 "Found anyName/except//anyName forbidden construct\n");
7017 ctxt->nbErrors++;
7018 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
7019 if (ctxt->error != NULL)
7020 ctxt->error(ctxt->userData,
7021 "Found nsName/except//anyName forbidden construct\n");
7022 ctxt->nbErrors++;
7023 }
7024 }
7025 /*
7026 * Thisd is not an else since "include" is transformed
7027 * into a div
7028 */
7029 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
7030 xmlChar *ns;
7031 xmlNodePtr child, ins, tmp;
7032
7033 /*
7034 * implements rule 4.11
7035 */
7036
7037 ns = xmlGetProp(cur, BAD_CAST "ns");
7038
7039 child = cur->children;
7040 ins = cur;
7041 while (child != NULL) {
7042 if (ns != NULL) {
7043 if (!xmlHasProp(child, BAD_CAST "ns")) {
7044 xmlSetProp(child, BAD_CAST "ns", ns);
7045 }
7046 }
7047 tmp = child->next;
7048 xmlUnlinkNode(child);
7049 ins = xmlAddNextSibling(ins, child);
7050 child = tmp;
7051 }
7052 if (ns != NULL)
7053 xmlFree(ns);
7054 delete = cur;
7055 goto skip_children;
7056 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007057 }
7058 }
7059 /*
7060 * Simplification 4.2 whitespaces
7061 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007062 else if ((cur->type == XML_TEXT_NODE) ||
7063 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007064 if (IS_BLANK_NODE(cur)) {
7065 if (cur->parent->type == XML_ELEMENT_NODE) {
7066 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
7067 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
7068 delete = cur;
7069 } else {
7070 delete = cur;
7071 goto skip_children;
7072 }
7073 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007074 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007075 delete = cur;
7076 goto skip_children;
7077 }
7078
7079 /*
7080 * Skip to next node
7081 */
7082 if (cur->children != NULL) {
7083 if ((cur->children->type != XML_ENTITY_DECL) &&
7084 (cur->children->type != XML_ENTITY_REF_NODE) &&
7085 (cur->children->type != XML_ENTITY_NODE)) {
7086 cur = cur->children;
7087 continue;
7088 }
7089 }
7090skip_children:
7091 if (cur->next != NULL) {
7092 cur = cur->next;
7093 continue;
7094 }
7095
7096 do {
7097 cur = cur->parent;
7098 if (cur == NULL)
7099 break;
7100 if (cur == root) {
7101 cur = NULL;
7102 break;
7103 }
7104 if (cur->next != NULL) {
7105 cur = cur->next;
7106 break;
7107 }
7108 } while (cur != NULL);
7109 }
7110 if (delete != NULL) {
7111 xmlUnlinkNode(delete);
7112 xmlFreeNode(delete);
7113 delete = NULL;
7114 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00007115}
Daniel Veillard6eadf632003-01-23 18:29:16 +00007116
Daniel Veillardc5312d72003-02-21 17:14:10 +00007117/**
7118 * xmlRelaxNGCleanupDoc:
7119 * @ctxt: a Relax-NG parser context
7120 * @doc: an xmldocPtr document pointer
7121 *
7122 * Cleanup the document from unwanted nodes for parsing, resolve
7123 * Include and externalRef lookups.
7124 *
7125 * Returns the cleaned up document or NULL in case of error
7126 */
7127static xmlDocPtr
7128xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
7129 xmlNodePtr root;
7130
7131 /*
7132 * Extract the root
7133 */
7134 root = xmlDocGetRootElement(doc);
7135 if (root == NULL) {
7136 if (ctxt->error != NULL)
7137 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7138 ctxt->URL);
7139 ctxt->nbErrors++;
7140 return (NULL);
7141 }
7142 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007143 return(doc);
7144}
7145
7146/**
7147 * xmlRelaxNGParse:
7148 * @ctxt: a Relax-NG parser context
7149 *
7150 * parse a schema definition resource and build an internal
7151 * XML Shema struture which can be used to validate instances.
7152 * *WARNING* this interface is highly subject to change
7153 *
7154 * Returns the internal XML RelaxNG structure built from the resource or
7155 * NULL in case of error
7156 */
7157xmlRelaxNGPtr
7158xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
7159{
7160 xmlRelaxNGPtr ret = NULL;
7161 xmlDocPtr doc;
7162 xmlNodePtr root;
7163
7164 xmlRelaxNGInitTypes();
7165
7166 if (ctxt == NULL)
7167 return (NULL);
7168
7169 /*
7170 * First step is to parse the input document into an DOM/Infoset
7171 */
7172 if (ctxt->URL != NULL) {
7173 doc = xmlParseFile((const char *) ctxt->URL);
7174 if (doc == NULL) {
7175 if (ctxt->error != NULL)
7176 ctxt->error(ctxt->userData,
7177 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
7178 ctxt->nbErrors++;
7179 return (NULL);
7180 }
7181 } else if (ctxt->buffer != NULL) {
7182 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
7183 if (doc == NULL) {
7184 if (ctxt->error != NULL)
7185 ctxt->error(ctxt->userData,
7186 "xmlRelaxNGParse: could not parse schemas\n");
7187 ctxt->nbErrors++;
7188 return (NULL);
7189 }
7190 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
7191 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
Daniel Veillard33300b42003-04-17 09:09:19 +00007192 } else if (ctxt->document != NULL) {
7193 doc = ctxt->document;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007194 } else {
7195 if (ctxt->error != NULL)
7196 ctxt->error(ctxt->userData,
7197 "xmlRelaxNGParse: nothing to parse\n");
7198 ctxt->nbErrors++;
7199 return (NULL);
7200 }
7201 ctxt->document = doc;
7202
7203 /*
7204 * Some preprocessing of the document content
7205 */
7206 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
7207 if (doc == NULL) {
7208 xmlFreeDoc(ctxt->document);
7209 ctxt->document = NULL;
7210 return(NULL);
7211 }
7212
Daniel Veillard6eadf632003-01-23 18:29:16 +00007213 /*
7214 * Then do the parsing for good
7215 */
7216 root = xmlDocGetRootElement(doc);
7217 if (root == NULL) {
7218 if (ctxt->error != NULL)
7219 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
7220 ctxt->URL);
7221 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007222 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007223 return (NULL);
7224 }
7225 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007226 if (ret == NULL) {
7227 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007228 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007229 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007230
7231 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00007232 * Check the ref/defines links
7233 */
7234 /*
7235 * try to preprocess interleaves
7236 */
7237 if (ctxt->interleaves != NULL) {
7238 xmlHashScan(ctxt->interleaves,
7239 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
7240 }
7241
7242 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007243 * if there was a parsing error return NULL
7244 */
7245 if (ctxt->nbErrors > 0) {
7246 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007247 ctxt->document = NULL;
7248 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007249 return(NULL);
7250 }
7251
7252 /*
Daniel Veillard52b48c72003-04-13 19:53:42 +00007253 * try to compile (parts of) the schemas
7254 */
Daniel Veillardce192eb2003-04-16 15:58:05 +00007255 if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
7256 if (ret->topgrammar->start->type != XML_RELAXNG_START) {
Daniel Veillardf4e55762003-04-15 23:32:22 +00007257 xmlRelaxNGDefinePtr def;
7258
7259 def = xmlRelaxNGNewDefine(ctxt, NULL);
7260 if (def != NULL) {
7261 def->type = XML_RELAXNG_START;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007262 def->content = ret->topgrammar->start;
7263 ret->topgrammar->start = def;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007264 }
7265 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007266 xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
Daniel Veillardf4e55762003-04-15 23:32:22 +00007267 }
Daniel Veillard52b48c72003-04-13 19:53:42 +00007268
7269 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00007270 * Transfer the pointer for cleanup at the schema level.
7271 */
7272 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007273 ctxt->document = NULL;
7274 ret->documents = ctxt->documents;
7275 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00007276
Daniel Veillarde2a5a082003-02-02 14:35:17 +00007277 ret->includes = ctxt->includes;
7278 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00007279 ret->defNr = ctxt->defNr;
7280 ret->defTab = ctxt->defTab;
7281 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007282 if (ctxt->idref == 1)
7283 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007284
7285 return (ret);
7286}
7287
7288/**
7289 * xmlRelaxNGSetParserErrors:
7290 * @ctxt: a Relax-NG validation context
7291 * @err: the error callback
7292 * @warn: the warning callback
7293 * @ctx: contextual data for the callbacks
7294 *
7295 * Set the callback functions used to handle errors for a validation context
7296 */
7297void
7298xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
7299 xmlRelaxNGValidityErrorFunc err,
7300 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7301 if (ctxt == NULL)
7302 return;
7303 ctxt->error = err;
7304 ctxt->warning = warn;
7305 ctxt->userData = ctx;
7306}
7307/************************************************************************
7308 * *
7309 * Dump back a compiled form *
7310 * *
7311 ************************************************************************/
7312static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
7313
7314/**
7315 * xmlRelaxNGDumpDefines:
7316 * @output: the file output
7317 * @defines: a list of define structures
7318 *
7319 * Dump a RelaxNG structure back
7320 */
7321static void
7322xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
7323 while (defines != NULL) {
7324 xmlRelaxNGDumpDefine(output, defines);
7325 defines = defines->next;
7326 }
7327}
7328
7329/**
7330 * xmlRelaxNGDumpDefine:
7331 * @output: the file output
7332 * @define: a define structure
7333 *
7334 * Dump a RelaxNG structure back
7335 */
7336static void
7337xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
7338 if (define == NULL)
7339 return;
7340 switch(define->type) {
7341 case XML_RELAXNG_EMPTY:
7342 fprintf(output, "<empty/>\n");
7343 break;
7344 case XML_RELAXNG_NOT_ALLOWED:
7345 fprintf(output, "<notAllowed/>\n");
7346 break;
7347 case XML_RELAXNG_TEXT:
7348 fprintf(output, "<text/>\n");
7349 break;
7350 case XML_RELAXNG_ELEMENT:
7351 fprintf(output, "<element>\n");
7352 if (define->name != NULL) {
7353 fprintf(output, "<name");
7354 if (define->ns != NULL)
7355 fprintf(output, " ns=\"%s\"", define->ns);
7356 fprintf(output, ">%s</name>\n", define->name);
7357 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007358 xmlRelaxNGDumpDefines(output, define->attrs);
7359 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007360 fprintf(output, "</element>\n");
7361 break;
7362 case XML_RELAXNG_LIST:
7363 fprintf(output, "<list>\n");
7364 xmlRelaxNGDumpDefines(output, define->content);
7365 fprintf(output, "</list>\n");
7366 break;
7367 case XML_RELAXNG_ONEORMORE:
7368 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007369 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007370 fprintf(output, "</oneOrMore>\n");
7371 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007372 case XML_RELAXNG_ZEROORMORE:
7373 fprintf(output, "<zeroOrMore>\n");
7374 xmlRelaxNGDumpDefines(output, define->content);
7375 fprintf(output, "</zeroOrMore>\n");
7376 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007377 case XML_RELAXNG_CHOICE:
7378 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007379 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007380 fprintf(output, "</choice>\n");
7381 break;
7382 case XML_RELAXNG_GROUP:
7383 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007384 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007385 fprintf(output, "</group>\n");
7386 break;
7387 case XML_RELAXNG_INTERLEAVE:
7388 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007389 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007390 fprintf(output, "</interleave>\n");
7391 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007392 case XML_RELAXNG_OPTIONAL:
7393 fprintf(output, "<optional>\n");
7394 xmlRelaxNGDumpDefines(output, define->content);
7395 fprintf(output, "</optional>\n");
7396 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007397 case XML_RELAXNG_ATTRIBUTE:
7398 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007399 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007400 fprintf(output, "</attribute>\n");
7401 break;
7402 case XML_RELAXNG_DEF:
7403 fprintf(output, "<define");
7404 if (define->name != NULL)
7405 fprintf(output, " name=\"%s\"", define->name);
7406 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007407 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007408 fprintf(output, "</define>\n");
7409 break;
7410 case XML_RELAXNG_REF:
7411 fprintf(output, "<ref");
7412 if (define->name != NULL)
7413 fprintf(output, " name=\"%s\"", define->name);
7414 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007415 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007416 fprintf(output, "</ref>\n");
7417 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00007418 case XML_RELAXNG_PARENTREF:
7419 fprintf(output, "<parentRef");
7420 if (define->name != NULL)
7421 fprintf(output, " name=\"%s\"", define->name);
7422 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007423 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00007424 fprintf(output, "</parentRef>\n");
7425 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007426 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00007427 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00007428 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00007429 fprintf(output, "</externalRef>\n");
7430 break;
7431 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00007432 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007433 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00007434 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007435 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007436 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00007437 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00007438 TODO
7439 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00007440 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007441 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00007442 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007443 }
7444}
7445
7446/**
7447 * xmlRelaxNGDumpGrammar:
7448 * @output: the file output
7449 * @grammar: a grammar structure
7450 * @top: is this a top grammar
7451 *
7452 * Dump a RelaxNG structure back
7453 */
7454static void
7455xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
7456{
7457 if (grammar == NULL)
7458 return;
7459
7460 fprintf(output, "<grammar");
7461 if (top)
7462 fprintf(output,
7463 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7464 switch(grammar->combine) {
7465 case XML_RELAXNG_COMBINE_UNDEFINED:
7466 break;
7467 case XML_RELAXNG_COMBINE_CHOICE:
7468 fprintf(output, " combine=\"choice\"");
7469 break;
7470 case XML_RELAXNG_COMBINE_INTERLEAVE:
7471 fprintf(output, " combine=\"interleave\"");
7472 break;
7473 default:
7474 fprintf(output, " <!-- invalid combine value -->");
7475 }
7476 fprintf(output, ">\n");
7477 if (grammar->start == NULL) {
7478 fprintf(output, " <!-- grammar had no start -->");
7479 } else {
7480 fprintf(output, "<start>\n");
7481 xmlRelaxNGDumpDefine(output, grammar->start);
7482 fprintf(output, "</start>\n");
7483 }
7484 /* TODO ? Dump the defines ? */
7485 fprintf(output, "</grammar>\n");
7486}
7487
7488/**
7489 * xmlRelaxNGDump:
7490 * @output: the file output
7491 * @schema: a schema structure
7492 *
7493 * Dump a RelaxNG structure back
7494 */
7495void
7496xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7497{
7498 if (schema == NULL) {
7499 fprintf(output, "RelaxNG empty or failed to compile\n");
7500 return;
7501 }
7502 fprintf(output, "RelaxNG: ");
7503 if (schema->doc == NULL) {
7504 fprintf(output, "no document\n");
7505 } else if (schema->doc->URL != NULL) {
7506 fprintf(output, "%s\n", schema->doc->URL);
7507 } else {
7508 fprintf(output, "\n");
7509 }
7510 if (schema->topgrammar == NULL) {
7511 fprintf(output, "RelaxNG has no top grammar\n");
7512 return;
7513 }
7514 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7515}
7516
Daniel Veillardfebcca42003-02-16 15:44:18 +00007517/**
7518 * xmlRelaxNGDumpTree:
7519 * @output: the file output
7520 * @schema: a schema structure
7521 *
7522 * Dump the transformed RelaxNG tree.
7523 */
7524void
7525xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7526{
7527 if (schema == NULL) {
7528 fprintf(output, "RelaxNG empty or failed to compile\n");
7529 return;
7530 }
7531 if (schema->doc == NULL) {
7532 fprintf(output, "no document\n");
7533 } else {
7534 xmlDocDump(output, schema->doc);
7535 }
7536}
7537
Daniel Veillard6eadf632003-01-23 18:29:16 +00007538/************************************************************************
7539 * *
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007540 * Validation of compiled content *
Daniel Veillard6eadf632003-01-23 18:29:16 +00007541 * *
7542 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00007543static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7544 xmlRelaxNGDefinePtr define);
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007545
7546/**
7547 * xmlRelaxNGValidateCompiledCallback:
7548 * @exec: the regular expression instance
7549 * @token: the token which matched
7550 * @transdata: callback data, the define for the subelement if available
7551 @ @inputdata: callback data, the Relax NG validation context
7552 *
7553 * Handle the callback and if needed validate the element children.
7554 */
7555static void
7556xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7557 const xmlChar *token,
7558 void *transdata,
7559 void *inputdata) {
7560 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7561 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
7562 int ret;
7563
7564#ifdef DEBUG_COMPILE
7565 xmlGenericError(xmlGenericErrorContext,
7566 "Compiled callback for: '%s'\n", token);
7567#endif
7568 if (ctxt == NULL) {
7569 fprintf(stderr, "callback on %s missing context\n", token);
7570 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7571 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7572 return;
7573 }
7574 if (define == NULL) {
7575 if (token[0] == '#')
7576 return;
7577 fprintf(stderr, "callback on %s missing define\n", token);
7578 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7579 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7580 return;
7581 }
7582 if ((ctxt == NULL) || (define == NULL)) {
7583 fprintf(stderr, "callback on %s missing info\n", token);
7584 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7585 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7586 return;
7587 } else if (define->type != XML_RELAXNG_ELEMENT) {
7588 fprintf(stderr, "callback on %s define is not element\n", token);
7589 if (ctxt->errNo == XML_RELAXNG_OK)
7590 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7591 return;
7592 }
7593 ret = xmlRelaxNGValidateDefinition(ctxt, define);
7594}
7595
7596/**
7597 * xmlRelaxNGValidateCompiledContent:
7598 * @ctxt: the RelaxNG validation context
7599 * @regexp: the regular expression as compiled
7600 * @content: list of children to test against the regexp
7601 *
7602 * Validate the content model of an element or start using the regexp
7603 *
7604 * Returns 0 in case of success, -1 in case of error.
7605 */
7606static int
7607xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt,
7608 xmlRegexpPtr regexp, xmlNodePtr content) {
7609 xmlRegExecCtxtPtr exec;
7610 xmlNodePtr cur;
Daniel Veillard62163602003-04-17 09:36:38 +00007611 int ret = 0;
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007612
7613 if ((ctxt == NULL) || (regexp == NULL))
7614 return(-1);
7615 exec = xmlRegNewExecCtxt(regexp,
7616 xmlRelaxNGValidateCompiledCallback, ctxt);
7617 cur = content;
7618 while (cur != NULL) {
7619 ctxt->state->seq = cur;
7620 switch (cur->type) {
7621 case XML_TEXT_NODE:
7622 case XML_CDATA_SECTION_NODE:
7623 if (xmlIsBlankNode(cur))
7624 break;
7625 ret = xmlRegExecPushString(exec, BAD_CAST "#text", ctxt);
7626 if (ret < 0) {
7627 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, cur->parent->name);
7628 }
7629 break;
7630 case XML_ELEMENT_NODE:
7631 if (cur->ns != NULL) {
7632 ret = xmlRegExecPushString2(exec, cur->name,
7633 cur->ns->href, ctxt);
7634 } else {
7635 ret = xmlRegExecPushString(exec, cur->name, ctxt);
7636 }
7637 if (ret < 0) {
7638 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, cur->name);
7639 }
7640 break;
7641 default:
7642 break;
7643 }
7644 if (ret < 0) break;
7645 /*
7646 * Switch to next element
7647 */
7648 cur = cur->next;
7649 }
7650 ret = xmlRegExecPushString(exec, NULL, NULL);
7651 if (ret == 1) {
7652 ret = 0;
7653 ctxt->state->seq = NULL;
7654 } else if (ret == 0) {
7655 /*
Daniel Veillardf4e55762003-04-15 23:32:22 +00007656 * TODO: get some of the names needed to exit the current state of exec
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00007657 */
7658 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
7659 ret = -1;
7660 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7661 xmlRelaxNGDumpValidError(ctxt);
7662 } else {
7663 ret = -1;
7664 }
7665 xmlRegFreeExecCtxt(exec);
7666 return(ret);
7667}
7668
7669/************************************************************************
7670 * *
7671 * Progressive validation of when possible *
7672 * *
7673 ************************************************************************/
Daniel Veillardf4e55762003-04-15 23:32:22 +00007674static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7675 xmlRelaxNGDefinePtr defines);
7676static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt);
7677
7678/**
7679 * xmlRelaxNGElemPush:
7680 * @ctxt: the validation context
7681 * @exec: the regexp runtime for the new content model
7682 *
7683 * Push a new regexp for the current node content model on the stack
7684 *
7685 * Returns 0 in case of success and -1 in case of error.
7686 */
7687static int
7688xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRegExecCtxtPtr exec) {
7689 if (ctxt->elemTab == NULL) {
7690 ctxt->elemMax = 10;
7691 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlMalloc(ctxt->elemMax *
7692 sizeof(xmlRegExecCtxtPtr));
7693 if (ctxt->elemTab == NULL) {
7694 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7695 return(-1);
7696 }
7697 }
7698 if (ctxt->elemNr >= ctxt->elemMax) {
7699 ctxt->elemMax *= 2;
7700 ctxt->elemTab = (xmlRegExecCtxtPtr *) xmlRealloc(ctxt->elemTab,
7701 ctxt->elemMax * sizeof(xmlRegExecCtxtPtr));
7702 if (ctxt->elemTab == NULL) {
7703 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7704 return(-1);
7705 }
7706 }
7707 ctxt->elemTab[ctxt->elemNr++] = exec;
7708 ctxt->elem = exec;
7709 return(0);
7710}
7711
7712/**
7713 * xmlRelaxNGElemPop:
7714 * @ctxt: the validation context
7715 *
7716 * Pop the regexp of the current node content model from the stack
7717 *
7718 * Returns the exec or NULL if empty
7719 */
7720static xmlRegExecCtxtPtr
7721xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt) {
7722 xmlRegExecCtxtPtr ret;
7723
7724 if (ctxt->elemNr <= 0) return(NULL);
7725 ctxt->elemNr--;
7726 ret = ctxt->elemTab[ctxt->elemNr];
7727 ctxt->elemTab[ctxt->elemNr] = NULL;
7728 if (ctxt->elemNr > 0)
7729 ctxt->elem = ctxt->elemTab[ctxt->elemNr - 1];
7730 else
7731 ctxt->elem = NULL;
7732 return(ret);
7733}
7734
7735/**
7736 * xmlRelaxNGValidateProgressiveCallback:
7737 * @exec: the regular expression instance
7738 * @token: the token which matched
7739 * @transdata: callback data, the define for the subelement if available
7740 @ @inputdata: callback data, the Relax NG validation context
7741 *
7742 * Handle the callback and if needed validate the element children.
7743 * some of the in/out informations are passed via the context in @inputdata.
7744 */
7745static void
7746xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
7747 const xmlChar *token,
7748 void *transdata,
7749 void *inputdata) {
7750 xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
7751 xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
Daniel Veillardce192eb2003-04-16 15:58:05 +00007752 xmlRelaxNGValidStatePtr state, oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007753 xmlNodePtr node = ctxt->pnode;
Daniel Veillardc3ca5ba2003-05-09 22:26:28 +00007754 int ret = 0, oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007755
7756#ifdef DEBUG_PROGRESSIVE
7757 xmlGenericError(xmlGenericErrorContext,
7758 "Progressive callback for: '%s'\n", token);
7759#endif
7760 if (ctxt == NULL) {
7761 fprintf(stderr, "callback on %s missing context\n", token);
7762 return;
7763 }
7764 ctxt->pstate = 1;
7765 if (define == NULL) {
7766 if (token[0] == '#')
7767 return;
7768 fprintf(stderr, "callback on %s missing define\n", token);
7769 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7770 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7771 ctxt->pstate = -1;
7772 return;
7773 }
7774 if ((ctxt == NULL) || (define == NULL)) {
7775 fprintf(stderr, "callback on %s missing info\n", token);
7776 if ((ctxt != NULL) && (ctxt->errNo == XML_RELAXNG_OK))
7777 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7778 ctxt->pstate = -1;
7779 return;
7780 } else if (define->type != XML_RELAXNG_ELEMENT) {
7781 fprintf(stderr, "callback on %s define is not element\n", token);
7782 if (ctxt->errNo == XML_RELAXNG_OK)
7783 ctxt->errNo = XML_RELAXNG_ERR_INTERNAL;
7784 ctxt->pstate = -1;
7785 return;
7786 }
7787 if (node->type != XML_ELEMENT_NODE) {
7788 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
7789 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7790 xmlRelaxNGDumpValidError(ctxt);
7791 ctxt->pstate = -1;
7792 return;
7793 }
7794 if (define->contModel == NULL) {
7795 /*
7796 * this node cannot be validated in a streamable fashion
7797 */
7798#ifdef DEBUG_PROGRESSIVE
7799 xmlGenericError(xmlGenericErrorContext,
7800 "Element '%s' validation is not streamable\n", token);
7801#endif
7802 ctxt->pstate = 0;
7803 ctxt->pdef = define;
7804 return;
7805 }
7806 exec = xmlRegNewExecCtxt(define->contModel,
7807 xmlRelaxNGValidateProgressiveCallback,
7808 ctxt);
7809 if (exec == NULL) {
7810 ctxt->pstate = -1;
7811 return;
7812 }
7813 xmlRelaxNGElemPush(ctxt, exec);
7814
7815 /*
7816 * Validate the attributes part of the content.
7817 */
7818 state = xmlRelaxNGNewValidState(ctxt, node);
7819 if (state == NULL) {
7820 ctxt->pstate = -1;
7821 return;
7822 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007823 oldstate = ctxt->state;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007824 ctxt->state = state;
7825 if (define->attrs != NULL) {
7826 ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
7827 if (ret != 0) {
7828 ctxt->pstate = -1;
7829 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
7830 }
7831 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007832 if (ctxt->state != NULL) {
7833 ctxt->state->seq = NULL;
7834 ret = xmlRelaxNGValidateElementEnd(ctxt);
7835 if (ret != 0) {
7836 ctxt->pstate = -1;
7837 }
7838 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
7839 } else if (ctxt->states != NULL) {
7840 int tmp = -1, i;
7841
7842 oldflags = ctxt->flags;
7843 ctxt->flags |= FLAGS_IGNORABLE;
7844
7845 for (i = 0; i < ctxt->states->nbState; i++) {
7846 state = ctxt->states->tabState[i];
7847 ctxt->state = state;
7848 ctxt->state->seq = NULL;
7849
7850 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
7851 tmp = 0;
7852 xmlRelaxNGFreeValidState(ctxt, state);
7853 }
7854 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7855 ctxt->states = NULL;
7856 if ((ret == 0) && (tmp == -1))
7857 ctxt->pstate = -1;
7858 ctxt->flags = oldflags;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007859 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00007860 if (ctxt->pstate == -1) {
7861 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
7862 xmlRelaxNGDumpValidError(ctxt);
7863 }
7864 }
7865 ctxt->state = oldstate;
Daniel Veillardf4e55762003-04-15 23:32:22 +00007866}
7867
7868/**
7869 * xmlRelaxNGValidatePushElement:
7870 * @ctxt: the validation context
7871 * @doc: a document instance
7872 * @elem: an element instance
7873 *
7874 * Push a new element start on the RelaxNG validation stack.
7875 *
7876 * returns 1 if no validation problem was found or 0 if validating the
7877 * element requires a full node, and -1 in case of error.
7878 */
7879int
Daniel Veillard33300b42003-04-17 09:09:19 +00007880xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt,
7881 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00007882 xmlNodePtr elem)
7883{
7884 int ret = 1;
7885
7886 if ((ctxt == NULL) || (elem == NULL))
7887 return (-1);
7888
7889#ifdef DEBUG_PROGRESSIVE
7890 xmlGenericError(xmlGenericErrorContext, "PushElem %s\n", elem->name);
7891#endif
7892 if (ctxt->elem == 0) {
7893 xmlRelaxNGPtr schema;
7894 xmlRelaxNGGrammarPtr grammar;
7895 xmlRegExecCtxtPtr exec;
7896 xmlRelaxNGDefinePtr define;
7897
7898 schema = ctxt->schema;
7899 if (schema == NULL) {
7900 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7901 return (-1);
7902 }
7903 grammar = schema->topgrammar;
7904 if ((grammar == NULL) || (grammar->start == NULL)) {
7905 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
7906 return (-1);
7907 }
7908 define = grammar->start;
7909 if (define->contModel == NULL) {
7910 ctxt->pdef = define;
7911 return (0);
7912 }
7913 exec = xmlRegNewExecCtxt(define->contModel,
7914 xmlRelaxNGValidateProgressiveCallback,
7915 ctxt);
7916 if (exec == NULL) {
7917 return (-1);
7918 }
7919 xmlRelaxNGElemPush(ctxt, exec);
7920 }
7921 ctxt->pnode = elem;
7922 ctxt->pstate = 0;
7923 if (elem->ns != NULL) {
7924 ret =
7925 xmlRegExecPushString2(ctxt->elem, elem->name, elem->ns->href,
7926 ctxt);
7927 } else {
7928 ret = xmlRegExecPushString(ctxt->elem, elem->name, ctxt);
7929 }
7930 if (ret < 0) {
7931 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG, elem->name);
7932 } else {
7933 if (ctxt->pstate == 0)
7934 ret = 0;
7935 else if (ctxt->pstate < 0)
7936 ret = -1;
7937 else
7938 ret = 1;
7939 }
7940#ifdef DEBUG_PROGRESSIVE
7941 if (ret < 0)
7942 xmlGenericError(xmlGenericErrorContext, "PushElem %s failed\n",
7943 elem->name);
7944#endif
7945 return (ret);
7946}
7947
7948/**
7949 * xmlRelaxNGValidatePushCData:
7950 * @ctxt: the RelaxNG validation context
7951 * @data: some character data read
7952 * @len: the lenght of the data
7953 *
7954 * check the CData parsed for validation in the current stack
7955 *
7956 * returns 1 if no validation problem was found or -1 otherwise
7957 */
7958int
7959xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillard33300b42003-04-17 09:09:19 +00007960 const xmlChar * data,
7961 int len ATTRIBUTE_UNUSED)
Daniel Veillardf4e55762003-04-15 23:32:22 +00007962{
7963 int ret = 1;
7964
7965 if ((ctxt == NULL) || (ctxt->elem == NULL) || (data == NULL))
7966 return (-1);
7967
7968#ifdef DEBUG_PROGRESSIVE
7969 xmlGenericError(xmlGenericErrorContext, "CDATA %s %d\n", data, len);
7970#endif
7971
7972 while (*data != 0) {
7973 if (!IS_BLANK(*data))
7974 break;
7975 data++;
7976 }
7977 if (*data == 0)
7978 return(1);
7979
7980 ret = xmlRegExecPushString(ctxt->elem, BAD_CAST "#text", ctxt);
7981 if (ret < 0) {
Daniel Veillard33300b42003-04-17 09:09:19 +00007982 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG, BAD_CAST " TODO ");
Daniel Veillardf4e55762003-04-15 23:32:22 +00007983#ifdef DEBUG_PROGRESSIVE
7984 xmlGenericError(xmlGenericErrorContext, "CDATA failed\n");
7985#endif
7986
7987 return(-1);
7988 }
7989 return(1);
7990}
7991
7992/**
7993 * xmlRelaxNGValidatePopElement:
7994 * @ctxt: the RelaxNG validation context
7995 * @doc: a document instance
7996 * @elem: an element instance
7997 *
7998 * Pop the element end from the RelaxNG validation stack.
7999 *
8000 * returns 1 if no validation problem was found or 0 otherwise
8001 */
8002int
8003xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt,
8004 xmlDocPtr doc ATTRIBUTE_UNUSED,
8005 xmlNodePtr elem) {
8006 int ret;
8007 xmlRegExecCtxtPtr exec;
8008
8009 if ((ctxt == NULL) || (ctxt->elem == NULL) || (elem == NULL)) return(-1);
8010#ifdef DEBUG_PROGRESSIVE
8011 xmlGenericError(xmlGenericErrorContext, "PopElem %s\n", elem->name);
8012#endif
8013 /*
8014 * verify that we reached a terminal state of the content model.
8015 */
8016 exec = xmlRelaxNGElemPop(ctxt);
8017 ret = xmlRegExecPushString(exec, NULL, NULL);
8018 if (ret == 0) {
8019 /*
8020 * TODO: get some of the names needed to exit the current state of exec
8021 */
8022 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, BAD_CAST "");
8023 ret = -1;
8024 } else if (ret < 0) {
8025 ret = -1;
8026 } else {
8027 ret = 1;
8028 }
8029 xmlRegFreeExecCtxt(exec);
8030#ifdef DEBUG_PROGRESSIVE
8031 if (ret < 0)
8032 xmlGenericError(xmlGenericErrorContext, "PopElem %s failed\n",
8033 elem->name);
8034#endif
8035 return(ret);
8036}
8037
8038/**
8039 * xmlRelaxNGValidateFullElement:
8040 * @ctxt: the validation context
8041 * @doc: a document instance
8042 * @elem: an element instance
8043 *
8044 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8045 * 0 and the content of the node has been expanded.
8046 *
8047 * returns 1 if no validation problem was found or -1 in case of error.
8048 */
8049int
Daniel Veillard33300b42003-04-17 09:09:19 +00008050xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt,
8051 xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillardf4e55762003-04-15 23:32:22 +00008052 xmlNodePtr elem) {
8053 int ret;
8054 xmlRelaxNGValidStatePtr state;
8055
8056 if ((ctxt == NULL) || (ctxt->pdef == NULL) || (elem == NULL)) return(-1);
8057#ifdef DEBUG_PROGRESSIVE
8058 xmlGenericError(xmlGenericErrorContext, "FullElem %s\n", elem->name);
8059#endif
8060 state = xmlRelaxNGNewValidState(ctxt, elem->parent);
8061 if (state == NULL) {
8062 return(-1);
8063 }
8064 state->seq = elem;
8065 ctxt->state = state;
8066 ctxt->errNo = XML_RELAXNG_OK;
8067 ret = xmlRelaxNGValidateDefinition(ctxt, ctxt->pdef);
8068 if ((ret != 0) || (ctxt->errNo != XML_RELAXNG_OK)) ret = -1;
8069 else ret = 1;
8070 xmlRelaxNGFreeValidState(ctxt, state);
8071 ctxt->state = NULL;
8072#ifdef DEBUG_PROGRESSIVE
8073 if (ret < 0)
8074 xmlGenericError(xmlGenericErrorContext, "FullElem %s failed\n",
8075 elem->name);
8076#endif
8077 return(ret);
8078}
8079
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00008080/************************************************************************
8081 * *
8082 * Generic interpreted validation implementation *
8083 * *
8084 ************************************************************************/
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008085static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8086 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008087
8088/**
8089 * xmlRelaxNGSkipIgnored:
8090 * @ctxt: a schema validation context
8091 * @node: the top node.
8092 *
8093 * Skip ignorable nodes in that context
8094 *
8095 * Returns the new sibling or NULL in case of error.
8096 */
8097static xmlNodePtr
8098xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
8099 xmlNodePtr node) {
8100 /*
8101 * TODO complete and handle entities
8102 */
8103 while ((node != NULL) &&
8104 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008105 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008106 (((node->type == XML_TEXT_NODE) ||
8107 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008108 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
8109 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00008110 node = node->next;
8111 }
8112 return(node);
8113}
8114
8115/**
Daniel Veillardedc91922003-01-26 00:52:04 +00008116 * xmlRelaxNGNormalize:
8117 * @ctxt: a schema validation context
8118 * @str: the string to normalize
8119 *
8120 * Implements the normalizeWhiteSpace( s ) function from
8121 * section 6.2.9 of the spec
8122 *
8123 * Returns the new string or NULL in case of error.
8124 */
8125static xmlChar *
8126xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
8127 xmlChar *ret, *p;
8128 const xmlChar *tmp;
8129 int len;
8130
8131 if (str == NULL)
8132 return(NULL);
8133 tmp = str;
8134 while (*tmp != 0) tmp++;
8135 len = tmp - str;
8136
Daniel Veillard3c908dc2003-04-19 00:07:51 +00008137 ret = (xmlChar *) xmlMallocAtomic((len + 1) * sizeof(xmlChar));
Daniel Veillardedc91922003-01-26 00:52:04 +00008138 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008139 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008140 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008141 } else {
8142 xmlGenericError(xmlGenericErrorContext,
8143 "xmlRelaxNGNormalize: out of memory\n");
8144 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008145 return(NULL);
8146 }
8147 p = ret;
8148 while (IS_BLANK(*str)) str++;
8149 while (*str != 0) {
8150 if (IS_BLANK(*str)) {
8151 while (IS_BLANK(*str)) str++;
8152 if (*str == 0)
8153 break;
8154 *p++ = ' ';
8155 } else
8156 *p++ = *str++;
8157 }
8158 *p = 0;
8159 return(ret);
8160}
8161
8162/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008163 * xmlRelaxNGValidateDatatype:
8164 * @ctxt: a Relax-NG validation context
8165 * @value: the string value
8166 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008167 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008168 *
8169 * Validate the given value against the dataype
8170 *
8171 * Returns 0 if the validation succeeded or an error code.
8172 */
8173static int
8174xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008175 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008176 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008177 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008178 void *result = NULL;
8179 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008180
8181 if ((define == NULL) || (define->data == NULL)) {
8182 return(-1);
8183 }
8184 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008185 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008186 if ((define->attrs != NULL) &&
8187 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008188 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008189 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008190 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008191 }
8192 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008193 ret = -1;
8194 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008195 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008196 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8197 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008198 return(-1);
8199 } else if (ret == 1) {
8200 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008201 } else if (ret == 2) {
8202 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008203 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008204 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008205 ret = -1;
8206 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008207 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008208 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
8209 if (lib->facet != NULL) {
8210 tmp = lib->facet(lib->data, define->name, cur->name,
8211 cur->value, value, result);
8212 if (tmp != 0)
8213 ret = -1;
8214 }
8215 cur = cur->next;
8216 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008217 if ((ret == 0) && (define->content != NULL)) {
8218 const xmlChar *oldvalue, *oldendvalue;
8219
8220 oldvalue = ctxt->state->value;
8221 oldendvalue = ctxt->state->endvalue;
8222 ctxt->state->value = (xmlChar *) value;
8223 ctxt->state->endvalue = NULL;
8224 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8225 ctxt->state->value = (xmlChar *) oldvalue;
8226 ctxt->state->endvalue = (xmlChar *) oldendvalue;
8227 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00008228 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
8229 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00008230 return(ret);
8231}
8232
8233/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008234 * xmlRelaxNGNextValue:
8235 * @ctxt: a Relax-NG validation context
8236 *
8237 * Skip to the next value when validating within a list
8238 *
8239 * Returns 0 if the operation succeeded or an error code.
8240 */
8241static int
8242xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
8243 xmlChar *cur;
8244
8245 cur = ctxt->state->value;
8246 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
8247 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00008248 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008249 return(0);
8250 }
8251 while (*cur != 0) cur++;
8252 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
8253 if (cur == ctxt->state->endvalue)
8254 ctxt->state->value = NULL;
8255 else
8256 ctxt->state->value = cur;
8257 return(0);
8258}
8259
8260/**
8261 * xmlRelaxNGValidateValueList:
8262 * @ctxt: a Relax-NG validation context
8263 * @defines: the list of definitions to verify
8264 *
8265 * Validate the given set of definitions for the current value
8266 *
8267 * Returns 0 if the validation succeeded or an error code.
8268 */
8269static int
8270xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
8271 xmlRelaxNGDefinePtr defines) {
8272 int ret = 0;
8273
8274 while (defines != NULL) {
8275 ret = xmlRelaxNGValidateValue(ctxt, defines);
8276 if (ret != 0)
8277 break;
8278 defines = defines->next;
8279 }
8280 return(ret);
8281}
8282
8283/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008284 * xmlRelaxNGValidateValue:
8285 * @ctxt: a Relax-NG validation context
8286 * @define: the definition to verify
8287 *
8288 * Validate the given definition for the current value
8289 *
8290 * Returns 0 if the validation succeeded or an error code.
8291 */
8292static int
8293xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
8294 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00008295 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008296 xmlChar *value;
8297
8298 value = ctxt->state->value;
8299 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008300 case XML_RELAXNG_EMPTY: {
8301 if ((value != NULL) && (value[0] != 0)) {
8302 int idx = 0;
8303
8304 while (IS_BLANK(value[idx]))
8305 idx++;
8306 if (value[idx] != 0)
8307 ret = -1;
8308 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008309 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00008310 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008311 case XML_RELAXNG_TEXT:
8312 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00008313 case XML_RELAXNG_VALUE: {
8314 if (!xmlStrEqual(value, define->value)) {
8315 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00008316 xmlRelaxNGTypeLibraryPtr lib;
8317
8318 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00008319 if ((lib != NULL) && (lib->comp != NULL)) {
8320 ret = lib->comp(lib->data, define->name,
8321 define->value, define->node,
8322 (void *) define->attrs,
8323 value, ctxt->state->node);
8324 } else
Daniel Veillardea3f3982003-01-26 19:45:18 +00008325 ret = -1;
8326 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008327 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00008328 return(-1);
8329 } else if (ret == 1) {
8330 ret = 0;
8331 } else {
8332 ret = -1;
8333 }
Daniel Veillardedc91922003-01-26 00:52:04 +00008334 } else {
8335 xmlChar *nval, *nvalue;
8336
8337 /*
8338 * TODO: trivial optimizations are possible by
8339 * computing at compile-time
8340 */
8341 nval = xmlRelaxNGNormalize(ctxt, define->value);
8342 nvalue = xmlRelaxNGNormalize(ctxt, value);
8343
Daniel Veillardea3f3982003-01-26 19:45:18 +00008344 if ((nval == NULL) || (nvalue == NULL) ||
8345 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00008346 ret = -1;
8347 if (nval != NULL)
8348 xmlFree(nval);
8349 if (nvalue != NULL)
8350 xmlFree(nvalue);
8351 }
8352 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008353 if (ret == 0)
8354 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00008355 break;
8356 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008357 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008358 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
8359 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008360 if (ret == 0)
8361 xmlRelaxNGNextValue(ctxt);
8362
8363 break;
8364 }
8365 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008366 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008367 xmlChar *oldvalue;
8368
8369 oldflags = ctxt->flags;
8370 ctxt->flags |= FLAGS_IGNORABLE;
8371
8372 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008373 while (list != NULL) {
8374 ret = xmlRelaxNGValidateValue(ctxt, list);
8375 if (ret == 0) {
8376 break;
8377 }
8378 ctxt->state->value = oldvalue;
8379 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008380 }
8381 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008382 if (ret != 0) {
8383 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8384 xmlRelaxNGDumpValidError(ctxt);
8385 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008386 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008387 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008388 if (ret == 0)
8389 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008390 break;
8391 }
8392 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008393 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008394 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00008395#ifdef DEBUG_LIST
8396 int nb_values = 0;
8397#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008398
8399 oldvalue = ctxt->state->value;
8400 oldend = ctxt->state->endvalue;
8401
8402 val = xmlStrdup(oldvalue);
8403 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00008404 val = xmlStrdup(BAD_CAST "");
8405 }
8406 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008407 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008408 return(-1);
8409 }
8410 cur = val;
8411 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00008412 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008413 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008414 cur++;
8415#ifdef DEBUG_LIST
8416 nb_values++;
8417#endif
8418 while (IS_BLANK(*cur))
8419 *cur++ = 0;
8420 } else
8421 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008422 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008423#ifdef DEBUG_LIST
8424 xmlGenericError(xmlGenericErrorContext,
8425 "list value: '%s' found %d items\n", oldvalue, nb_values);
8426 nb_values = 0;
8427#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008428 ctxt->state->endvalue = cur;
8429 cur = val;
8430 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008431
Daniel Veillardfd573f12003-03-16 17:52:32 +00008432 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008433
Daniel Veillardfd573f12003-03-16 17:52:32 +00008434 while (list != NULL) {
8435 if (ctxt->state->value == ctxt->state->endvalue)
8436 ctxt->state->value = NULL;
8437 ret = xmlRelaxNGValidateValue(ctxt, list);
8438 if (ret != 0) {
8439#ifdef DEBUG_LIST
8440 xmlGenericError(xmlGenericErrorContext,
8441 "Failed to validate value: '%s' with %d rule\n",
8442 ctxt->state->value, nb_values);
8443#endif
8444 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008445 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008446#ifdef DEBUG_LIST
8447 nb_values++;
8448#endif
8449 list = list->next;
8450 }
8451
8452 if ((ret == 0) && (ctxt->state->value != NULL) &&
8453 (ctxt->state->value != ctxt->state->endvalue)) {
8454 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
8455 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008456 }
8457 xmlFree(val);
8458 ctxt->state->value = oldvalue;
8459 ctxt->state->endvalue = oldend;
8460 break;
8461 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008462 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008463 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8464 if (ret != 0) {
8465 break;
8466 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008467 /* no break on purpose */
8468 case XML_RELAXNG_ZEROORMORE: {
8469 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008470
8471 oldflags = ctxt->flags;
8472 ctxt->flags |= FLAGS_IGNORABLE;
8473 cur = ctxt->state->value;
8474 temp = NULL;
8475 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
8476 (temp != cur)) {
8477 temp = cur;
8478 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
8479 if (ret != 0) {
8480 ctxt->state->value = temp;
8481 ret = 0;
8482 break;
8483 }
8484 cur = ctxt->state->value;
8485 }
8486 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00008487 if (ret != 0) {
8488 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8489 xmlRelaxNGDumpValidError(ctxt);
8490 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008491 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00008492 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00008493 break;
8494 }
Daniel Veillard416589a2003-02-17 17:25:42 +00008495 case XML_RELAXNG_EXCEPT: {
8496 xmlRelaxNGDefinePtr list;
8497
8498 list = define->content;
8499 while (list != NULL) {
8500 ret = xmlRelaxNGValidateValue(ctxt, list);
8501 if (ret == 0) {
8502 ret = -1;
8503 break;
8504 } else
8505 ret = 0;
8506 list = list->next;
8507 }
8508 break;
8509 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008510 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008511 case XML_RELAXNG_GROUP: {
8512 xmlRelaxNGDefinePtr list;
8513
8514 list = define->content;
8515 while (list != NULL) {
8516 ret = xmlRelaxNGValidateValue(ctxt, list);
8517 if (ret != 0) {
8518 ret = -1;
8519 break;
8520 } else
8521 ret = 0;
8522 list = list->next;
8523 }
Daniel Veillardd4310742003-02-18 21:12:46 +00008524 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008525 }
Daniel Veillard463a5472003-02-27 21:30:32 +00008526 case XML_RELAXNG_REF:
8527 case XML_RELAXNG_PARENTREF:
8528 ret = xmlRelaxNGValidateValue(ctxt, define->content);
8529 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008530 default:
8531 TODO
8532 ret = -1;
8533 }
8534 return(ret);
8535}
8536
8537/**
8538 * xmlRelaxNGValidateValueContent:
8539 * @ctxt: a Relax-NG validation context
8540 * @defines: the list of definitions to verify
8541 *
8542 * Validate the given definitions for the current value
8543 *
8544 * Returns 0 if the validation succeeded or an error code.
8545 */
8546static int
8547xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
8548 xmlRelaxNGDefinePtr defines) {
8549 int ret = 0;
8550
8551 while (defines != NULL) {
8552 ret = xmlRelaxNGValidateValue(ctxt, defines);
8553 if (ret != 0)
8554 break;
8555 defines = defines->next;
8556 }
8557 return(ret);
8558}
8559
8560/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008561 * xmlRelaxNGAttributeMatch:
8562 * @ctxt: a Relax-NG validation context
8563 * @define: the definition to check
8564 * @prop: the attribute
8565 *
8566 * Check if the attribute matches the definition nameClass
8567 *
8568 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8569 */
8570static int
8571xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
8572 xmlRelaxNGDefinePtr define,
8573 xmlAttrPtr prop) {
8574 int ret;
8575
8576 if (define->name != NULL) {
8577 if (!xmlStrEqual(define->name, prop->name))
8578 return(0);
8579 }
8580 if (define->ns != NULL) {
8581 if (define->ns[0] == 0) {
8582 if (prop->ns != NULL)
8583 return(0);
8584 } else {
8585 if ((prop->ns == NULL) ||
8586 (!xmlStrEqual(define->ns, prop->ns->href)))
8587 return(0);
8588 }
8589 }
8590 if (define->nameClass == NULL)
8591 return(1);
8592 define = define->nameClass;
8593 if (define->type == XML_RELAXNG_EXCEPT) {
8594 xmlRelaxNGDefinePtr list;
8595
8596 list = define->content;
8597 while (list != NULL) {
8598 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
8599 if (ret == 1)
8600 return(0);
8601 if (ret < 0)
8602 return(ret);
8603 list = list->next;
8604 }
8605 } else {
8606 TODO
8607 }
8608 return(1);
8609}
8610
8611/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008612 * xmlRelaxNGValidateAttribute:
8613 * @ctxt: a Relax-NG validation context
8614 * @define: the definition to verify
8615 *
8616 * Validate the given attribute definition for that node
8617 *
8618 * Returns 0 if the validation succeeded or an error code.
8619 */
8620static int
8621xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
8622 xmlRelaxNGDefinePtr define) {
8623 int ret = 0, i;
8624 xmlChar *value, *oldvalue;
8625 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008626 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008627
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008628 if (ctxt->state->nbAttrLeft <= 0)
8629 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008630 if (define->name != NULL) {
8631 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8632 tmp = ctxt->state->attrs[i];
8633 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
8634 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
8635 (tmp->ns == NULL)) ||
8636 ((tmp->ns != NULL) &&
8637 (xmlStrEqual(define->ns, tmp->ns->href)))) {
8638 prop = tmp;
8639 break;
8640 }
8641 }
8642 }
8643 if (prop != NULL) {
8644 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8645 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008646 oldseq = ctxt->state->seq;
8647 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008648 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00008649 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008650 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008651 if (ctxt->state->value != NULL)
8652 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008653 if (value != NULL)
8654 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008655 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008656 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008657 if (ret == 0) {
8658 /*
8659 * flag the attribute as processed
8660 */
8661 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008662 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008663 }
8664 } else {
8665 ret = -1;
8666 }
8667#ifdef DEBUG
8668 xmlGenericError(xmlGenericErrorContext,
8669 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
8670#endif
8671 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008672 for (i = 0;i < ctxt->state->nbAttrs;i++) {
8673 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00008674 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00008675 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008676 prop = tmp;
8677 break;
8678 }
8679 }
8680 if (prop != NULL) {
8681 value = xmlNodeListGetString(prop->doc, prop->children, 1);
8682 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008683 oldseq = ctxt->state->seq;
8684 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008685 ctxt->state->value = value;
8686 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00008687 if (ctxt->state->value != NULL)
8688 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008689 if (value != NULL)
8690 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00008691 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008692 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008693 if (ret == 0) {
8694 /*
8695 * flag the attribute as processed
8696 */
8697 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00008698 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008699 }
8700 } else {
8701 ret = -1;
8702 }
8703#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00008704 if (define->ns != NULL) {
8705 xmlGenericError(xmlGenericErrorContext,
8706 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
8707 define->ns, ret);
8708 } else {
8709 xmlGenericError(xmlGenericErrorContext,
8710 "xmlRelaxNGValidateAttribute(anyName): %d\n",
8711 ret);
8712 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00008713#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00008714 }
8715
8716 return(ret);
8717}
8718
8719/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008720 * xmlRelaxNGValidateAttributeList:
8721 * @ctxt: a Relax-NG validation context
8722 * @define: the list of definition to verify
8723 *
8724 * Validate the given node against the list of attribute definitions
8725 *
8726 * Returns 0 if the validation succeeded or an error code.
8727 */
8728static int
8729xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
8730 xmlRelaxNGDefinePtr defines) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00008731 int ret = 0, res;
8732 int needmore = 0;
8733 xmlRelaxNGDefinePtr cur;
8734
8735 cur = defines;
8736 while (cur != NULL) {
8737 if (cur->type == XML_RELAXNG_ATTRIBUTE) {
8738 if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
8739 ret = -1;
8740 } else
8741 needmore = 1;
8742 cur = cur->next;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008743 }
Daniel Veillardce192eb2003-04-16 15:58:05 +00008744 if (!needmore)
8745 return(ret);
8746 cur = defines;
8747 while (cur != NULL) {
8748 if (cur->type != XML_RELAXNG_ATTRIBUTE) {
8749 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8750 res = xmlRelaxNGValidateDefinition(ctxt, cur);
8751 if (res < 0)
8752 ret = -1;
8753 } else {
8754 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8755 return(-1);
8756 }
8757 if (res == -1) /* continues on -2 */
8758 break;
8759 }
8760 cur = cur->next;
8761 }
8762
Daniel Veillardfd573f12003-03-16 17:52:32 +00008763 return(ret);
8764}
8765
8766/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008767 * xmlRelaxNGNodeMatchesList:
8768 * @node: the node
8769 * @list: a NULL terminated array of definitions
8770 *
8771 * Check if a node can be matched by one of the definitions
8772 *
8773 * Returns 1 if matches 0 otherwise
8774 */
8775static int
8776xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
8777 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008778 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008779
8780 if ((node == NULL) || (list == NULL))
8781 return(0);
8782
8783 cur = list[i++];
8784 while (cur != NULL) {
8785 if ((node->type == XML_ELEMENT_NODE) &&
8786 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008787 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
8788 if (tmp == 1)
8789 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00008790 } else if (((node->type == XML_TEXT_NODE) ||
8791 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00008792 (cur->type == XML_RELAXNG_TEXT)) {
8793 return(1);
8794 }
8795 cur = list[i++];
8796 }
8797 return(0);
8798}
8799
8800/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008801 * xmlRelaxNGValidateInterleave:
8802 * @ctxt: a Relax-NG validation context
8803 * @define: the definition to verify
8804 *
8805 * Validate an interleave definition for a node.
8806 *
8807 * Returns 0 if the validation succeeded or an error code.
8808 */
8809static int
8810xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
8811 xmlRelaxNGDefinePtr define) {
8812 int ret = 0, i, nbgroups, left;
8813 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008814 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008815
8816 xmlRelaxNGValidStatePtr oldstate;
8817 xmlRelaxNGPartitionPtr partitions;
8818 xmlRelaxNGInterleaveGroupPtr group = NULL;
8819 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
8820 xmlNodePtr *list = NULL, *lasts = NULL;
8821
8822 if (define->data != NULL) {
8823 partitions = (xmlRelaxNGPartitionPtr) define->data;
8824 nbgroups = partitions->nbgroups;
8825 left = nbgroups;
8826 } else {
8827 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
8828 return(-1);
8829 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008830 /*
8831 * Optimizations for MIXED
8832 */
8833 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00008834 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008835 ctxt->flags |= FLAGS_MIXED_CONTENT;
8836 if (nbgroups == 2) {
8837 /*
8838 * this is a pure <mixed> case
8839 */
8840 if (ctxt->state != NULL)
8841 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8842 ctxt->state->seq);
8843 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
8844 ret = xmlRelaxNGValidateDefinition(ctxt,
8845 partitions->groups[1]->rule);
8846 else
8847 ret = xmlRelaxNGValidateDefinition(ctxt,
8848 partitions->groups[0]->rule);
8849 if (ret == 0) {
8850 if (ctxt->state != NULL)
8851 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
8852 ctxt->state->seq);
8853 }
8854 ctxt->flags = oldflags;
8855 return(ret);
8856 }
8857 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008858
8859 /*
8860 * Build arrays to store the first and last node of the chain
8861 * pertaining to each group
8862 */
8863 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8864 if (list == NULL) {
8865 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8866 return(-1);
8867 }
8868 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
8869 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
8870 if (lasts == NULL) {
8871 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8872 return(-1);
8873 }
8874 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
8875
8876 /*
8877 * Walk the sequence of children finding the right group and
8878 * sorting them in sequences.
8879 */
8880 cur = ctxt->state->seq;
8881 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8882 start = cur;
8883 while (cur != NULL) {
8884 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008885 if ((partitions->triage != NULL) &&
8886 (partitions->flags & IS_DETERMINIST)) {
8887 void *tmp = NULL;
8888
8889 if ((cur->type == XML_TEXT_NODE) ||
8890 (cur->type == XML_CDATA_SECTION_NODE)) {
8891 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
8892 NULL);
8893 } else if (cur->type == XML_ELEMENT_NODE) {
8894 if (cur->ns != NULL) {
8895 tmp = xmlHashLookup2(partitions->triage, cur->name,
8896 cur->ns->href);
8897 if (tmp == NULL)
8898 tmp = xmlHashLookup2(partitions->triage,
8899 BAD_CAST "#any", cur->ns->href);
8900 } else
8901 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
8902 if (tmp == NULL)
8903 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
8904 NULL);
8905 }
8906
8907 if (tmp == NULL) {
8908 i = nbgroups;
8909 } else {
8910 i = ((long) tmp) - 1;
8911 if (partitions->flags & IS_NEEDCHECK) {
8912 group = partitions->groups[i];
8913 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
8914 i = nbgroups;
8915 }
8916 }
8917 } else {
8918 for (i = 0;i < nbgroups;i++) {
8919 group = partitions->groups[i];
8920 if (group == NULL)
8921 continue;
8922 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
8923 break;
8924 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008925 }
8926 /*
8927 * We break as soon as an element not matched is found
8928 */
8929 if (i >= nbgroups) {
8930 break;
8931 }
8932 if (lasts[i] != NULL) {
8933 lasts[i]->next = cur;
8934 lasts[i] = cur;
8935 } else {
8936 list[i] = cur;
8937 lasts[i] = cur;
8938 }
8939 if (cur->next != NULL)
8940 lastchg = cur->next;
8941 else
8942 lastchg = cur;
8943 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
8944 }
8945 if (ret != 0) {
8946 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
8947 ret = -1;
8948 goto done;
8949 }
8950 lastelem = cur;
8951 oldstate = ctxt->state;
8952 for (i = 0;i < nbgroups;i++) {
8953 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
8954 group = partitions->groups[i];
8955 if (lasts[i] != NULL) {
8956 last = lasts[i]->next;
8957 lasts[i]->next = NULL;
8958 }
8959 ctxt->state->seq = list[i];
8960 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
8961 if (ret != 0)
8962 break;
8963 if (ctxt->state != NULL) {
8964 cur = ctxt->state->seq;
8965 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00008966 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008967 oldstate = ctxt->state;
8968 ctxt->state = NULL;
8969 if (cur != NULL) {
8970 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
8971 ret = -1;
8972 ctxt->state = oldstate;
8973 goto done;
8974 }
8975 } else if (ctxt->states != NULL) {
8976 int j;
8977 int found = 0;
8978
8979 for (j = 0;j < ctxt->states->nbState;j++) {
8980 cur = ctxt->states->tabState[j]->seq;
8981 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
8982 if (cur == NULL) {
8983 found = 1;
8984 break;
8985 }
8986 }
8987 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008988 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008989 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
8990 }
8991 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008992 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008993 }
8994 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8995 ctxt->states = NULL;
8996 if (found == 0) {
8997 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
8998 ret = -1;
8999 ctxt->state = oldstate;
9000 goto done;
9001 }
9002 } else {
9003 ret = -1;
9004 break;
9005 }
9006 if (lasts[i] != NULL) {
9007 lasts[i]->next = last;
9008 }
9009 }
9010 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00009011 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009012 ctxt->state = oldstate;
9013 ctxt->state->seq = lastelem;
9014 if (ret != 0) {
9015 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
9016 ret = -1;
9017 goto done;
9018 }
9019
9020done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00009021 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009022 /*
9023 * builds the next links chain from the prev one
9024 */
9025 cur = lastchg;
9026 while (cur != NULL) {
9027 if ((cur == start) || (cur->prev == NULL))
9028 break;
9029 cur->prev->next = cur;
9030 cur = cur->prev;
9031 }
9032 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00009033 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009034 }
9035
9036 xmlFree(list);
9037 xmlFree(lasts);
9038 return(ret);
9039}
9040
9041/**
9042 * xmlRelaxNGValidateDefinitionList:
9043 * @ctxt: a Relax-NG validation context
9044 * @define: the list of definition to verify
9045 *
9046 * Validate the given node content against the (list) of definitions
9047 *
9048 * Returns 0 if the validation succeeded or an error code.
9049 */
9050static int
9051xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
9052 xmlRelaxNGDefinePtr defines) {
9053 int ret = 0, res;
9054
9055
Daniel Veillard952379b2003-03-17 15:37:12 +00009056 if (defines == NULL) {
9057 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
9058 return(-1);
9059 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009060 while (defines != NULL) {
9061 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
9062 res = xmlRelaxNGValidateDefinition(ctxt, defines);
9063 if (res < 0)
9064 ret = -1;
9065 } else {
9066 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
9067 return(-1);
9068 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009069 if (res == -1) /* continues on -2 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00009070 break;
9071 defines = defines->next;
9072 }
9073
9074 return(ret);
9075}
9076
9077/**
9078 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00009079 * @ctxt: a Relax-NG validation context
9080 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00009081 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00009082 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009083 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00009084 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009085 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00009086 */
9087static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00009088xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
9089 xmlRelaxNGDefinePtr define,
9090 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00009091 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00009092
Daniel Veillardfd573f12003-03-16 17:52:32 +00009093 if (define->name != NULL) {
9094 if (!xmlStrEqual(elem->name, define->name)) {
9095 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
9096 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009097 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009098 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009099 if ((define->ns != NULL) && (define->ns[0] != 0)) {
9100 if (elem->ns == NULL) {
9101 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
9102 elem->name);
9103 return(0);
9104 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
9105 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
9106 elem->name, define->ns);
9107 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009108 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009109 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
9110 (define->name == NULL)) {
9111 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9112 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009113 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009114 } else if ((elem->ns != NULL) && (define->name != NULL)) {
9115 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
9116 define->name);
9117 return(0);
9118 }
9119
9120 if (define->nameClass == NULL)
9121 return(1);
9122
9123 define = define->nameClass;
9124 if (define->type == XML_RELAXNG_EXCEPT) {
9125 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009126 if (ctxt != NULL) {
9127 oldflags = ctxt->flags;
9128 ctxt->flags |= FLAGS_IGNORABLE;
9129 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009130
9131 list = define->content;
9132 while (list != NULL) {
9133 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9134 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009135 if (ctxt != NULL)
9136 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009137 return(0);
9138 }
9139 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009140 if (ctxt != NULL)
9141 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009142 return(ret);
9143 }
9144 list = list->next;
9145 }
9146 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009147 if (ctxt != NULL) {
9148 ctxt->flags = oldflags;
9149 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009150 } else if (define->type == XML_RELAXNG_CHOICE) {
9151 xmlRelaxNGDefinePtr list;
9152
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009153 if (ctxt != NULL) {
9154 oldflags = ctxt->flags;
9155 ctxt->flags |= FLAGS_IGNORABLE;
9156 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009157
9158 list = define->nameClass;
9159 while (list != NULL) {
9160 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
9161 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009162 if (ctxt != NULL)
9163 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009164 return(1);
9165 }
9166 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009167 if (ctxt != NULL)
9168 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009169 return(ret);
9170 }
9171 list = list->next;
9172 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009173 if (ctxt != NULL) {
9174 if (ret != 0) {
9175 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9176 xmlRelaxNGDumpValidError(ctxt);
9177 } else {
9178 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
9179 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009180 }
9181 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00009182 if (ctxt != NULL) {
9183 ctxt->flags = oldflags;
9184 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009185 } else {
9186 TODO
9187 ret = -1;
9188 }
9189 return(ret);
9190}
9191
9192/**
9193 * xmlRelaxNGValidateElementEnd:
9194 * @ctxt: a Relax-NG validation context
9195 *
9196 * Validate the end of the element, implements check that
9197 * there is nothing left not consumed in the element content
9198 * or in the attribute list.
9199 *
9200 * Returns 0 if the validation succeeded or an error code.
9201 */
9202static int
9203xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
9204 int ret = 0, i;
9205 xmlRelaxNGValidStatePtr state;
9206
9207 state = ctxt->state;
9208 if (state->seq != NULL) {
9209 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
9210 if (state->seq != NULL) {
9211 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
9212 state->node->name, state->seq->name);
9213 ret = -1;
9214 }
9215 }
9216 for (i = 0;i < state->nbAttrs;i++) {
9217 if (state->attrs[i] != NULL) {
9218 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
9219 state->attrs[i]->name, state->node->name);
9220 ret = -1;
9221 }
9222 }
9223 return(ret);
9224}
9225
9226/**
9227 * xmlRelaxNGValidateState:
9228 * @ctxt: a Relax-NG validation context
9229 * @define: the definition to verify
9230 *
9231 * Validate the current state against the definition
9232 *
9233 * Returns 0 if the validation succeeded or an error code.
9234 */
9235static int
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009236xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
9237 xmlRelaxNGDefinePtr define)
9238{
Daniel Veillardfd573f12003-03-16 17:52:32 +00009239 xmlNodePtr node;
9240 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009241 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009242
9243 if (define == NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009244 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
9245 return (-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009246 }
9247
9248 if (ctxt->state != NULL) {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009249 node = ctxt->state->seq;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009250 } else {
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009251 node = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009252 }
9253#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009254 for (i = 0; i < ctxt->depth; i++)
9255 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009256 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009257 "Start validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009258 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009259 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009260 if ((node != NULL) && (node->name != NULL))
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009261 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009262 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009263 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009264#endif
9265 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009266 switch (define->type) {
9267 case XML_RELAXNG_EMPTY:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009268 node = xmlRelaxNGSkipIgnored(ctxt, node);
9269 ret = 0;
9270 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009271 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009272 ret = -1;
9273 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009274 case XML_RELAXNG_TEXT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009275 while ((node != NULL) &&
9276 ((node->type == XML_TEXT_NODE) ||
9277 (node->type == XML_COMMENT_NODE) ||
9278 (node->type == XML_PI_NODE) ||
9279 (node->type == XML_CDATA_SECTION_NODE)))
9280 node = node->next;
9281 ctxt->state->seq = node;
9282 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009283 case XML_RELAXNG_ELEMENT:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009284 errNr = ctxt->errNr;
9285 node = xmlRelaxNGSkipIgnored(ctxt, node);
9286 if (node == NULL) {
9287 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
9288 ret = -1;
9289 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9290 xmlRelaxNGDumpValidError(ctxt);
9291 break;
9292 }
9293 if (node->type != XML_ELEMENT_NODE) {
9294 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
9295 ret = -1;
9296 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9297 xmlRelaxNGDumpValidError(ctxt);
9298 break;
9299 }
9300 /*
9301 * This node was already validated successfully against
9302 * this definition.
9303 */
9304 if (node->_private == define) {
9305 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9306 if (ctxt->errNr > errNr)
9307 xmlRelaxNGPopErrors(ctxt, errNr);
9308 if (ctxt->errNr != 0) {
9309 while ((ctxt->err != NULL) &&
9310 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME)
9311 && (xmlStrEqual(ctxt->err->arg2, node->name)))
9312 ||
9313 ((ctxt->err->err ==
9314 XML_RELAXNG_ERR_ELEMEXTRANS)
9315 && (xmlStrEqual(ctxt->err->arg1, node->name)))
9316 || (ctxt->err->err == XML_RELAXNG_ERR_NOELEM)
9317 || (ctxt->err->err ==
9318 XML_RELAXNG_ERR_NOTELEM)))
9319 xmlRelaxNGValidErrorPop(ctxt);
9320 }
9321 break;
9322 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009323
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009324 ret = xmlRelaxNGElementMatch(ctxt, define, node);
9325 if (ret <= 0) {
9326 ret = -1;
9327 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9328 xmlRelaxNGDumpValidError(ctxt);
9329 break;
9330 }
9331 ret = 0;
9332 if (ctxt->errNr != 0) {
9333 if (ctxt->errNr > errNr)
9334 xmlRelaxNGPopErrors(ctxt, errNr);
9335 while ((ctxt->err != NULL) &&
9336 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
9337 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
9338 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
9339 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
9340 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
9341 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
9342 xmlRelaxNGValidErrorPop(ctxt);
9343 }
9344 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009345
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009346 oldflags = ctxt->flags;
9347 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
9348 ctxt->flags -= FLAGS_MIXED_CONTENT;
9349 }
9350 state = xmlRelaxNGNewValidState(ctxt, node);
9351 if (state == NULL) {
9352 ret = -1;
9353 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
9354 xmlRelaxNGDumpValidError(ctxt);
9355 break;
9356 }
Daniel Veillard7fe1f3a2003-03-31 22:13:33 +00009357
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009358 oldstate = ctxt->state;
9359 ctxt->state = state;
9360 if (define->attrs != NULL) {
9361 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
9362 if (tmp != 0) {
9363 ret = -1;
9364 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
9365 }
9366 }
9367 if (define->contModel != NULL) {
Daniel Veillardce192eb2003-04-16 15:58:05 +00009368 xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
9369 xmlRelaxNGStatesPtr tmpstates = ctxt->states;
9370 xmlNodePtr nseq;
9371
9372 nstate = xmlRelaxNGNewValidState(ctxt, node);
9373 ctxt->state = nstate;
9374 ctxt->states = NULL;
9375
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009376 tmp = xmlRelaxNGValidateCompiledContent(ctxt,
9377 define->contModel,
9378 ctxt->state->seq);
Daniel Veillardce192eb2003-04-16 15:58:05 +00009379 nseq = ctxt->state->seq;
9380 ctxt->state = tmpstate;
9381 ctxt->states = tmpstates;
9382 xmlRelaxNGFreeValidState(ctxt, nstate);
9383
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009384#ifdef DEBUG_COMPILE
9385 xmlGenericError(xmlGenericErrorContext,
9386 "Validating content of '%s' : %d\n", define->name, tmp);
9387#endif
Daniel Veillardce192eb2003-04-16 15:58:05 +00009388 if (tmp != 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009389 ret = -1;
Daniel Veillardce192eb2003-04-16 15:58:05 +00009390
9391 if (ctxt->states != NULL) {
9392 tmp = -1;
9393
9394 ctxt->flags |= FLAGS_IGNORABLE;
9395
9396 for (i = 0; i < ctxt->states->nbState; i++) {
9397 state = ctxt->states->tabState[i];
9398 ctxt->state = state;
9399 ctxt->state->seq = nseq;
9400
9401 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9402 tmp = 0;
9403 xmlRelaxNGFreeValidState(ctxt, state);
9404 }
9405 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9406 ctxt->flags = oldflags;
9407 ctxt->states = NULL;
9408 if ((ret == 0) && (tmp == -1))
9409 ret = -1;
9410 } else {
9411 state = ctxt->state;
9412 ctxt->state->seq = nseq;
9413 if (ret == 0)
9414 ret = xmlRelaxNGValidateElementEnd(ctxt);
9415 xmlRelaxNGFreeValidState(ctxt, state);
9416 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009417 } else {
9418 if (define->content != NULL) {
9419 tmp = xmlRelaxNGValidateDefinitionList(ctxt,
9420 define->content);
9421 if (tmp != 0) {
9422 ret = -1;
9423 if (ctxt->state == NULL) {
9424 ctxt->state = oldstate;
9425 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9426 node->name);
9427 ctxt->state = NULL;
9428 } else {
9429 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID,
9430 node->name);
9431 }
9432
9433 }
9434 }
9435 if (ctxt->states != NULL) {
9436 tmp = -1;
9437
9438 ctxt->flags |= FLAGS_IGNORABLE;
9439
9440 for (i = 0; i < ctxt->states->nbState; i++) {
9441 state = ctxt->states->tabState[i];
9442 ctxt->state = state;
9443
9444 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
9445 tmp = 0;
9446 xmlRelaxNGFreeValidState(ctxt, state);
9447 }
9448 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9449 ctxt->flags = oldflags;
9450 ctxt->states = NULL;
9451 if ((ret == 0) && (tmp == -1))
9452 ret = -1;
9453 } else {
9454 state = ctxt->state;
9455 if (ret == 0)
9456 ret = xmlRelaxNGValidateElementEnd(ctxt);
9457 xmlRelaxNGFreeValidState(ctxt, state);
9458 }
9459 }
9460 if (ret == 0) {
9461 node->_private = define;
9462 }
9463 ctxt->flags = oldflags;
9464 ctxt->state = oldstate;
9465 if (oldstate != NULL)
9466 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
9467 if (ret != 0) {
9468 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9469 xmlRelaxNGDumpValidError(ctxt);
9470 ret = 0;
9471 } else {
9472 ret = -2;
9473 }
9474 } else {
9475 if (ctxt->errNr > errNr)
9476 xmlRelaxNGPopErrors(ctxt, errNr);
9477 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009478
9479#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009480 xmlGenericError(xmlGenericErrorContext,
9481 "xmlRelaxNGValidateDefinition(): validated %s : %d",
9482 node->name, ret);
9483 if (oldstate == NULL)
9484 xmlGenericError(xmlGenericErrorContext, ": no state\n");
9485 else if (oldstate->seq == NULL)
9486 xmlGenericError(xmlGenericErrorContext, ": done\n");
9487 else if (oldstate->seq->type == XML_ELEMENT_NODE)
9488 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
9489 oldstate->seq->name);
9490 else
9491 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
9492 oldstate->seq->name, oldstate->seq->type);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009493#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009494 break;
9495 case XML_RELAXNG_OPTIONAL:{
9496 errNr = ctxt->errNr;
9497 oldflags = ctxt->flags;
9498 ctxt->flags |= FLAGS_IGNORABLE;
9499 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9500 ret =
9501 xmlRelaxNGValidateDefinitionList(ctxt,
9502 define->content);
9503 if (ret != 0) {
9504 if (ctxt->state != NULL)
9505 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9506 ctxt->state = oldstate;
9507 ctxt->flags = oldflags;
9508 ret = 0;
9509 if (ctxt->errNr > errNr)
9510 xmlRelaxNGPopErrors(ctxt, errNr);
9511 break;
9512 }
9513 if (ctxt->states != NULL) {
9514 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9515 } else {
9516 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
9517 if (ctxt->states == NULL) {
9518 xmlRelaxNGFreeValidState(ctxt, oldstate);
9519 ctxt->flags = oldflags;
9520 ret = -1;
9521 if (ctxt->errNr > errNr)
9522 xmlRelaxNGPopErrors(ctxt, errNr);
9523 break;
9524 }
9525 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
9526 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
9527 ctxt->state = NULL;
9528 }
9529 ctxt->flags = oldflags;
9530 ret = 0;
9531 if (ctxt->errNr > errNr)
9532 xmlRelaxNGPopErrors(ctxt, errNr);
9533 break;
9534 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009535 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009536 errNr = ctxt->errNr;
9537 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9538 if (ret != 0) {
9539 break;
9540 }
9541 if (ctxt->errNr > errNr)
9542 xmlRelaxNGPopErrors(ctxt, errNr);
9543 /* no break on purpose */
9544 case XML_RELAXNG_ZEROORMORE:{
9545 int progress;
9546 xmlRelaxNGStatesPtr states = NULL, res = NULL;
9547 int base, j;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009548
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009549 errNr = ctxt->errNr;
9550 res = xmlRelaxNGNewStates(ctxt, 1);
9551 if (res == NULL) {
9552 ret = -1;
9553 break;
9554 }
9555 /*
9556 * All the input states are also exit states
9557 */
9558 if (ctxt->state != NULL) {
9559 xmlRelaxNGAddStates(ctxt, res,
9560 xmlRelaxNGCopyValidState(ctxt,
9561 ctxt->
9562 state));
9563 } else {
9564 for (j = 0; j < ctxt->states->nbState; j++) {
9565 xmlRelaxNGAddStates(ctxt, res,
9566 xmlRelaxNGCopyValidState(ctxt,
9567 ctxt->
9568 states->
9569 tabState
9570 [j]));
9571 }
9572 }
9573 oldflags = ctxt->flags;
9574 ctxt->flags |= FLAGS_IGNORABLE;
9575 do {
9576 progress = 0;
9577 base = res->nbState;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009578
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009579 if (ctxt->states != NULL) {
9580 states = ctxt->states;
9581 for (i = 0; i < states->nbState; i++) {
9582 ctxt->state = states->tabState[i];
9583 ctxt->states = NULL;
9584 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9585 define->
9586 content);
9587 if (ret == 0) {
9588 if (ctxt->state != NULL) {
9589 tmp = xmlRelaxNGAddStates(ctxt, res,
9590 ctxt->state);
9591 ctxt->state = NULL;
9592 if (tmp == 1)
9593 progress = 1;
9594 } else if (ctxt->states != NULL) {
9595 for (j = 0; j < ctxt->states->nbState;
9596 j++) {
9597 tmp =
9598 xmlRelaxNGAddStates(ctxt, res,
9599 ctxt->
9600 states->
9601 tabState
9602 [j]);
9603 if (tmp == 1)
9604 progress = 1;
9605 }
9606 xmlRelaxNGFreeStates(ctxt,
9607 ctxt->states);
9608 ctxt->states = NULL;
9609 }
9610 } else {
9611 if (ctxt->state != NULL) {
9612 xmlRelaxNGFreeValidState(ctxt,
9613 ctxt->state);
9614 ctxt->state = NULL;
9615 }
9616 }
9617 }
9618 } else {
9619 ret = xmlRelaxNGValidateDefinitionList(ctxt,
9620 define->
9621 content);
9622 if (ret != 0) {
9623 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9624 ctxt->state = NULL;
9625 } else {
9626 base = res->nbState;
9627 if (ctxt->state != NULL) {
9628 tmp = xmlRelaxNGAddStates(ctxt, res,
9629 ctxt->state);
9630 ctxt->state = NULL;
9631 if (tmp == 1)
9632 progress = 1;
9633 } else if (ctxt->states != NULL) {
9634 for (j = 0; j < ctxt->states->nbState; j++) {
9635 tmp = xmlRelaxNGAddStates(ctxt, res,
9636 ctxt->
9637 states->
9638 tabState[j]);
9639 if (tmp == 1)
9640 progress = 1;
9641 }
9642 if (states == NULL) {
9643 states = ctxt->states;
9644 } else {
9645 xmlRelaxNGFreeStates(ctxt,
9646 ctxt->states);
9647 }
9648 ctxt->states = NULL;
9649 }
9650 }
9651 }
9652 if (progress) {
9653 /*
9654 * Collect all the new nodes added at that step
9655 * and make them the new node set
9656 */
9657 if (res->nbState - base == 1) {
9658 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
9659 res->
9660 tabState
9661 [base]);
9662 } else {
9663 if (states == NULL) {
9664 xmlRelaxNGNewStates(ctxt,
9665 res->nbState - base);
9666 }
9667 states->nbState = 0;
9668 for (i = base; i < res->nbState; i++)
9669 xmlRelaxNGAddStates(ctxt, states,
9670 xmlRelaxNGCopyValidState
9671 (ctxt,
9672 res->tabState[i]));
9673 ctxt->states = states;
9674 }
9675 }
9676 } while (progress == 1);
9677 if (states != NULL) {
9678 xmlRelaxNGFreeStates(ctxt, states);
9679 }
9680 ctxt->states = res;
9681 ctxt->flags = oldflags;
9682 if (ctxt->errNr > errNr)
9683 xmlRelaxNGPopErrors(ctxt, errNr);
9684 ret = 0;
9685 break;
9686 }
9687 case XML_RELAXNG_CHOICE:{
9688 xmlRelaxNGDefinePtr list = NULL;
9689 xmlRelaxNGStatesPtr states = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009690
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009691 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009692
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009693 errNr = ctxt->errNr;
9694 if ((define->dflags & IS_TRIABLE)
9695 && (define->data != NULL)) {
9696 xmlHashTablePtr triage =
9697 (xmlHashTablePtr) define->data;
Daniel Veillarde063f482003-03-21 16:53:17 +00009698
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009699 /*
9700 * Something we can optimize cleanly there is only one
9701 * possble branch out !
9702 */
9703 if (node == NULL) {
9704 ret = -1;
9705 break;
9706 }
9707 if ((node->type == XML_TEXT_NODE) ||
9708 (node->type == XML_CDATA_SECTION_NODE)) {
9709 list =
9710 xmlHashLookup2(triage, BAD_CAST "#text", NULL);
9711 } else if (node->type == XML_ELEMENT_NODE) {
9712 if (node->ns != NULL) {
9713 list = xmlHashLookup2(triage, node->name,
9714 node->ns->href);
9715 if (list == NULL)
9716 list =
9717 xmlHashLookup2(triage, BAD_CAST "#any",
9718 node->ns->href);
9719 } else
9720 list =
9721 xmlHashLookup2(triage, node->name, NULL);
9722 if (list == NULL)
9723 list =
9724 xmlHashLookup2(triage, BAD_CAST "#any",
9725 NULL);
9726 }
9727 if (list == NULL) {
9728 ret = -1;
9729 break;
9730 }
9731 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9732 if (ret == 0) {
9733 }
9734 break;
9735 }
Daniel Veillarde063f482003-03-21 16:53:17 +00009736
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009737 list = define->content;
9738 oldflags = ctxt->flags;
9739 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009740
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009741 while (list != NULL) {
9742 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
9743 ret = xmlRelaxNGValidateDefinition(ctxt, list);
9744 if (ret == 0) {
9745 if (states == NULL) {
9746 states = xmlRelaxNGNewStates(ctxt, 1);
9747 }
9748 if (ctxt->state != NULL) {
9749 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
9750 } else if (ctxt->states != NULL) {
9751 for (i = 0; i < ctxt->states->nbState; i++) {
9752 xmlRelaxNGAddStates(ctxt, states,
9753 ctxt->states->
9754 tabState[i]);
9755 }
9756 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9757 ctxt->states = NULL;
9758 }
9759 } else {
9760 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9761 }
9762 ctxt->state = oldstate;
9763 list = list->next;
9764 }
9765 if (states != NULL) {
9766 xmlRelaxNGFreeValidState(ctxt, oldstate);
9767 ctxt->states = states;
9768 ctxt->state = NULL;
9769 ret = 0;
9770 } else {
9771 ctxt->states = NULL;
9772 }
9773 ctxt->flags = oldflags;
9774 if (ret != 0) {
9775 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
9776 xmlRelaxNGDumpValidError(ctxt);
9777 }
9778 } else {
9779 if (ctxt->errNr > errNr)
9780 xmlRelaxNGPopErrors(ctxt, errNr);
9781 }
9782 break;
9783 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00009784 case XML_RELAXNG_DEF:
9785 case XML_RELAXNG_GROUP:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009786 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
9787 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009788 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009789 ret = xmlRelaxNGValidateInterleave(ctxt, define);
9790 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009791 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009792 ret = xmlRelaxNGValidateAttribute(ctxt, define);
9793 break;
Daniel Veillardf4e55762003-04-15 23:32:22 +00009794 case XML_RELAXNG_START:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009795 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00009796 case XML_RELAXNG_REF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009797 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard952379b2003-03-17 15:37:12 +00009798 case XML_RELAXNG_PARENTREF:
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009799 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
9800 break;
9801 case XML_RELAXNG_DATATYPE:{
9802 xmlNodePtr child;
9803 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009804
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009805 child = node;
9806 while (child != NULL) {
9807 if (child->type == XML_ELEMENT_NODE) {
9808 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
9809 node->parent->name);
9810 ret = -1;
9811 break;
9812 } else if ((child->type == XML_TEXT_NODE) ||
9813 (child->type == XML_CDATA_SECTION_NODE)) {
9814 content = xmlStrcat(content, child->content);
9815 }
9816 /* TODO: handle entities ... */
9817 child = child->next;
9818 }
9819 if (ret == -1) {
9820 if (content != NULL)
9821 xmlFree(content);
9822 break;
9823 }
9824 if (content == NULL) {
9825 content = xmlStrdup(BAD_CAST "");
9826 if (content == NULL) {
9827 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9828 ret = -1;
9829 break;
9830 }
9831 }
9832 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
9833 ctxt->state->seq);
9834 if (ret == -1) {
9835 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
9836 } else if (ret == 0) {
9837 ctxt->state->seq = NULL;
9838 }
9839 if (content != NULL)
9840 xmlFree(content);
9841 break;
9842 }
9843 case XML_RELAXNG_VALUE:{
9844 xmlChar *content = NULL;
9845 xmlChar *oldvalue;
9846 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009847
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009848 child = node;
9849 while (child != NULL) {
9850 if (child->type == XML_ELEMENT_NODE) {
9851 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
9852 node->parent->name);
9853 ret = -1;
9854 break;
9855 } else if ((child->type == XML_TEXT_NODE) ||
9856 (child->type == XML_CDATA_SECTION_NODE)) {
9857 content = xmlStrcat(content, child->content);
9858 }
9859 /* TODO: handle entities ... */
9860 child = child->next;
9861 }
9862 if (ret == -1) {
9863 if (content != NULL)
9864 xmlFree(content);
9865 break;
9866 }
9867 if (content == NULL) {
9868 content = xmlStrdup(BAD_CAST "");
9869 if (content == NULL) {
9870 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9871 ret = -1;
9872 break;
9873 }
9874 }
9875 oldvalue = ctxt->state->value;
9876 ctxt->state->value = content;
9877 ret = xmlRelaxNGValidateValue(ctxt, define);
9878 ctxt->state->value = oldvalue;
9879 if (ret == -1) {
9880 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
9881 } else if (ret == 0) {
9882 ctxt->state->seq = NULL;
9883 }
9884 if (content != NULL)
9885 xmlFree(content);
9886 break;
9887 }
9888 case XML_RELAXNG_LIST:{
9889 xmlChar *content;
9890 xmlNodePtr child;
9891 xmlChar *oldvalue, *oldendvalue;
9892 int len;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009893
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009894 /*
9895 * Make sure it's only text nodes
9896 */
9897
9898 content = NULL;
9899 child = node;
9900 while (child != NULL) {
9901 if (child->type == XML_ELEMENT_NODE) {
9902 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
9903 node->parent->name);
9904 ret = -1;
9905 break;
9906 } else if ((child->type == XML_TEXT_NODE) ||
9907 (child->type == XML_CDATA_SECTION_NODE)) {
9908 content = xmlStrcat(content, child->content);
9909 }
9910 /* TODO: handle entities ... */
9911 child = child->next;
9912 }
9913 if (ret == -1) {
9914 if (content != NULL)
9915 xmlFree(content);
9916 break;
9917 }
9918 if (content == NULL) {
9919 content = xmlStrdup(BAD_CAST "");
9920 if (content == NULL) {
9921 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
9922 ret = -1;
9923 break;
9924 }
9925 }
9926 len = xmlStrlen(content);
9927 oldvalue = ctxt->state->value;
9928 oldendvalue = ctxt->state->endvalue;
9929 ctxt->state->value = content;
9930 ctxt->state->endvalue = content + len;
9931 ret = xmlRelaxNGValidateValue(ctxt, define);
9932 ctxt->state->value = oldvalue;
9933 ctxt->state->endvalue = oldendvalue;
9934 if (ret == -1) {
9935 VALID_ERR(XML_RELAXNG_ERR_LIST);
9936 } else if ((ret == 0) && (node != NULL)) {
9937 ctxt->state->seq = node->next;
9938 }
9939 if (content != NULL)
9940 xmlFree(content);
9941 break;
9942 }
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009943 case XML_RELAXNG_EXCEPT:
9944 case XML_RELAXNG_PARAM:
9945 TODO ret = -1;
9946 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009947 }
9948 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009949#ifdef DEBUG
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009950 for (i = 0; i < ctxt->depth; i++)
9951 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009952 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009953 "Validating %s ", xmlRelaxNGDefName(define));
Daniel Veillardfd573f12003-03-16 17:52:32 +00009954 if (define->name != NULL)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009955 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009956 if (ret == 0)
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009957 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00009958 else
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009959 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009960#endif
Daniel Veillardc58f4ef2003-04-14 16:11:26 +00009961 return (ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009962}
9963
9964/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00009965 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009966 * @ctxt: a Relax-NG validation context
9967 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009968 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009969 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009970 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00009971 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009972 */
9973static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00009974xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
9975 xmlRelaxNGDefinePtr define) {
9976 xmlRelaxNGStatesPtr states, res;
9977 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00009978
Daniel Veillardfd573f12003-03-16 17:52:32 +00009979 /*
9980 * We should NOT have both ctxt->state and ctxt->states
9981 */
9982 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9983 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009984 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009985 ctxt->state = NULL;
9986 }
9987
9988 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
9989 if (ctxt->states != NULL) {
9990 ctxt->state = ctxt->states->tabState[0];
9991 xmlRelaxNGFreeStates(ctxt, ctxt->states);
9992 ctxt->states = NULL;
9993 }
9994 ret = xmlRelaxNGValidateState(ctxt, define);
9995 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
9996 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00009997 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00009998 ctxt->state = NULL;
9999 }
10000 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
10001 ctxt->state = ctxt->states->tabState[0];
10002 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10003 ctxt->states = NULL;
10004 }
10005 return(ret);
10006 }
10007
10008 states = ctxt->states;
10009 ctxt->states = NULL;
10010 res = NULL;
10011 j = 0;
10012 oldflags = ctxt->flags;
10013 ctxt->flags |= FLAGS_IGNORABLE;
10014 for (i = 0;i < states->nbState;i++) {
10015 ctxt->state = states->tabState[i];
10016 ctxt->states = NULL;
10017 ret = xmlRelaxNGValidateState(ctxt, define);
10018 /*
10019 * We should NOT have both ctxt->state and ctxt->states
10020 */
10021 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10022 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010023 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010024 ctxt->state = NULL;
10025 }
10026 if (ret == 0) {
10027 if (ctxt->states == NULL) {
10028 if (res != NULL) {
10029 /* add the state to the container */
10030 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
10031 ctxt->state = NULL;
10032 } else {
10033 /* add the state directly in states */
10034 states->tabState[j++] = ctxt->state;
10035 ctxt->state = NULL;
10036 }
10037 } else {
10038 if (res == NULL) {
10039 /* make it the new container and copy other results */
10040 res = ctxt->states;
10041 ctxt->states = NULL;
10042 for (k = 0;k < j;k++)
10043 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
10044 } else {
10045 /* add all the new results to res and reff the container */
10046 for (k = 0;k < ctxt->states->nbState;k++)
10047 xmlRelaxNGAddStates(ctxt, res,
10048 ctxt->states->tabState[k]);
10049 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10050 ctxt->states = NULL;
10051 }
10052 }
10053 } else {
10054 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +000010055 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010056 ctxt->state = NULL;
10057 } else if (ctxt->states != NULL) {
10058 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +000010059 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010060 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10061 ctxt->states = NULL;
10062 }
10063 }
10064 }
10065 ctxt->flags = oldflags;
10066 if (res != NULL) {
10067 xmlRelaxNGFreeStates(ctxt, states);
10068 ctxt->states = res;
10069 ret = 0;
10070 } else if (j > 1) {
10071 states->nbState = j;
10072 ctxt->states = states;
10073 ret =0;
10074 } else if (j == 1) {
10075 ctxt->state = states->tabState[0];
10076 xmlRelaxNGFreeStates(ctxt, states);
10077 ret = 0;
10078 } else {
10079 ret = -1;
10080 xmlRelaxNGFreeStates(ctxt, states);
10081 if (ctxt->states != NULL) {
10082 xmlRelaxNGFreeStates(ctxt, ctxt->states);
10083 ctxt->states = NULL;
10084 }
10085 }
10086 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
10087 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +000010088 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010089 ctxt->state = NULL;
10090 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010091 return(ret);
10092}
10093
Daniel Veillard1564e6e2003-03-15 21:30:25 +000010094/**
Daniel Veillard6eadf632003-01-23 18:29:16 +000010095 * xmlRelaxNGValidateDocument:
10096 * @ctxt: a Relax-NG validation context
10097 * @doc: the document
10098 *
10099 * Validate the given document
10100 *
10101 * Returns 0 if the validation succeeded or an error code.
10102 */
10103static int
10104xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10105 int ret;
10106 xmlRelaxNGPtr schema;
10107 xmlRelaxNGGrammarPtr grammar;
10108 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010109 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010110
10111 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
10112 return(-1);
10113
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010114 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010115 schema = ctxt->schema;
10116 grammar = schema->topgrammar;
10117 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +000010118 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010119 return(-1);
10120 }
10121 state = xmlRelaxNGNewValidState(ctxt, NULL);
10122 ctxt->state = state;
10123 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010124 if ((ctxt->state != NULL) && (state->seq != NULL)) {
10125 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010126 node = state->seq;
10127 node = xmlRelaxNGSkipIgnored(ctxt, node);
10128 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +000010129 if (ret != -1) {
10130 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10131 ret = -1;
10132 }
10133 }
10134 } else if (ctxt->states != NULL) {
10135 int i;
10136 int tmp = -1;
10137
10138 for (i = 0;i < ctxt->states->nbState;i++) {
10139 state = ctxt->states->tabState[i];
10140 node = state->seq;
10141 node = xmlRelaxNGSkipIgnored(ctxt, node);
10142 if (node == NULL)
10143 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +000010144 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +000010145 }
10146 if (tmp == -1) {
10147 if (ret != -1) {
10148 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
10149 ret = -1;
10150 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010151 }
10152 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +000010153 if (ctxt->state != NULL) {
10154 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
10155 ctxt->state = NULL;
10156 }
Daniel Veillard580ced82003-03-21 21:22:48 +000010157 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +000010158 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +000010159#ifdef DEBUG
10160 else if (ctxt->errNr != 0) {
10161 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
10162 ctxt->errNr);
10163 xmlRelaxNGDumpValidError(ctxt);
10164 }
10165#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010166 if (ctxt->idref == 1) {
10167 xmlValidCtxt vctxt;
10168
10169 memset(&vctxt, 0, sizeof(xmlValidCtxt));
10170 vctxt.valid = 1;
10171 vctxt.error = ctxt->error;
10172 vctxt.warning = ctxt->warning;
10173 vctxt.userData = ctxt->userData;
10174
10175 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
10176 ret = -1;
10177 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010178 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
10179 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010180
10181 return(ret);
10182}
10183
Daniel Veillardfd573f12003-03-16 17:52:32 +000010184/************************************************************************
10185 * *
10186 * Validation interfaces *
10187 * *
10188 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +000010189/**
10190 * xmlRelaxNGNewValidCtxt:
10191 * @schema: a precompiled XML RelaxNGs
10192 *
10193 * Create an XML RelaxNGs validation context based on the given schema
10194 *
10195 * Returns the validation context or NULL in case of error
10196 */
10197xmlRelaxNGValidCtxtPtr
10198xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
10199 xmlRelaxNGValidCtxtPtr ret;
10200
10201 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
10202 if (ret == NULL) {
10203 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +000010204 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +000010205 return (NULL);
10206 }
10207 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
10208 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +000010209 ret->error = xmlGenericError;
10210 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +000010211 ret->errNr = 0;
10212 ret->errMax = 0;
10213 ret->err = NULL;
10214 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +000010215 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +000010216 ret->states = NULL;
10217 ret->freeState = NULL;
10218 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +000010219 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +000010220 return (ret);
10221}
10222
10223/**
10224 * xmlRelaxNGFreeValidCtxt:
10225 * @ctxt: the schema validation context
10226 *
10227 * Free the resources associated to the schema validation context
10228 */
10229void
10230xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +000010231 int k;
10232
Daniel Veillard6eadf632003-01-23 18:29:16 +000010233 if (ctxt == NULL)
10234 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +000010235 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +000010236 xmlRelaxNGFreeStates(NULL, ctxt->states);
10237 if (ctxt->freeState != NULL) {
10238 for (k = 0;k < ctxt->freeState->nbState;k++) {
10239 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
10240 }
10241 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
10242 }
Daniel Veillard798024a2003-03-19 10:36:09 +000010243 if (ctxt->freeStates != NULL) {
10244 for (k = 0;k < ctxt->freeStatesNr;k++) {
10245 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
10246 }
10247 xmlFree(ctxt->freeStates);
10248 }
Daniel Veillard42f12e92003-03-07 18:32:59 +000010249 if (ctxt->errTab != NULL)
10250 xmlFree(ctxt->errTab);
Daniel Veillardf4e55762003-04-15 23:32:22 +000010251 if (ctxt->elemTab != NULL) {
10252 xmlRegExecCtxtPtr exec;
10253
10254 exec = xmlRelaxNGElemPop(ctxt);
10255 while (exec != NULL) {
10256 xmlRegFreeExecCtxt(exec);
10257 exec = xmlRelaxNGElemPop(ctxt);
10258 }
10259 xmlFree(ctxt->elemTab);
10260 }
Daniel Veillard6eadf632003-01-23 18:29:16 +000010261 xmlFree(ctxt);
10262}
10263
10264/**
10265 * xmlRelaxNGSetValidErrors:
10266 * @ctxt: a Relax-NG validation context
10267 * @err: the error function
10268 * @warn: the warning function
10269 * @ctx: the functions context
10270 *
10271 * Set the error and warning callback informations
10272 */
10273void
10274xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
10275 xmlRelaxNGValidityErrorFunc err,
10276 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
10277 if (ctxt == NULL)
10278 return;
10279 ctxt->error = err;
10280 ctxt->warning = warn;
10281 ctxt->userData = ctx;
10282}
10283
10284/**
10285 * xmlRelaxNGValidateDoc:
10286 * @ctxt: a Relax-NG validation context
10287 * @doc: a parsed document tree
10288 *
10289 * Validate a document tree in memory.
10290 *
10291 * Returns 0 if the document is valid, a positive error code
10292 * number otherwise and -1 in case of internal or API error.
10293 */
10294int
10295xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
10296 int ret;
10297
10298 if ((ctxt == NULL) || (doc == NULL))
10299 return(-1);
10300
10301 ctxt->doc = doc;
10302
10303 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +000010304 /*
10305 * TODO: build error codes
10306 */
10307 if (ret == -1)
10308 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +000010309 return(ret);
10310}
10311
10312#endif /* LIBXML_SCHEMAS_ENABLED */
10313