blob: ea17cf1c092f165c3ce390d5e6d2b38e43c03d94 [file] [log] [blame]
Daniel Veillard6eadf632003-01-23 18:29:16 +00001/*
2 * relaxng.c : implementation of the Relax-NG handling and validity checking
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <veillard@redhat.com>
7 */
8
Daniel Veillardd41f4f42003-01-29 21:07:52 +00009/**
10 * TODO:
Daniel Veillardd41f4f42003-01-29 21:07:52 +000011 * - error reporting
Daniel Veillard1ed7f362003-02-03 10:57:45 +000012 * - handle namespace declarations as attributes.
Daniel Veillardf4b4f982003-02-13 11:02:08 +000013 * - add support for DTD compatibility spec
14 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
Daniel Veillardfd573f12003-03-16 17:52:32 +000015 * - report better mem allocations at runtime and abort immediately.
Daniel Veillardd41f4f42003-01-29 21:07:52 +000016 */
17
Daniel Veillard6eadf632003-01-23 18:29:16 +000018#define IN_LIBXML
19#include "libxml.h"
20
21#ifdef LIBXML_SCHEMAS_ENABLED
22
23#include <string.h>
24#include <stdio.h>
25#include <libxml/xmlmemory.h>
26#include <libxml/parser.h>
27#include <libxml/parserInternals.h>
28#include <libxml/hash.h>
29#include <libxml/uri.h>
30
31#include <libxml/relaxng.h>
32
33#include <libxml/xmlschemastypes.h>
34#include <libxml/xmlautomata.h>
35#include <libxml/xmlregexp.h>
Daniel Veillardc6e997c2003-01-27 12:35:42 +000036#include <libxml/xmlschemastypes.h>
Daniel Veillard6eadf632003-01-23 18:29:16 +000037
38/*
39 * The Relax-NG namespace
40 */
41static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
42 "http://relaxng.org/ns/structure/1.0";
43
44#define IS_RELAXNG(node, type) \
45 ((node != NULL) && (node->ns != NULL) && \
46 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
47 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
48
49
Daniel Veillard952379b2003-03-17 15:37:12 +000050/* #define DEBUG 1 */
Daniel Veillardc482e262003-02-26 14:48:48 +000051/* #define DEBUG_GRAMMAR 1 */
Daniel Veillard71531f32003-02-05 13:19:53 +000052/* #define DEBUG_CONTENT 1 */
53/* #define DEBUG_TYPE 1 */
54/* #define DEBUG_VALID 1 */
Daniel Veillarde5b110b2003-02-04 14:43:39 +000055/* #define DEBUG_INTERLEAVE 1 */
Daniel Veillard416589a2003-02-17 17:25:42 +000056/* #define DEBUG_LIST 1 */
Daniel Veillard5add8682003-03-10 13:13:58 +000057/* #define DEBUG_INCLUDE */
Daniel Veillarda507fbf2003-03-31 16:09:37 +000058/* #define DEBUG_ERROR 1 */
Daniel Veillard6eadf632003-01-23 18:29:16 +000059
60#define UNBOUNDED (1 << 30)
Daniel Veillard5f1946a2003-03-31 16:38:16 +000061#define MAX_ERROR 5
62
Daniel Veillard6eadf632003-01-23 18:29:16 +000063#define TODO \
64 xmlGenericError(xmlGenericErrorContext, \
65 "Unimplemented block at %s:%d\n", \
66 __FILE__, __LINE__);
67
68typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
69typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
70
71typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
72typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
73
Daniel Veillardd41f4f42003-01-29 21:07:52 +000074typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
75typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
76
Daniel Veillarda9d912d2003-02-01 17:43:10 +000077typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
78typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
79
Daniel Veillard6eadf632003-01-23 18:29:16 +000080typedef enum {
81 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
82 XML_RELAXNG_COMBINE_CHOICE, /* choice */
83 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
84} xmlRelaxNGCombine;
85
Daniel Veillard4c5cf702003-02-21 15:40:34 +000086typedef enum {
87 XML_RELAXNG_CONTENT_ERROR = -1,
88 XML_RELAXNG_CONTENT_EMPTY = 0,
89 XML_RELAXNG_CONTENT_SIMPLE,
90 XML_RELAXNG_CONTENT_COMPLEX
91} xmlRelaxNGContentType;
92
Daniel Veillard6eadf632003-01-23 18:29:16 +000093typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
94typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
95
96struct _xmlRelaxNGGrammar {
97 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
98 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
99 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
100 xmlRelaxNGDefinePtr start; /* <start> content */
101 xmlRelaxNGCombine combine; /* the default combine value */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000102 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000103 xmlHashTablePtr defs; /* define* */
104 xmlHashTablePtr refs; /* references */
105};
106
107
Daniel Veillard6eadf632003-01-23 18:29:16 +0000108typedef enum {
Daniel Veillard77648bb2003-02-20 15:03:22 +0000109 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000110 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
111 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
Daniel Veillard144fae12003-02-03 13:17:57 +0000112 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000113 XML_RELAXNG_TEXT, /* textual content */
114 XML_RELAXNG_ELEMENT, /* an element */
115 XML_RELAXNG_DATATYPE, /* extenal data type definition */
Daniel Veillard8fe98712003-02-19 00:19:14 +0000116 XML_RELAXNG_PARAM, /* extenal data type parameter */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000117 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
118 XML_RELAXNG_LIST, /* a list of patterns */
119 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
120 XML_RELAXNG_DEF, /* a definition */
121 XML_RELAXNG_REF, /* reference to a definition */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000122 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
Daniel Veillard419a7682003-02-03 23:22:49 +0000123 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000124 XML_RELAXNG_OPTIONAL, /* optional patterns */
125 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000126 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
127 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
128 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000129 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000130 XML_RELAXNG_START /* Used to keep track of starts on grammars */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000131} xmlRelaxNGType;
132
Daniel Veillardfd573f12003-03-16 17:52:32 +0000133#define IS_NULLABLE 1
134#define IS_NOT_NULLABLE 2
135#define IS_INDETERMINIST 4
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000136#define IS_MIXED 8
Daniel Veillarde063f482003-03-21 16:53:17 +0000137#define IS_TRIABLE 16
138#define IS_PROCESSED 32
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000139
Daniel Veillard6eadf632003-01-23 18:29:16 +0000140struct _xmlRelaxNGDefine {
141 xmlRelaxNGType type; /* the type of definition */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000142 xmlNodePtr node; /* the node in the source */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000143 xmlChar *name; /* the element local name if present */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000144 xmlChar *ns; /* the namespace local name if present */
Daniel Veillardedc91922003-01-26 00:52:04 +0000145 xmlChar *value; /* value when available */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000146 void *data; /* data lib or specific pointer */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000147 xmlRelaxNGDefinePtr content;/* the expected content */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000148 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000149 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000150 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
Daniel Veillard3b2e4e12003-02-03 08:52:58 +0000151 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000152 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
Daniel Veillardfd573f12003-03-16 17:52:32 +0000153 short depth; /* used for the cycle detection */
Daniel Veillarde063f482003-03-21 16:53:17 +0000154 short dflags; /* define related flags */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000155};
156
157/**
158 * _xmlRelaxNG:
159 *
160 * A RelaxNGs definition
161 */
162struct _xmlRelaxNG {
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000163 void *_private; /* unused by the library for users or bindings */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000164 xmlRelaxNGGrammarPtr topgrammar;
165 xmlDocPtr doc;
166
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000167 int idref; /* requires idref checking */
168
Daniel Veillard6eadf632003-01-23 18:29:16 +0000169 xmlHashTablePtr defs; /* define */
170 xmlHashTablePtr refs; /* references */
Daniel Veillardc482e262003-02-26 14:48:48 +0000171 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
172 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard419a7682003-02-03 23:22:49 +0000173 int defNr; /* number of defines used */
174 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000175
Daniel Veillard6eadf632003-01-23 18:29:16 +0000176};
177
Daniel Veillard77648bb2003-02-20 15:03:22 +0000178#define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
179#define XML_RELAXNG_IN_ONEORMORE (1 << 1)
180#define XML_RELAXNG_IN_LIST (1 << 2)
181#define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
182#define XML_RELAXNG_IN_START (1 << 4)
183#define XML_RELAXNG_IN_OOMGROUP (1 << 5)
184#define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
185#define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
Daniel Veillardc5312d72003-02-21 17:14:10 +0000186#define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
187#define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000188
189struct _xmlRelaxNGParserCtxt {
190 void *userData; /* user specific data block */
191 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
192 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000193 xmlRelaxNGValidErr err;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000194
195 xmlRelaxNGPtr schema; /* The schema in use */
196 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
Daniel Veillard419a7682003-02-03 23:22:49 +0000197 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000198 int flags; /* parser flags */
199 int nbErrors; /* number of errors at parse time */
200 int nbWarnings; /* number of warnings at parse time */
Daniel Veillard276be4a2003-01-24 01:03:34 +0000201 const xmlChar *define; /* the current define scope */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000202 xmlRelaxNGDefinePtr def; /* the current define */
203
204 int nbInterleaves;
205 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000206
Daniel Veillardc482e262003-02-26 14:48:48 +0000207 xmlRelaxNGDocumentPtr documents; /* all the documents loaded */
208 xmlRelaxNGIncludePtr includes; /* all the includes loaded */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000209 xmlChar *URL;
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000210 xmlDocPtr document;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000211
Daniel Veillard419a7682003-02-03 23:22:49 +0000212 int defNr; /* number of defines used */
213 int defMax; /* number of defines aloocated */
214 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
215
Daniel Veillard6eadf632003-01-23 18:29:16 +0000216 const char *buffer;
217 int size;
218
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000219 /* the document stack */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000220 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000221 int docNr; /* Depth of the parsing stack */
222 int docMax; /* Max depth of the parsing stack */
223 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000224
225 /* the include stack */
Daniel Veillardd4310742003-02-18 21:12:46 +0000226 xmlRelaxNGIncludePtr inc; /* Current parsed include */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000227 int incNr; /* Depth of the include parsing stack */
228 int incMax; /* Max depth of the parsing stack */
229 xmlRelaxNGIncludePtr *incTab; /* array of incs */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000230
231 int idref; /* requires idref checking */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000232};
233
234#define FLAGS_IGNORABLE 1
235#define FLAGS_NEGATIVE 2
Daniel Veillard249d7bb2003-03-19 21:02:29 +0000236#define FLAGS_MIXED_CONTENT 4
Daniel Veillard6eadf632003-01-23 18:29:16 +0000237
238/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000239 * xmlRelaxNGInterleaveGroup:
240 *
241 * A RelaxNGs partition set associated to lists of definitions
242 */
243typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
244typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
245struct _xmlRelaxNGInterleaveGroup {
246 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
247 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000248 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000249};
250
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000251#define IS_DETERMINIST 1
252#define IS_NEEDCHECK 2
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000253/**
254 * xmlRelaxNGPartitions:
255 *
256 * A RelaxNGs partition associated to an interleave group
257 */
258typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
259typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
260struct _xmlRelaxNGPartition {
261 int nbgroups; /* number of groups in the partitions */
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000262 xmlHashTablePtr triage; /* hash table used to direct nodes to the
263 right group when possible */
264 int flags; /* determinist ? */
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000265 xmlRelaxNGInterleaveGroupPtr *groups;
266};
267
268/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000269 * xmlRelaxNGValidState:
270 *
271 * A RelaxNGs validation state
272 */
273#define MAX_ATTR 20
274typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
275typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
276struct _xmlRelaxNGValidState {
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000277 xmlNodePtr node; /* the current node */
278 xmlNodePtr seq; /* the sequence of children left to validate */
279 int nbAttrs; /* the number of attributes */
Daniel Veillard798024a2003-03-19 10:36:09 +0000280 int maxAttrs; /* the size of attrs */
Daniel Veillard1ed7f362003-02-03 10:57:45 +0000281 int nbAttrLeft; /* the number of attributes left to validate */
Daniel Veillardc6e997c2003-01-27 12:35:42 +0000282 xmlChar *value; /* the value when operating on string */
283 xmlChar *endvalue; /* the end value when operating on string */
Daniel Veillard798024a2003-03-19 10:36:09 +0000284 xmlAttrPtr *attrs; /* the array of attributes */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000285};
286
287/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000288 * xmlRelaxNGStates:
289 *
290 * A RelaxNGs container for validation state
291 */
292typedef struct _xmlRelaxNGStates xmlRelaxNGStates;
293typedef xmlRelaxNGStates *xmlRelaxNGStatesPtr;
294struct _xmlRelaxNGStates {
295 int nbState; /* the number of states */
296 int maxState; /* the size of the array */
297 xmlRelaxNGValidStatePtr *tabState;
298};
299
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000300#define ERROR_IS_DUP 1
Daniel Veillardfd573f12003-03-16 17:52:32 +0000301/**
Daniel Veillard42f12e92003-03-07 18:32:59 +0000302 * xmlRelaxNGValidError:
303 *
304 * A RelaxNGs validation error
305 */
306typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError;
307typedef xmlRelaxNGValidError *xmlRelaxNGValidErrorPtr;
308struct _xmlRelaxNGValidError {
309 xmlRelaxNGValidErr err; /* the error number */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000310 int flags; /* flags */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000311 xmlNodePtr node; /* the current node */
312 xmlNodePtr seq; /* the current child */
313 const xmlChar * arg1; /* first arg */
314 const xmlChar * arg2; /* second arg */
315};
316
317/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000318 * xmlRelaxNGValidCtxt:
319 *
320 * A RelaxNGs validation context
321 */
322
323struct _xmlRelaxNGValidCtxt {
324 void *userData; /* user specific data block */
325 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
326 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
327
328 xmlRelaxNGPtr schema; /* The schema in use */
329 xmlDocPtr doc; /* the document being validated */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000330 int flags; /* validation flags */
Daniel Veillard231d7912003-02-09 14:22:17 +0000331 int depth; /* validation depth */
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000332 int idref; /* requires idref checking */
Daniel Veillarda507fbf2003-03-31 16:09:37 +0000333 int errNo; /* the first error found */
Daniel Veillard42f12e92003-03-07 18:32:59 +0000334
335 /*
336 * Errors accumulated in branches may have to be stacked to be
337 * provided back when it's sure they affect validation.
338 */
339 xmlRelaxNGValidErrorPtr err; /* Last error */
340 int errNr; /* Depth of the error stack */
341 int errMax; /* Max depth of the error stack */
342 xmlRelaxNGValidErrorPtr errTab; /* stack of errors */
Daniel Veillard1564e6e2003-03-15 21:30:25 +0000343
Daniel Veillardfd573f12003-03-16 17:52:32 +0000344 xmlRelaxNGValidStatePtr state; /* the current validation state */
345 xmlRelaxNGStatesPtr states; /* the accumulated state list */
Daniel Veillard798024a2003-03-19 10:36:09 +0000346
347 xmlRelaxNGStatesPtr freeState; /* the pool of free valid states */
348 int freeStatesNr;
349 int freeStatesMax;
350 xmlRelaxNGStatesPtr *freeStates; /* the pool of free state groups */
Daniel Veillard6eadf632003-01-23 18:29:16 +0000351};
352
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000353/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000354 * xmlRelaxNGInclude:
355 *
356 * Structure associated to a RelaxNGs document element
357 */
358struct _xmlRelaxNGInclude {
Daniel Veillardc482e262003-02-26 14:48:48 +0000359 xmlRelaxNGIncludePtr next; /* keep a chain of includes */
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000360 xmlChar *href; /* the normalized href value */
361 xmlDocPtr doc; /* the associated XML document */
362 xmlRelaxNGDefinePtr content;/* the definitions */
363 xmlRelaxNGPtr schema; /* the schema */
364};
365
366/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000367 * xmlRelaxNGDocument:
368 *
369 * Structure associated to a RelaxNGs document element
370 */
371struct _xmlRelaxNGDocument {
Daniel Veillardc482e262003-02-26 14:48:48 +0000372 xmlRelaxNGDocumentPtr next; /* keep a chain of documents */
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000373 xmlChar *href; /* the normalized href value */
374 xmlDocPtr doc; /* the associated XML document */
375 xmlRelaxNGDefinePtr content;/* the definitions */
376 xmlRelaxNGPtr schema; /* the schema */
377};
378
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000379
Daniel Veillard6eadf632003-01-23 18:29:16 +0000380/************************************************************************
381 * *
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000382 * Preliminary type checking interfaces *
383 * *
384 ************************************************************************/
385/**
386 * xmlRelaxNGTypeHave:
387 * @data: data needed for the library
388 * @type: the type name
389 * @value: the value to check
390 *
391 * Function provided by a type library to check if a type is exported
392 *
393 * Returns 1 if yes, 0 if no and -1 in case of error.
394 */
395typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
396
397/**
398 * xmlRelaxNGTypeCheck:
399 * @data: data needed for the library
400 * @type: the type name
401 * @value: the value to check
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000402 * @result: place to store the result if needed
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000403 *
404 * Function provided by a type library to check if a value match a type
405 *
406 * Returns 1 if yes, 0 if no and -1 in case of error.
407 */
408typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
Daniel Veillardc3da18a2003-03-18 00:31:04 +0000409 const xmlChar *value, void **result,
410 xmlNodePtr node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000411
412/**
413 * xmlRelaxNGFacetCheck:
414 * @data: data needed for the library
415 * @type: the type name
416 * @facet: the facet name
417 * @val: the facet value
418 * @strval: the string value
419 * @value: the value to check
420 *
421 * Function provided by a type library to check a value facet
422 *
423 * Returns 1 if yes, 0 if no and -1 in case of error.
424 */
425typedef int (*xmlRelaxNGFacetCheck) (void *data, const xmlChar *type,
426 const xmlChar *facet, const xmlChar *val,
427 const xmlChar *strval, void *value);
428
429/**
430 * xmlRelaxNGTypeFree:
431 * @data: data needed for the library
432 * @result: the value to free
433 *
434 * Function provided by a type library to free a returned result
435 */
436typedef void (*xmlRelaxNGTypeFree) (void *data, void *result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000437
438/**
439 * xmlRelaxNGTypeCompare:
440 * @data: data needed for the library
441 * @type: the type name
442 * @value1: the first value
443 * @value2: the second value
444 *
445 * Function provided by a type library to compare two values accordingly
446 * to a type.
447 *
448 * Returns 1 if yes, 0 if no and -1 in case of error.
449 */
450typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
451 const xmlChar *value1,
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000452 xmlNodePtr ctxt1,
453 void *comp1,
454 const xmlChar *value2,
455 xmlNodePtr ctxt2);
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000456typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
457typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
458struct _xmlRelaxNGTypeLibrary {
459 const xmlChar *namespace; /* the datatypeLibrary value */
460 void *data; /* data needed for the library */
461 xmlRelaxNGTypeHave have; /* the export function */
462 xmlRelaxNGTypeCheck check; /* the checking function */
463 xmlRelaxNGTypeCompare comp; /* the compare function */
Daniel Veillard8bc6cf92003-02-27 17:42:22 +0000464 xmlRelaxNGFacetCheck facet; /* the facet check function */
465 xmlRelaxNGTypeFree freef; /* the freeing function */
Daniel Veillarddd1655c2003-01-25 18:01:32 +0000466};
467
468/************************************************************************
469 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +0000470 * Allocation functions *
471 * *
472 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +0000473static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
474static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
Daniel Veillardd2298792003-02-14 16:54:11 +0000475static void xmlRelaxNGNormExtSpace(xmlChar *value);
Daniel Veillardc482e262003-02-26 14:48:48 +0000476static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000477static int xmlRelaxNGEqualValidState(
478 xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
479 xmlRelaxNGValidStatePtr state1,
480 xmlRelaxNGValidStatePtr state2);
Daniel Veillard798024a2003-03-19 10:36:09 +0000481static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
482 xmlRelaxNGValidStatePtr state);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000483
484/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000485 * xmlRelaxNGFreeDocument:
486 * @docu: a document structure
487 *
488 * Deallocate a RelaxNG document structure.
489 */
490static void
491xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
492{
493 if (docu == NULL)
494 return;
495
496 if (docu->href != NULL)
497 xmlFree(docu->href);
498 if (docu->doc != NULL)
499 xmlFreeDoc(docu->doc);
500 if (docu->schema != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000501 xmlRelaxNGFreeInnerSchema(docu->schema);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000502 xmlFree(docu);
503}
504
505/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000506 * xmlRelaxNGFreeDocumentList:
507 * @docu: a list of document structure
508 *
509 * Deallocate a RelaxNG document structures.
510 */
511static void
512xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu)
513{
514 xmlRelaxNGDocumentPtr next;
515 while (docu != NULL) {
516 next = docu->next;
517 xmlRelaxNGFreeDocument(docu);
518 docu = next;
519 }
520}
521
522/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000523 * xmlRelaxNGFreeInclude:
524 * @incl: a include structure
525 *
526 * Deallocate a RelaxNG include structure.
527 */
528static void
529xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
530{
531 if (incl == NULL)
532 return;
533
534 if (incl->href != NULL)
535 xmlFree(incl->href);
536 if (incl->doc != NULL)
537 xmlFreeDoc(incl->doc);
538 if (incl->schema != NULL)
539 xmlRelaxNGFree(incl->schema);
540 xmlFree(incl);
541}
542
543/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000544 * xmlRelaxNGFreeIncludeList:
545 * @incl: a include structure list
546 *
547 * Deallocate a RelaxNG include structure.
548 */
549static void
550xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl)
551{
552 xmlRelaxNGIncludePtr next;
553 while (incl != NULL) {
554 next = incl->next;
555 xmlRelaxNGFreeInclude(incl);
556 incl = next;
557 }
558}
559
560/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000561 * xmlRelaxNGNewRelaxNG:
562 * @ctxt: a Relax-NG validation context (optional)
563 *
564 * Allocate a new RelaxNG structure.
565 *
566 * Returns the newly allocated structure or NULL in case or error
567 */
568static xmlRelaxNGPtr
569xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
570{
571 xmlRelaxNGPtr ret;
572
573 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
574 if (ret == NULL) {
575 if ((ctxt != NULL) && (ctxt->error != NULL))
576 ctxt->error(ctxt->userData, "Out of memory\n");
577 ctxt->nbErrors++;
578 return (NULL);
579 }
580 memset(ret, 0, sizeof(xmlRelaxNG));
581
582 return (ret);
583}
584
585/**
Daniel Veillardc482e262003-02-26 14:48:48 +0000586 * xmlRelaxNGFreeInnerSchema:
587 * @schema: a schema structure
588 *
589 * Deallocate a RelaxNG schema structure.
590 */
591static void
592xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema)
593{
594 if (schema == NULL)
595 return;
596
597 if (schema->doc != NULL)
598 xmlFreeDoc(schema->doc);
599 if (schema->defTab != NULL) {
600 int i;
601
602 for (i = 0;i < schema->defNr;i++)
603 xmlRelaxNGFreeDefine(schema->defTab[i]);
604 xmlFree(schema->defTab);
605 }
606
607 xmlFree(schema);
608}
609
610/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000611 * xmlRelaxNGFree:
612 * @schema: a schema structure
613 *
614 * Deallocate a RelaxNG structure.
615 */
616void
617xmlRelaxNGFree(xmlRelaxNGPtr schema)
618{
619 if (schema == NULL)
620 return;
621
Daniel Veillard6eadf632003-01-23 18:29:16 +0000622 if (schema->topgrammar != NULL)
623 xmlRelaxNGFreeGrammar(schema->topgrammar);
624 if (schema->doc != NULL)
625 xmlFreeDoc(schema->doc);
Daniel Veillardd41f4f42003-01-29 21:07:52 +0000626 if (schema->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000627 xmlRelaxNGFreeDocumentList(schema->documents);
Daniel Veillarda9d912d2003-02-01 17:43:10 +0000628 if (schema->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +0000629 xmlRelaxNGFreeIncludeList(schema->includes);
Daniel Veillard419a7682003-02-03 23:22:49 +0000630 if (schema->defTab != NULL) {
631 int i;
632
633 for (i = 0;i < schema->defNr;i++)
634 xmlRelaxNGFreeDefine(schema->defTab[i]);
635 xmlFree(schema->defTab);
636 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000637
638 xmlFree(schema);
639}
640
641/**
642 * xmlRelaxNGNewGrammar:
643 * @ctxt: a Relax-NG validation context (optional)
644 *
645 * Allocate a new RelaxNG grammar.
646 *
647 * Returns the newly allocated structure or NULL in case or error
648 */
649static xmlRelaxNGGrammarPtr
650xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
651{
652 xmlRelaxNGGrammarPtr ret;
653
654 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
655 if (ret == NULL) {
656 if ((ctxt != NULL) && (ctxt->error != NULL))
657 ctxt->error(ctxt->userData, "Out of memory\n");
658 ctxt->nbErrors++;
659 return (NULL);
660 }
661 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
662
663 return (ret);
664}
665
666/**
667 * xmlRelaxNGFreeGrammar:
668 * @grammar: a grammar structure
669 *
670 * Deallocate a RelaxNG grammar structure.
671 */
672static void
673xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
674{
675 if (grammar == NULL)
676 return;
677
Daniel Veillardc482e262003-02-26 14:48:48 +0000678 if (grammar->children != NULL) {
679 xmlRelaxNGFreeGrammar(grammar->children);
680 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000681 if (grammar->next != NULL) {
682 xmlRelaxNGFreeGrammar(grammar->next);
683 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000684 if (grammar->refs != NULL) {
685 xmlHashFree(grammar->refs, NULL);
686 }
687 if (grammar->defs != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000688 xmlHashFree(grammar->defs, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000689 }
690
691 xmlFree(grammar);
692}
693
694/**
695 * xmlRelaxNGNewDefine:
696 * @ctxt: a Relax-NG validation context
697 * @node: the node in the input document.
698 *
699 * Allocate a new RelaxNG define.
700 *
701 * Returns the newly allocated structure or NULL in case or error
702 */
703static xmlRelaxNGDefinePtr
Daniel Veillardfd573f12003-03-16 17:52:32 +0000704xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
Daniel Veillard6eadf632003-01-23 18:29:16 +0000705{
706 xmlRelaxNGDefinePtr ret;
707
Daniel Veillard419a7682003-02-03 23:22:49 +0000708 if (ctxt->defMax == 0) {
709 ctxt->defMax = 16;
710 ctxt->defNr = 0;
711 ctxt->defTab = (xmlRelaxNGDefinePtr *)
712 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
713 if (ctxt->defTab == NULL) {
714 if ((ctxt != NULL) && (ctxt->error != NULL))
715 ctxt->error(ctxt->userData, "Out of memory\n");
716 ctxt->nbErrors++;
717 return (NULL);
718 }
719 } else if (ctxt->defMax <= ctxt->defNr) {
720 xmlRelaxNGDefinePtr *tmp;
721 ctxt->defMax *= 2;
722 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
723 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
724 if (tmp == NULL) {
725 if ((ctxt != NULL) && (ctxt->error != NULL))
726 ctxt->error(ctxt->userData, "Out of memory\n");
727 ctxt->nbErrors++;
728 return (NULL);
729 }
730 ctxt->defTab = tmp;
731 }
Daniel Veillard6eadf632003-01-23 18:29:16 +0000732 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
733 if (ret == NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +0000734 if ((ctxt != NULL) && (ctxt->error != NULL))
735 ctxt->error(ctxt->userData, "Out of memory\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +0000736 ctxt->nbErrors++;
Daniel Veillard419a7682003-02-03 23:22:49 +0000737 return(NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000738 }
739 memset(ret, 0, sizeof(xmlRelaxNGDefine));
Daniel Veillard419a7682003-02-03 23:22:49 +0000740 ctxt->defTab[ctxt->defNr++] = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000741 ret->node = node;
Daniel Veillardd4310742003-02-18 21:12:46 +0000742 ret->depth = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +0000743 return (ret);
744}
745
746/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000747 * xmlRelaxNGFreePartition:
748 * @partitions: a partition set structure
749 *
750 * Deallocate RelaxNG partition set structures.
751 */
752static void
753xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
754 xmlRelaxNGInterleaveGroupPtr group;
755 int j;
756
757 if (partitions != NULL) {
758 if (partitions->groups != NULL) {
759 for (j = 0;j < partitions->nbgroups;j++) {
760 group = partitions->groups[j];
761 if (group != NULL) {
762 if (group->defs != NULL)
763 xmlFree(group->defs);
Daniel Veillard44e1dd02003-02-21 23:23:28 +0000764 if (group->attrs != NULL)
765 xmlFree(group->attrs);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000766 xmlFree(group);
767 }
768 }
769 xmlFree(partitions->groups);
770 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +0000771 if (partitions->triage != NULL) {
772 xmlHashFree(partitions->triage, NULL);
773 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +0000774 xmlFree(partitions);
775 }
776}
777/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000778 * xmlRelaxNGFreeDefine:
779 * @define: a define structure
780 *
781 * Deallocate a RelaxNG define structure.
782 */
783static void
784xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
785{
786 if (define == NULL)
787 return;
788
Daniel Veillarde637c4a2003-03-30 21:10:09 +0000789 if ((define->type == XML_RELAXNG_VALUE) &&
790 (define->attrs != NULL)) {
791 xmlRelaxNGTypeLibraryPtr lib;
792
793 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
794 if ((lib != NULL) && (lib->freef != NULL))
795 lib->freef(lib->data, (void *) define->attrs);
796 }
Daniel Veillard419a7682003-02-03 23:22:49 +0000797 if ((define->data != NULL) &&
798 (define->type == XML_RELAXNG_INTERLEAVE))
799 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
Daniel Veillarde063f482003-03-21 16:53:17 +0000800 if ((define->data != NULL) &&
801 (define->type == XML_RELAXNG_CHOICE))
802 xmlHashFree((xmlHashTablePtr) define->data, NULL);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000803 if (define->name != NULL)
804 xmlFree(define->name);
805 if (define->ns != NULL)
806 xmlFree(define->ns);
Daniel Veillardedc91922003-01-26 00:52:04 +0000807 if (define->value != NULL)
808 xmlFree(define->value);
Daniel Veillard6eadf632003-01-23 18:29:16 +0000809 xmlFree(define);
810}
811
812/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000813 * xmlRelaxNGNewStates:
814 * @ctxt: a Relax-NG validation context
815 * @size: the default size for the container
816 *
817 * Allocate a new RelaxNG validation state container
818 * TODO: keep a pool in the ctxt
819 *
820 * Returns the newly allocated structure or NULL in case or error
821 */
822static xmlRelaxNGStatesPtr
823xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt, int size)
824{
825 xmlRelaxNGStatesPtr ret;
826
Daniel Veillard798024a2003-03-19 10:36:09 +0000827 if ((ctxt != NULL) &&
828 (ctxt->freeState != NULL) &&
829 (ctxt->freeStatesNr > 0)) {
830 ctxt->freeStatesNr--;
831 ret = ctxt->freeStates[ctxt->freeStatesNr];
832 ret->nbState = 0;
833 return(ret);
834 }
Daniel Veillardfd573f12003-03-16 17:52:32 +0000835 if (size < 16) size = 16;
836
837 ret = (xmlRelaxNGStatesPtr) xmlMalloc(sizeof(xmlRelaxNGStates) +
838 (size - 1) * sizeof(xmlRelaxNGValidStatePtr));
839 if (ret == NULL) {
840 if ((ctxt != NULL) && (ctxt->error != NULL))
841 ctxt->error(ctxt->userData, "Out of memory\n");
842 return (NULL);
843 }
844 ret->nbState = 0;
845 ret->maxState = size;
846 ret->tabState = (xmlRelaxNGValidStatePtr *) xmlMalloc(
847 (size) * sizeof(xmlRelaxNGValidStatePtr));
848 if (ret->tabState == NULL) {
849 if ((ctxt != NULL) && (ctxt->error != NULL))
850 ctxt->error(ctxt->userData, "Out of memory\n");
851 xmlFree(ret->tabState);
852 return (NULL);
853 }
854 return(ret);
855}
856
857/**
Daniel Veillard798024a2003-03-19 10:36:09 +0000858 * xmlRelaxNGAddStateUniq:
859 * @ctxt: a Relax-NG validation context
860 * @states: the states container
861 * @state: the validation state
862 *
863 * Add a RelaxNG validation state to the container without checking
864 * for unicity.
865 *
866 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
867 */
868static int
869xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt,
870 xmlRelaxNGStatesPtr states,
871 xmlRelaxNGValidStatePtr state)
872{
873 if (state == NULL) {
874 return(-1);
875 }
876 if (states->nbState >= states->maxState) {
877 xmlRelaxNGValidStatePtr *tmp;
878 int size;
879
880 size = states->maxState * 2;
881 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
882 (size) * sizeof(xmlRelaxNGValidStatePtr));
883 if (tmp == NULL) {
884 if ((ctxt != NULL) && (ctxt->error != NULL))
885 ctxt->error(ctxt->userData, "Out of memory\n");
886 return(-1);
887 }
888 states->tabState = tmp;
889 states->maxState = size;
890 }
891 states->tabState[states->nbState++] = state;
892 return(1);
893}
894
895/**
Daniel Veillardfd573f12003-03-16 17:52:32 +0000896 * xmlRelaxNGAddState:
897 * @ctxt: a Relax-NG validation context
898 * @states: the states container
899 * @state: the validation state
900 *
901 * Add a RelaxNG validation state to the container
902 *
903 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
904 */
905static int
906xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGStatesPtr states,
907 xmlRelaxNGValidStatePtr state)
908{
909 int i;
910
911 if (state == NULL) {
912 return(-1);
913 }
914 if (states->nbState >= states->maxState) {
915 xmlRelaxNGValidStatePtr *tmp;
916 int size;
917
918 size = states->maxState * 2;
919 tmp = (xmlRelaxNGValidStatePtr *) xmlRealloc(states->tabState,
920 (size) * sizeof(xmlRelaxNGValidStatePtr));
921 if (tmp == NULL) {
922 if ((ctxt != NULL) && (ctxt->error != NULL))
923 ctxt->error(ctxt->userData, "Out of memory\n");
924 return(-1);
925 }
926 states->tabState = tmp;
927 states->maxState = size;
928 }
929 for (i = 0;i < states->nbState;i++) {
930 if (xmlRelaxNGEqualValidState(ctxt, state, states->tabState[i])) {
Daniel Veillard798024a2003-03-19 10:36:09 +0000931 xmlRelaxNGFreeValidState(ctxt, state);
Daniel Veillardfd573f12003-03-16 17:52:32 +0000932 return(0);
933 }
934 }
935 states->tabState[states->nbState++] = state;
936 return(1);
937}
938
939/**
940 * xmlRelaxNGFreeStates:
941 * @ctxt: a Relax-NG validation context
942 * @states: teh container
943 *
944 * Free a RelaxNG validation state container
Daniel Veillardfd573f12003-03-16 17:52:32 +0000945 */
946static void
Daniel Veillard798024a2003-03-19 10:36:09 +0000947xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt,
Daniel Veillardfd573f12003-03-16 17:52:32 +0000948 xmlRelaxNGStatesPtr states)
949{
Daniel Veillard798024a2003-03-19 10:36:09 +0000950 if (states == NULL)
951 return;
Daniel Veillard798024a2003-03-19 10:36:09 +0000952 if ((ctxt != NULL) && (ctxt->freeStates == NULL)) {
953 ctxt->freeStatesMax = 40;
954 ctxt->freeStatesNr = 0;
955 ctxt->freeStates = (xmlRelaxNGStatesPtr *)
956 xmlMalloc(ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
957 if (ctxt->freeStates == NULL) {
958 if ((ctxt != NULL) && (ctxt->error != NULL))
959 ctxt->error(ctxt->userData, "Out of memory\n");
960 }
961 } else if ((ctxt != NULL) && (ctxt->freeStatesNr >= ctxt->freeStatesMax)) {
962 xmlRelaxNGStatesPtr *tmp;
963
964 tmp = (xmlRelaxNGStatesPtr *) xmlRealloc(ctxt->freeStates,
965 2 * ctxt->freeStatesMax * sizeof(xmlRelaxNGStatesPtr));
966 if (tmp == NULL) {
967 if ((ctxt != NULL) && (ctxt->error != NULL))
968 ctxt->error(ctxt->userData, "Out of memory\n");
969 xmlFree(states->tabState);
970 xmlFree(states);
971 return;
972 }
973 ctxt->freeStates = tmp;
974 ctxt->freeStatesMax *= 2;
975 }
976 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +0000977 xmlFree(states->tabState);
978 xmlFree(states);
Daniel Veillard798024a2003-03-19 10:36:09 +0000979 } else {
980 ctxt->freeStates[ctxt->freeStatesNr++] = states;
Daniel Veillardfd573f12003-03-16 17:52:32 +0000981 }
982}
983
984/**
Daniel Veillard6eadf632003-01-23 18:29:16 +0000985 * xmlRelaxNGNewValidState:
986 * @ctxt: a Relax-NG validation context
987 * @node: the current node or NULL for the document
988 *
989 * Allocate a new RelaxNG validation state
990 *
991 * Returns the newly allocated structure or NULL in case or error
992 */
993static xmlRelaxNGValidStatePtr
994xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
995{
996 xmlRelaxNGValidStatePtr ret;
997 xmlAttrPtr attr;
998 xmlAttrPtr attrs[MAX_ATTR];
999 int nbAttrs = 0;
1000 xmlNodePtr root = NULL;
1001
1002 if (node == NULL) {
1003 root = xmlDocGetRootElement(ctxt->doc);
1004 if (root == NULL)
1005 return(NULL);
1006 } else {
1007 attr = node->properties;
1008 while (attr != NULL) {
1009 if (nbAttrs < MAX_ATTR)
1010 attrs[nbAttrs++] = attr;
1011 else
1012 nbAttrs++;
1013 attr = attr->next;
1014 }
1015 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001016 if ((ctxt->freeState != NULL) &&
1017 (ctxt->freeState->nbState > 0)) {
1018 ctxt->freeState->nbState--;
1019 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1020 } else {
1021 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1022 if (ret == NULL) {
1023 if ((ctxt != NULL) && (ctxt->error != NULL))
1024 ctxt->error(ctxt->userData, "Out of memory\n");
1025 return (NULL);
1026 }
1027 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillard6eadf632003-01-23 18:29:16 +00001028 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00001029 ret->value = NULL;
1030 ret->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001031 if (node == NULL) {
1032 ret->node = (xmlNodePtr) ctxt->doc;
1033 ret->seq = root;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001034 } else {
1035 ret->node = node;
1036 ret->seq = node->children;
Daniel Veillard798024a2003-03-19 10:36:09 +00001037 }
1038 ret->nbAttrs = 0;
1039 if (nbAttrs > 0) {
1040 if (ret->attrs == NULL) {
1041 if (nbAttrs < 4) ret->maxAttrs = 4;
1042 else ret->maxAttrs = nbAttrs;
1043 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1044 sizeof(xmlAttrPtr));
1045 if (ret->attrs == NULL) {
1046 if ((ctxt != NULL) && (ctxt->error != NULL))
1047 ctxt->error(ctxt->userData, "Out of memory\n");
1048 return (ret);
1049 }
1050 } else if (ret->maxAttrs < nbAttrs) {
1051 xmlAttrPtr *tmp;
1052
1053 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, nbAttrs *
1054 sizeof(xmlAttrPtr));
1055 if (tmp == NULL) {
1056 if ((ctxt != NULL) && (ctxt->error != NULL))
1057 ctxt->error(ctxt->userData, "Out of memory\n");
1058 return (ret);
1059 }
1060 ret->attrs = tmp;
1061 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001062 ret->nbAttrs = nbAttrs;
Daniel Veillard798024a2003-03-19 10:36:09 +00001063 if (nbAttrs < MAX_ATTR) {
1064 memcpy(ret->attrs, attrs, sizeof(xmlAttrPtr) * nbAttrs);
1065 } else {
1066 attr = node->properties;
1067 nbAttrs = 0;
1068 while (attr != NULL) {
1069 ret->attrs[nbAttrs++] = attr;
1070 attr = attr->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001071 }
1072 }
1073 }
Daniel Veillard1ed7f362003-02-03 10:57:45 +00001074 ret->nbAttrLeft = ret->nbAttrs;
Daniel Veillard6eadf632003-01-23 18:29:16 +00001075 return (ret);
1076}
1077
1078/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00001079 * xmlRelaxNGCopyValidState:
1080 * @ctxt: a Relax-NG validation context
1081 * @state: a validation state
1082 *
1083 * Copy the validation state
1084 *
1085 * Returns the newly allocated structure or NULL in case or error
1086 */
1087static xmlRelaxNGValidStatePtr
1088xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
1089 xmlRelaxNGValidStatePtr state)
1090{
1091 xmlRelaxNGValidStatePtr ret;
Daniel Veillard798024a2003-03-19 10:36:09 +00001092 unsigned int maxAttrs;
1093 xmlAttrPtr *attrs;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001094
1095 if (state == NULL)
1096 return(NULL);
Daniel Veillard798024a2003-03-19 10:36:09 +00001097 if ((ctxt->freeState != NULL) &&
1098 (ctxt->freeState->nbState > 0)) {
1099 ctxt->freeState->nbState--;
1100 ret = ctxt->freeState->tabState[ctxt->freeState->nbState];
1101 } else {
1102 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState));
1103 if (ret == NULL) {
1104 if ((ctxt != NULL) && (ctxt->error != NULL))
1105 ctxt->error(ctxt->userData, "Out of memory\n");
1106 return (NULL);
1107 }
1108 memset(ret, 0, sizeof(xmlRelaxNGValidState));
Daniel Veillardfd573f12003-03-16 17:52:32 +00001109 }
Daniel Veillard798024a2003-03-19 10:36:09 +00001110 attrs = ret->attrs;
1111 maxAttrs = ret->maxAttrs;
1112 memcpy(ret, state, sizeof(xmlRelaxNGValidState));
1113 ret->attrs = attrs;
1114 ret->maxAttrs = maxAttrs;
1115 if (state->nbAttrs > 0) {
1116 if (ret->attrs == NULL) {
1117 ret->maxAttrs = state->maxAttrs;
1118 ret->attrs = (xmlAttrPtr *) xmlMalloc(ret->maxAttrs *
1119 sizeof(xmlAttrPtr));
1120 if (ret->attrs == NULL) {
1121 if ((ctxt != NULL) && (ctxt->error != NULL))
1122 ctxt->error(ctxt->userData, "Out of memory\n");
1123 ret->nbAttrs = 0;
1124 return (ret);
1125 }
1126 } else if (ret->maxAttrs < state->nbAttrs) {
1127 xmlAttrPtr *tmp;
1128
1129 tmp = (xmlAttrPtr *) xmlRealloc(ret->attrs, state->maxAttrs *
1130 sizeof(xmlAttrPtr));
1131 if (tmp == NULL) {
1132 if ((ctxt != NULL) && (ctxt->error != NULL))
1133 ctxt->error(ctxt->userData, "Out of memory\n");
1134 ret->nbAttrs = 0;
1135 return (ret);
1136 }
1137 ret->maxAttrs = state->maxAttrs;
1138 }
1139 memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
1140 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00001141 return(ret);
1142}
1143
1144/**
1145 * xmlRelaxNGEqualValidState:
1146 * @ctxt: a Relax-NG validation context
1147 * @state1: a validation state
1148 * @state2: a validation state
1149 *
1150 * Compare the validation states for equality
1151 *
1152 * Returns 1 if equald, 0 otherwise
1153 */
1154static int
1155xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
1156 xmlRelaxNGValidStatePtr state1,
1157 xmlRelaxNGValidStatePtr state2)
1158{
1159 int i;
1160
1161 if ((state1 == NULL) || (state2 == NULL))
1162 return(0);
1163 if (state1 == state2)
1164 return(1);
1165 if (state1->node != state2->node)
1166 return(0);
1167 if (state1->seq != state2->seq)
1168 return(0);
1169 if (state1->nbAttrLeft != state2->nbAttrLeft)
1170 return(0);
1171 if (state1->nbAttrs != state2->nbAttrs)
1172 return(0);
1173 if (state1->endvalue != state2->endvalue)
1174 return(0);
1175 if ((state1->value != state2->value) &&
1176 (!xmlStrEqual(state1->value, state2->value)))
1177 return(0);
1178 for (i = 0;i < state1->nbAttrs;i++) {
1179 if (state1->attrs[i] != state2->attrs[i])
1180 return(0);
1181 }
1182 return(1);
1183}
1184
1185/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00001186 * xmlRelaxNGFreeValidState:
1187 * @state: a validation state structure
1188 *
1189 * Deallocate a RelaxNG validation state structure.
1190 */
1191static void
Daniel Veillard798024a2003-03-19 10:36:09 +00001192xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt,
1193 xmlRelaxNGValidStatePtr state)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001194{
1195 if (state == NULL)
1196 return;
1197
Daniel Veillard798024a2003-03-19 10:36:09 +00001198 if ((ctxt != NULL) && (ctxt->freeState == NULL)) {
1199 ctxt->freeState = xmlRelaxNGNewStates(ctxt, 40);
1200 }
1201 if ((ctxt == NULL) || (ctxt->freeState == NULL)) {
1202 if (state->attrs != NULL)
1203 xmlFree(state->attrs);
1204 xmlFree(state);
1205 } else {
1206 xmlRelaxNGAddStatesUniq(ctxt, ctxt->freeState, state);
1207 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00001208}
1209
1210/************************************************************************
1211 * *
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001212 * Document functions *
1213 * *
1214 ************************************************************************/
1215static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
1216 xmlDocPtr doc);
1217
1218/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001219 * xmlRelaxNGIncludePush:
1220 * @ctxt: the parser context
1221 * @value: the element doc
1222 *
1223 * Pushes a new include on top of the include stack
1224 *
1225 * Returns 0 in case of error, the index in the stack otherwise
1226 */
1227static int
1228xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
1229 xmlRelaxNGIncludePtr value)
1230{
1231 if (ctxt->incTab == NULL) {
1232 ctxt->incMax = 4;
1233 ctxt->incNr = 0;
1234 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
1235 ctxt->incMax * sizeof(ctxt->incTab[0]));
1236 if (ctxt->incTab == NULL) {
1237 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1238 return (0);
1239 }
1240 }
1241 if (ctxt->incNr >= ctxt->incMax) {
1242 ctxt->incMax *= 2;
1243 ctxt->incTab =
1244 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
1245 ctxt->incMax *
1246 sizeof(ctxt->incTab[0]));
1247 if (ctxt->incTab == NULL) {
1248 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1249 return (0);
1250 }
1251 }
1252 ctxt->incTab[ctxt->incNr] = value;
1253 ctxt->inc = value;
1254 return (ctxt->incNr++);
1255}
1256
1257/**
1258 * xmlRelaxNGIncludePop:
1259 * @ctxt: the parser context
1260 *
1261 * Pops the top include from the include stack
1262 *
1263 * Returns the include just removed
1264 */
1265static xmlRelaxNGIncludePtr
1266xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
1267{
1268 xmlRelaxNGIncludePtr ret;
1269
1270 if (ctxt->incNr <= 0)
1271 return (0);
1272 ctxt->incNr--;
1273 if (ctxt->incNr > 0)
1274 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
1275 else
1276 ctxt->inc = NULL;
1277 ret = ctxt->incTab[ctxt->incNr];
1278 ctxt->incTab[ctxt->incNr] = 0;
1279 return (ret);
1280}
1281
1282/**
Daniel Veillard5add8682003-03-10 13:13:58 +00001283 * xmlRelaxNGRemoveRedefine:
1284 * @ctxt: the parser context
1285 * @URL: the normalized URL
1286 * @target: the included target
1287 * @name: the define name to eliminate
1288 *
1289 * Applies the elimination algorithm of 4.7
1290 *
1291 * Returns 0 in case of error, 1 in case of success.
1292 */
1293static int
1294xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt,
1295 const xmlChar *URL ATTRIBUTE_UNUSED,
1296 xmlNodePtr target, const xmlChar *name) {
1297 int found = 0;
1298 xmlNodePtr tmp, tmp2;
1299 xmlChar *name2;
1300
1301#ifdef DEBUG_INCLUDE
Daniel Veillard952379b2003-03-17 15:37:12 +00001302 if (name == NULL)
1303 xmlGenericError(xmlGenericErrorContext,
1304 "Elimination of <include> start from %s\n", URL);
1305 else
1306 xmlGenericError(xmlGenericErrorContext,
1307 "Elimination of <include> define %s from %s\n", name, URL);
Daniel Veillard5add8682003-03-10 13:13:58 +00001308#endif
1309 tmp = target;
1310 while (tmp != NULL) {
1311 tmp2 = tmp->next;
1312 if ((name == NULL) && (IS_RELAXNG(tmp, "start"))) {
1313 found = 1;
1314 xmlUnlinkNode(tmp);
1315 xmlFreeNode(tmp);
1316 } else if ((name != NULL) && (IS_RELAXNG(tmp, "define"))) {
1317 name2 = xmlGetProp(tmp, BAD_CAST "name");
1318 xmlRelaxNGNormExtSpace(name2);
1319 if (name2 != NULL) {
1320 if (xmlStrEqual(name, name2)) {
1321 found = 1;
1322 xmlUnlinkNode(tmp);
1323 xmlFreeNode(tmp);
1324 }
1325 xmlFree(name2);
1326 }
1327 } else if (IS_RELAXNG(tmp, "include")) {
1328 xmlChar *href = NULL;
1329 xmlRelaxNGDocumentPtr inc = tmp->_private;
1330
1331 if ((inc != NULL) && (inc->doc != NULL) &&
1332 (inc->doc->children != NULL)) {
1333
1334 if (xmlStrEqual(inc->doc->children->name, BAD_CAST "grammar")) {
1335#ifdef DEBUG_INCLUDE
1336 href = xmlGetProp(tmp, BAD_CAST "href");
1337#endif
1338 if (xmlRelaxNGRemoveRedefine(ctxt, href,
1339 inc->doc->children->children, name) == 1) {
1340 found = 1;
1341 }
1342 if (href != NULL)
1343 xmlFree(href);
1344 }
1345 }
1346 }
1347 tmp = tmp2;
1348 }
1349 return(found);
1350}
1351
1352/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001353 * xmlRelaxNGLoadInclude:
1354 * @ctxt: the parser context
1355 * @URL: the normalized URL
1356 * @node: the include node.
Daniel Veillard416589a2003-02-17 17:25:42 +00001357 * @ns: the namespace passed from the context.
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001358 *
1359 * First lookup if the document is already loaded into the parser context,
1360 * check against recursion. If not found the resource is loaded and
1361 * the content is preprocessed before being returned back to the caller.
1362 *
1363 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1364 */
1365static xmlRelaxNGIncludePtr
1366xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillard416589a2003-02-17 17:25:42 +00001367 xmlNodePtr node, const xmlChar *ns) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001368 xmlRelaxNGIncludePtr ret = NULL;
1369 xmlDocPtr doc;
1370 int i;
Daniel Veillard5add8682003-03-10 13:13:58 +00001371 xmlNodePtr root, cur;
1372
1373#ifdef DEBUG_INCLUDE
1374 xmlGenericError(xmlGenericErrorContext,
1375 "xmlRelaxNGLoadInclude(%s)\n", URL);
1376#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001377
1378 /*
1379 * check against recursion in the stack
1380 */
1381 for (i = 0;i < ctxt->incNr;i++) {
1382 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
1383 if (ctxt->error != NULL)
1384 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00001385 "Detected an Include recursion for %s\n",
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001386 URL);
1387 ctxt->nbErrors++;
1388 return(NULL);
1389 }
1390 }
1391
1392 /*
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001393 * load the document
1394 */
1395 doc = xmlParseFile((const char *) URL);
1396 if (doc == NULL) {
1397 if (ctxt->error != NULL)
1398 ctxt->error(ctxt->userData,
1399 "xmlRelaxNG: could not load %s\n", URL);
1400 ctxt->nbErrors++;
1401 return (NULL);
1402 }
1403
Daniel Veillard5add8682003-03-10 13:13:58 +00001404#ifdef DEBUG_INCLUDE
1405 xmlGenericError(xmlGenericErrorContext,
1406 "Parsed %s Okay\n", URL);
1407#endif
1408
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001409 /*
1410 * Allocate the document structures and register it first.
1411 */
1412 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
1413 if (ret == NULL) {
1414 if (ctxt->error != NULL)
1415 ctxt->error(ctxt->userData,
1416 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1417 ctxt->nbErrors++;
1418 xmlFreeDoc(doc);
1419 return (NULL);
1420 }
1421 memset(ret, 0, sizeof(xmlRelaxNGInclude));
1422 ret->doc = doc;
1423 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001424 ret->next = ctxt->includes;
1425 ctxt->includes = ret;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001426
1427 /*
Daniel Veillard416589a2003-02-17 17:25:42 +00001428 * transmit the ns if needed
1429 */
1430 if (ns != NULL) {
1431 root = xmlDocGetRootElement(doc);
1432 if (root != NULL) {
1433 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1434 xmlSetProp(root, BAD_CAST"ns", ns);
1435 }
1436 }
1437 }
1438
1439 /*
Daniel Veillardc482e262003-02-26 14:48:48 +00001440 * push it on the stack
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001441 */
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001442 xmlRelaxNGIncludePush(ctxt, ret);
1443
1444 /*
1445 * Some preprocessing of the document content, this include recursing
1446 * in the include stack.
1447 */
Daniel Veillard5add8682003-03-10 13:13:58 +00001448#ifdef DEBUG_INCLUDE
1449 xmlGenericError(xmlGenericErrorContext,
1450 "cleanup of %s\n", URL);
1451#endif
1452
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001453 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1454 if (doc == NULL) {
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001455 ctxt->inc = NULL;
1456 return(NULL);
1457 }
1458
1459 /*
1460 * Pop up the include from the stack
1461 */
1462 xmlRelaxNGIncludePop(ctxt);
1463
Daniel Veillard5add8682003-03-10 13:13:58 +00001464#ifdef DEBUG_INCLUDE
1465 xmlGenericError(xmlGenericErrorContext,
1466 "Checking of %s\n", URL);
1467#endif
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001468 /*
1469 * Check that the top element is a grammar
1470 */
1471 root = xmlDocGetRootElement(doc);
1472 if (root == NULL) {
1473 if (ctxt->error != NULL)
1474 ctxt->error(ctxt->userData,
1475 "xmlRelaxNG: included document is empty %s\n", URL);
1476 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001477 return (NULL);
1478 }
1479 if (!IS_RELAXNG(root, "grammar")) {
1480 if (ctxt->error != NULL)
1481 ctxt->error(ctxt->userData,
1482 "xmlRelaxNG: included document %s root is not a grammar\n",
1483 URL);
1484 ctxt->nbErrors++;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001485 return (NULL);
1486 }
1487
1488 /*
1489 * Elimination of redefined rules in the include.
1490 */
1491 cur = node->children;
1492 while (cur != NULL) {
1493 if (IS_RELAXNG(cur, "start")) {
1494 int found = 0;
1495
Daniel Veillard5add8682003-03-10 13:13:58 +00001496 found = xmlRelaxNGRemoveRedefine(ctxt, URL, root->children, NULL);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001497 if (!found) {
1498 if (ctxt->error != NULL)
1499 ctxt->error(ctxt->userData,
1500 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1501 URL);
1502 ctxt->nbErrors++;
1503 }
1504 } else if (IS_RELAXNG(cur, "define")) {
Daniel Veillard5add8682003-03-10 13:13:58 +00001505 xmlChar *name;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001506
1507 name = xmlGetProp(cur, BAD_CAST "name");
1508 if (name == NULL) {
1509 if (ctxt->error != NULL)
1510 ctxt->error(ctxt->userData,
1511 "xmlRelaxNG: include %s has define without name\n",
1512 URL);
1513 ctxt->nbErrors++;
1514 } else {
Daniel Veillard5add8682003-03-10 13:13:58 +00001515 int found;
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001516
Daniel Veillardd2298792003-02-14 16:54:11 +00001517 xmlRelaxNGNormExtSpace(name);
Daniel Veillard5add8682003-03-10 13:13:58 +00001518 found = xmlRelaxNGRemoveRedefine(ctxt, URL,
1519 root->children, name);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001520 if (!found) {
1521 if (ctxt->error != NULL)
1522 ctxt->error(ctxt->userData,
1523 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1524 URL, name);
1525 ctxt->nbErrors++;
1526 }
1527 xmlFree(name);
1528 }
1529 }
1530 cur = cur->next;
1531 }
1532
1533
1534 return(ret);
1535}
1536
1537/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001538 * xmlRelaxNGValidErrorPush:
1539 * @ctxt: the validation context
1540 * @err: the error code
1541 * @arg1: the first string argument
1542 * @arg2: the second string argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001543 * @dup: arg need to be duplicated
Daniel Veillard42f12e92003-03-07 18:32:59 +00001544 *
1545 * Pushes a new error on top of the error stack
1546 *
1547 * Returns 0 in case of error, the index in the stack otherwise
1548 */
1549static int
1550xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001551 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00001552{
1553 xmlRelaxNGValidErrorPtr cur;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00001554#ifdef DEBUG_ERROR
1555 xmlGenericError(xmlGenericErrorContext,
1556 "Pushing error %d at %d on stack\n", err, ctxt->errNr);
1557#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00001558 if (ctxt->errTab == NULL) {
1559 ctxt->errMax = 8;
1560 ctxt->errNr = 0;
1561 ctxt->errTab = (xmlRelaxNGValidErrorPtr) xmlMalloc(
1562 ctxt->errMax * sizeof(xmlRelaxNGValidError));
1563 if (ctxt->errTab == NULL) {
1564 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1565 return (0);
1566 }
Daniel Veillard20863822003-03-22 17:51:47 +00001567 ctxt->err = NULL;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001568 }
1569 if (ctxt->errNr >= ctxt->errMax) {
Daniel Veillard20863822003-03-22 17:51:47 +00001570 ctxt->errMax *= 2;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001571 ctxt->errTab =
1572 (xmlRelaxNGValidErrorPtr) xmlRealloc(ctxt->errTab,
Daniel Veillard20863822003-03-22 17:51:47 +00001573 ctxt->errMax * sizeof(xmlRelaxNGValidError));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001574 if (ctxt->errTab == NULL) {
1575 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1576 return (0);
1577 }
Daniel Veillard20863822003-03-22 17:51:47 +00001578 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
Daniel Veillard42f12e92003-03-07 18:32:59 +00001579 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001580 if ((ctxt->err != NULL) && (ctxt->state != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00001581 (ctxt->err->node == ctxt->state->node) &&
1582 (ctxt->err->err == err))
1583 return(ctxt->errNr);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001584 cur = &ctxt->errTab[ctxt->errNr];
1585 cur->err = err;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001586 if (dup) {
1587 cur->arg1 = xmlStrdup(arg1);
1588 cur->arg2 = xmlStrdup(arg2);
1589 cur->flags = ERROR_IS_DUP;
1590 } else {
1591 cur->arg1 = arg1;
1592 cur->arg2 = arg2;
1593 cur->flags = 0;
1594 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001595 if (ctxt->state != NULL) {
1596 cur->node = ctxt->state->node;
1597 cur->seq = ctxt->state->seq;
1598 } else {
1599 cur->node = NULL;
1600 cur->seq = NULL;
1601 }
1602 ctxt->err = cur;
1603 return (ctxt->errNr++);
1604}
1605
1606/**
1607 * xmlRelaxNGValidErrorPop:
1608 * @ctxt: the validation context
1609 *
1610 * Pops the top error from the error stack
Daniel Veillard42f12e92003-03-07 18:32:59 +00001611 */
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001612static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001613xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt)
1614{
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001615 xmlRelaxNGValidErrorPtr cur;
Daniel Veillard42f12e92003-03-07 18:32:59 +00001616
Daniel Veillard580ced82003-03-21 21:22:48 +00001617 if (ctxt->errNr <= 0) {
1618 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001619 return;
Daniel Veillard580ced82003-03-21 21:22:48 +00001620 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001621 ctxt->errNr--;
1622 if (ctxt->errNr > 0)
1623 ctxt->err = &ctxt->errTab[ctxt->errNr - 1];
1624 else
1625 ctxt->err = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001626 cur = &ctxt->errTab[ctxt->errNr];
1627 if (cur->flags & ERROR_IS_DUP) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001628 if (cur->arg1 != NULL)
1629 xmlFree((xmlChar *)cur->arg1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001630 cur->arg1 = NULL;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00001631 if (cur->arg2 != NULL)
1632 xmlFree((xmlChar *)cur->arg2);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001633 cur->arg2 = NULL;
1634 cur->flags = 0;
1635 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00001636}
1637
Daniel Veillard42f12e92003-03-07 18:32:59 +00001638/**
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001639 * xmlRelaxNGDocumentPush:
1640 * @ctxt: the parser context
1641 * @value: the element doc
1642 *
1643 * Pushes a new doc on top of the doc stack
1644 *
1645 * Returns 0 in case of error, the index in the stack otherwise
1646 */
1647static int
1648xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1649 xmlRelaxNGDocumentPtr value)
1650{
1651 if (ctxt->docTab == NULL) {
1652 ctxt->docMax = 4;
1653 ctxt->docNr = 0;
1654 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1655 ctxt->docMax * sizeof(ctxt->docTab[0]));
1656 if (ctxt->docTab == NULL) {
1657 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1658 return (0);
1659 }
1660 }
1661 if (ctxt->docNr >= ctxt->docMax) {
1662 ctxt->docMax *= 2;
1663 ctxt->docTab =
1664 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1665 ctxt->docMax *
1666 sizeof(ctxt->docTab[0]));
1667 if (ctxt->docTab == NULL) {
1668 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1669 return (0);
1670 }
1671 }
1672 ctxt->docTab[ctxt->docNr] = value;
1673 ctxt->doc = value;
1674 return (ctxt->docNr++);
1675}
1676
1677/**
1678 * xmlRelaxNGDocumentPop:
1679 * @ctxt: the parser context
1680 *
1681 * Pops the top doc from the doc stack
1682 *
1683 * Returns the doc just removed
1684 */
1685static xmlRelaxNGDocumentPtr
1686xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1687{
1688 xmlRelaxNGDocumentPtr ret;
1689
1690 if (ctxt->docNr <= 0)
1691 return (0);
1692 ctxt->docNr--;
1693 if (ctxt->docNr > 0)
1694 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1695 else
1696 ctxt->doc = NULL;
1697 ret = ctxt->docTab[ctxt->docNr];
1698 ctxt->docTab[ctxt->docNr] = 0;
1699 return (ret);
1700}
1701
1702/**
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001703 * xmlRelaxNGLoadExternalRef:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001704 * @ctxt: the parser context
1705 * @URL: the normalized URL
1706 * @ns: the inherited ns if any
1707 *
1708 * First lookup if the document is already loaded into the parser context,
1709 * check against recursion. If not found the resource is loaded and
1710 * the content is preprocessed before being returned back to the caller.
1711 *
1712 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1713 */
1714static xmlRelaxNGDocumentPtr
Daniel Veillarda9d912d2003-02-01 17:43:10 +00001715xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001716 const xmlChar *ns) {
1717 xmlRelaxNGDocumentPtr ret = NULL;
1718 xmlDocPtr doc;
1719 xmlNodePtr root;
1720 int i;
1721
1722 /*
1723 * check against recursion in the stack
1724 */
1725 for (i = 0;i < ctxt->docNr;i++) {
1726 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1727 if (ctxt->error != NULL)
1728 ctxt->error(ctxt->userData,
1729 "Detected an externalRef recursion for %s\n",
1730 URL);
1731 ctxt->nbErrors++;
1732 return(NULL);
1733 }
1734 }
1735
1736 /*
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001737 * load the document
1738 */
1739 doc = xmlParseFile((const char *) URL);
1740 if (doc == NULL) {
1741 if (ctxt->error != NULL)
1742 ctxt->error(ctxt->userData,
1743 "xmlRelaxNG: could not load %s\n", URL);
1744 ctxt->nbErrors++;
1745 return (NULL);
1746 }
1747
1748 /*
1749 * Allocate the document structures and register it first.
1750 */
1751 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1752 if (ret == NULL) {
1753 if (ctxt->error != NULL)
1754 ctxt->error(ctxt->userData,
1755 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1756 ctxt->nbErrors++;
1757 xmlFreeDoc(doc);
1758 return (NULL);
1759 }
1760 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1761 ret->doc = doc;
1762 ret->href = xmlStrdup(URL);
Daniel Veillardc482e262003-02-26 14:48:48 +00001763 ret->next = ctxt->documents;
1764 ctxt->documents = ret;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001765
1766 /*
1767 * transmit the ns if needed
1768 */
1769 if (ns != NULL) {
1770 root = xmlDocGetRootElement(doc);
1771 if (root != NULL) {
1772 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1773 xmlSetProp(root, BAD_CAST"ns", ns);
1774 }
1775 }
1776 }
1777
1778 /*
1779 * push it on the stack and register it in the hash table
1780 */
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001781 xmlRelaxNGDocumentPush(ctxt, ret);
1782
1783 /*
1784 * Some preprocessing of the document content
1785 */
1786 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1787 if (doc == NULL) {
Daniel Veillardd41f4f42003-01-29 21:07:52 +00001788 ctxt->doc = NULL;
1789 return(NULL);
1790 }
1791
1792 xmlRelaxNGDocumentPop(ctxt);
1793
1794 return(ret);
1795}
1796
1797/************************************************************************
1798 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00001799 * Error functions *
1800 * *
1801 ************************************************************************/
1802
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001803#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
1804#define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
1805#define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
1806#define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
1807#define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00001808
Daniel Veillardfd573f12003-03-16 17:52:32 +00001809#ifdef DEBUG
Daniel Veillard231d7912003-02-09 14:22:17 +00001810static const char *
1811xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1812 if (def == NULL)
1813 return("none");
1814 switch(def->type) {
1815 case XML_RELAXNG_EMPTY: return("empty");
1816 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1817 case XML_RELAXNG_EXCEPT: return("except");
1818 case XML_RELAXNG_TEXT: return("text");
1819 case XML_RELAXNG_ELEMENT: return("element");
1820 case XML_RELAXNG_DATATYPE: return("datatype");
1821 case XML_RELAXNG_VALUE: return("value");
1822 case XML_RELAXNG_LIST: return("list");
1823 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1824 case XML_RELAXNG_DEF: return("def");
1825 case XML_RELAXNG_REF: return("ref");
1826 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1827 case XML_RELAXNG_PARENTREF: return("parentRef");
Daniel Veillardfd573f12003-03-16 17:52:32 +00001828 case XML_RELAXNG_OPTIONAL: return("optional");
1829 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
Daniel Veillard231d7912003-02-09 14:22:17 +00001830 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1831 case XML_RELAXNG_CHOICE: return("choice");
1832 case XML_RELAXNG_GROUP: return("group");
1833 case XML_RELAXNG_INTERLEAVE: return("interleave");
1834 case XML_RELAXNG_START: return("start");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001835 case XML_RELAXNG_NOOP: return("noop");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00001836 case XML_RELAXNG_PARAM: return("param");
Daniel Veillard231d7912003-02-09 14:22:17 +00001837 }
1838 return("unknown");
1839}
Daniel Veillardfd573f12003-03-16 17:52:32 +00001840#endif
Daniel Veillardd2298792003-02-14 16:54:11 +00001841
Daniel Veillard6eadf632003-01-23 18:29:16 +00001842/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00001843 * xmlRelaxNGGetErrorString:
1844 * @err: the error code
1845 * @arg1: the first string argument
1846 * @arg2: the second string argument
Daniel Veillard6eadf632003-01-23 18:29:16 +00001847 *
Daniel Veillard42f12e92003-03-07 18:32:59 +00001848 * computes a formatted error string for the given error code and args
1849 *
1850 * Returns the error string, it must be deallocated by the caller
1851 */
1852static xmlChar *
Daniel Veillardfd573f12003-03-16 17:52:32 +00001853xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err, const xmlChar *arg1,
1854 const xmlChar *arg2) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00001855 char msg[1000];
1856
1857 if (arg1 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001858 arg1 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001859 if (arg2 == NULL)
Daniel Veillardfd573f12003-03-16 17:52:32 +00001860 arg2 = BAD_CAST "";
Daniel Veillard42f12e92003-03-07 18:32:59 +00001861
1862 msg[0] = 0;
1863 switch (err) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001864 case XML_RELAXNG_OK:
1865 return(NULL);
1866 case XML_RELAXNG_ERR_MEMORY:
1867 return(xmlCharStrdup("out of memory"));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001868 case XML_RELAXNG_ERR_TYPE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00001869 snprintf(msg, 1000, "failed to validate type %s", arg1);
1870 break;
1871 case XML_RELAXNG_ERR_TYPEVAL:
Daniel Veillardc4c21552003-03-29 10:53:38 +00001872 snprintf(msg, 1000, "Type %s doesn't allow value '%s'", arg1, arg2);
Daniel Veillardfd573f12003-03-16 17:52:32 +00001873 break;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00001874 case XML_RELAXNG_ERR_DUPID:
1875 snprintf(msg, 1000, "ID %s redefined", arg1);
1876 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001877 case XML_RELAXNG_ERR_TYPECMP:
1878 snprintf(msg, 1000, "failed to compare type %s", arg1);
1879 break;
1880 case XML_RELAXNG_ERR_NOSTATE:
1881 return(xmlCharStrdup("Internal error: no state"));
1882 case XML_RELAXNG_ERR_NODEFINE:
1883 return(xmlCharStrdup("Internal error: no define"));
Daniel Veillard952379b2003-03-17 15:37:12 +00001884 case XML_RELAXNG_ERR_INTERNAL:
1885 snprintf(msg, 1000, "Internal error: %s", arg1);
1886 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001887 case XML_RELAXNG_ERR_LISTEXTRA:
1888 snprintf(msg, 1000, "Extra data in list: %s", arg1);
1889 break;
1890 case XML_RELAXNG_ERR_INTERNODATA:
1891 return(xmlCharStrdup("Internal: interleave block has no data"));
1892 case XML_RELAXNG_ERR_INTERSEQ:
1893 return(xmlCharStrdup("Invalid sequence in interleave"));
1894 case XML_RELAXNG_ERR_INTEREXTRA:
1895 snprintf(msg, 1000, "Extra element %s in interleave", arg1);
1896 break;
1897 case XML_RELAXNG_ERR_ELEMNAME:
1898 snprintf(msg, 1000, "Expecting element %s, got %s", arg1, arg2);
1899 break;
1900 case XML_RELAXNG_ERR_ELEMNONS:
1901 snprintf(msg, 1000, "Expecting a namespace for element %s", arg1);
1902 break;
1903 case XML_RELAXNG_ERR_ELEMWRONGNS:
1904 snprintf(msg, 1000, "Element %s has wrong namespace: expecting %s",
1905 arg1, arg2);
1906 break;
1907 case XML_RELAXNG_ERR_ELEMEXTRANS:
1908 snprintf(msg, 1000, "Expecting no namespace for element %s", arg1);
1909 break;
1910 case XML_RELAXNG_ERR_ELEMNOTEMPTY:
1911 snprintf(msg, 1000, "Expecting element %s to be empty", arg1);
1912 break;
1913 case XML_RELAXNG_ERR_NOELEM:
1914 snprintf(msg, 1000, "Expecting an element %s, got nothing", arg1);
1915 break;
1916 case XML_RELAXNG_ERR_NOTELEM:
1917 return(xmlCharStrdup("Expecting an element got text"));
1918 case XML_RELAXNG_ERR_ATTRVALID:
1919 snprintf(msg, 1000, "Element %s failed to validate attributes",
1920 arg1);
1921 break;
1922 case XML_RELAXNG_ERR_CONTENTVALID:
1923 snprintf(msg, 1000, "Element %s failed to validate content",
1924 arg1);
1925 break;
1926 case XML_RELAXNG_ERR_EXTRACONTENT:
1927 snprintf(msg, 1000, "Element %s has extra content: %s",
1928 arg1, arg2);
1929 break;
1930 case XML_RELAXNG_ERR_INVALIDATTR:
1931 snprintf(msg, 1000, "Invalid attribute %s for element %s",
1932 arg1, arg2);
1933 break;
Daniel Veillardc4c21552003-03-29 10:53:38 +00001934 case XML_RELAXNG_ERR_LACKDATA:
1935 snprintf(msg, 1000, "Datatype element %s contains no data",
1936 arg1);
1937 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001938 case XML_RELAXNG_ERR_DATAELEM:
1939 snprintf(msg, 1000, "Datatype element %s has child elements",
1940 arg1);
1941 break;
1942 case XML_RELAXNG_ERR_VALELEM:
1943 snprintf(msg, 1000, "Value element %s has child elements",
1944 arg1);
1945 break;
1946 case XML_RELAXNG_ERR_LISTELEM:
1947 snprintf(msg, 1000, "List element %s has child elements",
1948 arg1);
1949 break;
1950 case XML_RELAXNG_ERR_DATATYPE:
1951 snprintf(msg, 1000, "Error validating datatype %s",
1952 arg1);
1953 break;
1954 case XML_RELAXNG_ERR_VALUE:
1955 snprintf(msg, 1000, "Error validating value %s",
1956 arg1);
1957 break;
1958 case XML_RELAXNG_ERR_LIST:
1959 return(xmlCharStrdup("Error validating list"));
1960 case XML_RELAXNG_ERR_NOGRAMMAR:
1961 return(xmlCharStrdup("No top grammar defined"));
1962 case XML_RELAXNG_ERR_EXTRADATA:
1963 return(xmlCharStrdup("Extra data in the document"));
1964 default:
1965 TODO
Daniel Veillard42f12e92003-03-07 18:32:59 +00001966 }
1967 if (msg[0] == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00001968 snprintf(msg, 1000, "Unknown error code %d", err);
Daniel Veillard42f12e92003-03-07 18:32:59 +00001969 }
1970 msg[1000] = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00001971 return(xmlStrdup((xmlChar *) msg));
Daniel Veillard42f12e92003-03-07 18:32:59 +00001972}
1973
1974/**
1975 * xmlRelaxNGValidErrorContext:
1976 * @ctxt: the validation context
1977 * @node: the node
1978 * @child: the node child generating the problem.
1979 *
1980 * Dump informations about the kocation of the error in the instance
Daniel Veillard6eadf632003-01-23 18:29:16 +00001981 */
1982static void
Daniel Veillard42f12e92003-03-07 18:32:59 +00001983xmlRelaxNGValidErrorContext(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node,
1984 xmlNodePtr child)
Daniel Veillard6eadf632003-01-23 18:29:16 +00001985{
1986 int line = 0;
1987 const xmlChar *file = NULL;
1988 const xmlChar *name = NULL;
1989 const char *type = "error";
1990
1991 if ((ctxt == NULL) || (ctxt->error == NULL))
1992 return;
1993
1994 if (child != NULL)
1995 node = child;
1996
1997 if (node != NULL) {
1998 if ((node->type == XML_DOCUMENT_NODE) ||
1999 (node->type == XML_HTML_DOCUMENT_NODE)) {
2000 xmlDocPtr doc = (xmlDocPtr) node;
2001
2002 file = doc->URL;
2003 } else {
2004 /*
2005 * Try to find contextual informations to report
2006 */
2007 if (node->type == XML_ELEMENT_NODE) {
2008 line = (int) node->content;
2009 } else if ((node->prev != NULL) &&
2010 (node->prev->type == XML_ELEMENT_NODE)) {
2011 line = (int) node->prev->content;
2012 } else if ((node->parent != NULL) &&
2013 (node->parent->type == XML_ELEMENT_NODE)) {
2014 line = (int) node->parent->content;
2015 }
2016 if ((node->doc != NULL) && (node->doc->URL != NULL))
2017 file = node->doc->URL;
2018 if (node->name != NULL)
2019 name = node->name;
2020 }
2021 }
2022
Daniel Veillard42f12e92003-03-07 18:32:59 +00002023 type = "RNG validity error";
Daniel Veillard6eadf632003-01-23 18:29:16 +00002024
2025 if ((file != NULL) && (line != 0) && (name != NULL))
2026 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
2027 type, file, line, name);
2028 else if ((file != NULL) && (name != NULL))
2029 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
2030 type, file, name);
2031 else if ((file != NULL) && (line != 0))
2032 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
2033 else if (file != NULL)
2034 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
2035 else if (name != NULL)
2036 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
2037 else
2038 ctxt->error(ctxt->userData, "%s\n", type);
2039}
Daniel Veillard42f12e92003-03-07 18:32:59 +00002040
2041/**
2042 * xmlRelaxNGShowValidError:
2043 * @ctxt: the validation context
2044 * @err: the error number
2045 * @node: the node
2046 * @child: the node child generating the problem.
2047 * @arg1: the first argument
2048 * @arg2: the second argument
2049 *
2050 * Show a validation error.
2051 */
2052static void
2053xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
2054 xmlNodePtr node, xmlNodePtr child,
2055 const xmlChar *arg1, const xmlChar *arg2)
2056{
2057 xmlChar *msg;
2058
2059 if (ctxt->error == NULL)
2060 return;
2061
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002062#ifdef DEBUG_ERROR
2063 xmlGenericError(xmlGenericErrorContext,
2064 "Show error %d\n", err);
2065#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002066 msg = xmlRelaxNGGetErrorString(err, arg1, arg2);
2067 if (msg == NULL)
2068 return;
2069
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002070 if (ctxt->errNo == XML_RELAXNG_OK)
2071 ctxt->errNo = err;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002072 xmlRelaxNGValidErrorContext(ctxt, node, child);
2073 ctxt->error(ctxt->userData, "%s\n", msg);
2074 xmlFree(msg);
2075}
2076
2077/**
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002078 * xmlRelaxNGPopErrors:
2079 * @ctxt: the validation context
2080 * @level: the error level in the stack
2081 *
2082 * pop and discard all errors until the given level is reached
2083 */
2084static void
2085xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt, int level) {
2086 int i;
2087 xmlRelaxNGValidErrorPtr err;
2088
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002089#ifdef DEBUG_ERROR
2090 xmlGenericError(xmlGenericErrorContext,
2091 "Pop errors till level %d\n", level);
2092#endif
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002093 for (i = level;i < ctxt->errNr;i++) {
2094 err = &ctxt->errTab[i];
2095 if (err->flags & ERROR_IS_DUP) {
2096 if (err->arg1 != NULL)
2097 xmlFree((xmlChar *)err->arg1);
2098 err->arg1 = NULL;
2099 if (err->arg2 != NULL)
2100 xmlFree((xmlChar *)err->arg2);
2101 err->arg2 = NULL;
2102 err->flags = 0;
2103 }
2104 }
2105 ctxt->errNr = level;
Daniel Veillard580ced82003-03-21 21:22:48 +00002106 if (ctxt->errNr <= 0)
2107 ctxt->err = NULL;
Daniel Veillard28c52ab2003-03-18 11:39:17 +00002108}
2109/**
Daniel Veillard42f12e92003-03-07 18:32:59 +00002110 * xmlRelaxNGDumpValidError:
2111 * @ctxt: the validation context
2112 *
2113 * Show all validation error over a given index.
2114 */
2115static void
2116xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002117 int i, j, k;
Daniel Veillard580ced82003-03-21 21:22:48 +00002118 xmlRelaxNGValidErrorPtr err, dup;
Daniel Veillard42f12e92003-03-07 18:32:59 +00002119
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002120#ifdef DEBUG_ERROR
2121 xmlGenericError(xmlGenericErrorContext,
2122 "Dumping error stack %d errors\n", ctxt->errNr);
2123#endif
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002124 for (i = 0, k = 0;i < ctxt->errNr;i++) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00002125 err = &ctxt->errTab[i];
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002126 if (k < MAX_ERROR) {
2127 for (j = 0;j < i;j++) {
2128 dup = &ctxt->errTab[j];
2129 if ((err->err == dup->err) && (err->node == dup->node) &&
2130 (xmlStrEqual(err->arg1, dup->arg1)) &&
2131 (xmlStrEqual(err->arg2, dup->arg2))) {
2132 goto skip;
2133 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002134 }
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002135 xmlRelaxNGShowValidError(ctxt, err->err, err->node, err->seq,
2136 err->arg1, err->arg2);
2137 k++;
Daniel Veillard580ced82003-03-21 21:22:48 +00002138 }
Daniel Veillard580ced82003-03-21 21:22:48 +00002139skip:
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002140 if (err->flags & ERROR_IS_DUP) {
2141 if (err->arg1 != NULL)
2142 xmlFree((xmlChar *)err->arg1);
2143 err->arg1 = NULL;
2144 if (err->arg2 != NULL)
2145 xmlFree((xmlChar *)err->arg2);
2146 err->arg2 = NULL;
2147 err->flags = 0;
2148 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00002149 }
2150 ctxt->errNr = 0;
2151}
2152/**
2153 * xmlRelaxNGAddValidError:
2154 * @ctxt: the validation context
2155 * @err: the error number
2156 * @arg1: the first argument
2157 * @arg2: the second argument
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002158 * @dup: need to dup the args
Daniel Veillard42f12e92003-03-07 18:32:59 +00002159 *
2160 * Register a validation error, either generating it if it's sure
2161 * or stacking it for later handling if unsure.
2162 */
2163static void
2164xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt, xmlRelaxNGValidErr err,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002165 const xmlChar *arg1, const xmlChar *arg2, int dup)
Daniel Veillard42f12e92003-03-07 18:32:59 +00002166{
2167 if ((ctxt == NULL) || (ctxt->error == NULL))
2168 return;
2169
Daniel Veillarda507fbf2003-03-31 16:09:37 +00002170#ifdef DEBUG_ERROR
2171 xmlGenericError(xmlGenericErrorContext,
2172 "Adding error %d\n", err);
2173#endif
Daniel Veillard42f12e92003-03-07 18:32:59 +00002174 /*
2175 * generate the error directly
2176 */
2177 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) {
2178 xmlNodePtr node, seq;
2179 /*
2180 * Flush first any stacked error which might be the
2181 * real cause of the problem.
2182 */
2183 if (ctxt->errNr != 0)
2184 xmlRelaxNGDumpValidError(ctxt);
2185 if (ctxt->state != NULL) {
2186 node = ctxt->state->node;
2187 seq = ctxt->state->seq;
2188 } else {
2189 node = seq = NULL;
2190 }
2191 xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
2192 }
2193 /*
2194 * Stack the error for later processing if needed
2195 */
2196 else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002197 xmlRelaxNGValidErrorPush(ctxt, err, arg1, arg2, dup);
Daniel Veillard42f12e92003-03-07 18:32:59 +00002198 }
2199}
2200
Daniel Veillard6eadf632003-01-23 18:29:16 +00002201
2202/************************************************************************
2203 * *
2204 * Type library hooks *
2205 * *
2206 ************************************************************************/
Daniel Veillardea3f3982003-01-26 19:45:18 +00002207static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
2208 const xmlChar *str);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002209
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002210/**
2211 * xmlRelaxNGSchemaTypeHave:
2212 * @data: data needed for the library
2213 * @type: the type name
2214 *
2215 * Check if the given type is provided by
2216 * the W3C XMLSchema Datatype library.
2217 *
2218 * Returns 1 if yes, 0 if no and -1 in case of error.
2219 */
2220static int
2221xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002222 const xmlChar *type) {
2223 xmlSchemaTypePtr typ;
2224
2225 if (type == NULL)
2226 return(-1);
2227 typ = xmlSchemaGetPredefinedType(type,
2228 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2229 if (typ == NULL)
2230 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002231 return(1);
2232}
2233
2234/**
2235 * xmlRelaxNGSchemaTypeCheck:
2236 * @data: data needed for the library
2237 * @type: the type name
2238 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002239 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002240 *
2241 * Check if the given type and value are validated by
2242 * the W3C XMLSchema Datatype library.
2243 *
2244 * Returns 1 if yes, 0 if no and -1 in case of error.
2245 */
2246static int
2247xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002248 const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002249 const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002250 void **result,
2251 xmlNodePtr node) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002252 xmlSchemaTypePtr typ;
2253 int ret;
2254
2255 /*
2256 * TODO: the type should be cached ab provided back, interface subject
2257 * to changes.
2258 * TODO: handle facets, may require an additional interface and keep
2259 * the value returned from the validation.
2260 */
2261 if ((type == NULL) || (value == NULL))
2262 return(-1);
2263 typ = xmlSchemaGetPredefinedType(type,
2264 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2265 if (typ == NULL)
2266 return(-1);
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002267 ret = xmlSchemaValPredefTypeNode(typ, value,
2268 (xmlSchemaValPtr *) result, node);
2269 if (ret == 2) /* special ID error code */
2270 return(2);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00002271 if (ret == 0)
2272 return(1);
2273 if (ret > 0)
2274 return(0);
2275 return(-1);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002276}
2277
2278/**
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002279 * xmlRelaxNGSchemaFacetCheck:
2280 * @data: data needed for the library
2281 * @type: the type name
2282 * @facet: the facet name
2283 * @val: the facet value
2284 * @strval: the string value
2285 * @value: the value to check
2286 *
2287 * Function provided by a type library to check a value facet
2288 *
2289 * Returns 1 if yes, 0 if no and -1 in case of error.
2290 */
2291static int
Daniel Veillard42f12e92003-03-07 18:32:59 +00002292xmlRelaxNGSchemaFacetCheck (void *data ATTRIBUTE_UNUSED, const xmlChar *type,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002293 const xmlChar *facetname, const xmlChar *val,
2294 const xmlChar *strval, void *value) {
2295 xmlSchemaFacetPtr facet;
2296 xmlSchemaTypePtr typ;
2297 int ret;
2298
2299 if ((type == NULL) || (strval == NULL))
2300 return(-1);
2301 typ = xmlSchemaGetPredefinedType(type,
2302 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2303 if (typ == NULL)
2304 return(-1);
2305
2306 facet = xmlSchemaNewFacet();
2307 if (facet == NULL)
2308 return(-1);
2309
2310 if (xmlStrEqual(facetname, BAD_CAST "minInclusive")) {
2311 facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
2312 } else if (xmlStrEqual(facetname, BAD_CAST "minExclusive")) {
2313 facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
2314 } else if (xmlStrEqual(facetname, BAD_CAST "maxInclusive")) {
2315 facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
2316 } else if (xmlStrEqual(facetname, BAD_CAST "maxExclusive")) {
2317 facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
2318 } else if (xmlStrEqual(facetname, BAD_CAST "totalDigits")) {
2319 facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
2320 } else if (xmlStrEqual(facetname, BAD_CAST "fractionDigits")) {
2321 facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
2322 } else if (xmlStrEqual(facetname, BAD_CAST "pattern")) {
2323 facet->type = XML_SCHEMA_FACET_PATTERN;
2324 } else if (xmlStrEqual(facetname, BAD_CAST "enumeration")) {
2325 facet->type = XML_SCHEMA_FACET_ENUMERATION;
2326 } else if (xmlStrEqual(facetname, BAD_CAST "whiteSpace")) {
2327 facet->type = XML_SCHEMA_FACET_WHITESPACE;
2328 } else if (xmlStrEqual(facetname, BAD_CAST "length")) {
2329 facet->type = XML_SCHEMA_FACET_LENGTH;
2330 } else if (xmlStrEqual(facetname, BAD_CAST "maxLength")) {
2331 facet->type = XML_SCHEMA_FACET_MAXLENGTH;
2332 } else if (xmlStrEqual(facetname, BAD_CAST "minLength")) {
2333 facet->type = XML_SCHEMA_FACET_MINLENGTH;
2334 } else {
2335 xmlSchemaFreeFacet(facet);
2336 return(-1);
2337 }
2338 facet->value = xmlStrdup(val);
2339 ret = xmlSchemaCheckFacet(facet, typ, NULL, type);
2340 if (ret != 0) {
2341 xmlSchemaFreeFacet(facet);
2342 return(-1);
2343 }
2344 ret = xmlSchemaValidateFacet(typ, facet, strval, value);
2345 xmlSchemaFreeFacet(facet);
2346 if (ret != 0)
2347 return(-1);
2348 return(0);
2349}
2350
2351/**
Daniel Veillard80b19092003-03-28 13:29:53 +00002352 * xmlRelaxNGSchemaFreeValue:
2353 * @data: data needed for the library
2354 * @value: the value to free
2355 *
2356 * Function provided by a type library to free a Schemas value
2357 *
2358 * Returns 1 if yes, 0 if no and -1 in case of error.
2359 */
2360static void
2361xmlRelaxNGSchemaFreeValue (void *data ATTRIBUTE_UNUSED, void *value) {
2362 xmlSchemaFreeValue(value);
2363}
2364
2365/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002366 * xmlRelaxNGSchemaTypeCompare:
2367 * @data: data needed for the library
2368 * @type: the type name
2369 * @value1: the first value
2370 * @value2: the second value
2371 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002372 * Compare two values for equality accordingly a type from the W3C XMLSchema
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002373 * Datatype library.
2374 *
Daniel Veillard80b19092003-03-28 13:29:53 +00002375 * Returns 1 if equal, 0 if no and -1 in case of error.
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002376 */
2377static int
2378xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002379 const xmlChar *type,
2380 const xmlChar *value1,
2381 xmlNodePtr ctxt1,
2382 void *comp1,
2383 const xmlChar *value2,
2384 xmlNodePtr ctxt2) {
Daniel Veillard80b19092003-03-28 13:29:53 +00002385 int ret;
2386 xmlSchemaTypePtr typ;
2387 xmlSchemaValPtr res1 = NULL, res2 = NULL;
2388
2389 if ((type == NULL) || (value1 == NULL) || (value2 == NULL))
2390 return(-1);
2391 typ = xmlSchemaGetPredefinedType(type,
2392 BAD_CAST "http://www.w3.org/2001/XMLSchema");
2393 if (typ == NULL)
2394 return(-1);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002395 if (comp1 == NULL) {
2396 ret = xmlSchemaValPredefTypeNode(typ, value1, &res1, ctxt1);
2397 if (ret != 0)
2398 return(-1);
2399 if (res1 == NULL)
2400 return(-1);
2401 } else {
2402 res1 = (xmlSchemaValPtr) comp1;
2403 }
2404 ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
Daniel Veillard80b19092003-03-28 13:29:53 +00002405 if (ret != 0) {
2406 xmlSchemaFreeValue(res1);
2407 return(-1);
2408 }
2409 if (res1 == NULL) {
2410 xmlSchemaFreeValue(res1);
2411 return(-1);
2412 }
2413 ret = xmlSchemaCompareValues(res1, res2);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002414 if (res1 != (xmlSchemaValPtr) comp1)
2415 xmlSchemaFreeValue(res1);
Daniel Veillard80b19092003-03-28 13:29:53 +00002416 xmlSchemaFreeValue(res2);
2417 if (ret == -2)
2418 return(-1);
2419 if (ret == 0)
2420 return(1);
2421 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002422}
2423
2424/**
2425 * xmlRelaxNGDefaultTypeHave:
2426 * @data: data needed for the library
2427 * @type: the type name
2428 *
2429 * Check if the given type is provided by
2430 * the default datatype library.
2431 *
2432 * Returns 1 if yes, 0 if no and -1 in case of error.
2433 */
2434static int
2435xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
2436 if (type == NULL)
2437 return(-1);
2438 if (xmlStrEqual(type, BAD_CAST "string"))
2439 return(1);
2440 if (xmlStrEqual(type, BAD_CAST "token"))
2441 return(1);
2442 return(0);
2443}
2444
2445/**
2446 * xmlRelaxNGDefaultTypeCheck:
2447 * @data: data needed for the library
2448 * @type: the type name
2449 * @value: the value to check
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002450 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002451 *
2452 * Check if the given type and value are validated by
2453 * the default datatype library.
2454 *
2455 * Returns 1 if yes, 0 if no and -1 in case of error.
2456 */
2457static int
2458xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
2459 const xmlChar *type ATTRIBUTE_UNUSED,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002460 const xmlChar *value ATTRIBUTE_UNUSED,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00002461 void **result ATTRIBUTE_UNUSED,
2462 xmlNodePtr node ATTRIBUTE_UNUSED) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002463 if (value == NULL)
2464 return(-1);
2465 if (xmlStrEqual(type, BAD_CAST "string"))
2466 return(1);
2467 if (xmlStrEqual(type, BAD_CAST "token")) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002468 return(1);
2469 }
2470
2471 return(0);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002472}
2473
2474/**
2475 * xmlRelaxNGDefaultTypeCompare:
2476 * @data: data needed for the library
2477 * @type: the type name
2478 * @value1: the first value
2479 * @value2: the second value
2480 *
2481 * Compare two values accordingly a type from the default
2482 * datatype library.
2483 *
2484 * Returns 1 if yes, 0 if no and -1 in case of error.
2485 */
2486static int
2487xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002488 const xmlChar *type,
2489 const xmlChar *value1,
2490 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED,
2491 void *comp1 ATTRIBUTE_UNUSED,
2492 const xmlChar *value2,
2493 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00002494 int ret = -1;
2495
2496 if (xmlStrEqual(type, BAD_CAST "string")) {
2497 ret = xmlStrEqual(value1, value2);
2498 } else if (xmlStrEqual(type, BAD_CAST "token")) {
2499 if (!xmlStrEqual(value1, value2)) {
2500 xmlChar *nval, *nvalue;
2501
2502 /*
2503 * TODO: trivial optimizations are possible by
2504 * computing at compile-time
2505 */
2506 nval = xmlRelaxNGNormalize(NULL, value1);
2507 nvalue = xmlRelaxNGNormalize(NULL, value2);
2508
Daniel Veillardd4310742003-02-18 21:12:46 +00002509 if ((nval == NULL) || (nvalue == NULL))
Daniel Veillardea3f3982003-01-26 19:45:18 +00002510 ret = -1;
Daniel Veillardd4310742003-02-18 21:12:46 +00002511 else if (xmlStrEqual(nval, nvalue))
2512 ret = 1;
2513 else
2514 ret = 0;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002515 if (nval != NULL)
2516 xmlFree(nval);
2517 if (nvalue != NULL)
2518 xmlFree(nvalue);
Daniel Veillardd4310742003-02-18 21:12:46 +00002519 } else
2520 ret = 1;
Daniel Veillardea3f3982003-01-26 19:45:18 +00002521 }
2522 return(ret);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002523}
2524
2525static int xmlRelaxNGTypeInitialized = 0;
2526static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
2527
2528/**
2529 * xmlRelaxNGFreeTypeLibrary:
2530 * @lib: the type library structure
2531 * @namespace: the URI bound to the library
2532 *
2533 * Free the structure associated to the type library
2534 */
Daniel Veillard6eadf632003-01-23 18:29:16 +00002535static void
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002536xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
2537 const xmlChar *namespace ATTRIBUTE_UNUSED) {
2538 if (lib == NULL)
2539 return;
2540 if (lib->namespace != NULL)
2541 xmlFree((xmlChar *)lib->namespace);
2542 xmlFree(lib);
2543}
2544
2545/**
2546 * xmlRelaxNGRegisterTypeLibrary:
2547 * @namespace: the URI bound to the library
2548 * @data: data associated to the library
2549 * @have: the provide function
2550 * @check: the checking function
2551 * @comp: the comparison function
2552 *
2553 * Register a new type library
2554 *
2555 * Returns 0 in case of success and -1 in case of error.
2556 */
2557static int
2558xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
2559 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002560 xmlRelaxNGTypeCompare comp, xmlRelaxNGFacetCheck facet,
2561 xmlRelaxNGTypeFree freef) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002562 xmlRelaxNGTypeLibraryPtr lib;
2563 int ret;
2564
2565 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
2566 (check == NULL) || (comp == NULL))
2567 return(-1);
2568 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
2569 xmlGenericError(xmlGenericErrorContext,
2570 "Relax-NG types library '%s' already registered\n",
2571 namespace);
2572 return(-1);
2573 }
2574 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
2575 if (lib == NULL) {
2576 xmlGenericError(xmlGenericErrorContext,
2577 "Relax-NG types library '%s' malloc() failed\n",
2578 namespace);
2579 return (-1);
2580 }
2581 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
2582 lib->namespace = xmlStrdup(namespace);
2583 lib->data = data;
2584 lib->have = have;
2585 lib->comp = comp;
2586 lib->check = check;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002587 lib->facet = facet;
2588 lib->freef = freef;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002589 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
2590 if (ret < 0) {
2591 xmlGenericError(xmlGenericErrorContext,
2592 "Relax-NG types library failed to register '%s'\n",
2593 namespace);
2594 xmlRelaxNGFreeTypeLibrary(lib, namespace);
2595 return(-1);
2596 }
2597 return(0);
2598}
2599
2600/**
2601 * xmlRelaxNGInitTypes:
2602 *
2603 * Initilize the default type libraries.
2604 *
2605 * Returns 0 in case of success and -1 in case of error.
2606 */
2607static int
Daniel Veillard6eadf632003-01-23 18:29:16 +00002608xmlRelaxNGInitTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002609 if (xmlRelaxNGTypeInitialized != 0)
2610 return(0);
2611 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
2612 if (xmlRelaxNGRegisteredTypes == NULL) {
2613 xmlGenericError(xmlGenericErrorContext,
2614 "Failed to allocate sh table for Relax-NG types\n");
2615 return(-1);
2616 }
2617 xmlRelaxNGRegisterTypeLibrary(
2618 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
2619 NULL,
2620 xmlRelaxNGSchemaTypeHave,
2621 xmlRelaxNGSchemaTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002622 xmlRelaxNGSchemaTypeCompare,
2623 xmlRelaxNGSchemaFacetCheck,
Daniel Veillard80b19092003-03-28 13:29:53 +00002624 xmlRelaxNGSchemaFreeValue);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002625 xmlRelaxNGRegisterTypeLibrary(
2626 xmlRelaxNGNs,
2627 NULL,
2628 xmlRelaxNGDefaultTypeHave,
2629 xmlRelaxNGDefaultTypeCheck,
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00002630 xmlRelaxNGDefaultTypeCompare,
2631 NULL,
2632 NULL);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002633 xmlRelaxNGTypeInitialized = 1;
2634 return(0);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002635}
2636
2637/**
2638 * xmlRelaxNGCleanupTypes:
2639 *
2640 * Cleanup the default Schemas type library associated to RelaxNG
2641 */
2642void
2643xmlRelaxNGCleanupTypes(void) {
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002644 if (xmlRelaxNGTypeInitialized == 0)
2645 return;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002646 xmlSchemaCleanupTypes();
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002647 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
2648 xmlRelaxNGFreeTypeLibrary);
2649 xmlRelaxNGTypeInitialized = 0;
Daniel Veillard6eadf632003-01-23 18:29:16 +00002650}
2651
2652/************************************************************************
2653 * *
Daniel Veillard952379b2003-03-17 15:37:12 +00002654 * Compiling element content into regexp *
2655 * *
2656 * Sometime the element content can be compiled into a pure regexp, *
2657 * This allows a faster execution and streamability at that level *
2658 * *
2659 ************************************************************************/
2660
2661/**
2662 * xmlRelaxNGIsCompileable:
2663 * @define: the definition to check
2664 *
2665 * Check if a definition is nullable.
2666 *
2667 * Returns 1 if yes, 0 if no and -1 in case of error
2668 */
2669static int
2670xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def) {
2671 if (def == NULL) {
2672 return(-1);
2673 }
2674 switch(def->type) {
2675 case XML_RELAXNG_REF:
2676 case XML_RELAXNG_EXTERNALREF:
2677 case XML_RELAXNG_PARENTREF:
2678 case XML_RELAXNG_NOOP:
2679 case XML_RELAXNG_START:
2680 return(xmlRelaxNGIsCompileable(def->content));
2681 case XML_RELAXNG_TEXT:
2682 case XML_RELAXNG_DATATYPE:
2683 case XML_RELAXNG_LIST:
2684 case XML_RELAXNG_PARAM:
2685 case XML_RELAXNG_VALUE:
2686
2687 case XML_RELAXNG_EMPTY:
2688 case XML_RELAXNG_ELEMENT:
2689 return(1);
2690 case XML_RELAXNG_OPTIONAL:
2691 case XML_RELAXNG_ZEROORMORE:
2692 case XML_RELAXNG_ONEORMORE:
2693 case XML_RELAXNG_CHOICE:
2694 case XML_RELAXNG_GROUP:
2695 case XML_RELAXNG_DEF: {
2696 xmlRelaxNGDefinePtr list;
2697 int ret;
2698
2699 list = def->content;
2700 while (list != NULL) {
2701 ret = xmlRelaxNGIsCompileable(list);
2702 if (ret != 1)
2703 return(ret);
2704 list = list->next;
2705 }
2706 return(1);
2707 }
2708 case XML_RELAXNG_EXCEPT:
2709 case XML_RELAXNG_ATTRIBUTE:
2710 case XML_RELAXNG_INTERLEAVE:
2711 return(0);
2712 case XML_RELAXNG_NOT_ALLOWED:
2713 return(-1);
2714 }
2715 return(-1);
2716}
2717
2718/************************************************************************
2719 * *
Daniel Veillard6eadf632003-01-23 18:29:16 +00002720 * Parsing functions *
2721 * *
2722 ************************************************************************/
2723
2724static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
2725 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2726static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
2727 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
2728static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
Daniel Veillard154877e2003-01-30 12:17:05 +00002729 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00002730static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
2731 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00002732static xmlRelaxNGPtr xmlRelaxNGParseDocument(
2733 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00002734static int xmlRelaxNGParseGrammarContent(
2735 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00002736static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
2737 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
2738 xmlRelaxNGDefinePtr def);
Daniel Veillard419a7682003-02-03 23:22:49 +00002739static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
2740 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002741static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
2742 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002743
2744
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002745#define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
Daniel Veillard6eadf632003-01-23 18:29:16 +00002746
2747/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00002748 * xmlRelaxNGIsNullable:
2749 * @define: the definition to verify
2750 *
2751 * Check if a definition is nullable.
2752 *
2753 * Returns 1 if yes, 0 if no and -1 in case of error
2754 */
2755static int
2756xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define) {
2757 int ret;
2758 if (define == NULL)
2759 return(-1);
2760
Daniel Veillarde063f482003-03-21 16:53:17 +00002761 if (define->dflags & IS_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002762 return(1);
Daniel Veillarde063f482003-03-21 16:53:17 +00002763 if (define->dflags & IS_NOT_NULLABLE)
Daniel Veillardfd573f12003-03-16 17:52:32 +00002764 return(0);
2765 switch (define->type) {
2766 case XML_RELAXNG_EMPTY:
2767 case XML_RELAXNG_TEXT:
2768 ret = 1; break;
2769 case XML_RELAXNG_NOOP:
2770 case XML_RELAXNG_DEF:
2771 case XML_RELAXNG_REF:
2772 case XML_RELAXNG_EXTERNALREF:
2773 case XML_RELAXNG_PARENTREF:
2774 case XML_RELAXNG_ONEORMORE:
2775 ret = xmlRelaxNGIsNullable(define->content);
2776 break;
2777 case XML_RELAXNG_EXCEPT:
2778 case XML_RELAXNG_NOT_ALLOWED:
2779 case XML_RELAXNG_ELEMENT:
2780 case XML_RELAXNG_DATATYPE:
2781 case XML_RELAXNG_PARAM:
2782 case XML_RELAXNG_VALUE:
2783 case XML_RELAXNG_LIST:
2784 case XML_RELAXNG_ATTRIBUTE:
2785 ret = 0; break;
2786 case XML_RELAXNG_CHOICE: {
2787 xmlRelaxNGDefinePtr list = define->content;
2788
2789 while (list != NULL) {
2790 ret = xmlRelaxNGIsNullable(list);
2791 if (ret != 0)
2792 goto done;
2793 list = list->next;
2794 }
2795 ret = 0; break;
2796 }
2797 case XML_RELAXNG_START:
2798 case XML_RELAXNG_INTERLEAVE:
2799 case XML_RELAXNG_GROUP: {
2800 xmlRelaxNGDefinePtr list = define->content;
2801
2802 while (list != NULL) {
2803 ret = xmlRelaxNGIsNullable(list);
2804 if (ret != 1)
2805 goto done;
2806 list = list->next;
2807 }
2808 return(1);
2809 }
2810 default:
2811 return(-1);
2812 }
2813done:
2814 if (ret == 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00002815 define->dflags |= IS_NOT_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002816 if (ret == 1)
Daniel Veillarde063f482003-03-21 16:53:17 +00002817 define->dflags |= IS_NULLABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00002818 return(ret);
2819}
2820
2821/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00002822 * xmlRelaxNGIsBlank:
2823 * @str: a string
2824 *
2825 * Check if a string is ignorable c.f. 4.2. Whitespace
2826 *
2827 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
2828 */
2829static int
2830xmlRelaxNGIsBlank(xmlChar *str) {
2831 if (str == NULL)
2832 return(1);
2833 while (*str != 0) {
2834 if (!(IS_BLANK(*str))) return(0);
2835 str++;
2836 }
2837 return(1);
2838}
2839
Daniel Veillard6eadf632003-01-23 18:29:16 +00002840/**
2841 * xmlRelaxNGGetDataTypeLibrary:
2842 * @ctxt: a Relax-NG parser context
2843 * @node: the current data or value element
2844 *
2845 * Applies algorithm from 4.3. datatypeLibrary attribute
2846 *
2847 * Returns the datatypeLibary value or NULL if not found
2848 */
2849static xmlChar *
2850xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2851 xmlNodePtr node) {
2852 xmlChar *ret, *escape;
2853
Daniel Veillard6eadf632003-01-23 18:29:16 +00002854 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
2855 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2856 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002857 if (ret[0] == 0) {
2858 xmlFree(ret);
2859 return(NULL);
2860 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002861 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
Daniel Veillard6eadf632003-01-23 18:29:16 +00002862 if (escape == NULL) {
2863 return(ret);
2864 }
2865 xmlFree(ret);
2866 return(escape);
2867 }
2868 }
2869 node = node->parent;
2870 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002871 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
2872 if (ret != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002873 if (ret[0] == 0) {
2874 xmlFree(ret);
2875 return(NULL);
2876 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002877 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
2878 if (escape == NULL) {
2879 return(ret);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002880 }
Daniel Veillarde5b110b2003-02-04 14:43:39 +00002881 xmlFree(ret);
2882 return(escape);
Daniel Veillard6eadf632003-01-23 18:29:16 +00002883 }
2884 node = node->parent;
2885 }
2886 return(NULL);
2887}
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002888
2889/**
Daniel Veillardedc91922003-01-26 00:52:04 +00002890 * xmlRelaxNGParseValue:
2891 * @ctxt: a Relax-NG parser context
2892 * @node: the data node.
2893 *
2894 * parse the content of a RelaxNG value node.
2895 *
2896 * Returns the definition pointer or NULL in case of error
2897 */
2898static xmlRelaxNGDefinePtr
2899xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2900 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillard5f1946a2003-03-31 16:38:16 +00002901 xmlRelaxNGTypeLibraryPtr lib = NULL;
Daniel Veillardedc91922003-01-26 00:52:04 +00002902 xmlChar *type;
2903 xmlChar *library;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002904 int success = 0;
Daniel Veillardedc91922003-01-26 00:52:04 +00002905
Daniel Veillardfd573f12003-03-16 17:52:32 +00002906 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00002907 if (def == NULL)
2908 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00002909 def->type = XML_RELAXNG_VALUE;
Daniel Veillardedc91922003-01-26 00:52:04 +00002910
2911 type = xmlGetProp(node, BAD_CAST "type");
2912 if (type != NULL) {
Daniel Veillardd2298792003-02-14 16:54:11 +00002913 xmlRelaxNGNormExtSpace(type);
2914 if (xmlValidateNCName(type, 0)) {
2915 if (ctxt->error != NULL)
2916 ctxt->error(ctxt->userData,
2917 "value type '%s' is not an NCName\n",
2918 type);
2919 ctxt->nbErrors++;
2920 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002921 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
2922 if (library == NULL)
2923 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
2924
2925 def->name = type;
2926 def->ns = library;
2927
2928 lib = (xmlRelaxNGTypeLibraryPtr)
2929 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
2930 if (lib == NULL) {
2931 if (ctxt->error != NULL)
2932 ctxt->error(ctxt->userData,
2933 "Use of unregistered type library '%s'\n",
2934 library);
2935 ctxt->nbErrors++;
2936 def->data = NULL;
2937 } else {
2938 def->data = lib;
2939 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002940 if (ctxt->error != NULL)
2941 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002942 "Internal error with type library '%s': no 'have'\n",
2943 library);
2944 ctxt->nbErrors++;
2945 } else {
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002946 success = lib->have(lib->data, def->name);
2947 if (success != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002948 if (ctxt->error != NULL)
2949 ctxt->error(ctxt->userData,
Daniel Veillardedc91922003-01-26 00:52:04 +00002950 "Error type '%s' is not exported by type library '%s'\n",
2951 def->name, library);
2952 ctxt->nbErrors++;
2953 }
2954 }
2955 }
2956 }
2957 if (node->children == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00002958 def->value = xmlStrdup(BAD_CAST "");
Daniel Veillard39eb88b2003-03-11 11:21:28 +00002959 } else if (((node->children->type != XML_TEXT_NODE) &&
2960 (node->children->type != XML_CDATA_SECTION_NODE)) ||
Daniel Veillardedc91922003-01-26 00:52:04 +00002961 (node->children->next != NULL)) {
2962 if (ctxt->error != NULL)
2963 ctxt->error(ctxt->userData,
2964 "Expecting a single text value for <value>content\n");
2965 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002966 } else if (def != NULL) {
Daniel Veillardedc91922003-01-26 00:52:04 +00002967 def->value = xmlNodeGetContent(node);
2968 if (def->value == NULL) {
2969 if (ctxt->error != NULL)
2970 ctxt->error(ctxt->userData,
2971 "Element <value> has no content\n");
2972 ctxt->nbErrors++;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00002973 } else if ((lib != NULL) && (lib->check != NULL) && (success == 1)) {
2974 void *val = NULL;
2975
2976 success = lib->check(lib->data, def->name, def->value, &val, node);
2977 if (success != 1) {
2978 if (ctxt->error != NULL)
2979 ctxt->error(ctxt->userData,
2980 "Value '%s' is not acceptable for type '%s'\n",
2981 def->value, def->name);
2982 ctxt->nbErrors++;
2983 } else {
2984 if (val != NULL)
2985 def->attrs = val;
2986 }
Daniel Veillardedc91922003-01-26 00:52:04 +00002987 }
2988 }
2989 /* TODO check ahead of time that the value is okay per the type */
2990 return(def);
2991}
2992
2993/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00002994 * xmlRelaxNGParseData:
2995 * @ctxt: a Relax-NG parser context
2996 * @node: the data node.
2997 *
2998 * parse the content of a RelaxNG data node.
2999 *
3000 * Returns the definition pointer or NULL in case of error
3001 */
3002static xmlRelaxNGDefinePtr
3003xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003004 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003005 xmlRelaxNGDefinePtr param, lastparam = NULL;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003006 xmlRelaxNGTypeLibraryPtr lib;
3007 xmlChar *type;
3008 xmlChar *library;
3009 xmlNodePtr content;
3010 int tmp;
3011
3012 type = xmlGetProp(node, BAD_CAST "type");
3013 if (type == NULL) {
3014 if (ctxt->error != NULL)
3015 ctxt->error(ctxt->userData,
3016 "data has no type\n");
3017 ctxt->nbErrors++;
3018 return(NULL);
3019 }
Daniel Veillardd2298792003-02-14 16:54:11 +00003020 xmlRelaxNGNormExtSpace(type);
3021 if (xmlValidateNCName(type, 0)) {
3022 if (ctxt->error != NULL)
3023 ctxt->error(ctxt->userData,
3024 "data type '%s' is not an NCName\n",
3025 type);
3026 ctxt->nbErrors++;
3027 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003028 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
3029 if (library == NULL)
3030 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
3031
Daniel Veillardfd573f12003-03-16 17:52:32 +00003032 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003033 if (def == NULL) {
3034 xmlFree(type);
3035 return(NULL);
3036 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003037 def->type = XML_RELAXNG_DATATYPE;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003038 def->name = type;
3039 def->ns = library;
3040
3041 lib = (xmlRelaxNGTypeLibraryPtr)
3042 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
3043 if (lib == NULL) {
3044 if (ctxt->error != NULL)
3045 ctxt->error(ctxt->userData,
3046 "Use of unregistered type library '%s'\n",
3047 library);
3048 ctxt->nbErrors++;
3049 def->data = NULL;
3050 } else {
3051 def->data = lib;
3052 if (lib->have == NULL) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003053 if (ctxt->error != NULL)
3054 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003055 "Internal error with type library '%s': no 'have'\n",
3056 library);
3057 ctxt->nbErrors++;
3058 } else {
3059 tmp = lib->have(lib->data, def->name);
3060 if (tmp != 1) {
Daniel Veillard1703c5f2003-02-10 14:28:44 +00003061 if (ctxt->error != NULL)
3062 ctxt->error(ctxt->userData,
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003063 "Error type '%s' is not exported by type library '%s'\n",
3064 def->name, library);
3065 ctxt->nbErrors++;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00003066 } else if ((xmlStrEqual(library, BAD_CAST
3067 "http://www.w3.org/2001/XMLSchema-datatypes")) &&
3068 ((xmlStrEqual(def->name, BAD_CAST "IDREF")) ||
3069 (xmlStrEqual(def->name, BAD_CAST "IDREFS")))) {
3070 ctxt->idref = 1;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003071 }
3072 }
3073 }
3074 content = node->children;
Daniel Veillard416589a2003-02-17 17:25:42 +00003075
3076 /*
3077 * Handle optional params
3078 */
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003079 while (content != NULL) {
Daniel Veillard416589a2003-02-17 17:25:42 +00003080 if (!xmlStrEqual(content->name, BAD_CAST "param"))
3081 break;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003082 if (xmlStrEqual(library,
3083 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
3084 if (ctxt->error != NULL)
3085 ctxt->error(ctxt->userData,
3086 "Type library '%s' does not allow type parameters\n",
3087 library);
3088 ctxt->nbErrors++;
3089 content = content->next;
3090 while ((content != NULL) &&
3091 (xmlStrEqual(content->name, BAD_CAST "param")))
3092 content = content->next;
3093 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003094 param = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003095 if (param != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003096 param->type = XML_RELAXNG_PARAM;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003097 param->name = xmlGetProp(content, BAD_CAST "name");
3098 if (param->name == NULL) {
3099 if (ctxt->error != NULL)
3100 ctxt->error(ctxt->userData,
3101 "param has no name\n");
3102 ctxt->nbErrors++;
3103 }
3104 param->value = xmlNodeGetContent(content);
3105 if (lastparam == NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003106 def->attrs = lastparam = param;
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003107 } else {
3108 lastparam->next = param;
3109 lastparam = param;
3110 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00003111 if (lib != NULL) {
3112 }
Daniel Veillard8fe98712003-02-19 00:19:14 +00003113 }
Daniel Veillard4c5cf702003-02-21 15:40:34 +00003114 content = content->next;
Daniel Veillard8fe98712003-02-19 00:19:14 +00003115 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003116 }
Daniel Veillard416589a2003-02-17 17:25:42 +00003117 /*
3118 * Handle optional except
3119 */
3120 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
3121 xmlNodePtr child;
3122 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
3123
Daniel Veillardfd573f12003-03-16 17:52:32 +00003124 except = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard416589a2003-02-17 17:25:42 +00003125 if (except == NULL) {
3126 return(def);
3127 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003128 except->type = XML_RELAXNG_EXCEPT;
Daniel Veillard416589a2003-02-17 17:25:42 +00003129 child = content->children;
3130 if (last == NULL) {
3131 def->content = except;
3132 } else {
3133 last->next = except;
3134 }
3135 if (child == NULL) {
3136 if (ctxt->error != NULL)
3137 ctxt->error(ctxt->userData,
3138 "except has no content\n");
3139 ctxt->nbErrors++;
3140 }
3141 while (child != NULL) {
3142 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
3143 if (tmp2 != NULL) {
3144 if (last2 == NULL) {
3145 except->content = last2 = tmp2;
3146 } else {
3147 last2->next = tmp2;
3148 last2 = tmp2;
3149 }
3150 }
3151 child = child->next;
3152 }
3153 content = content->next;
3154 }
3155 /*
3156 * Check there is no unhandled data
3157 */
3158 if (content != NULL) {
3159 if (ctxt->error != NULL)
3160 ctxt->error(ctxt->userData,
3161 "Element data has unexpected content %s\n", content->name);
3162 ctxt->nbErrors++;
3163 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00003164
3165 return(def);
3166}
3167
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003168static const xmlChar *invalidName = BAD_CAST "\1";
3169
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003170/**
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003171 * xmlRelaxNGCompareNameClasses:
3172 * @defs1: the first element/attribute defs
3173 * @defs2: the second element/attribute defs
3174 * @name: the restriction on the name
3175 * @ns: the restriction on the namespace
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003176 *
3177 * Compare the 2 lists of element definitions. The comparison is
3178 * that if both lists do not accept the same QNames, it returns 1
3179 * If the 2 lists can accept the same QName the comparison returns 0
3180 *
3181 * Returns 1 disttinct, 0 if equal
3182 */
3183static int
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003184xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
3185 xmlRelaxNGDefinePtr def2) {
3186 int ret = 1;
3187 xmlNode node;
3188 xmlNs ns;
3189 xmlRelaxNGValidCtxt ctxt;
3190 ctxt.flags = FLAGS_IGNORABLE;
3191
Daniel Veillard42f12e92003-03-07 18:32:59 +00003192 memset(&ctxt, 0, sizeof(xmlRelaxNGValidCtxt));
3193
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003194 if ((def1->type == XML_RELAXNG_ELEMENT) ||
3195 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
3196 if (def2->type == XML_RELAXNG_TEXT)
3197 return(1);
3198 if (def1->name != NULL) {
3199 node.name = def1->name;
3200 } else {
3201 node.name = invalidName;
3202 }
3203 node.ns = &ns;
3204 if (def1->ns != NULL) {
3205 if (def1->ns[0] == 0) {
3206 node.ns = NULL;
3207 } else {
3208 ns.href = def1->ns;
3209 }
3210 } else {
3211 ns.href = invalidName;
3212 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003213 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003214 if (def1->nameClass != NULL) {
3215 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
3216 } else {
3217 ret = 0;
3218 }
3219 } else {
3220 ret = 1;
3221 }
3222 } else if (def1->type == XML_RELAXNG_TEXT) {
3223 if (def2->type == XML_RELAXNG_TEXT)
3224 return(0);
3225 return(1);
3226 } else if (def1->type == XML_RELAXNG_EXCEPT) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003227 TODO
3228 ret = 0;
3229 } else {
3230 TODO
3231 ret = 0;
3232 }
3233 if (ret == 0)
3234 return(ret);
3235 if ((def2->type == XML_RELAXNG_ELEMENT) ||
3236 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
3237 if (def2->name != NULL) {
3238 node.name = def2->name;
3239 } else {
3240 node.name = invalidName;
3241 }
3242 node.ns = &ns;
3243 if (def2->ns != NULL) {
3244 if (def2->ns[0] == 0) {
3245 node.ns = NULL;
3246 } else {
3247 ns.href = def2->ns;
3248 }
3249 } else {
3250 ns.href = invalidName;
3251 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003252 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003253 if (def2->nameClass != NULL) {
3254 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
3255 } else {
3256 ret = 0;
3257 }
3258 } else {
3259 ret = 1;
3260 }
3261 } else {
3262 TODO
3263 ret = 0;
3264 }
3265
3266 return(ret);
3267}
3268
3269/**
3270 * xmlRelaxNGCompareElemDefLists:
3271 * @ctxt: a Relax-NG parser context
3272 * @defs1: the first list of element/attribute defs
3273 * @defs2: the second list of element/attribute defs
3274 *
3275 * Compare the 2 lists of element or attribute definitions. The comparison
3276 * is that if both lists do not accept the same QNames, it returns 1
3277 * If the 2 lists can accept the same QName the comparison returns 0
3278 *
3279 * Returns 1 disttinct, 0 if equal
3280 */
3281static int
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003282xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
3283 xmlRelaxNGDefinePtr *def1,
3284 xmlRelaxNGDefinePtr *def2) {
3285 xmlRelaxNGDefinePtr *basedef2 = def2;
3286
Daniel Veillard154877e2003-01-30 12:17:05 +00003287 if ((def1 == NULL) || (def2 == NULL))
3288 return(1);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003289 if ((*def1 == NULL) || (*def2 == NULL))
3290 return(1);
3291 while (*def1 != NULL) {
3292 while ((*def2) != NULL) {
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00003293 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
3294 return(0);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003295 def2++;
3296 }
3297 def2 = basedef2;
3298 def1++;
3299 }
3300 return(1);
3301}
3302
3303/**
3304 * xmlRelaxNGGetElements:
3305 * @ctxt: a Relax-NG parser context
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003306 * @def: the definition definition
3307 * @eora: gather elements (0) or attributes (1)
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003308 *
3309 * Compute the list of top elements a definition can generate
3310 *
3311 * Returns a list of elements or NULL if none was found.
3312 */
3313static xmlRelaxNGDefinePtr *
3314xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003315 xmlRelaxNGDefinePtr def,
3316 int eora) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003317 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003318 int len = 0;
3319 int max = 0;
3320
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003321 /*
3322 * Don't run that check in case of error. Infinite recursion
3323 * becomes possible.
3324 */
3325 if (ctxt->nbErrors != 0)
3326 return(NULL);
3327
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003328 parent = NULL;
3329 cur = def;
3330 while (cur != NULL) {
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003331 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
3332 (cur->type == XML_RELAXNG_TEXT))) ||
3333 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003334 if (ret == NULL) {
3335 max = 10;
3336 ret = (xmlRelaxNGDefinePtr *)
3337 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
3338 if (ret == NULL) {
3339 if (ctxt->error != NULL)
3340 ctxt->error(ctxt->userData,
3341 "Out of memory in element search\n");
3342 ctxt->nbErrors++;
3343 return(NULL);
3344 }
3345 } else if (max <= len) {
3346 max *= 2;
3347 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
3348 if (ret == NULL) {
3349 if (ctxt->error != NULL)
3350 ctxt->error(ctxt->userData,
3351 "Out of memory in element search\n");
3352 ctxt->nbErrors++;
3353 return(NULL);
3354 }
3355 }
Daniel Veillardb08c9812003-01-28 23:09:49 +00003356 ret[len++] = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003357 ret[len] = NULL;
3358 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
3359 (cur->type == XML_RELAXNG_INTERLEAVE) ||
3360 (cur->type == XML_RELAXNG_GROUP) ||
3361 (cur->type == XML_RELAXNG_ONEORMORE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00003362 (cur->type == XML_RELAXNG_ZEROORMORE) ||
3363 (cur->type == XML_RELAXNG_OPTIONAL) ||
Daniel Veillard952379b2003-03-17 15:37:12 +00003364 (cur->type == XML_RELAXNG_PARENTREF) ||
Daniel Veillardb08c9812003-01-28 23:09:49 +00003365 (cur->type == XML_RELAXNG_REF) ||
3366 (cur->type == XML_RELAXNG_DEF)) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003367 /*
3368 * Don't go within elements or attributes or string values.
3369 * Just gather the element top list
3370 */
3371 if (cur->content != NULL) {
3372 parent = cur;
3373 cur = cur->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003374 tmp = cur;
3375 while (tmp != NULL) {
3376 tmp->parent = parent;
3377 tmp = tmp->next;
3378 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003379 continue;
3380 }
3381 }
Daniel Veillard154877e2003-01-30 12:17:05 +00003382 if (cur == def)
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003383 break;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003384 if (cur->next != NULL) {
3385 cur = cur->next;
3386 continue;
3387 }
3388 do {
3389 cur = cur->parent;
3390 if (cur == NULL) break;
3391 if (cur == def) return(ret);
3392 if (cur->next != NULL) {
3393 cur = cur->next;
3394 break;
3395 }
3396 } while (cur != NULL);
3397 }
3398 return(ret);
3399}
3400
3401/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003402 * xmlRelaxNGCheckChoiceDeterminism:
3403 * @ctxt: a Relax-NG parser context
3404 * @def: the choice definition
3405 *
3406 * Also used to find indeterministic pattern in choice
3407 */
3408static void
3409xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt,
3410 xmlRelaxNGDefinePtr def) {
3411 xmlRelaxNGDefinePtr **list;
3412 xmlRelaxNGDefinePtr cur;
3413 int nbchild = 0, i, j, ret;
3414 int is_nullable = 0;
3415 int is_indeterminist = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003416 xmlHashTablePtr triage = NULL;
3417 int is_triable = 1;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003418
3419 if ((def == NULL) ||
3420 (def->type != XML_RELAXNG_CHOICE))
3421 return;
3422
Daniel Veillarde063f482003-03-21 16:53:17 +00003423 if (def->dflags & IS_PROCESSED)
3424 return;
3425
Daniel Veillardfd573f12003-03-16 17:52:32 +00003426 /*
3427 * Don't run that check in case of error. Infinite recursion
3428 * becomes possible.
3429 */
3430 if (ctxt->nbErrors != 0)
3431 return;
3432
3433 is_nullable = xmlRelaxNGIsNullable(def);
3434
3435 cur = def->content;
3436 while (cur != NULL) {
3437 nbchild++;
3438 cur = cur->next;
3439 }
3440
3441 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3442 sizeof(xmlRelaxNGDefinePtr *));
3443 if (list == NULL) {
3444 if (ctxt->error != NULL)
3445 ctxt->error(ctxt->userData,
3446 "Out of memory in choice computation\n");
3447 ctxt->nbErrors++;
3448 return;
3449 }
3450 i = 0;
Daniel Veillarde063f482003-03-21 16:53:17 +00003451 /*
3452 * a bit strong but safe
3453 */
3454 if (is_nullable == 0) {
3455 triage = xmlHashCreate(10);
3456 } else {
3457 is_triable = 0;
3458 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003459 cur = def->content;
3460 while (cur != NULL) {
3461 list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
Daniel Veillarde063f482003-03-21 16:53:17 +00003462 if ((list[i] == NULL) || (list[i][0] == NULL)) {
3463 is_triable = 0;
3464 } else if (is_triable == 1) {
3465 xmlRelaxNGDefinePtr *tmp;
3466 int res;
3467
3468 tmp = list[i];
3469 while ((*tmp != NULL) && (is_triable == 1)) {
3470 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3471 res = xmlHashAddEntry2(triage,
3472 BAD_CAST "#text", NULL,
3473 (void *)cur);
3474 if (res != 0)
3475 is_triable = -1;
3476 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3477 ((*tmp)->name != NULL)) {
3478 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3479 res = xmlHashAddEntry2(triage,
3480 (*tmp)->name, NULL,
3481 (void *)cur);
3482 else
3483 res = xmlHashAddEntry2(triage,
3484 (*tmp)->name, (*tmp)->ns,
3485 (void *)cur);
3486 if (res != 0)
3487 is_triable = -1;
3488 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3489 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3490 res = xmlHashAddEntry2(triage,
3491 BAD_CAST "#any", NULL,
3492 (void *)cur);
3493 else
3494 res = xmlHashAddEntry2(triage,
3495 BAD_CAST "#any", (*tmp)->ns,
3496 (void *)cur);
3497 if (res != 0)
3498 is_triable = -1;
3499 } else {
3500 is_triable = -1;
3501 }
3502 tmp++;
3503 }
3504 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003505 i++;
3506 cur = cur->next;
3507 }
3508
3509 for (i = 0;i < nbchild;i++) {
3510 if (list[i] == NULL)
3511 continue;
3512 for (j = 0;j < i;j++) {
3513 if (list[j] == NULL)
3514 continue;
3515 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3516 if (ret == 0) {
3517 is_indeterminist = 1;
3518 }
3519 }
3520 }
3521 for (i = 0;i < nbchild;i++) {
3522 if (list[i] != NULL)
3523 xmlFree(list[i]);
3524 }
3525
3526 xmlFree(list);
3527 if (is_indeterminist) {
Daniel Veillarde063f482003-03-21 16:53:17 +00003528 def->dflags |= IS_INDETERMINIST;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003529 }
Daniel Veillarde063f482003-03-21 16:53:17 +00003530 if (is_triable == 1) {
3531 def->dflags |= IS_TRIABLE;
3532 def->data = triage;
3533 } else if (triage != NULL) {
3534 xmlHashFree(triage, NULL);
3535 }
3536 def->dflags |= IS_PROCESSED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003537}
3538
3539/**
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003540 * xmlRelaxNGCheckGroupAttrs:
3541 * @ctxt: a Relax-NG parser context
3542 * @def: the group definition
3543 *
3544 * Detects violations of rule 7.3
3545 */
3546static void
3547xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
3548 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00003549 xmlRelaxNGDefinePtr **list;
3550 xmlRelaxNGDefinePtr cur;
3551 int nbchild = 0, i, j, ret;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003552
3553 if ((def == NULL) ||
3554 ((def->type != XML_RELAXNG_GROUP) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00003555 (def->type != XML_RELAXNG_ELEMENT)))
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003556 return;
3557
Daniel Veillarde063f482003-03-21 16:53:17 +00003558 if (def->dflags & IS_PROCESSED)
3559 return;
3560
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003561 /*
3562 * Don't run that check in case of error. Infinite recursion
3563 * becomes possible.
3564 */
3565 if (ctxt->nbErrors != 0)
3566 return;
3567
Daniel Veillardfd573f12003-03-16 17:52:32 +00003568 cur = def->attrs;
3569 while (cur != NULL) {
3570 nbchild++;
3571 cur = cur->next;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003572 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003573 cur = def->content;
3574 while (cur != NULL) {
3575 nbchild++;
3576 cur = cur->next;
3577 }
3578
3579 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
3580 sizeof(xmlRelaxNGDefinePtr *));
3581 if (list == NULL) {
3582 if (ctxt->error != NULL)
3583 ctxt->error(ctxt->userData,
3584 "Out of memory in group computation\n");
3585 ctxt->nbErrors++;
3586 return;
3587 }
3588 i = 0;
3589 cur = def->attrs;
3590 while (cur != NULL) {
3591 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3592 i++;
3593 cur = cur->next;
3594 }
3595 cur = def->content;
3596 while (cur != NULL) {
3597 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
3598 i++;
3599 cur = cur->next;
3600 }
3601
3602 for (i = 0;i < nbchild;i++) {
3603 if (list[i] == NULL)
3604 continue;
3605 for (j = 0;j < i;j++) {
3606 if (list[j] == NULL)
3607 continue;
3608 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
3609 if (ret == 0) {
3610 if (ctxt->error != NULL)
3611 ctxt->error(ctxt->userData,
3612 "Attributes conflicts in group\n");
3613 ctxt->nbErrors++;
3614 }
3615 }
3616 }
3617 for (i = 0;i < nbchild;i++) {
3618 if (list[i] != NULL)
3619 xmlFree(list[i]);
3620 }
3621
3622 xmlFree(list);
Daniel Veillarde063f482003-03-21 16:53:17 +00003623 def->dflags |= IS_PROCESSED;
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003624}
3625
3626/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00003627 * xmlRelaxNGComputeInterleaves:
3628 * @def: the interleave definition
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003629 * @ctxt: a Relax-NG parser context
Daniel Veillardfd573f12003-03-16 17:52:32 +00003630 * @name: the definition name
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003631 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00003632 * A lot of work for preprocessing interleave definitions
3633 * is potentially needed to get a decent execution speed at runtime
3634 * - trying to get a total order on the element nodes generated
3635 * by the interleaves, order the list of interleave definitions
3636 * following that order.
3637 * - if <text/> is used to handle mixed content, it is better to
3638 * flag this in the define and simplify the runtime checking
3639 * algorithm
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003640 */
3641static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00003642xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
3643 xmlRelaxNGParserCtxtPtr ctxt,
3644 xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003645 xmlRelaxNGDefinePtr cur, *tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003646
Daniel Veillardfd573f12003-03-16 17:52:32 +00003647 xmlRelaxNGPartitionPtr partitions = NULL;
3648 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
3649 xmlRelaxNGInterleaveGroupPtr group;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003650 int i,j,ret, res;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003651 int nbgroups = 0;
3652 int nbchild = 0;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003653 int is_mixed = 0;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003654 int is_determinist = 1;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003655
Daniel Veillard44e1dd02003-02-21 23:23:28 +00003656 /*
3657 * Don't run that check in case of error. Infinite recursion
3658 * becomes possible.
3659 */
3660 if (ctxt->nbErrors != 0)
3661 return;
3662
Daniel Veillardfd573f12003-03-16 17:52:32 +00003663#ifdef DEBUG_INTERLEAVE
3664 xmlGenericError(xmlGenericErrorContext,
3665 "xmlRelaxNGComputeInterleaves(%s)\n",
3666 name);
3667#endif
3668 cur = def->content;
3669 while (cur != NULL) {
3670 nbchild++;
3671 cur = cur->next;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003672 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003673
3674#ifdef DEBUG_INTERLEAVE
3675 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
3676#endif
3677 groups = (xmlRelaxNGInterleaveGroupPtr *)
3678 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
3679 if (groups == NULL)
3680 goto error;
3681 cur = def->content;
3682 while (cur != NULL) {
3683 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
3684 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
3685 if (groups[nbgroups] == NULL)
3686 goto error;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003687 if (cur->type == XML_RELAXNG_TEXT)
3688 is_mixed++;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003689 groups[nbgroups]->rule = cur;
3690 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
3691 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
3692 nbgroups++;
3693 cur = cur->next;
3694 }
3695#ifdef DEBUG_INTERLEAVE
3696 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
3697#endif
3698
3699 /*
3700 * Let's check that all rules makes a partitions according to 7.4
3701 */
3702 partitions = (xmlRelaxNGPartitionPtr)
3703 xmlMalloc(sizeof(xmlRelaxNGPartition));
3704 if (partitions == NULL)
3705 goto error;
Daniel Veillard20863822003-03-22 17:51:47 +00003706 memset(partitions, 0, sizeof(xmlRelaxNGPartition));
Daniel Veillardfd573f12003-03-16 17:52:32 +00003707 partitions->nbgroups = nbgroups;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003708 partitions->triage = xmlHashCreate(nbgroups);
Daniel Veillardfd573f12003-03-16 17:52:32 +00003709 for (i = 0;i < nbgroups;i++) {
3710 group = groups[i];
3711 for (j = i+1;j < nbgroups;j++) {
3712 if (groups[j] == NULL)
3713 continue;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003714
Daniel Veillardfd573f12003-03-16 17:52:32 +00003715 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
3716 groups[j]->defs);
3717 if (ret == 0) {
3718 if (ctxt->error != NULL)
3719 ctxt->error(ctxt->userData,
3720 "Element or text conflicts in interleave\n");
3721 ctxt->nbErrors++;
3722 }
3723 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
3724 groups[j]->attrs);
3725 if (ret == 0) {
3726 if (ctxt->error != NULL)
3727 ctxt->error(ctxt->userData,
3728 "Attributes conflicts in interleave\n");
3729 ctxt->nbErrors++;
3730 }
3731 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003732 tmp = group->defs;
3733 if ((tmp != NULL) && (*tmp != NULL)) {
3734 while (*tmp != NULL) {
3735 if ((*tmp)->type == XML_RELAXNG_TEXT) {
3736 res = xmlHashAddEntry2(partitions->triage,
3737 BAD_CAST "#text", NULL,
3738 (void *)(i + 1));
3739 if (res != 0)
3740 is_determinist = -1;
3741 } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
3742 ((*tmp)->name != NULL)) {
3743 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3744 res = xmlHashAddEntry2(partitions->triage,
3745 (*tmp)->name, NULL,
3746 (void *)(i + 1));
3747 else
3748 res = xmlHashAddEntry2(partitions->triage,
3749 (*tmp)->name, (*tmp)->ns,
3750 (void *)(i + 1));
3751 if (res != 0)
3752 is_determinist = -1;
3753 } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
3754 if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
3755 res = xmlHashAddEntry2(partitions->triage,
3756 BAD_CAST "#any", NULL,
3757 (void *)(i + 1));
3758 else
3759 res = xmlHashAddEntry2(partitions->triage,
3760 BAD_CAST "#any", (*tmp)->ns,
3761 (void *)(i + 1));
3762 if ((*tmp)->nameClass != NULL)
3763 is_determinist = 2;
3764 if (res != 0)
3765 is_determinist = -1;
3766 } else {
3767 is_determinist = -1;
3768 }
3769 tmp++;
3770 }
3771 } else {
3772 is_determinist = 0;
3773 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003774 }
3775 partitions->groups = groups;
3776
3777 /*
3778 * and save the partition list back in the def
3779 */
3780 def->data = partitions;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00003781 if (is_mixed != 0)
Daniel Veillarde063f482003-03-21 16:53:17 +00003782 def->dflags |= IS_MIXED;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00003783 if (is_determinist == 1)
3784 partitions->flags = IS_DETERMINIST;
3785 if (is_determinist == 2)
3786 partitions->flags = IS_DETERMINIST | IS_NEEDCHECK;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003787 return;
3788
3789error:
3790 if (ctxt->error != NULL)
3791 ctxt->error(ctxt->userData,
3792 "Out of memory in interleave computation\n");
3793 ctxt->nbErrors++;
3794 if (groups != NULL) {
3795 for (i = 0;i < nbgroups;i++)
3796 if (groups[i] != NULL) {
3797 if (groups[i]->defs != NULL)
3798 xmlFree(groups[i]->defs);
3799 xmlFree(groups[i]);
3800 }
3801 xmlFree(groups);
3802 }
3803 xmlRelaxNGFreePartition(partitions);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003804}
3805
3806/**
3807 * xmlRelaxNGParseInterleave:
3808 * @ctxt: a Relax-NG parser context
3809 * @node: the data node.
3810 *
3811 * parse the content of a RelaxNG interleave node.
3812 *
3813 * Returns the definition pointer or NULL in case of error
3814 */
3815static xmlRelaxNGDefinePtr
3816xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3817 xmlRelaxNGDefinePtr def = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00003818 xmlRelaxNGDefinePtr last = NULL, cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003819 xmlNodePtr child;
3820
Daniel Veillardfd573f12003-03-16 17:52:32 +00003821 def = xmlRelaxNGNewDefine(ctxt, node);
3822 if (def == NULL) {
3823 return(NULL);
3824 }
3825 def->type = XML_RELAXNG_INTERLEAVE;
3826
3827 if (ctxt->interleaves == NULL)
3828 ctxt->interleaves = xmlHashCreate(10);
3829 if (ctxt->interleaves == NULL) {
3830 if (ctxt->error != NULL)
3831 ctxt->error(ctxt->userData,
3832 "Failed to create interleaves hash table\n");
3833 ctxt->nbErrors++;
3834 } else {
3835 char name[32];
3836
3837 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
3838 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
3839 if (ctxt->error != NULL)
3840 ctxt->error(ctxt->userData,
3841 "Failed to add %s to hash table\n", name);
3842 ctxt->nbErrors++;
3843 }
3844 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003845 child = node->children;
Daniel Veillardd2298792003-02-14 16:54:11 +00003846 if (child == NULL) {
3847 if (ctxt->error != NULL)
3848 ctxt->error(ctxt->userData, "Element interleave is empty\n");
3849 ctxt->nbErrors++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00003850 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003851 while (child != NULL) {
3852 if (IS_RELAXNG(child, "element")) {
3853 cur = xmlRelaxNGParseElement(ctxt, child);
3854 } else {
3855 cur = xmlRelaxNGParsePattern(ctxt, child);
3856 }
3857 if (cur != NULL) {
3858 cur->parent = def;
3859 if (last == NULL) {
3860 def->content = last = cur;
3861 } else {
3862 last->next = cur;
3863 last = cur;
3864 }
3865 }
3866 child = child->next;
3867 }
3868
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00003869 return(def);
3870}
Daniel Veillard6eadf632003-01-23 18:29:16 +00003871
3872/**
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003873 * xmlRelaxNGParseInclude:
3874 * @ctxt: a Relax-NG parser context
3875 * @node: the include node
3876 *
3877 * Integrate the content of an include node in the current grammar
3878 *
3879 * Returns 0 in case of success or -1 in case of error
3880 */
3881static int
3882xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3883 xmlRelaxNGIncludePtr incl;
3884 xmlNodePtr root;
3885 int ret = 0, tmp;
3886
3887 incl = node->_private;
3888 if (incl == NULL) {
3889 if (ctxt->error != NULL)
3890 ctxt->error(ctxt->userData,
3891 "Include node has no data\n");
3892 ctxt->nbErrors++;
3893 return(-1);
3894 }
3895 root = xmlDocGetRootElement(incl->doc);
3896 if (root == NULL) {
3897 if (ctxt->error != NULL)
3898 ctxt->error(ctxt->userData,
3899 "Include document is empty\n");
3900 ctxt->nbErrors++;
3901 return(-1);
3902 }
3903 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
3904 if (ctxt->error != NULL)
3905 ctxt->error(ctxt->userData,
3906 "Include document root is not a grammar\n");
3907 ctxt->nbErrors++;
3908 return(-1);
3909 }
3910
3911 /*
3912 * Merge the definition from both the include and the internal list
3913 */
3914 if (root->children != NULL) {
3915 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
3916 if (tmp != 0)
3917 ret = -1;
3918 }
3919 if (node->children != NULL) {
3920 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
3921 if (tmp != 0)
3922 ret = -1;
3923 }
3924 return(ret);
3925}
3926
3927/**
Daniel Veillard276be4a2003-01-24 01:03:34 +00003928 * xmlRelaxNGParseDefine:
3929 * @ctxt: a Relax-NG parser context
3930 * @node: the define node
3931 *
3932 * parse the content of a RelaxNG define element node.
3933 *
Daniel Veillarde2a5a082003-02-02 14:35:17 +00003934 * Returns 0 in case of success or -1 in case of error
Daniel Veillard276be4a2003-01-24 01:03:34 +00003935 */
3936static int
3937xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3938 xmlChar *name;
3939 int ret = 0, tmp;
3940 xmlRelaxNGDefinePtr def;
3941 const xmlChar *olddefine;
3942
3943 name = xmlGetProp(node, BAD_CAST "name");
3944 if (name == NULL) {
3945 if (ctxt->error != NULL)
3946 ctxt->error(ctxt->userData,
3947 "define has no name\n");
3948 ctxt->nbErrors++;
3949 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00003950 xmlRelaxNGNormExtSpace(name);
3951 if (xmlValidateNCName(name, 0)) {
3952 if (ctxt->error != NULL)
3953 ctxt->error(ctxt->userData,
3954 "define name '%s' is not an NCName\n",
3955 name);
3956 ctxt->nbErrors++;
3957 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003958 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003959 if (def == NULL) {
3960 xmlFree(name);
3961 return(-1);
3962 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00003963 def->type = XML_RELAXNG_DEF;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003964 def->name = name;
3965 if (node->children == NULL) {
3966 if (ctxt->error != NULL)
3967 ctxt->error(ctxt->userData,
3968 "define has no children\n");
3969 ctxt->nbErrors++;
3970 } else {
3971 olddefine = ctxt->define;
3972 ctxt->define = name;
Daniel Veillard154877e2003-01-30 12:17:05 +00003973 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
Daniel Veillard276be4a2003-01-24 01:03:34 +00003974 ctxt->define = olddefine;
3975 }
3976 if (ctxt->grammar->defs == NULL)
3977 ctxt->grammar->defs = xmlHashCreate(10);
3978 if (ctxt->grammar->defs == NULL) {
3979 if (ctxt->error != NULL)
3980 ctxt->error(ctxt->userData,
3981 "Could not create definition hash\n");
3982 ctxt->nbErrors++;
3983 ret = -1;
Daniel Veillard276be4a2003-01-24 01:03:34 +00003984 } else {
3985 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
3986 if (tmp < 0) {
Daniel Veillard154877e2003-01-30 12:17:05 +00003987 xmlRelaxNGDefinePtr prev;
3988
3989 prev = xmlHashLookup(ctxt->grammar->defs, name);
3990 if (prev == NULL) {
3991 if (ctxt->error != NULL)
3992 ctxt->error(ctxt->userData,
3993 "Internal error on define aggregation of %s\n",
3994 name);
3995 ctxt->nbErrors++;
3996 ret = -1;
Daniel Veillard154877e2003-01-30 12:17:05 +00003997 } else {
3998 while (prev->nextHash != NULL)
3999 prev = prev->nextHash;
4000 prev->nextHash = def;
4001 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004002 }
4003 }
4004 }
4005 return(ret);
4006}
4007
4008/**
Daniel Veillardfebcca42003-02-16 15:44:18 +00004009 * xmlRelaxNGProcessExternalRef:
4010 * @ctxt: the parser context
4011 * @node: the externlRef node
4012 *
4013 * Process and compile an externlRef node
4014 *
4015 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4016 */
4017static xmlRelaxNGDefinePtr
4018xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4019 xmlRelaxNGDocumentPtr docu;
4020 xmlNodePtr root, tmp;
4021 xmlChar *ns;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004022 int newNs = 0, oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004023 xmlRelaxNGDefinePtr def;
4024
4025 docu = node->_private;
4026 if (docu != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004027 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardfebcca42003-02-16 15:44:18 +00004028 if (def == NULL)
4029 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004030 def->type = XML_RELAXNG_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004031
4032 if (docu->content == NULL) {
4033 /*
4034 * Then do the parsing for good
4035 */
4036 root = xmlDocGetRootElement(docu->doc);
4037 if (root == NULL) {
4038 if (ctxt->error != NULL)
4039 ctxt->error(ctxt->userData,
4040 "xmlRelaxNGParse: %s is empty\n",
4041 ctxt->URL);
4042 ctxt->nbErrors++;
4043 return (NULL);
4044 }
4045 /*
4046 * ns transmission rules
4047 */
4048 ns = xmlGetProp(root, BAD_CAST "ns");
4049 if (ns == NULL) {
4050 tmp = node;
4051 while ((tmp != NULL) &&
4052 (tmp->type == XML_ELEMENT_NODE)) {
4053 ns = xmlGetProp(tmp, BAD_CAST "ns");
4054 if (ns != NULL) {
4055 break;
4056 }
4057 tmp = tmp->parent;
4058 }
4059 if (ns != NULL) {
4060 xmlSetProp(root, BAD_CAST "ns", ns);
4061 newNs = 1;
4062 xmlFree(ns);
4063 }
4064 } else {
4065 xmlFree(ns);
4066 }
4067
4068 /*
4069 * Parsing to get a precompiled schemas.
4070 */
Daniel Veillard77648bb2003-02-20 15:03:22 +00004071 oldflags = ctxt->flags;
4072 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004073 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard77648bb2003-02-20 15:03:22 +00004074 ctxt->flags = oldflags;
Daniel Veillardfebcca42003-02-16 15:44:18 +00004075 if ((docu->schema != NULL) &&
4076 (docu->schema->topgrammar != NULL)) {
4077 docu->content = docu->schema->topgrammar->start;
4078 }
4079
4080 /*
4081 * the externalRef may be reused in a different ns context
4082 */
4083 if (newNs == 1) {
4084 xmlUnsetProp(root, BAD_CAST "ns");
4085 }
4086 }
4087 def->content = docu->content;
4088 } else {
4089 def = NULL;
4090 }
4091 return(def);
4092}
4093
4094/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004095 * xmlRelaxNGParsePattern:
4096 * @ctxt: a Relax-NG parser context
4097 * @node: the pattern node.
4098 *
4099 * parse the content of a RelaxNG pattern node.
4100 *
Daniel Veillard276be4a2003-01-24 01:03:34 +00004101 * Returns the definition pointer or NULL in case of error or if no
4102 * pattern is generated.
Daniel Veillard6eadf632003-01-23 18:29:16 +00004103 */
4104static xmlRelaxNGDefinePtr
4105xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4106 xmlRelaxNGDefinePtr def = NULL;
4107
Daniel Veillardd2298792003-02-14 16:54:11 +00004108 if (node == NULL) {
4109 return(NULL);
4110 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004111 if (IS_RELAXNG(node, "element")) {
4112 def = xmlRelaxNGParseElement(ctxt, node);
4113 } else if (IS_RELAXNG(node, "attribute")) {
4114 def = xmlRelaxNGParseAttribute(ctxt, node);
4115 } else if (IS_RELAXNG(node, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004116 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004117 if (def == NULL)
4118 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004119 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004120 if (node->children != NULL) {
4121 if (ctxt->error != NULL)
4122 ctxt->error(ctxt->userData, "empty: had a child node\n");
4123 ctxt->nbErrors++;
4124 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004125 } else if (IS_RELAXNG(node, "text")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004126 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004127 if (def == NULL)
4128 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004129 def->type = XML_RELAXNG_TEXT;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004130 if (node->children != NULL) {
4131 if (ctxt->error != NULL)
4132 ctxt->error(ctxt->userData, "text: had a child node\n");
4133 ctxt->nbErrors++;
4134 }
4135 } else if (IS_RELAXNG(node, "zeroOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004136 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004137 if (def == NULL)
4138 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004139 def->type = XML_RELAXNG_ZEROORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004140 if (node->children == NULL) {
4141 if (ctxt->error != NULL)
4142 ctxt->error(ctxt->userData,
4143 "Element %s is empty\n", node->name);
4144 ctxt->nbErrors++;
4145 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004146 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
Daniel Veillardd2298792003-02-14 16:54:11 +00004147 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004148 } else if (IS_RELAXNG(node, "oneOrMore")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004149 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004150 if (def == NULL)
4151 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004152 def->type = XML_RELAXNG_ONEORMORE;
Daniel Veillardd2298792003-02-14 16:54:11 +00004153 if (node->children == NULL) {
4154 if (ctxt->error != NULL)
4155 ctxt->error(ctxt->userData,
4156 "Element %s is empty\n", node->name);
4157 ctxt->nbErrors++;
4158 } else {
4159 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4160 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004161 } else if (IS_RELAXNG(node, "optional")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004162 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004163 if (def == NULL)
4164 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004165 def->type = XML_RELAXNG_OPTIONAL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004166 if (node->children == NULL) {
4167 if (ctxt->error != NULL)
4168 ctxt->error(ctxt->userData,
4169 "Element %s is empty\n", node->name);
4170 ctxt->nbErrors++;
4171 } else {
4172 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
4173 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004174 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004175 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004176 if (def == NULL)
4177 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004178 def->type = XML_RELAXNG_CHOICE;
4179 if (node->children == NULL) {
4180 if (ctxt->error != NULL)
4181 ctxt->error(ctxt->userData,
4182 "Element %s is empty\n", node->name);
4183 ctxt->nbErrors++;
4184 } else {
4185 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4186 }
4187 } else if (IS_RELAXNG(node, "group")) {
4188 def = xmlRelaxNGNewDefine(ctxt, node);
4189 if (def == NULL)
4190 return(NULL);
4191 def->type = XML_RELAXNG_GROUP;
4192 if (node->children == NULL) {
4193 if (ctxt->error != NULL)
4194 ctxt->error(ctxt->userData,
4195 "Element %s is empty\n", node->name);
4196 ctxt->nbErrors++;
4197 } else {
4198 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4199 }
4200 } else if (IS_RELAXNG(node, "ref")) {
4201 def = xmlRelaxNGNewDefine(ctxt, node);
4202 if (def == NULL)
4203 return(NULL);
4204 def->type = XML_RELAXNG_REF;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004205 def->name = xmlGetProp(node, BAD_CAST "name");
4206 if (def->name == NULL) {
4207 if (ctxt->error != NULL)
4208 ctxt->error(ctxt->userData,
4209 "ref has no name\n");
4210 ctxt->nbErrors++;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004211 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004212 xmlRelaxNGNormExtSpace(def->name);
4213 if (xmlValidateNCName(def->name, 0)) {
4214 if (ctxt->error != NULL)
4215 ctxt->error(ctxt->userData,
4216 "ref name '%s' is not an NCName\n",
4217 def->name);
4218 ctxt->nbErrors++;
4219 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004220 }
4221 if (node->children != NULL) {
4222 if (ctxt->error != NULL)
4223 ctxt->error(ctxt->userData,
4224 "ref is not empty\n");
4225 ctxt->nbErrors++;
4226 }
4227 if (ctxt->grammar->refs == NULL)
4228 ctxt->grammar->refs = xmlHashCreate(10);
4229 if (ctxt->grammar->refs == NULL) {
4230 if (ctxt->error != NULL)
4231 ctxt->error(ctxt->userData,
4232 "Could not create references hash\n");
4233 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004234 def = NULL;
4235 } else {
4236 int tmp;
4237
4238 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
4239 if (tmp < 0) {
4240 xmlRelaxNGDefinePtr prev;
4241
4242 prev = (xmlRelaxNGDefinePtr)
4243 xmlHashLookup(ctxt->grammar->refs, def->name);
4244 if (prev == NULL) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004245 if (def->name != NULL) {
4246 if (ctxt->error != NULL)
4247 ctxt->error(ctxt->userData,
4248 "Error refs definitions '%s'\n",
4249 def->name);
4250 } else {
4251 if (ctxt->error != NULL)
4252 ctxt->error(ctxt->userData,
4253 "Error refs definitions\n");
4254 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004255 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004256 def = NULL;
4257 } else {
4258 def->nextHash = prev->nextHash;
4259 prev->nextHash = def;
4260 }
4261 }
4262 }
Daniel Veillarddd1655c2003-01-25 18:01:32 +00004263 } else if (IS_RELAXNG(node, "data")) {
4264 def = xmlRelaxNGParseData(ctxt, node);
Daniel Veillardedc91922003-01-26 00:52:04 +00004265 } else if (IS_RELAXNG(node, "value")) {
4266 def = xmlRelaxNGParseValue(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004267 } else if (IS_RELAXNG(node, "list")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004268 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00004269 if (def == NULL)
4270 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004271 def->type = XML_RELAXNG_LIST;
Daniel Veillardd2298792003-02-14 16:54:11 +00004272 if (node->children == NULL) {
4273 if (ctxt->error != NULL)
4274 ctxt->error(ctxt->userData,
4275 "Element %s is empty\n", node->name);
4276 ctxt->nbErrors++;
4277 } else {
4278 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
4279 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004280 } else if (IS_RELAXNG(node, "interleave")) {
4281 def = xmlRelaxNGParseInterleave(ctxt, node);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004282 } else if (IS_RELAXNG(node, "externalRef")) {
Daniel Veillardfebcca42003-02-16 15:44:18 +00004283 def = xmlRelaxNGProcessExternalRef(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004284 } else if (IS_RELAXNG(node, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004285 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004286 if (def == NULL)
4287 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004288 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004289 if (node->children != NULL) {
4290 if (ctxt->error != NULL)
4291 ctxt->error(ctxt->userData,
4292 "xmlRelaxNGParse: notAllowed element is not empty\n");
4293 ctxt->nbErrors++;
4294 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004295 } else if (IS_RELAXNG(node, "grammar")) {
4296 xmlRelaxNGGrammarPtr grammar, old;
4297 xmlRelaxNGGrammarPtr oldparent;
4298
Daniel Veillardc482e262003-02-26 14:48:48 +00004299#ifdef DEBUG_GRAMMAR
4300 xmlGenericError(xmlGenericErrorContext, "Found <grammar> pattern\n");
4301#endif
4302
Daniel Veillard419a7682003-02-03 23:22:49 +00004303 oldparent = ctxt->parentgrammar;
4304 old = ctxt->grammar;
4305 ctxt->parentgrammar = old;
4306 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4307 if (old != NULL) {
4308 ctxt->grammar = old;
4309 ctxt->parentgrammar = oldparent;
Daniel Veillardc482e262003-02-26 14:48:48 +00004310#if 0
Daniel Veillard419a7682003-02-03 23:22:49 +00004311 if (grammar != NULL) {
4312 grammar->next = old->next;
4313 old->next = grammar;
4314 }
Daniel Veillardc482e262003-02-26 14:48:48 +00004315#endif
Daniel Veillard419a7682003-02-03 23:22:49 +00004316 }
4317 if (grammar != NULL)
4318 def = grammar->start;
4319 else
4320 def = NULL;
4321 } else if (IS_RELAXNG(node, "parentRef")) {
4322 if (ctxt->parentgrammar == NULL) {
4323 if (ctxt->error != NULL)
4324 ctxt->error(ctxt->userData,
4325 "Use of parentRef without a parent grammar\n");
4326 ctxt->nbErrors++;
4327 return(NULL);
4328 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00004329 def = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard419a7682003-02-03 23:22:49 +00004330 if (def == NULL)
4331 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004332 def->type = XML_RELAXNG_PARENTREF;
Daniel Veillard419a7682003-02-03 23:22:49 +00004333 def->name = xmlGetProp(node, BAD_CAST "name");
4334 if (def->name == NULL) {
4335 if (ctxt->error != NULL)
4336 ctxt->error(ctxt->userData,
4337 "parentRef has no name\n");
4338 ctxt->nbErrors++;
Daniel Veillardd2298792003-02-14 16:54:11 +00004339 } else {
4340 xmlRelaxNGNormExtSpace(def->name);
4341 if (xmlValidateNCName(def->name, 0)) {
4342 if (ctxt->error != NULL)
4343 ctxt->error(ctxt->userData,
4344 "parentRef name '%s' is not an NCName\n",
4345 def->name);
4346 ctxt->nbErrors++;
4347 }
Daniel Veillard419a7682003-02-03 23:22:49 +00004348 }
4349 if (node->children != NULL) {
4350 if (ctxt->error != NULL)
4351 ctxt->error(ctxt->userData,
4352 "parentRef is not empty\n");
4353 ctxt->nbErrors++;
4354 }
4355 if (ctxt->parentgrammar->refs == NULL)
4356 ctxt->parentgrammar->refs = xmlHashCreate(10);
4357 if (ctxt->parentgrammar->refs == NULL) {
4358 if (ctxt->error != NULL)
4359 ctxt->error(ctxt->userData,
4360 "Could not create references hash\n");
4361 ctxt->nbErrors++;
4362 def = NULL;
Daniel Veillardd2298792003-02-14 16:54:11 +00004363 } else if (def->name != NULL) {
Daniel Veillard419a7682003-02-03 23:22:49 +00004364 int tmp;
4365
4366 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
4367 if (tmp < 0) {
4368 xmlRelaxNGDefinePtr prev;
4369
4370 prev = (xmlRelaxNGDefinePtr)
4371 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
4372 if (prev == NULL) {
4373 if (ctxt->error != NULL)
4374 ctxt->error(ctxt->userData,
4375 "Internal error parentRef definitions '%s'\n",
4376 def->name);
4377 ctxt->nbErrors++;
4378 def = NULL;
4379 } else {
4380 def->nextHash = prev->nextHash;
4381 prev->nextHash = def;
4382 }
4383 }
4384 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004385 } else if (IS_RELAXNG(node, "mixed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004386 if (node->children == NULL) {
4387 if (ctxt->error != NULL)
4388 ctxt->error(ctxt->userData,
4389 "Mixed is empty\n");
4390 ctxt->nbErrors++;
4391 def = NULL;
4392 } else {
4393 def = xmlRelaxNGParseInterleave(ctxt, node);
4394 if (def != NULL) {
4395 xmlRelaxNGDefinePtr tmp;
4396
4397 if ((def->content != NULL) && (def->content->next != NULL)) {
4398 tmp = xmlRelaxNGNewDefine(ctxt, node);
4399 if (tmp != NULL) {
4400 tmp->type = XML_RELAXNG_GROUP;
4401 tmp->content = def->content;
4402 def->content = tmp;
4403 }
4404 }
4405
4406 tmp = xmlRelaxNGNewDefine(ctxt, node);
4407 if (tmp == NULL)
4408 return(def);
4409 tmp->type = XML_RELAXNG_TEXT;
4410 tmp->next = def->content;
4411 def->content = tmp;
4412 }
4413 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004414 } else {
4415 if (ctxt->error != NULL)
4416 ctxt->error(ctxt->userData,
4417 "Unexpected node %s is not a pattern\n",
4418 node->name);
4419 ctxt->nbErrors++;
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004420 def = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004421 }
4422 return(def);
4423}
4424
4425/**
4426 * xmlRelaxNGParseAttribute:
4427 * @ctxt: a Relax-NG parser context
4428 * @node: the element node
4429 *
4430 * parse the content of a RelaxNG attribute node.
4431 *
4432 * Returns the definition pointer or NULL in case of error.
4433 */
4434static xmlRelaxNGDefinePtr
4435xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
Daniel Veillardd2298792003-02-14 16:54:11 +00004436 xmlRelaxNGDefinePtr ret, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004437 xmlNodePtr child;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004438 int old_flags;
4439
Daniel Veillardfd573f12003-03-16 17:52:32 +00004440 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004441 if (ret == NULL)
4442 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004443 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004444 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004445 child = node->children;
4446 if (child == NULL) {
4447 if (ctxt->error != NULL)
4448 ctxt->error(ctxt->userData,
4449 "xmlRelaxNGParseattribute: attribute has no children\n");
4450 ctxt->nbErrors++;
4451 return(ret);
4452 }
4453 old_flags = ctxt->flags;
4454 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004455 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4456 if (cur != NULL)
4457 child = child->next;
4458
Daniel Veillardd2298792003-02-14 16:54:11 +00004459 if (child != NULL) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00004460 cur = xmlRelaxNGParsePattern(ctxt, child);
4461 if (cur != NULL) {
4462 switch (cur->type) {
4463 case XML_RELAXNG_EMPTY:
4464 case XML_RELAXNG_NOT_ALLOWED:
4465 case XML_RELAXNG_TEXT:
4466 case XML_RELAXNG_ELEMENT:
4467 case XML_RELAXNG_DATATYPE:
4468 case XML_RELAXNG_VALUE:
4469 case XML_RELAXNG_LIST:
4470 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004471 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004472 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004473 case XML_RELAXNG_DEF:
4474 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004475 case XML_RELAXNG_ZEROORMORE:
4476 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004477 case XML_RELAXNG_CHOICE:
4478 case XML_RELAXNG_GROUP:
4479 case XML_RELAXNG_INTERLEAVE:
Daniel Veillard77648bb2003-02-20 15:03:22 +00004480 case XML_RELAXNG_ATTRIBUTE:
Daniel Veillardd2298792003-02-14 16:54:11 +00004481 ret->content = cur;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004482 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004483 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004484 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004485 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004486 case XML_RELAXNG_EXCEPT:
Daniel Veillardd2298792003-02-14 16:54:11 +00004487 if (ctxt->error != NULL)
4488 ctxt->error(ctxt->userData,
4489 "attribute has invalid content\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004490 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004491 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004492 case XML_RELAXNG_NOOP:
4493 TODO
4494 if (ctxt->error != NULL)
4495 ctxt->error(ctxt->userData,
4496 "Internal error, noop found\n");
4497 ctxt->nbErrors++;
4498 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004499 }
4500 }
4501 child = child->next;
4502 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004503 if (child != NULL) {
4504 if (ctxt->error != NULL)
4505 ctxt->error(ctxt->userData, "attribute has multiple children\n");
4506 ctxt->nbErrors++;
4507 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004508 ctxt->flags = old_flags;
4509 return(ret);
4510}
4511
4512/**
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004513 * xmlRelaxNGParseExceptNameClass:
4514 * @ctxt: a Relax-NG parser context
4515 * @node: the except node
Daniel Veillard144fae12003-02-03 13:17:57 +00004516 * @attr: 1 if within an attribute, 0 if within an element
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004517 *
4518 * parse the content of a RelaxNG nameClass node.
4519 *
4520 * Returns the definition pointer or NULL in case of error.
4521 */
4522static xmlRelaxNGDefinePtr
Daniel Veillard144fae12003-02-03 13:17:57 +00004523xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
4524 xmlNodePtr node, int attr) {
4525 xmlRelaxNGDefinePtr ret, cur, last = NULL;
4526 xmlNodePtr child;
4527
Daniel Veillardd2298792003-02-14 16:54:11 +00004528 if (!IS_RELAXNG(node, "except")) {
4529 if (ctxt->error != NULL)
4530 ctxt->error(ctxt->userData,
4531 "Expecting an except node\n");
4532 ctxt->nbErrors++;
Daniel Veillard144fae12003-02-03 13:17:57 +00004533 return(NULL);
Daniel Veillardd2298792003-02-14 16:54:11 +00004534 }
4535 if (node->next != NULL) {
4536 if (ctxt->error != NULL)
4537 ctxt->error(ctxt->userData,
4538 "exceptNameClass allows only a single except node\n");
4539 ctxt->nbErrors++;
4540 }
Daniel Veillard144fae12003-02-03 13:17:57 +00004541 if (node->children == NULL) {
4542 if (ctxt->error != NULL)
4543 ctxt->error(ctxt->userData,
4544 "except has no content\n");
4545 ctxt->nbErrors++;
4546 return(NULL);
4547 }
4548
Daniel Veillardfd573f12003-03-16 17:52:32 +00004549 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard144fae12003-02-03 13:17:57 +00004550 if (ret == NULL)
4551 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004552 ret->type = XML_RELAXNG_EXCEPT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004553 child = node->children;
4554 while (child != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004555 cur = xmlRelaxNGNewDefine(ctxt, child);
Daniel Veillard144fae12003-02-03 13:17:57 +00004556 if (cur == NULL)
4557 break;
4558 if (attr)
4559 cur->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004560 else
4561 cur->type = XML_RELAXNG_ELEMENT;
Daniel Veillard144fae12003-02-03 13:17:57 +00004562
Daniel Veillard419a7682003-02-03 23:22:49 +00004563 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
Daniel Veillard144fae12003-02-03 13:17:57 +00004564 if (last == NULL) {
4565 ret->content = cur;
4566 } else {
4567 last->next = cur;
4568 }
4569 last = cur;
4570 }
4571 child = child->next;
4572 }
4573
4574 return(ret);
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004575}
4576
4577/**
4578 * xmlRelaxNGParseNameClass:
4579 * @ctxt: a Relax-NG parser context
4580 * @node: the nameClass node
4581 * @def: the current definition
4582 *
4583 * parse the content of a RelaxNG nameClass node.
4584 *
4585 * Returns the definition pointer or NULL in case of error.
4586 */
4587static xmlRelaxNGDefinePtr
4588xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
4589 xmlRelaxNGDefinePtr def) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004590 xmlRelaxNGDefinePtr ret, tmp;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004591 xmlChar *val;
4592
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004593 ret = def;
4594 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
4595 (IS_RELAXNG(node, "nsName"))) {
4596 if ((def->type != XML_RELAXNG_ELEMENT) &&
4597 (def->type != XML_RELAXNG_ATTRIBUTE)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004598 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004599 if (ret == NULL)
4600 return(NULL);
4601 ret->parent = def;
4602 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
4603 ret->type = XML_RELAXNG_ATTRIBUTE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004604 else
4605 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004606 }
4607 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004608 if (IS_RELAXNG(node, "name")) {
4609 val = xmlNodeGetContent(node);
Daniel Veillardd2298792003-02-14 16:54:11 +00004610 xmlRelaxNGNormExtSpace(val);
4611 if (xmlValidateNCName(val, 0)) {
4612 if (ctxt->error != NULL) {
4613 if (node->parent != NULL)
4614 ctxt->error(ctxt->userData,
4615 "Element %s name '%s' is not an NCName\n",
4616 node->parent->name, val);
4617 else
4618 ctxt->error(ctxt->userData,
4619 "name '%s' is not an NCName\n",
4620 val);
4621 }
4622 ctxt->nbErrors++;
4623 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004624 ret->name = val;
4625 val = xmlGetProp(node, BAD_CAST "ns");
4626 ret->ns = val;
Daniel Veillard416589a2003-02-17 17:25:42 +00004627 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4628 (val != NULL) &&
4629 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4630 ctxt->error(ctxt->userData,
4631 "Attribute with namespace '%s' is not allowed\n",
4632 val);
4633 ctxt->nbErrors++;
4634 }
4635 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4636 (val != NULL) &&
4637 (val[0] == 0) &&
4638 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
4639 ctxt->error(ctxt->userData,
4640 "Attribute with QName 'xmlns' is not allowed\n",
4641 val);
4642 ctxt->nbErrors++;
4643 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004644 } else if (IS_RELAXNG(node, "anyName")) {
4645 ret->name = NULL;
4646 ret->ns = NULL;
4647 if (node->children != NULL) {
4648 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004649 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4650 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004651 }
4652 } else if (IS_RELAXNG(node, "nsName")) {
4653 ret->name = NULL;
4654 ret->ns = xmlGetProp(node, BAD_CAST "ns");
4655 if (ret->ns == NULL) {
4656 if (ctxt->error != NULL)
4657 ctxt->error(ctxt->userData,
4658 "nsName has no ns attribute\n");
4659 ctxt->nbErrors++;
4660 }
Daniel Veillard416589a2003-02-17 17:25:42 +00004661 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
4662 (ret->ns != NULL) &&
4663 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
4664 ctxt->error(ctxt->userData,
4665 "Attribute with namespace '%s' is not allowed\n",
4666 ret->ns);
4667 ctxt->nbErrors++;
4668 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004669 if (node->children != NULL) {
4670 ret->nameClass =
Daniel Veillard144fae12003-02-03 13:17:57 +00004671 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
4672 (def->type == XML_RELAXNG_ATTRIBUTE));
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004673 }
4674 } else if (IS_RELAXNG(node, "choice")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004675 xmlNodePtr child;
4676 xmlRelaxNGDefinePtr last = NULL;
4677
4678 ret = xmlRelaxNGNewDefine(ctxt, node);
4679 if (ret == NULL)
4680 return(NULL);
4681 ret->parent = def;
4682 ret->type = XML_RELAXNG_CHOICE;
4683
Daniel Veillardd2298792003-02-14 16:54:11 +00004684 if (node->children == NULL) {
4685 if (ctxt->error != NULL)
4686 ctxt->error(ctxt->userData,
4687 "Element choice is empty\n");
4688 ctxt->nbErrors++;
4689 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004690
4691 child = node->children;
4692 while (child != NULL) {
4693 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
4694 if (tmp != NULL) {
4695 if (last == NULL) {
4696 last = ret->nameClass = tmp;
4697 } else {
4698 last->next = tmp;
4699 last = tmp;
4700 }
4701 }
4702 child = child->next;
4703 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004704 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004705 } else {
4706 if (ctxt->error != NULL)
4707 ctxt->error(ctxt->userData,
Daniel Veillardfd573f12003-03-16 17:52:32 +00004708 "expecting name, anyName, nsName or choice : got %s\n",
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004709 node->name);
4710 ctxt->nbErrors++;
4711 return(NULL);
4712 }
Daniel Veillard2e9b1652003-02-19 13:29:45 +00004713 if (ret != def) {
4714 if (def->nameClass == NULL) {
4715 def->nameClass = ret;
4716 } else {
4717 tmp = def->nameClass;
4718 while (tmp->next != NULL) {
4719 tmp = tmp->next;
4720 }
4721 tmp->next = ret;
4722 }
4723 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004724 return(ret);
4725}
4726
4727/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00004728 * xmlRelaxNGParseElement:
4729 * @ctxt: a Relax-NG parser context
4730 * @node: the element node
4731 *
4732 * parse the content of a RelaxNG element node.
4733 *
4734 * Returns the definition pointer or NULL in case of error.
4735 */
4736static xmlRelaxNGDefinePtr
4737xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4738 xmlRelaxNGDefinePtr ret, cur, last;
4739 xmlNodePtr child;
Daniel Veillard276be4a2003-01-24 01:03:34 +00004740 const xmlChar *olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004741
Daniel Veillardfd573f12003-03-16 17:52:32 +00004742 ret = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004743 if (ret == NULL)
4744 return(NULL);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004745 ret->type = XML_RELAXNG_ELEMENT;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004746 ret->parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004747 child = node->children;
4748 if (child == NULL) {
4749 if (ctxt->error != NULL)
4750 ctxt->error(ctxt->userData,
4751 "xmlRelaxNGParseElement: element has no children\n");
4752 ctxt->nbErrors++;
4753 return(ret);
4754 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00004755 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
4756 if (cur != NULL)
4757 child = child->next;
4758
Daniel Veillard6eadf632003-01-23 18:29:16 +00004759 if (child == NULL) {
4760 if (ctxt->error != NULL)
4761 ctxt->error(ctxt->userData,
4762 "xmlRelaxNGParseElement: element has no content\n");
4763 ctxt->nbErrors++;
4764 return(ret);
4765 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004766 olddefine = ctxt->define;
4767 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004768 last = NULL;
4769 while (child != NULL) {
4770 cur = xmlRelaxNGParsePattern(ctxt, child);
4771 if (cur != NULL) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004772 cur->parent = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004773 switch (cur->type) {
4774 case XML_RELAXNG_EMPTY:
4775 case XML_RELAXNG_NOT_ALLOWED:
4776 case XML_RELAXNG_TEXT:
4777 case XML_RELAXNG_ELEMENT:
4778 case XML_RELAXNG_DATATYPE:
4779 case XML_RELAXNG_VALUE:
4780 case XML_RELAXNG_LIST:
4781 case XML_RELAXNG_REF:
Daniel Veillard419a7682003-02-03 23:22:49 +00004782 case XML_RELAXNG_PARENTREF:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004783 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004784 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004785 case XML_RELAXNG_ZEROORMORE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004786 case XML_RELAXNG_ONEORMORE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00004787 case XML_RELAXNG_OPTIONAL:
Daniel Veillard6eadf632003-01-23 18:29:16 +00004788 case XML_RELAXNG_CHOICE:
4789 case XML_RELAXNG_GROUP:
4790 case XML_RELAXNG_INTERLEAVE:
4791 if (last == NULL) {
4792 ret->content = last = cur;
4793 } else {
4794 if ((last->type == XML_RELAXNG_ELEMENT) &&
4795 (ret->content == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004796 ret->content = xmlRelaxNGNewDefine(ctxt, node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004797 if (ret->content != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004798 ret->content->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004799 ret->content->content = last;
4800 } else {
4801 ret->content = last;
4802 }
4803 }
4804 last->next = cur;
4805 last = cur;
4806 }
4807 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00004808 case XML_RELAXNG_ATTRIBUTE:
4809 cur->next = ret->attrs;
4810 ret->attrs = cur;
4811 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004812 case XML_RELAXNG_START:
Daniel Veillard8fe98712003-02-19 00:19:14 +00004813 case XML_RELAXNG_PARAM:
Daniel Veillard144fae12003-02-03 13:17:57 +00004814 case XML_RELAXNG_EXCEPT:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004815 TODO
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004816 ctxt->nbErrors++;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00004817 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00004818 case XML_RELAXNG_NOOP:
4819 TODO
4820 if (ctxt->error != NULL)
4821 ctxt->error(ctxt->userData,
4822 "Internal error, noop found\n");
4823 ctxt->nbErrors++;
4824 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004825 }
4826 }
4827 child = child->next;
4828 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00004829 ctxt->define = olddefine;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004830 return(ret);
4831}
4832
4833/**
4834 * xmlRelaxNGParsePatterns:
4835 * @ctxt: a Relax-NG parser context
4836 * @nodes: list of nodes
Daniel Veillard154877e2003-01-30 12:17:05 +00004837 * @group: use an implicit <group> for elements
Daniel Veillard6eadf632003-01-23 18:29:16 +00004838 *
4839 * parse the content of a RelaxNG start node.
4840 *
4841 * Returns the definition pointer or NULL in case of error.
4842 */
4843static xmlRelaxNGDefinePtr
Daniel Veillard154877e2003-01-30 12:17:05 +00004844xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
4845 int group) {
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004846 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004847
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004848 parent = ctxt->def;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004849 while (nodes != NULL) {
4850 if (IS_RELAXNG(nodes, "element")) {
4851 cur = xmlRelaxNGParseElement(ctxt, nodes);
4852 if (def == NULL) {
4853 def = last = cur;
4854 } else {
Daniel Veillard154877e2003-01-30 12:17:05 +00004855 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
4856 (def == last)) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004857 def = xmlRelaxNGNewDefine(ctxt, nodes);
4858 def->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004859 def->content = last;
4860 }
4861 last->next = cur;
4862 last = cur;
4863 }
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00004864 cur->parent = parent;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004865 } else {
4866 cur = xmlRelaxNGParsePattern(ctxt, nodes);
Daniel Veillard419a7682003-02-03 23:22:49 +00004867 if (cur != NULL) {
4868 if (def == NULL) {
4869 def = last = cur;
4870 } else {
4871 last->next = cur;
4872 last = cur;
4873 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004874 }
4875 }
4876 nodes = nodes->next;
4877 }
4878 return(def);
4879}
4880
4881/**
4882 * xmlRelaxNGParseStart:
4883 * @ctxt: a Relax-NG parser context
4884 * @nodes: start children nodes
4885 *
4886 * parse the content of a RelaxNG start node.
4887 *
4888 * Returns 0 in case of success, -1 in case of error
4889 */
4890static int
4891xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4892 int ret = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00004893 xmlRelaxNGDefinePtr def = NULL, last;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004894
Daniel Veillardd2298792003-02-14 16:54:11 +00004895 if (nodes == NULL) {
4896 if (ctxt->error != NULL)
4897 ctxt->error(ctxt->userData,
4898 "start has no children\n");
4899 ctxt->nbErrors++;
4900 return(-1);
4901 }
4902 if (IS_RELAXNG(nodes, "empty")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004903 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004904 if (def == NULL)
4905 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004906 def->type = XML_RELAXNG_EMPTY;
Daniel Veillardd2298792003-02-14 16:54:11 +00004907 if (nodes->children != NULL) {
4908 if (ctxt->error != NULL)
4909 ctxt->error(ctxt->userData, "element empty is not empty\n");
Daniel Veillard1703c5f2003-02-10 14:28:44 +00004910 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004911 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004912 } else if (IS_RELAXNG(nodes, "notAllowed")) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00004913 def = xmlRelaxNGNewDefine(ctxt, nodes);
Daniel Veillardd2298792003-02-14 16:54:11 +00004914 if (def == NULL)
4915 return(-1);
Daniel Veillardfd573f12003-03-16 17:52:32 +00004916 def->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardd2298792003-02-14 16:54:11 +00004917 if (nodes->children != NULL) {
4918 if (ctxt->error != NULL)
4919 ctxt->error(ctxt->userData,
4920 "element notAllowed is not empty\n");
4921 ctxt->nbErrors++;
4922 }
Daniel Veillardd2298792003-02-14 16:54:11 +00004923 } else {
4924 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
Daniel Veillard2df2de22003-02-17 23:34:33 +00004925 }
4926 if (ctxt->grammar->start != NULL) {
4927 last = ctxt->grammar->start;
4928 while (last->next != NULL)
4929 last = last->next;
4930 last->next = def;
4931 } else {
Daniel Veillardd2298792003-02-14 16:54:11 +00004932 ctxt->grammar->start = def;
4933 }
4934 nodes = nodes->next;
4935 if (nodes != NULL) {
4936 if (ctxt->error != NULL)
4937 ctxt->error(ctxt->userData,
4938 "start more than one children\n");
4939 ctxt->nbErrors++;
4940 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004941 }
4942 return(ret);
4943}
4944
4945/**
4946 * xmlRelaxNGParseGrammarContent:
4947 * @ctxt: a Relax-NG parser context
4948 * @nodes: grammar children nodes
4949 *
4950 * parse the content of a RelaxNG grammar node.
4951 *
4952 * Returns 0 in case of success, -1 in case of error
4953 */
4954static int
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004955xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
Daniel Veillard6eadf632003-01-23 18:29:16 +00004956{
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004957 int ret = 0, tmp;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004958
4959 if (nodes == NULL) {
4960 if (ctxt->error != NULL)
4961 ctxt->error(ctxt->userData,
4962 "grammar has no children\n");
4963 ctxt->nbErrors++;
4964 return(-1);
4965 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00004966 while (nodes != NULL) {
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004967 if (IS_RELAXNG(nodes, "start")) {
4968 if (nodes->children == NULL) {
4969 if (ctxt->error != NULL)
4970 ctxt->error(ctxt->userData,
Daniel Veillardd2298792003-02-14 16:54:11 +00004971 "start has no children\n");
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004972 ctxt->nbErrors++;
4973 } else {
4974 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
4975 if (tmp != 0)
4976 ret = -1;
4977 }
4978 } else if (IS_RELAXNG(nodes, "define")) {
4979 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
4980 if (tmp != 0)
4981 ret = -1;
4982 } else if (IS_RELAXNG(nodes, "include")) {
4983 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
4984 if (tmp != 0)
4985 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00004986 } else {
4987 if (ctxt->error != NULL)
4988 ctxt->error(ctxt->userData,
Daniel Veillarde2a5a082003-02-02 14:35:17 +00004989 "grammar has unexpected child %s\n", nodes->name);
Daniel Veillard6eadf632003-01-23 18:29:16 +00004990 ctxt->nbErrors++;
4991 ret = -1;
4992 }
4993 nodes = nodes->next;
4994 }
4995 return (ret);
4996}
4997
4998/**
4999 * xmlRelaxNGCheckReference:
5000 * @ref: the ref
5001 * @ctxt: a Relax-NG parser context
5002 * @name: the name associated to the defines
5003 *
5004 * Applies the 4.17. combine attribute rule for all the define
5005 * element of a given grammar using the same name.
5006 */
5007static void
5008xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
5009 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5010 xmlRelaxNGGrammarPtr grammar;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005011 xmlRelaxNGDefinePtr def, cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005012
5013 grammar = ctxt->grammar;
5014 if (grammar == NULL) {
5015 if (ctxt->error != NULL)
5016 ctxt->error(ctxt->userData,
5017 "Internal error: no grammar in CheckReference %s\n",
5018 name);
5019 ctxt->nbErrors++;
5020 return;
5021 }
5022 if (ref->content != NULL) {
5023 if (ctxt->error != NULL)
5024 ctxt->error(ctxt->userData,
5025 "Internal error: reference has content in CheckReference %s\n",
5026 name);
5027 ctxt->nbErrors++;
5028 return;
5029 }
5030 if (grammar->defs != NULL) {
5031 def = xmlHashLookup(grammar->defs, name);
5032 if (def != NULL) {
Daniel Veillard276be4a2003-01-24 01:03:34 +00005033 cur = ref;
5034 while (cur != NULL) {
5035 cur->content = def;
5036 cur = cur->nextHash;
5037 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005038 } else {
Daniel Veillardd4310742003-02-18 21:12:46 +00005039 if (ctxt->error != NULL)
5040 ctxt->error(ctxt->userData,
5041 "Reference %s has no matching definition\n",
5042 name);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00005043 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005044 }
Daniel Veillardd4310742003-02-18 21:12:46 +00005045 } else {
5046 if (ctxt->error != NULL)
5047 ctxt->error(ctxt->userData,
5048 "Reference %s has no matching definition\n",
5049 name);
5050 ctxt->nbErrors++;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005051 }
5052 /*
5053 * TODO: make a closure and verify there is no loop !
5054 */
5055}
5056
5057/**
5058 * xmlRelaxNGCheckCombine:
5059 * @define: the define(s) list
5060 * @ctxt: a Relax-NG parser context
5061 * @name: the name associated to the defines
5062 *
5063 * Applies the 4.17. combine attribute rule for all the define
5064 * element of a given grammar using the same name.
5065 */
5066static void
5067xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
5068 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
5069 xmlChar *combine;
5070 int choiceOrInterleave = -1;
5071 int missing = 0;
5072 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
5073
5074 if (define->nextHash == NULL)
5075 return;
5076 cur = define;
5077 while (cur != NULL) {
5078 combine = xmlGetProp(cur->node, BAD_CAST "combine");
5079 if (combine != NULL) {
5080 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5081 if (choiceOrInterleave == -1)
5082 choiceOrInterleave = 1;
5083 else if (choiceOrInterleave == 0) {
5084 if (ctxt->error != NULL)
5085 ctxt->error(ctxt->userData,
5086 "Defines for %s use both 'choice' and 'interleave'\n",
5087 name);
5088 ctxt->nbErrors++;
5089 }
Daniel Veillard154877e2003-01-30 12:17:05 +00005090 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005091 if (choiceOrInterleave == -1)
5092 choiceOrInterleave = 0;
5093 else if (choiceOrInterleave == 1) {
5094 if (ctxt->error != NULL)
5095 ctxt->error(ctxt->userData,
5096 "Defines for %s use both 'choice' and 'interleave'\n",
5097 name);
5098 ctxt->nbErrors++;
5099 }
5100 } else {
5101 if (ctxt->error != NULL)
5102 ctxt->error(ctxt->userData,
5103 "Defines for %s use unknown combine value '%s''\n",
5104 name, combine);
5105 ctxt->nbErrors++;
5106 }
5107 xmlFree(combine);
5108 } else {
5109 if (missing == 0)
5110 missing = 1;
5111 else {
5112 if (ctxt->error != NULL)
5113 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005114 "Some defines for %s needs the combine attribute\n",
Daniel Veillard6eadf632003-01-23 18:29:16 +00005115 name);
5116 ctxt->nbErrors++;
5117 }
5118 }
5119
5120 cur = cur->nextHash;
5121 }
5122#ifdef DEBUG
5123 xmlGenericError(xmlGenericErrorContext,
5124 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5125 name, choiceOrInterleave);
5126#endif
5127 if (choiceOrInterleave == -1)
5128 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005129 cur = xmlRelaxNGNewDefine(ctxt, define->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005130 if (cur == NULL)
5131 return;
5132 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005133 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005134 else
5135 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005136 tmp = define;
5137 last = NULL;
5138 while (tmp != NULL) {
5139 if (tmp->content != NULL) {
5140 if (tmp->content->next != NULL) {
5141 /*
5142 * we need first to create a wrapper.
5143 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00005144 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005145 if (tmp2 == NULL)
5146 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005147 tmp2->type = XML_RELAXNG_GROUP;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005148 tmp2->content = tmp->content;
5149 } else {
5150 tmp2 = tmp->content;
5151 }
5152 if (last == NULL) {
5153 cur->content = tmp2;
5154 } else {
5155 last->next = tmp2;
5156 }
5157 last = tmp2;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005158 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005159 tmp->content = cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005160 tmp = tmp->nextHash;
5161 }
5162 define->content = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005163 if (choiceOrInterleave == 0) {
5164 if (ctxt->interleaves == NULL)
5165 ctxt->interleaves = xmlHashCreate(10);
5166 if (ctxt->interleaves == NULL) {
5167 if (ctxt->error != NULL)
5168 ctxt->error(ctxt->userData,
5169 "Failed to create interleaves hash table\n");
5170 ctxt->nbErrors++;
5171 } else {
5172 char tmpname[32];
5173
5174 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5175 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5176 if (ctxt->error != NULL)
5177 ctxt->error(ctxt->userData,
5178 "Failed to add %s to hash table\n", tmpname);
5179 ctxt->nbErrors++;
5180 }
5181 }
5182 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005183}
5184
5185/**
5186 * xmlRelaxNGCombineStart:
5187 * @ctxt: a Relax-NG parser context
5188 * @grammar: the grammar
5189 *
5190 * Applies the 4.17. combine rule for all the start
5191 * element of a given grammar.
5192 */
5193static void
5194xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
5195 xmlRelaxNGGrammarPtr grammar) {
5196 xmlRelaxNGDefinePtr starts;
5197 xmlChar *combine;
5198 int choiceOrInterleave = -1;
5199 int missing = 0;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005200 xmlRelaxNGDefinePtr cur;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005201
Daniel Veillard2df2de22003-02-17 23:34:33 +00005202 starts = grammar->start;
5203 if ((starts == NULL) || (starts->next == NULL))
Daniel Veillard6eadf632003-01-23 18:29:16 +00005204 return;
5205 cur = starts;
5206 while (cur != NULL) {
Daniel Veillard2df2de22003-02-17 23:34:33 +00005207 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
5208 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
5209 combine = NULL;
5210 if (ctxt->error != NULL)
5211 ctxt->error(ctxt->userData,
5212 "Internal error: start element not found\n");
5213 ctxt->nbErrors++;
5214 } else {
5215 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
5216 }
5217
Daniel Veillard6eadf632003-01-23 18:29:16 +00005218 if (combine != NULL) {
5219 if (xmlStrEqual(combine, BAD_CAST "choice")) {
5220 if (choiceOrInterleave == -1)
5221 choiceOrInterleave = 1;
5222 else if (choiceOrInterleave == 0) {
5223 if (ctxt->error != NULL)
5224 ctxt->error(ctxt->userData,
5225 "<start> use both 'choice' and 'interleave'\n");
5226 ctxt->nbErrors++;
5227 }
Daniel Veillard2df2de22003-02-17 23:34:33 +00005228 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00005229 if (choiceOrInterleave == -1)
5230 choiceOrInterleave = 0;
5231 else if (choiceOrInterleave == 1) {
5232 if (ctxt->error != NULL)
5233 ctxt->error(ctxt->userData,
5234 "<start> use both 'choice' and 'interleave'\n");
5235 ctxt->nbErrors++;
5236 }
5237 } else {
5238 if (ctxt->error != NULL)
5239 ctxt->error(ctxt->userData,
5240 "<start> uses unknown combine value '%s''\n", combine);
5241 ctxt->nbErrors++;
5242 }
5243 xmlFree(combine);
5244 } else {
5245 if (missing == 0)
5246 missing = 1;
5247 else {
5248 if (ctxt->error != NULL)
5249 ctxt->error(ctxt->userData,
Daniel Veillardc482e262003-02-26 14:48:48 +00005250 "Some <start> element miss the combine attribute\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00005251 ctxt->nbErrors++;
5252 }
5253 }
5254
Daniel Veillard2df2de22003-02-17 23:34:33 +00005255 cur = cur->next;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005256 }
5257#ifdef DEBUG
5258 xmlGenericError(xmlGenericErrorContext,
5259 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5260 choiceOrInterleave);
5261#endif
5262 if (choiceOrInterleave == -1)
5263 choiceOrInterleave = 0;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005264 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005265 if (cur == NULL)
5266 return;
5267 if (choiceOrInterleave == 0)
Daniel Veillard6eadf632003-01-23 18:29:16 +00005268 cur->type = XML_RELAXNG_INTERLEAVE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005269 else
5270 cur->type = XML_RELAXNG_CHOICE;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005271 cur->content = grammar->start;
5272 grammar->start = cur;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005273 if (choiceOrInterleave == 0) {
5274 if (ctxt->interleaves == NULL)
5275 ctxt->interleaves = xmlHashCreate(10);
5276 if (ctxt->interleaves == NULL) {
5277 if (ctxt->error != NULL)
5278 ctxt->error(ctxt->userData,
5279 "Failed to create interleaves hash table\n");
5280 ctxt->nbErrors++;
5281 } else {
5282 char tmpname[32];
5283
5284 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
5285 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
5286 if (ctxt->error != NULL)
5287 ctxt->error(ctxt->userData,
5288 "Failed to add %s to hash table\n", tmpname);
5289 ctxt->nbErrors++;
5290 }
5291 }
5292 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005293}
5294
5295/**
Daniel Veillardd4310742003-02-18 21:12:46 +00005296 * xmlRelaxNGCheckCycles:
5297 * @ctxt: a Relax-NG parser context
5298 * @nodes: grammar children nodes
5299 * @depth: the counter
5300 *
5301 * Check for cycles.
5302 *
5303 * Returns 0 if check passed, and -1 in case of error
5304 */
5305static int
5306xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
5307 xmlRelaxNGDefinePtr cur, int depth) {
5308 int ret = 0;
5309
5310 while ((ret == 0) && (cur != NULL)) {
5311 if ((cur->type == XML_RELAXNG_REF) ||
5312 (cur->type == XML_RELAXNG_PARENTREF)) {
5313 if (cur->depth == -1) {
5314 cur->depth = depth;
5315 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
5316 cur->depth = -2;
5317 } else if (depth == cur->depth) {
5318 if (ctxt->error != NULL)
5319 ctxt->error(ctxt->userData,
5320 "Detected a cycle in %s references\n", cur->name);
5321 ctxt->nbErrors++;
5322 return(-1);
5323 }
5324 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5325 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
5326 } else {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005327 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
Daniel Veillardd4310742003-02-18 21:12:46 +00005328 }
5329 cur = cur->next;
5330 }
5331 return(ret);
5332}
5333
5334/**
Daniel Veillard77648bb2003-02-20 15:03:22 +00005335 * xmlRelaxNGTryUnlink:
5336 * @ctxt: a Relax-NG parser context
5337 * @cur: the definition to unlink
5338 * @parent: the parent definition
5339 * @prev: the previous sibling definition
5340 *
5341 * Try to unlink a definition. If not possble make it a NOOP
5342 *
5343 * Returns the new prev definition
5344 */
5345static xmlRelaxNGDefinePtr
5346xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
5347 xmlRelaxNGDefinePtr cur,
5348 xmlRelaxNGDefinePtr parent,
5349 xmlRelaxNGDefinePtr prev) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005350 if (prev != NULL) {
5351 prev->next = cur->next;
5352 } else {
5353 if (parent != NULL) {
5354 if (parent->content == cur)
5355 parent->content = cur->next;
5356 else if (parent->attrs == cur)
5357 parent->attrs = cur->next;
5358 else if (parent->nameClass == cur)
5359 parent->nameClass = cur->next;
5360 } else {
5361 cur->type = XML_RELAXNG_NOOP;
5362 prev = cur;
5363 }
5364 }
5365 return(prev);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005366}
5367
5368/**
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005369 * xmlRelaxNGSimplify:
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005370 * @ctxt: a Relax-NG parser context
5371 * @nodes: grammar children nodes
5372 *
5373 * Check for simplification of empty and notAllowed
5374 */
5375static void
5376xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
5377 xmlRelaxNGDefinePtr cur,
5378 xmlRelaxNGDefinePtr parent) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005379 xmlRelaxNGDefinePtr prev = NULL;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005380
Daniel Veillardfd573f12003-03-16 17:52:32 +00005381 while (cur != NULL) {
5382 if ((cur->type == XML_RELAXNG_REF) ||
5383 (cur->type == XML_RELAXNG_PARENTREF)) {
5384 if (cur->depth != -3) {
5385 cur->depth = -3;
5386 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005387 }
5388 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005389 cur->parent = parent;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005390 if ((parent != NULL) &&
5391 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5392 (parent->type == XML_RELAXNG_LIST) ||
5393 (parent->type == XML_RELAXNG_GROUP) ||
5394 (parent->type == XML_RELAXNG_INTERLEAVE) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00005395 (parent->type == XML_RELAXNG_ONEORMORE) ||
5396 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005397 parent->type = XML_RELAXNG_NOT_ALLOWED;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005398 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005399 }
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005400 if ((parent != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00005401 (parent->type == XML_RELAXNG_CHOICE)) {
5402 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5403 } else
5404 prev = cur;
5405 } else if (cur->type == XML_RELAXNG_EMPTY){
5406 cur->parent = parent;
5407 if ((parent != NULL) &&
5408 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5409 (parent->type == XML_RELAXNG_ZEROORMORE))) {
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005410 parent->type = XML_RELAXNG_EMPTY;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005411 break;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005412 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005413 if ((parent != NULL) &&
5414 ((parent->type == XML_RELAXNG_GROUP) ||
5415 (parent->type == XML_RELAXNG_INTERLEAVE))) {
5416 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5417 } else
5418 prev = cur;
5419 } else {
5420 cur->parent = parent;
5421 if (cur->content != NULL)
5422 xmlRelaxNGSimplify(ctxt, cur->content, cur);
Daniel Veillarde637c4a2003-03-30 21:10:09 +00005423 if ((cur->type != XML_RELAXNG_VALUE) && (cur->attrs != NULL))
Daniel Veillardfd573f12003-03-16 17:52:32 +00005424 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
5425 if (cur->nameClass != NULL)
5426 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
5427 /*
5428 * This may result in a simplification
5429 */
5430 if ((cur->type == XML_RELAXNG_GROUP) ||
5431 (cur->type == XML_RELAXNG_INTERLEAVE)) {
5432 if (cur->content == NULL)
5433 cur->type = XML_RELAXNG_EMPTY;
5434 else if (cur->content->next == NULL) {
5435 if ((parent == NULL) && (prev == NULL)) {
5436 cur->type = XML_RELAXNG_NOOP;
5437 } else if (prev == NULL) {
5438 parent->content = cur->content;
5439 cur->content->next = cur->next;
5440 cur = cur->content;
5441 } else {
5442 cur->content->next = cur->next;
5443 prev->next = cur->content;
5444 cur = cur->content;
5445 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005446 }
5447 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005448 /*
5449 * the current node may have been transformed back
5450 */
5451 if ((cur->type == XML_RELAXNG_EXCEPT) &&
5452 (cur->content != NULL) &&
5453 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
5454 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5455 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
5456 if ((parent != NULL) &&
5457 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
5458 (parent->type == XML_RELAXNG_LIST) ||
5459 (parent->type == XML_RELAXNG_GROUP) ||
5460 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5461 (parent->type == XML_RELAXNG_ONEORMORE) ||
5462 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5463 parent->type = XML_RELAXNG_NOT_ALLOWED;
5464 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005465 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005466 if ((parent != NULL) &&
5467 (parent->type == XML_RELAXNG_CHOICE)) {
5468 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5469 } else
5470 prev = cur;
5471 } else if (cur->type == XML_RELAXNG_EMPTY){
5472 if ((parent != NULL) &&
5473 ((parent->type == XML_RELAXNG_ONEORMORE) ||
5474 (parent->type == XML_RELAXNG_ZEROORMORE))) {
5475 parent->type = XML_RELAXNG_EMPTY;
5476 break;
5477 }
5478 if ((parent != NULL) &&
5479 ((parent->type == XML_RELAXNG_GROUP) ||
5480 (parent->type == XML_RELAXNG_INTERLEAVE) ||
5481 (parent->type == XML_RELAXNG_CHOICE))) {
5482 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
5483 } else
5484 prev = cur;
5485 } else {
5486 prev = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005487 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005488 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005489 cur = cur->next;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005490 }
5491}
5492
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005493/**
5494 * xmlRelaxNGGroupContentType:
5495 * @ct1: the first content type
5496 * @ct2: the second content type
5497 *
5498 * Try to group 2 content types
5499 *
5500 * Returns the content type
5501 */
5502static xmlRelaxNGContentType
5503xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
5504 xmlRelaxNGContentType ct2) {
5505 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5506 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5507 return(XML_RELAXNG_CONTENT_ERROR);
5508 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
5509 return(ct2);
5510 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
5511 return(ct1);
5512 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
5513 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5514 return(XML_RELAXNG_CONTENT_COMPLEX);
5515 return(XML_RELAXNG_CONTENT_ERROR);
5516}
5517
5518/**
5519 * xmlRelaxNGMaxContentType:
5520 * @ct1: the first content type
5521 * @ct2: the second content type
5522 *
5523 * Compute the max content-type
5524 *
5525 * Returns the content type
5526 */
5527static xmlRelaxNGContentType
5528xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
5529 xmlRelaxNGContentType ct2) {
5530 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
5531 (ct2 == XML_RELAXNG_CONTENT_ERROR))
5532 return(XML_RELAXNG_CONTENT_ERROR);
5533 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
5534 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
5535 return(XML_RELAXNG_CONTENT_SIMPLE);
5536 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
5537 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
5538 return(XML_RELAXNG_CONTENT_COMPLEX);
5539 return(XML_RELAXNG_CONTENT_EMPTY);
5540}
Daniel Veillard77648bb2003-02-20 15:03:22 +00005541
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005542/**
5543 * xmlRelaxNGCheckRules:
5544 * @ctxt: a Relax-NG parser context
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005545 * @cur: the current definition
Daniel Veillard77648bb2003-02-20 15:03:22 +00005546 * @flags: some accumulated flags
Daniel Veillardfd573f12003-03-16 17:52:32 +00005547 * @ptype: the parent type
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005548 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005549 * Check for rules in section 7.1 and 7.2
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005550 *
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005551 * Returns the content type of @cur
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005552 */
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005553static xmlRelaxNGContentType
Daniel Veillardfd573f12003-03-16 17:52:32 +00005554xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
5555 xmlRelaxNGDefinePtr cur, int flags,
5556 xmlRelaxNGType ptype) {
Daniel Veillard4c5cf702003-02-21 15:40:34 +00005557 int nflags = flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00005558 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005559
Daniel Veillardfd573f12003-03-16 17:52:32 +00005560 while (cur != NULL) {
5561 ret = XML_RELAXNG_CONTENT_EMPTY;
5562 if ((cur->type == XML_RELAXNG_REF) ||
5563 (cur->type == XML_RELAXNG_PARENTREF)) {
5564 if (flags & XML_RELAXNG_IN_LIST) {
5565 if (ctxt->error != NULL)
5566 ctxt->error(ctxt->userData,
5567 "Found forbidden pattern list//ref\n");
5568 ctxt->nbErrors++;
5569 }
5570 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5571 if (ctxt->error != NULL)
5572 ctxt->error(ctxt->userData,
5573 "Found forbidden pattern data/except//ref\n");
5574 ctxt->nbErrors++;
5575 }
5576 if (cur->depth > -4) {
5577 cur->depth = -4;
5578 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
5579 flags, cur->type);
5580 cur->depth = ret - 15 ;
5581 } else if (cur->depth == -4) {
5582 ret = XML_RELAXNG_CONTENT_COMPLEX;
5583 } else {
5584 ret = (xmlRelaxNGContentType) cur->depth + 15;
5585 }
5586 } else if (cur->type == XML_RELAXNG_ELEMENT) {
5587 /*
5588 * The 7.3 Attribute derivation rule for groups is plugged there
5589 */
5590 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5591 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5592 if (ctxt->error != NULL)
5593 ctxt->error(ctxt->userData,
5594 "Found forbidden pattern data/except//element(ref)\n");
5595 ctxt->nbErrors++;
5596 }
5597 if (flags & XML_RELAXNG_IN_LIST) {
5598 if (ctxt->error != NULL)
5599 ctxt->error(ctxt->userData,
5600 "Found forbidden pattern list//element(ref)\n");
5601 ctxt->nbErrors++;
5602 }
5603 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5604 if (ctxt->error != NULL)
5605 ctxt->error(ctxt->userData,
5606 "Found forbidden pattern attribute//element(ref)\n");
5607 ctxt->nbErrors++;
5608 }
5609 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5610 if (ctxt->error != NULL)
5611 ctxt->error(ctxt->userData,
Daniel Veillard463a5472003-02-27 21:30:32 +00005612 "Found forbidden pattern attribute//element(ref)\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005613 ctxt->nbErrors++;
5614 }
5615 /*
5616 * reset since in the simple form elements are only child
5617 * of grammar/define
5618 */
5619 nflags = 0;
5620 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
5621 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
5622 if (ctxt->error != NULL)
5623 ctxt->error(ctxt->userData,
5624 "Element %s attributes have a content type error\n",
5625 cur->name);
5626 ctxt->nbErrors++;
5627 }
5628 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5629 if (ret == XML_RELAXNG_CONTENT_ERROR) {
5630 if (ctxt->error != NULL)
5631 ctxt->error(ctxt->userData,
5632 "Element %s has a content type error\n",
5633 cur->name);
5634 ctxt->nbErrors++;
5635 } else {
5636 ret = XML_RELAXNG_CONTENT_COMPLEX;
5637 }
5638 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
5639 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
5640 if (ctxt->error != NULL)
5641 ctxt->error(ctxt->userData,
5642 "Found forbidden pattern attribute//attribute\n");
5643 ctxt->nbErrors++;
5644 }
5645 if (flags & XML_RELAXNG_IN_LIST) {
5646 if (ctxt->error != NULL)
5647 ctxt->error(ctxt->userData,
5648 "Found forbidden pattern list//attribute\n");
5649 ctxt->nbErrors++;
5650 }
5651 if (flags & XML_RELAXNG_IN_OOMGROUP) {
5652 if (ctxt->error != NULL)
5653 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005654 "Found forbidden pattern oneOrMore//group//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005655 ctxt->nbErrors++;
5656 }
5657 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
5658 if (ctxt->error != NULL)
5659 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005660 "Found forbidden pattern oneOrMore//interleave//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005661 ctxt->nbErrors++;
5662 }
5663 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5664 if (ctxt->error != NULL)
5665 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005666 "Found forbidden pattern data/except//attribute\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005667 ctxt->nbErrors++;
5668 }
5669 if (flags & XML_RELAXNG_IN_START) {
5670 if (ctxt->error != NULL)
5671 ctxt->error(ctxt->userData,
5672 "Found forbidden pattern start//attribute\n");
5673 ctxt->nbErrors++;
5674 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00005675 if ((!(flags & XML_RELAXNG_IN_ONEORMORE)) && (cur->name == NULL)) {
5676 if (cur->ns == NULL) {
5677 if (ctxt->error != NULL)
5678 ctxt->error(ctxt->userData,
5679 "Found anyName attribute without oneOrMore ancestor\n");
5680 ctxt->nbErrors++;
5681 } else {
5682 if (ctxt->error != NULL)
5683 ctxt->error(ctxt->userData,
5684 "Found nsName attribute without oneOrMore ancestor\n");
5685 ctxt->nbErrors++;
5686 }
Daniel Veillard77648bb2003-02-20 15:03:22 +00005687 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005688 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
5689 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5690 ret = XML_RELAXNG_CONTENT_EMPTY;
5691 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
5692 (cur->type == XML_RELAXNG_ZEROORMORE)) {
5693 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5694 if (ctxt->error != NULL)
5695 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005696 "Found forbidden pattern data/except//oneOrMore\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005697 ctxt->nbErrors++;
5698 }
5699 if (flags & XML_RELAXNG_IN_START) {
5700 if (ctxt->error != NULL)
5701 ctxt->error(ctxt->userData,
5702 "Found forbidden pattern start//oneOrMore\n");
5703 ctxt->nbErrors++;
5704 }
5705 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
5706 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5707 ret = xmlRelaxNGGroupContentType(ret, ret);
5708 } else if (cur->type == XML_RELAXNG_LIST) {
5709 if (flags & XML_RELAXNG_IN_LIST) {
5710 if (ctxt->error != NULL)
5711 ctxt->error(ctxt->userData,
5712 "Found forbidden pattern list//list\n");
5713 ctxt->nbErrors++;
5714 }
5715 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5716 if (ctxt->error != NULL)
5717 ctxt->error(ctxt->userData,
5718 "Found forbidden pattern data/except//list\n");
5719 ctxt->nbErrors++;
5720 }
5721 if (flags & XML_RELAXNG_IN_START) {
5722 if (ctxt->error != NULL)
5723 ctxt->error(ctxt->userData,
5724 "Found forbidden pattern start//list\n");
5725 ctxt->nbErrors++;
5726 }
5727 nflags = flags | XML_RELAXNG_IN_LIST;
5728 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5729 } else if (cur->type == XML_RELAXNG_GROUP) {
5730 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5731 if (ctxt->error != NULL)
5732 ctxt->error(ctxt->userData,
5733 "Found forbidden pattern data/except//group\n");
5734 ctxt->nbErrors++;
5735 }
5736 if (flags & XML_RELAXNG_IN_START) {
5737 if (ctxt->error != NULL)
5738 ctxt->error(ctxt->userData,
5739 "Found forbidden pattern start//group\n");
5740 ctxt->nbErrors++;
5741 }
5742 if (flags & XML_RELAXNG_IN_ONEORMORE)
5743 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
5744 else
5745 nflags = flags;
5746 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5747 /*
5748 * The 7.3 Attribute derivation rule for groups is plugged there
5749 */
5750 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
5751 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
5752 if (flags & XML_RELAXNG_IN_LIST) {
5753 if (ctxt->error != NULL)
5754 ctxt->error(ctxt->userData,
5755 "Found forbidden pattern list//interleave\n");
5756 ctxt->nbErrors++;
5757 }
5758 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5759 if (ctxt->error != NULL)
5760 ctxt->error(ctxt->userData,
Daniel Veillard77648bb2003-02-20 15:03:22 +00005761 "Found forbidden pattern data/except//interleave\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00005762 ctxt->nbErrors++;
5763 }
5764 if (flags & XML_RELAXNG_IN_START) {
5765 if (ctxt->error != NULL)
5766 ctxt->error(ctxt->userData,
5767 "Found forbidden pattern start//interleave\n");
5768 ctxt->nbErrors++;
5769 }
5770 if (flags & XML_RELAXNG_IN_ONEORMORE)
5771 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
5772 else
5773 nflags = flags;
5774 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5775 } else if (cur->type == XML_RELAXNG_EXCEPT) {
5776 if ((cur->parent != NULL) &&
5777 (cur->parent->type == XML_RELAXNG_DATATYPE))
5778 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
5779 else
5780 nflags = flags;
5781 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
5782 } else if (cur->type == XML_RELAXNG_DATATYPE) {
5783 if (flags & XML_RELAXNG_IN_START) {
5784 if (ctxt->error != NULL)
5785 ctxt->error(ctxt->userData,
5786 "Found forbidden pattern start//data\n");
5787 ctxt->nbErrors++;
5788 }
5789 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5790 ret = XML_RELAXNG_CONTENT_SIMPLE;
5791 } else if (cur->type == XML_RELAXNG_VALUE) {
5792 if (flags & XML_RELAXNG_IN_START) {
5793 if (ctxt->error != NULL)
5794 ctxt->error(ctxt->userData,
5795 "Found forbidden pattern start//value\n");
5796 ctxt->nbErrors++;
5797 }
5798 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5799 ret = XML_RELAXNG_CONTENT_SIMPLE;
5800 } else if (cur->type == XML_RELAXNG_TEXT) {
5801 if (flags & XML_RELAXNG_IN_LIST) {
5802 if (ctxt->error != NULL)
5803 ctxt->error(ctxt->userData,
5804 "Found forbidden pattern list//text\n");
5805 ctxt->nbErrors++;
5806 }
5807 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5808 if (ctxt->error != NULL)
5809 ctxt->error(ctxt->userData,
5810 "Found forbidden pattern data/except//text\n");
5811 ctxt->nbErrors++;
5812 }
5813 if (flags & XML_RELAXNG_IN_START) {
5814 if (ctxt->error != NULL)
5815 ctxt->error(ctxt->userData,
5816 "Found forbidden pattern start//text\n");
5817 ctxt->nbErrors++;
5818 }
5819 ret = XML_RELAXNG_CONTENT_COMPLEX;
5820 } else if (cur->type == XML_RELAXNG_EMPTY) {
5821 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
5822 if (ctxt->error != NULL)
5823 ctxt->error(ctxt->userData,
5824 "Found forbidden pattern data/except//empty\n");
5825 ctxt->nbErrors++;
5826 }
5827 if (flags & XML_RELAXNG_IN_START) {
5828 if (ctxt->error != NULL)
5829 ctxt->error(ctxt->userData,
5830 "Found forbidden pattern start//empty\n");
5831 ctxt->nbErrors++;
5832 }
5833 ret = XML_RELAXNG_CONTENT_EMPTY;
5834 } else if (cur->type == XML_RELAXNG_CHOICE) {
5835 xmlRelaxNGCheckChoiceDeterminism(ctxt, cur);
5836 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5837 } else {
5838 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
5839 }
5840 cur = cur->next;
5841 if (ptype == XML_RELAXNG_GROUP) {
5842 val = xmlRelaxNGGroupContentType(val, ret);
5843 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
5844 tmp = xmlRelaxNGGroupContentType(val, ret);
5845 if (tmp != XML_RELAXNG_CONTENT_ERROR)
5846 tmp = xmlRelaxNGMaxContentType(val, ret);
5847 } else if (ptype == XML_RELAXNG_CHOICE) {
5848 val = xmlRelaxNGMaxContentType(val, ret);
5849 } else if (ptype == XML_RELAXNG_LIST) {
5850 val = XML_RELAXNG_CONTENT_SIMPLE;
5851 } else if (ptype == XML_RELAXNG_EXCEPT) {
5852 if (ret == XML_RELAXNG_CONTENT_ERROR)
5853 val = XML_RELAXNG_CONTENT_ERROR;
5854 else
5855 val = XML_RELAXNG_CONTENT_SIMPLE;
5856 } else {
5857 val = xmlRelaxNGGroupContentType(val, ret);
5858 }
5859
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005860 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00005861 return(val);
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005862}
Daniel Veillard1c745ad2003-02-20 00:11:02 +00005863
5864/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00005865 * xmlRelaxNGParseGrammar:
5866 * @ctxt: a Relax-NG parser context
5867 * @nodes: grammar children nodes
5868 *
5869 * parse a Relax-NG <grammar> node
5870 *
5871 * Returns the internal xmlRelaxNGGrammarPtr built or
5872 * NULL in case of error
5873 */
5874static xmlRelaxNGGrammarPtr
5875xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
5876 xmlRelaxNGGrammarPtr ret, tmp, old;
5877
Daniel Veillardc482e262003-02-26 14:48:48 +00005878#ifdef DEBUG_GRAMMAR
5879 xmlGenericError(xmlGenericErrorContext, "Parsing a new grammar\n");
5880#endif
5881
Daniel Veillard6eadf632003-01-23 18:29:16 +00005882 ret = xmlRelaxNGNewGrammar(ctxt);
5883 if (ret == NULL)
5884 return(NULL);
5885
5886 /*
5887 * Link the new grammar in the tree
5888 */
5889 ret->parent = ctxt->grammar;
5890 if (ctxt->grammar != NULL) {
5891 tmp = ctxt->grammar->children;
5892 if (tmp == NULL) {
5893 ctxt->grammar->children = ret;
5894 } else {
5895 while (tmp->next != NULL)
5896 tmp = tmp->next;
5897 tmp->next = ret;
5898 }
5899 }
5900
5901 old = ctxt->grammar;
5902 ctxt->grammar = ret;
5903 xmlRelaxNGParseGrammarContent(ctxt, nodes);
5904 ctxt->grammar = ret;
Daniel Veillard2df2de22003-02-17 23:34:33 +00005905 if (ctxt->grammar == NULL) {
5906 if (ctxt->error != NULL)
5907 ctxt->error(ctxt->userData,
5908 "Failed to parse <grammar> content\n");
5909 ctxt->nbErrors++;
5910 } else if (ctxt->grammar->start == NULL) {
5911 if (ctxt->error != NULL)
5912 ctxt->error(ctxt->userData,
5913 "Element <grammar> has no <start>\n");
5914 ctxt->nbErrors++;
5915 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00005916
5917 /*
5918 * Apply 4.17 mergingd rules to defines and starts
5919 */
5920 xmlRelaxNGCombineStart(ctxt, ret);
5921 if (ret->defs != NULL) {
5922 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
5923 ctxt);
5924 }
5925
5926 /*
5927 * link together defines and refs in this grammar
5928 */
5929 if (ret->refs != NULL) {
5930 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
5931 ctxt);
5932 }
Daniel Veillard952379b2003-03-17 15:37:12 +00005933
Daniel Veillard6eadf632003-01-23 18:29:16 +00005934 ctxt->grammar = old;
5935 return(ret);
5936}
5937
5938/**
5939 * xmlRelaxNGParseDocument:
5940 * @ctxt: a Relax-NG parser context
5941 * @node: the root node of the RelaxNG schema
5942 *
5943 * parse a Relax-NG definition resource and build an internal
5944 * xmlRelaxNG struture which can be used to validate instances.
5945 *
5946 * Returns the internal XML RelaxNG structure built or
5947 * NULL in case of error
5948 */
5949static xmlRelaxNGPtr
5950xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
5951 xmlRelaxNGPtr schema = NULL;
Daniel Veillard276be4a2003-01-24 01:03:34 +00005952 const xmlChar *olddefine;
Daniel Veillarde431a272003-01-29 23:02:33 +00005953 xmlRelaxNGGrammarPtr old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005954
5955 if ((ctxt == NULL) || (node == NULL))
5956 return (NULL);
5957
5958 schema = xmlRelaxNGNewRelaxNG(ctxt);
5959 if (schema == NULL)
5960 return(NULL);
5961
Daniel Veillard276be4a2003-01-24 01:03:34 +00005962 olddefine = ctxt->define;
5963 ctxt->define = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005964 if (IS_RELAXNG(node, "grammar")) {
5965 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
5966 } else {
Daniel Veillardc482e262003-02-26 14:48:48 +00005967 xmlRelaxNGGrammarPtr tmp, ret;
5968
5969 schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
Daniel Veillard6eadf632003-01-23 18:29:16 +00005970 if (schema->topgrammar == NULL) {
5971 return(schema);
5972 }
Daniel Veillardc482e262003-02-26 14:48:48 +00005973 /*
5974 * Link the new grammar in the tree
5975 */
5976 ret->parent = ctxt->grammar;
5977 if (ctxt->grammar != NULL) {
5978 tmp = ctxt->grammar->children;
5979 if (tmp == NULL) {
5980 ctxt->grammar->children = ret;
5981 } else {
5982 while (tmp->next != NULL)
5983 tmp = tmp->next;
5984 tmp->next = ret;
5985 }
5986 }
Daniel Veillarde431a272003-01-29 23:02:33 +00005987 old = ctxt->grammar;
Daniel Veillardc482e262003-02-26 14:48:48 +00005988 ctxt->grammar = ret;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005989 xmlRelaxNGParseStart(ctxt, node);
Daniel Veillarde431a272003-01-29 23:02:33 +00005990 if (old != NULL)
5991 ctxt->grammar = old;
Daniel Veillard6eadf632003-01-23 18:29:16 +00005992 }
Daniel Veillard276be4a2003-01-24 01:03:34 +00005993 ctxt->define = olddefine;
Daniel Veillardd4310742003-02-18 21:12:46 +00005994 if (schema->topgrammar->start != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005995 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
Daniel Veillard77648bb2003-02-20 15:03:22 +00005996 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00005997 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
5998 while ((schema->topgrammar->start != NULL) &&
5999 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
6000 (schema->topgrammar->start->next != NULL))
6001 schema->topgrammar->start = schema->topgrammar->start->content;
6002 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
6003 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006004 }
Daniel Veillardd4310742003-02-18 21:12:46 +00006005 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006006
6007#ifdef DEBUG
6008 if (schema == NULL)
6009 xmlGenericError(xmlGenericErrorContext,
6010 "xmlRelaxNGParseDocument() failed\n");
6011#endif
6012
6013 return (schema);
6014}
6015
6016/************************************************************************
6017 * *
6018 * Reading RelaxNGs *
6019 * *
6020 ************************************************************************/
6021
6022/**
6023 * xmlRelaxNGNewParserCtxt:
6024 * @URL: the location of the schema
6025 *
6026 * Create an XML RelaxNGs parse context for that file/resource expected
6027 * to contain an XML RelaxNGs file.
6028 *
6029 * Returns the parser context or NULL in case of error
6030 */
6031xmlRelaxNGParserCtxtPtr
6032xmlRelaxNGNewParserCtxt(const char *URL) {
6033 xmlRelaxNGParserCtxtPtr ret;
6034
6035 if (URL == NULL)
6036 return(NULL);
6037
6038 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6039 if (ret == NULL) {
6040 xmlGenericError(xmlGenericErrorContext,
6041 "Failed to allocate new schama parser context for %s\n", URL);
6042 return (NULL);
6043 }
6044 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6045 ret->URL = xmlStrdup((const xmlChar *)URL);
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006046 ret->error = xmlGenericError;
6047 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006048 return (ret);
6049}
6050
6051/**
6052 * xmlRelaxNGNewMemParserCtxt:
6053 * @buffer: a pointer to a char array containing the schemas
6054 * @size: the size of the array
6055 *
6056 * Create an XML RelaxNGs parse context for that memory buffer expected
6057 * to contain an XML RelaxNGs file.
6058 *
6059 * Returns the parser context or NULL in case of error
6060 */
6061xmlRelaxNGParserCtxtPtr
6062xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
6063 xmlRelaxNGParserCtxtPtr ret;
6064
6065 if ((buffer == NULL) || (size <= 0))
6066 return(NULL);
6067
6068 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
6069 if (ret == NULL) {
6070 xmlGenericError(xmlGenericErrorContext,
6071 "Failed to allocate new schama parser context\n");
6072 return (NULL);
6073 }
6074 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
6075 ret->buffer = buffer;
6076 ret->size = size;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00006077 ret->error = xmlGenericError;
6078 ret->userData = xmlGenericErrorContext;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006079 return (ret);
6080}
6081
6082/**
6083 * xmlRelaxNGFreeParserCtxt:
6084 * @ctxt: the schema parser context
6085 *
6086 * Free the resources associated to the schema parser context
6087 */
6088void
6089xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
6090 if (ctxt == NULL)
6091 return;
6092 if (ctxt->URL != NULL)
6093 xmlFree(ctxt->URL);
6094 if (ctxt->doc != NULL)
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006095 xmlFreeDoc(ctxt->document);
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00006096 if (ctxt->interleaves != NULL)
6097 xmlHashFree(ctxt->interleaves, NULL);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006098 if (ctxt->documents != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006099 xmlRelaxNGFreeDocumentList(ctxt->documents);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006100 if (ctxt->includes != NULL)
Daniel Veillardc482e262003-02-26 14:48:48 +00006101 xmlRelaxNGFreeIncludeList(ctxt->includes);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006102 if (ctxt->docTab != NULL)
6103 xmlFree(ctxt->docTab);
Daniel Veillarda9d912d2003-02-01 17:43:10 +00006104 if (ctxt->incTab != NULL)
6105 xmlFree(ctxt->incTab);
Daniel Veillard419a7682003-02-03 23:22:49 +00006106 if (ctxt->defTab != NULL) {
6107 int i;
6108
6109 for (i = 0;i < ctxt->defNr;i++)
6110 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
6111 xmlFree(ctxt->defTab);
6112 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006113 xmlFree(ctxt);
6114}
6115
Daniel Veillard6eadf632003-01-23 18:29:16 +00006116/**
Daniel Veillardd2298792003-02-14 16:54:11 +00006117 * xmlRelaxNGNormExtSpace:
6118 * @value: a value
6119 *
6120 * Removes the leading and ending spaces of the value
6121 * The string is modified "in situ"
6122 */
6123static void
6124xmlRelaxNGNormExtSpace(xmlChar *value) {
6125 xmlChar *start = value;
6126 xmlChar *cur = value;
6127 if (value == NULL)
6128 return;
6129
6130 while (IS_BLANK(*cur)) cur++;
6131 if (cur == start) {
6132 do {
6133 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
6134 if (*cur == 0)
6135 return;
6136 start = cur;
6137 while (IS_BLANK(*cur)) cur++;
6138 if (*cur == 0) {
6139 *start = 0;
6140 return;
6141 }
6142 } while (1);
6143 } else {
6144 do {
6145 while ((*cur != 0) && (!IS_BLANK(*cur)))
6146 *start++ = *cur++;
6147 if (*cur == 0) {
6148 *start = 0;
6149 return;
6150 }
6151 /* don't try to normalize the inner spaces */
6152 while (IS_BLANK(*cur)) cur++;
6153 *start++ = *cur++;
6154 if (*cur == 0) {
6155 *start = 0;
6156 return;
6157 }
6158 } while (1);
6159 }
6160}
6161
6162/**
6163 * xmlRelaxNGCheckAttributes:
6164 * @ctxt: a Relax-NG parser context
6165 * @node: a Relax-NG node
6166 *
6167 * Check all the attributes on the given node
6168 */
6169static void
6170xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
6171 xmlAttrPtr cur, next;
6172
6173 cur = node->properties;
6174 while (cur != NULL) {
6175 next = cur->next;
6176 if ((cur->ns == NULL) ||
6177 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
6178 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6179 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
6180 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
6181 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
6182 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
Daniel Veillard2df2de22003-02-17 23:34:33 +00006183 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
Daniel Veillardd2298792003-02-14 16:54:11 +00006184 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6185 if (ctxt->error != NULL)
6186 ctxt->error(ctxt->userData,
6187 "Attribute %s is not allowed on %s\n",
6188 cur->name, node->name);
6189 ctxt->nbErrors++;
6190 }
6191 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
6192 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
6193 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
6194 if (ctxt->error != NULL)
6195 ctxt->error(ctxt->userData,
6196 "Attribute %s is not allowed on %s\n",
6197 cur->name, node->name);
6198 ctxt->nbErrors++;
6199 }
6200 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
6201 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
6202 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
6203 if (ctxt->error != NULL)
6204 ctxt->error(ctxt->userData,
6205 "Attribute %s is not allowed on %s\n",
6206 cur->name, node->name);
6207 ctxt->nbErrors++;
6208 }
6209 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
6210 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
6211 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
6212 if (ctxt->error != NULL)
6213 ctxt->error(ctxt->userData,
6214 "Attribute %s is not allowed on %s\n",
6215 cur->name, node->name);
6216 ctxt->nbErrors++;
6217 }
6218 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
6219 xmlChar *val;
6220 xmlURIPtr uri;
6221
6222 val = xmlNodeListGetString(node->doc, cur->children, 1);
6223 if (val != NULL) {
6224 if (val[0] != 0) {
6225 uri = xmlParseURI((const char *) val);
6226 if (uri == NULL) {
6227 if (ctxt->error != NULL)
6228 ctxt->error(ctxt->userData,
6229 "Attribute %s contains invalid URI %s\n",
6230 cur->name, val);
6231 ctxt->nbErrors++;
6232 } else {
6233 if (uri->scheme == NULL) {
6234 if (ctxt->error != NULL)
6235 ctxt->error(ctxt->userData,
6236 "Attribute %s URI %s is not absolute\n",
6237 cur->name, val);
6238 ctxt->nbErrors++;
6239 }
6240 if (uri->fragment != NULL) {
6241 if (ctxt->error != NULL)
6242 ctxt->error(ctxt->userData,
6243 "Attribute %s URI %s has a fragment ID\n",
6244 cur->name, val);
6245 ctxt->nbErrors++;
6246 }
6247 xmlFreeURI(uri);
6248 }
6249 }
6250 xmlFree(val);
6251 }
6252 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
6253 if (ctxt->error != NULL)
6254 ctxt->error(ctxt->userData,
6255 "Unknown attribute %s on %s\n",
6256 cur->name, node->name);
6257 ctxt->nbErrors++;
6258 }
6259 }
6260 cur = next;
6261 }
6262}
6263
6264/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00006265 * xmlRelaxNGCleanupTree:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006266 * @ctxt: a Relax-NG parser context
Daniel Veillardc5312d72003-02-21 17:14:10 +00006267 * @root: an xmlNodePtr subtree
Daniel Veillard6eadf632003-01-23 18:29:16 +00006268 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00006269 * Cleanup the subtree from unwanted nodes for parsing, resolve
6270 * Include and externalRef lookups.
Daniel Veillard6eadf632003-01-23 18:29:16 +00006271 */
Daniel Veillardc5312d72003-02-21 17:14:10 +00006272static void
Daniel Veillardfd573f12003-03-16 17:52:32 +00006273xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
Daniel Veillardc5312d72003-02-21 17:14:10 +00006274 xmlNodePtr cur, delete;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006275
Daniel Veillard6eadf632003-01-23 18:29:16 +00006276 delete = NULL;
6277 cur = root;
6278 while (cur != NULL) {
6279 if (delete != NULL) {
6280 xmlUnlinkNode(delete);
6281 xmlFreeNode(delete);
6282 delete = NULL;
6283 }
6284 if (cur->type == XML_ELEMENT_NODE) {
6285 /*
6286 * Simplification 4.1. Annotations
6287 */
6288 if ((cur->ns == NULL) ||
6289 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
Daniel Veillardd2298792003-02-14 16:54:11 +00006290 if ((cur->parent != NULL) &&
6291 (cur->parent->type == XML_ELEMENT_NODE) &&
6292 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
6293 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
6294 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
6295 if (ctxt->error != NULL)
6296 ctxt->error(ctxt->userData,
6297 "element %s doesn't allow foreign elements\n",
6298 cur->parent->name);
6299 ctxt->nbErrors++;
6300 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006301 delete = cur;
6302 goto skip_children;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006303 } else {
6304 xmlRelaxNGCleanupAttributes(ctxt, cur);
6305 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
6306 xmlChar *href, *ns, *base, *URL;
6307 xmlRelaxNGDocumentPtr docu;
6308 xmlNodePtr tmp;
6309
6310 ns = xmlGetProp(cur, BAD_CAST "ns");
6311 if (ns == NULL) {
6312 tmp = cur->parent;
6313 while ((tmp != NULL) &&
6314 (tmp->type == XML_ELEMENT_NODE)) {
6315 ns = xmlGetProp(tmp, BAD_CAST "ns");
6316 if (ns != NULL)
6317 break;
6318 tmp = tmp->parent;
6319 }
6320 }
6321 href = xmlGetProp(cur, BAD_CAST "href");
6322 if (href == NULL) {
6323 if (ctxt->error != NULL)
6324 ctxt->error(ctxt->userData,
6325 "xmlRelaxNGParse: externalRef has no href attribute\n");
6326 ctxt->nbErrors++;
6327 delete = cur;
6328 goto skip_children;
6329 }
6330 base = xmlNodeGetBase(cur->doc, cur);
6331 URL = xmlBuildURI(href, base);
6332 if (URL == NULL) {
6333 if (ctxt->error != NULL)
6334 ctxt->error(ctxt->userData,
6335 "Failed to compute URL for externalRef %s\n", href);
6336 ctxt->nbErrors++;
6337 if (href != NULL)
6338 xmlFree(href);
6339 if (base != NULL)
6340 xmlFree(base);
6341 delete = cur;
6342 goto skip_children;
6343 }
6344 if (href != NULL)
6345 xmlFree(href);
6346 if (base != NULL)
6347 xmlFree(base);
6348 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
6349 if (docu == NULL) {
6350 if (ctxt->error != NULL)
6351 ctxt->error(ctxt->userData,
6352 "Failed to load externalRef %s\n", URL);
6353 ctxt->nbErrors++;
6354 xmlFree(URL);
6355 delete = cur;
6356 goto skip_children;
6357 }
6358 if (ns != NULL)
6359 xmlFree(ns);
6360 xmlFree(URL);
6361 cur->_private = docu;
6362 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
6363 xmlChar *href, *ns, *base, *URL;
6364 xmlRelaxNGIncludePtr incl;
6365 xmlNodePtr tmp;
6366
6367 href = xmlGetProp(cur, BAD_CAST "href");
6368 if (href == NULL) {
6369 if (ctxt->error != NULL)
6370 ctxt->error(ctxt->userData,
6371 "xmlRelaxNGParse: include has no href attribute\n");
6372 ctxt->nbErrors++;
6373 delete = cur;
6374 goto skip_children;
6375 }
6376 base = xmlNodeGetBase(cur->doc, cur);
6377 URL = xmlBuildURI(href, base);
6378 if (URL == NULL) {
6379 if (ctxt->error != NULL)
6380 ctxt->error(ctxt->userData,
6381 "Failed to compute URL for include %s\n", href);
6382 ctxt->nbErrors++;
6383 if (href != NULL)
6384 xmlFree(href);
6385 if (base != NULL)
6386 xmlFree(base);
6387 delete = cur;
6388 goto skip_children;
6389 }
6390 if (href != NULL)
6391 xmlFree(href);
6392 if (base != NULL)
6393 xmlFree(base);
6394 ns = xmlGetProp(cur, BAD_CAST "ns");
6395 if (ns == NULL) {
6396 tmp = cur->parent;
6397 while ((tmp != NULL) &&
6398 (tmp->type == XML_ELEMENT_NODE)) {
6399 ns = xmlGetProp(tmp, BAD_CAST "ns");
6400 if (ns != NULL)
6401 break;
6402 tmp = tmp->parent;
6403 }
6404 }
6405 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
6406 if (ns != NULL)
6407 xmlFree(ns);
6408 if (incl == NULL) {
6409 if (ctxt->error != NULL)
6410 ctxt->error(ctxt->userData,
6411 "Failed to load include %s\n", URL);
6412 ctxt->nbErrors++;
6413 xmlFree(URL);
6414 delete = cur;
6415 goto skip_children;
6416 }
6417 xmlFree(URL);
6418 cur->_private = incl;
6419 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
6420 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
6421 xmlChar *name, *ns;
6422 xmlNodePtr text = NULL;
6423
6424 /*
6425 * Simplification 4.8. name attribute of element
6426 * and attribute elements
6427 */
6428 name = xmlGetProp(cur, BAD_CAST "name");
6429 if (name != NULL) {
6430 if (cur->children == NULL) {
6431 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
6432 name);
6433 } else {
6434 xmlNodePtr node;
6435 node = xmlNewNode(cur->ns, BAD_CAST "name");
6436 if (node != NULL) {
6437 xmlAddPrevSibling(cur->children, node);
6438 text = xmlNewText(name);
6439 xmlAddChild(node, text);
6440 text = node;
6441 }
6442 }
6443 if (text == NULL) {
6444 if (ctxt->error != NULL)
6445 ctxt->error(ctxt->userData,
6446 "Failed to create a name %s element\n", name);
6447 ctxt->nbErrors++;
6448 }
6449 xmlUnsetProp(cur, BAD_CAST "name");
6450 xmlFree(name);
6451 ns = xmlGetProp(cur, BAD_CAST "ns");
6452 if (ns != NULL) {
6453 if (text != NULL) {
6454 xmlSetProp(text, BAD_CAST "ns", ns);
6455 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
6456 }
6457 xmlFree(ns);
6458 } else if (xmlStrEqual(cur->name,
6459 BAD_CAST "attribute")) {
6460 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
6461 }
6462 }
6463 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
6464 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
6465 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
6466 /*
6467 * Simplification 4.8. name attribute of element
6468 * and attribute elements
6469 */
6470 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
6471 xmlNodePtr node;
6472 xmlChar *ns = NULL;
6473
6474 node = cur->parent;
6475 while ((node != NULL) &&
6476 (node->type == XML_ELEMENT_NODE)) {
6477 ns = xmlGetProp(node, BAD_CAST "ns");
6478 if (ns != NULL) {
6479 break;
6480 }
6481 node = node->parent;
6482 }
6483 if (ns == NULL) {
6484 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
6485 } else {
6486 xmlSetProp(cur, BAD_CAST "ns", ns);
6487 xmlFree(ns);
6488 }
6489 }
6490 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
6491 xmlChar *name, *local, *prefix;
6492
6493 /*
6494 * Simplification: 4.10. QNames
6495 */
6496 name = xmlNodeGetContent(cur);
6497 if (name != NULL) {
6498 local = xmlSplitQName2(name, &prefix);
6499 if (local != NULL) {
6500 xmlNsPtr ns;
6501
6502 ns = xmlSearchNs(cur->doc, cur, prefix);
6503 if (ns == NULL) {
6504 if (ctxt->error != NULL)
6505 ctxt->error(ctxt->userData,
6506 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
6507 ctxt->nbErrors++;
6508 } else {
6509 xmlSetProp(cur, BAD_CAST "ns", ns->href);
6510 xmlNodeSetContent(cur, local);
6511 }
6512 xmlFree(local);
6513 xmlFree(prefix);
6514 }
6515 xmlFree(name);
6516 }
6517 }
6518 /*
6519 * 4.16
6520 */
6521 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
6522 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6523 if (ctxt->error != NULL)
6524 ctxt->error(ctxt->userData,
6525 "Found nsName/except//nsName forbidden construct\n");
6526 ctxt->nbErrors++;
6527 }
6528 }
6529 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
6530 (cur != root)) {
6531 int oldflags = ctxt->flags;
6532
6533 /*
6534 * 4.16
6535 */
6536 if ((cur->parent != NULL) &&
6537 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
6538 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
6539 xmlRelaxNGCleanupTree(ctxt, cur);
6540 ctxt->flags = oldflags;
6541 goto skip_children;
6542 } else if ((cur->parent != NULL) &&
6543 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
6544 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
6545 xmlRelaxNGCleanupTree(ctxt, cur);
6546 ctxt->flags = oldflags;
6547 goto skip_children;
6548 }
6549 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
6550 /*
6551 * 4.16
6552 */
6553 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
6554 if (ctxt->error != NULL)
6555 ctxt->error(ctxt->userData,
6556 "Found anyName/except//anyName forbidden construct\n");
6557 ctxt->nbErrors++;
6558 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
6559 if (ctxt->error != NULL)
6560 ctxt->error(ctxt->userData,
6561 "Found nsName/except//anyName forbidden construct\n");
6562 ctxt->nbErrors++;
6563 }
6564 }
6565 /*
6566 * Thisd is not an else since "include" is transformed
6567 * into a div
6568 */
6569 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
6570 xmlChar *ns;
6571 xmlNodePtr child, ins, tmp;
6572
6573 /*
6574 * implements rule 4.11
6575 */
6576
6577 ns = xmlGetProp(cur, BAD_CAST "ns");
6578
6579 child = cur->children;
6580 ins = cur;
6581 while (child != NULL) {
6582 if (ns != NULL) {
6583 if (!xmlHasProp(child, BAD_CAST "ns")) {
6584 xmlSetProp(child, BAD_CAST "ns", ns);
6585 }
6586 }
6587 tmp = child->next;
6588 xmlUnlinkNode(child);
6589 ins = xmlAddNextSibling(ins, child);
6590 child = tmp;
6591 }
6592 if (ns != NULL)
6593 xmlFree(ns);
6594 delete = cur;
6595 goto skip_children;
6596 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006597 }
6598 }
6599 /*
6600 * Simplification 4.2 whitespaces
6601 */
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006602 else if ((cur->type == XML_TEXT_NODE) ||
6603 (cur->type == XML_CDATA_SECTION_NODE)) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006604 if (IS_BLANK_NODE(cur)) {
6605 if (cur->parent->type == XML_ELEMENT_NODE) {
6606 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
6607 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
6608 delete = cur;
6609 } else {
6610 delete = cur;
6611 goto skip_children;
6612 }
6613 }
Daniel Veillard39eb88b2003-03-11 11:21:28 +00006614 } else {
Daniel Veillard6eadf632003-01-23 18:29:16 +00006615 delete = cur;
6616 goto skip_children;
6617 }
6618
6619 /*
6620 * Skip to next node
6621 */
6622 if (cur->children != NULL) {
6623 if ((cur->children->type != XML_ENTITY_DECL) &&
6624 (cur->children->type != XML_ENTITY_REF_NODE) &&
6625 (cur->children->type != XML_ENTITY_NODE)) {
6626 cur = cur->children;
6627 continue;
6628 }
6629 }
6630skip_children:
6631 if (cur->next != NULL) {
6632 cur = cur->next;
6633 continue;
6634 }
6635
6636 do {
6637 cur = cur->parent;
6638 if (cur == NULL)
6639 break;
6640 if (cur == root) {
6641 cur = NULL;
6642 break;
6643 }
6644 if (cur->next != NULL) {
6645 cur = cur->next;
6646 break;
6647 }
6648 } while (cur != NULL);
6649 }
6650 if (delete != NULL) {
6651 xmlUnlinkNode(delete);
6652 xmlFreeNode(delete);
6653 delete = NULL;
6654 }
Daniel Veillardc5312d72003-02-21 17:14:10 +00006655}
Daniel Veillard6eadf632003-01-23 18:29:16 +00006656
Daniel Veillardc5312d72003-02-21 17:14:10 +00006657/**
6658 * xmlRelaxNGCleanupDoc:
6659 * @ctxt: a Relax-NG parser context
6660 * @doc: an xmldocPtr document pointer
6661 *
6662 * Cleanup the document from unwanted nodes for parsing, resolve
6663 * Include and externalRef lookups.
6664 *
6665 * Returns the cleaned up document or NULL in case of error
6666 */
6667static xmlDocPtr
6668xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
6669 xmlNodePtr root;
6670
6671 /*
6672 * Extract the root
6673 */
6674 root = xmlDocGetRootElement(doc);
6675 if (root == NULL) {
6676 if (ctxt->error != NULL)
6677 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6678 ctxt->URL);
6679 ctxt->nbErrors++;
6680 return (NULL);
6681 }
6682 xmlRelaxNGCleanupTree(ctxt, root);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006683 return(doc);
6684}
6685
6686/**
6687 * xmlRelaxNGParse:
6688 * @ctxt: a Relax-NG parser context
6689 *
6690 * parse a schema definition resource and build an internal
6691 * XML Shema struture which can be used to validate instances.
6692 * *WARNING* this interface is highly subject to change
6693 *
6694 * Returns the internal XML RelaxNG structure built from the resource or
6695 * NULL in case of error
6696 */
6697xmlRelaxNGPtr
6698xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
6699{
6700 xmlRelaxNGPtr ret = NULL;
6701 xmlDocPtr doc;
6702 xmlNodePtr root;
6703
6704 xmlRelaxNGInitTypes();
6705
6706 if (ctxt == NULL)
6707 return (NULL);
6708
6709 /*
6710 * First step is to parse the input document into an DOM/Infoset
6711 */
6712 if (ctxt->URL != NULL) {
6713 doc = xmlParseFile((const char *) ctxt->URL);
6714 if (doc == NULL) {
6715 if (ctxt->error != NULL)
6716 ctxt->error(ctxt->userData,
6717 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
6718 ctxt->nbErrors++;
6719 return (NULL);
6720 }
6721 } else if (ctxt->buffer != NULL) {
6722 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
6723 if (doc == NULL) {
6724 if (ctxt->error != NULL)
6725 ctxt->error(ctxt->userData,
6726 "xmlRelaxNGParse: could not parse schemas\n");
6727 ctxt->nbErrors++;
6728 return (NULL);
6729 }
6730 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6731 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
6732 } else {
6733 if (ctxt->error != NULL)
6734 ctxt->error(ctxt->userData,
6735 "xmlRelaxNGParse: nothing to parse\n");
6736 ctxt->nbErrors++;
6737 return (NULL);
6738 }
6739 ctxt->document = doc;
6740
6741 /*
6742 * Some preprocessing of the document content
6743 */
6744 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
6745 if (doc == NULL) {
6746 xmlFreeDoc(ctxt->document);
6747 ctxt->document = NULL;
6748 return(NULL);
6749 }
6750
Daniel Veillard6eadf632003-01-23 18:29:16 +00006751 /*
6752 * Then do the parsing for good
6753 */
6754 root = xmlDocGetRootElement(doc);
6755 if (root == NULL) {
6756 if (ctxt->error != NULL)
6757 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
6758 ctxt->URL);
6759 ctxt->nbErrors++;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006760 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006761 return (NULL);
6762 }
6763 ret = xmlRelaxNGParseDocument(ctxt, root);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006764 if (ret == NULL) {
6765 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006766 return(NULL);
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006767 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00006768
6769 /*
Daniel Veillardfd573f12003-03-16 17:52:32 +00006770 * Check the ref/defines links
6771 */
6772 /*
6773 * try to preprocess interleaves
6774 */
6775 if (ctxt->interleaves != NULL) {
6776 xmlHashScan(ctxt->interleaves,
6777 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
6778 }
6779
6780 /*
Daniel Veillard6eadf632003-01-23 18:29:16 +00006781 * if there was a parsing error return NULL
6782 */
6783 if (ctxt->nbErrors > 0) {
6784 xmlRelaxNGFree(ret);
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006785 ctxt->document = NULL;
6786 xmlFreeDoc(doc);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006787 return(NULL);
6788 }
6789
6790 /*
6791 * Transfer the pointer for cleanup at the schema level.
6792 */
6793 ret->doc = doc;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006794 ctxt->document = NULL;
6795 ret->documents = ctxt->documents;
6796 ctxt->documents = NULL;
Daniel Veillard3ebc7d42003-02-24 17:17:58 +00006797
Daniel Veillarde2a5a082003-02-02 14:35:17 +00006798 ret->includes = ctxt->includes;
6799 ctxt->includes = NULL;
Daniel Veillard419a7682003-02-03 23:22:49 +00006800 ret->defNr = ctxt->defNr;
6801 ret->defTab = ctxt->defTab;
6802 ctxt->defTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006803 if (ctxt->idref == 1)
6804 ret->idref = 1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006805
6806 return (ret);
6807}
6808
6809/**
6810 * xmlRelaxNGSetParserErrors:
6811 * @ctxt: a Relax-NG validation context
6812 * @err: the error callback
6813 * @warn: the warning callback
6814 * @ctx: contextual data for the callbacks
6815 *
6816 * Set the callback functions used to handle errors for a validation context
6817 */
6818void
6819xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
6820 xmlRelaxNGValidityErrorFunc err,
6821 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
6822 if (ctxt == NULL)
6823 return;
6824 ctxt->error = err;
6825 ctxt->warning = warn;
6826 ctxt->userData = ctx;
6827}
6828/************************************************************************
6829 * *
6830 * Dump back a compiled form *
6831 * *
6832 ************************************************************************/
6833static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
6834
6835/**
6836 * xmlRelaxNGDumpDefines:
6837 * @output: the file output
6838 * @defines: a list of define structures
6839 *
6840 * Dump a RelaxNG structure back
6841 */
6842static void
6843xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
6844 while (defines != NULL) {
6845 xmlRelaxNGDumpDefine(output, defines);
6846 defines = defines->next;
6847 }
6848}
6849
6850/**
6851 * xmlRelaxNGDumpDefine:
6852 * @output: the file output
6853 * @define: a define structure
6854 *
6855 * Dump a RelaxNG structure back
6856 */
6857static void
6858xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
6859 if (define == NULL)
6860 return;
6861 switch(define->type) {
6862 case XML_RELAXNG_EMPTY:
6863 fprintf(output, "<empty/>\n");
6864 break;
6865 case XML_RELAXNG_NOT_ALLOWED:
6866 fprintf(output, "<notAllowed/>\n");
6867 break;
6868 case XML_RELAXNG_TEXT:
6869 fprintf(output, "<text/>\n");
6870 break;
6871 case XML_RELAXNG_ELEMENT:
6872 fprintf(output, "<element>\n");
6873 if (define->name != NULL) {
6874 fprintf(output, "<name");
6875 if (define->ns != NULL)
6876 fprintf(output, " ns=\"%s\"", define->ns);
6877 fprintf(output, ">%s</name>\n", define->name);
6878 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00006879 xmlRelaxNGDumpDefines(output, define->attrs);
6880 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006881 fprintf(output, "</element>\n");
6882 break;
6883 case XML_RELAXNG_LIST:
6884 fprintf(output, "<list>\n");
6885 xmlRelaxNGDumpDefines(output, define->content);
6886 fprintf(output, "</list>\n");
6887 break;
6888 case XML_RELAXNG_ONEORMORE:
6889 fprintf(output, "<oneOrMore>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006890 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006891 fprintf(output, "</oneOrMore>\n");
6892 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006893 case XML_RELAXNG_ZEROORMORE:
6894 fprintf(output, "<zeroOrMore>\n");
6895 xmlRelaxNGDumpDefines(output, define->content);
6896 fprintf(output, "</zeroOrMore>\n");
6897 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006898 case XML_RELAXNG_CHOICE:
6899 fprintf(output, "<choice>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006900 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006901 fprintf(output, "</choice>\n");
6902 break;
6903 case XML_RELAXNG_GROUP:
6904 fprintf(output, "<group>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006905 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006906 fprintf(output, "</group>\n");
6907 break;
6908 case XML_RELAXNG_INTERLEAVE:
6909 fprintf(output, "<interleave>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006910 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006911 fprintf(output, "</interleave>\n");
6912 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00006913 case XML_RELAXNG_OPTIONAL:
6914 fprintf(output, "<optional>\n");
6915 xmlRelaxNGDumpDefines(output, define->content);
6916 fprintf(output, "</optional>\n");
6917 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006918 case XML_RELAXNG_ATTRIBUTE:
6919 fprintf(output, "<attribute>\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006920 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006921 fprintf(output, "</attribute>\n");
6922 break;
6923 case XML_RELAXNG_DEF:
6924 fprintf(output, "<define");
6925 if (define->name != NULL)
6926 fprintf(output, " name=\"%s\"", define->name);
6927 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006928 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006929 fprintf(output, "</define>\n");
6930 break;
6931 case XML_RELAXNG_REF:
6932 fprintf(output, "<ref");
6933 if (define->name != NULL)
6934 fprintf(output, " name=\"%s\"", define->name);
6935 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006936 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard6eadf632003-01-23 18:29:16 +00006937 fprintf(output, "</ref>\n");
6938 break;
Daniel Veillard419a7682003-02-03 23:22:49 +00006939 case XML_RELAXNG_PARENTREF:
6940 fprintf(output, "<parentRef");
6941 if (define->name != NULL)
6942 fprintf(output, " name=\"%s\"", define->name);
6943 fprintf(output, ">\n");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006944 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard419a7682003-02-03 23:22:49 +00006945 fprintf(output, "</parentRef>\n");
6946 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006947 case XML_RELAXNG_EXTERNALREF:
Daniel Veillard416589a2003-02-17 17:25:42 +00006948 fprintf(output, "<externalRef>");
Daniel Veillardfd573f12003-03-16 17:52:32 +00006949 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillarde431a272003-01-29 23:02:33 +00006950 fprintf(output, "</externalRef>\n");
6951 break;
6952 case XML_RELAXNG_DATATYPE:
Daniel Veillard6eadf632003-01-23 18:29:16 +00006953 case XML_RELAXNG_VALUE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006954 TODO
Daniel Veillard6eadf632003-01-23 18:29:16 +00006955 break;
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006956 case XML_RELAXNG_START:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006957 case XML_RELAXNG_EXCEPT:
Daniel Veillard8fe98712003-02-19 00:19:14 +00006958 case XML_RELAXNG_PARAM:
Daniel Veillardd41f4f42003-01-29 21:07:52 +00006959 TODO
6960 break;
Daniel Veillard77648bb2003-02-20 15:03:22 +00006961 case XML_RELAXNG_NOOP:
Daniel Veillardfd573f12003-03-16 17:52:32 +00006962 xmlRelaxNGDumpDefines(output, define->content);
Daniel Veillard77648bb2003-02-20 15:03:22 +00006963 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00006964 }
6965}
6966
6967/**
6968 * xmlRelaxNGDumpGrammar:
6969 * @output: the file output
6970 * @grammar: a grammar structure
6971 * @top: is this a top grammar
6972 *
6973 * Dump a RelaxNG structure back
6974 */
6975static void
6976xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
6977{
6978 if (grammar == NULL)
6979 return;
6980
6981 fprintf(output, "<grammar");
6982 if (top)
6983 fprintf(output,
6984 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
6985 switch(grammar->combine) {
6986 case XML_RELAXNG_COMBINE_UNDEFINED:
6987 break;
6988 case XML_RELAXNG_COMBINE_CHOICE:
6989 fprintf(output, " combine=\"choice\"");
6990 break;
6991 case XML_RELAXNG_COMBINE_INTERLEAVE:
6992 fprintf(output, " combine=\"interleave\"");
6993 break;
6994 default:
6995 fprintf(output, " <!-- invalid combine value -->");
6996 }
6997 fprintf(output, ">\n");
6998 if (grammar->start == NULL) {
6999 fprintf(output, " <!-- grammar had no start -->");
7000 } else {
7001 fprintf(output, "<start>\n");
7002 xmlRelaxNGDumpDefine(output, grammar->start);
7003 fprintf(output, "</start>\n");
7004 }
7005 /* TODO ? Dump the defines ? */
7006 fprintf(output, "</grammar>\n");
7007}
7008
7009/**
7010 * xmlRelaxNGDump:
7011 * @output: the file output
7012 * @schema: a schema structure
7013 *
7014 * Dump a RelaxNG structure back
7015 */
7016void
7017xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
7018{
7019 if (schema == NULL) {
7020 fprintf(output, "RelaxNG empty or failed to compile\n");
7021 return;
7022 }
7023 fprintf(output, "RelaxNG: ");
7024 if (schema->doc == NULL) {
7025 fprintf(output, "no document\n");
7026 } else if (schema->doc->URL != NULL) {
7027 fprintf(output, "%s\n", schema->doc->URL);
7028 } else {
7029 fprintf(output, "\n");
7030 }
7031 if (schema->topgrammar == NULL) {
7032 fprintf(output, "RelaxNG has no top grammar\n");
7033 return;
7034 }
7035 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
7036}
7037
Daniel Veillardfebcca42003-02-16 15:44:18 +00007038/**
7039 * xmlRelaxNGDumpTree:
7040 * @output: the file output
7041 * @schema: a schema structure
7042 *
7043 * Dump the transformed RelaxNG tree.
7044 */
7045void
7046xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
7047{
7048 if (schema == NULL) {
7049 fprintf(output, "RelaxNG empty or failed to compile\n");
7050 return;
7051 }
7052 if (schema->doc == NULL) {
7053 fprintf(output, "no document\n");
7054 } else {
7055 xmlDocDump(output, schema->doc);
7056 }
7057}
7058
Daniel Veillard6eadf632003-01-23 18:29:16 +00007059/************************************************************************
7060 * *
7061 * Validation implementation *
7062 * *
7063 ************************************************************************/
Daniel Veillardfd573f12003-03-16 17:52:32 +00007064static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
7065 xmlRelaxNGDefinePtr define);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007066static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7067 xmlRelaxNGDefinePtr define);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007068
7069/**
7070 * xmlRelaxNGSkipIgnored:
7071 * @ctxt: a schema validation context
7072 * @node: the top node.
7073 *
7074 * Skip ignorable nodes in that context
7075 *
7076 * Returns the new sibling or NULL in case of error.
7077 */
7078static xmlNodePtr
7079xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
7080 xmlNodePtr node) {
7081 /*
7082 * TODO complete and handle entities
7083 */
7084 while ((node != NULL) &&
7085 ((node->type == XML_COMMENT_NODE) ||
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007086 (node->type == XML_PI_NODE) ||
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007087 (((node->type == XML_TEXT_NODE) ||
7088 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007089 ((ctxt->flags & FLAGS_MIXED_CONTENT) ||
7090 (IS_BLANK_NODE(node)))))) {
Daniel Veillard6eadf632003-01-23 18:29:16 +00007091 node = node->next;
7092 }
7093 return(node);
7094}
7095
7096/**
Daniel Veillardedc91922003-01-26 00:52:04 +00007097 * xmlRelaxNGNormalize:
7098 * @ctxt: a schema validation context
7099 * @str: the string to normalize
7100 *
7101 * Implements the normalizeWhiteSpace( s ) function from
7102 * section 6.2.9 of the spec
7103 *
7104 * Returns the new string or NULL in case of error.
7105 */
7106static xmlChar *
7107xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
7108 xmlChar *ret, *p;
7109 const xmlChar *tmp;
7110 int len;
7111
7112 if (str == NULL)
7113 return(NULL);
7114 tmp = str;
7115 while (*tmp != 0) tmp++;
7116 len = tmp - str;
7117
7118 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
7119 if (ret == NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007120 if (ctxt != NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007121 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007122 } else {
7123 xmlGenericError(xmlGenericErrorContext,
7124 "xmlRelaxNGNormalize: out of memory\n");
7125 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007126 return(NULL);
7127 }
7128 p = ret;
7129 while (IS_BLANK(*str)) str++;
7130 while (*str != 0) {
7131 if (IS_BLANK(*str)) {
7132 while (IS_BLANK(*str)) str++;
7133 if (*str == 0)
7134 break;
7135 *p++ = ' ';
7136 } else
7137 *p++ = *str++;
7138 }
7139 *p = 0;
7140 return(ret);
7141}
7142
7143/**
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007144 * xmlRelaxNGValidateDatatype:
7145 * @ctxt: a Relax-NG validation context
7146 * @value: the string value
7147 * @type: the datatype definition
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007148 * @node: the node
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007149 *
7150 * Validate the given value against the dataype
7151 *
7152 * Returns 0 if the validation succeeded or an error code.
7153 */
7154static int
7155xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007156 xmlRelaxNGDefinePtr define, xmlNodePtr node) {
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007157 int ret, tmp;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007158 xmlRelaxNGTypeLibraryPtr lib;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007159 void *result = NULL;
7160 xmlRelaxNGDefinePtr cur;
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007161
7162 if ((define == NULL) || (define->data == NULL)) {
7163 return(-1);
7164 }
7165 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007166 if (lib->check != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007167 if ((define->attrs != NULL) &&
7168 (define->attrs->type == XML_RELAXNG_PARAM)) {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007169 ret = lib->check(lib->data, define->name, value, &result, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007170 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007171 ret = lib->check(lib->data, define->name, value, NULL, node);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007172 }
7173 } else
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007174 ret = -1;
7175 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007176 VALID_ERR2(XML_RELAXNG_ERR_TYPE, define->name);
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007177 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7178 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007179 return(-1);
7180 } else if (ret == 1) {
7181 ret = 0;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007182 } else if (ret == 2) {
7183 VALID_ERR2P(XML_RELAXNG_ERR_DUPID, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007184 } else {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007185 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL, define->name, value);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007186 ret = -1;
7187 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007188 cur = define->attrs;
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007189 while ((ret == 0) && (cur != NULL) && (cur->type == XML_RELAXNG_PARAM)) {
7190 if (lib->facet != NULL) {
7191 tmp = lib->facet(lib->data, define->name, cur->name,
7192 cur->value, value, result);
7193 if (tmp != 0)
7194 ret = -1;
7195 }
7196 cur = cur->next;
7197 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007198 if ((ret == 0) && (define->content != NULL)) {
7199 const xmlChar *oldvalue, *oldendvalue;
7200
7201 oldvalue = ctxt->state->value;
7202 oldendvalue = ctxt->state->endvalue;
7203 ctxt->state->value = (xmlChar *) value;
7204 ctxt->state->endvalue = NULL;
7205 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7206 ctxt->state->value = (xmlChar *) oldvalue;
7207 ctxt->state->endvalue = (xmlChar *) oldendvalue;
7208 }
Daniel Veillard8bc6cf92003-02-27 17:42:22 +00007209 if ((result != NULL) && (lib != NULL) && (lib->freef != NULL))
7210 lib->freef(lib->data, result);
Daniel Veillarddd1655c2003-01-25 18:01:32 +00007211 return(ret);
7212}
7213
7214/**
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007215 * xmlRelaxNGNextValue:
7216 * @ctxt: a Relax-NG validation context
7217 *
7218 * Skip to the next value when validating within a list
7219 *
7220 * Returns 0 if the operation succeeded or an error code.
7221 */
7222static int
7223xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
7224 xmlChar *cur;
7225
7226 cur = ctxt->state->value;
7227 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
7228 ctxt->state->value = NULL;
Daniel Veillarde5b110b2003-02-04 14:43:39 +00007229 ctxt->state->endvalue = NULL;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007230 return(0);
7231 }
7232 while (*cur != 0) cur++;
7233 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
7234 if (cur == ctxt->state->endvalue)
7235 ctxt->state->value = NULL;
7236 else
7237 ctxt->state->value = cur;
7238 return(0);
7239}
7240
7241/**
7242 * xmlRelaxNGValidateValueList:
7243 * @ctxt: a Relax-NG validation context
7244 * @defines: the list of definitions to verify
7245 *
7246 * Validate the given set of definitions for the current value
7247 *
7248 * Returns 0 if the validation succeeded or an error code.
7249 */
7250static int
7251xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
7252 xmlRelaxNGDefinePtr defines) {
7253 int ret = 0;
7254
7255 while (defines != NULL) {
7256 ret = xmlRelaxNGValidateValue(ctxt, defines);
7257 if (ret != 0)
7258 break;
7259 defines = defines->next;
7260 }
7261 return(ret);
7262}
7263
7264/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007265 * xmlRelaxNGValidateValue:
7266 * @ctxt: a Relax-NG validation context
7267 * @define: the definition to verify
7268 *
7269 * Validate the given definition for the current value
7270 *
7271 * Returns 0 if the validation succeeded or an error code.
7272 */
7273static int
7274xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
7275 xmlRelaxNGDefinePtr define) {
Daniel Veillardedc91922003-01-26 00:52:04 +00007276 int ret = 0, oldflags;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007277 xmlChar *value;
7278
7279 value = ctxt->state->value;
7280 switch (define->type) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007281 case XML_RELAXNG_EMPTY: {
7282 if ((value != NULL) && (value[0] != 0)) {
7283 int idx = 0;
7284
7285 while (IS_BLANK(value[idx]))
7286 idx++;
7287 if (value[idx] != 0)
7288 ret = -1;
7289 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007290 break;
Daniel Veillardd4310742003-02-18 21:12:46 +00007291 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00007292 case XML_RELAXNG_TEXT:
7293 break;
Daniel Veillardedc91922003-01-26 00:52:04 +00007294 case XML_RELAXNG_VALUE: {
7295 if (!xmlStrEqual(value, define->value)) {
7296 if (define->name != NULL) {
Daniel Veillardea3f3982003-01-26 19:45:18 +00007297 xmlRelaxNGTypeLibraryPtr lib;
7298
7299 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
Daniel Veillarde637c4a2003-03-30 21:10:09 +00007300 if ((lib != NULL) && (lib->comp != NULL)) {
7301 ret = lib->comp(lib->data, define->name,
7302 define->value, define->node,
7303 (void *) define->attrs,
7304 value, ctxt->state->node);
7305 } else
Daniel Veillardea3f3982003-01-26 19:45:18 +00007306 ret = -1;
7307 if (ret < 0) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007308 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP, define->name);
Daniel Veillardea3f3982003-01-26 19:45:18 +00007309 return(-1);
7310 } else if (ret == 1) {
7311 ret = 0;
7312 } else {
7313 ret = -1;
7314 }
Daniel Veillardedc91922003-01-26 00:52:04 +00007315 } else {
7316 xmlChar *nval, *nvalue;
7317
7318 /*
7319 * TODO: trivial optimizations are possible by
7320 * computing at compile-time
7321 */
7322 nval = xmlRelaxNGNormalize(ctxt, define->value);
7323 nvalue = xmlRelaxNGNormalize(ctxt, value);
7324
Daniel Veillardea3f3982003-01-26 19:45:18 +00007325 if ((nval == NULL) || (nvalue == NULL) ||
7326 (!xmlStrEqual(nval, nvalue)))
Daniel Veillardedc91922003-01-26 00:52:04 +00007327 ret = -1;
7328 if (nval != NULL)
7329 xmlFree(nval);
7330 if (nvalue != NULL)
7331 xmlFree(nvalue);
7332 }
7333 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007334 if (ret == 0)
7335 xmlRelaxNGNextValue(ctxt);
Daniel Veillardedc91922003-01-26 00:52:04 +00007336 break;
7337 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007338 case XML_RELAXNG_DATATYPE: {
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007339 ret = xmlRelaxNGValidateDatatype(ctxt, value, define,
7340 ctxt->state->seq);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007341 if (ret == 0)
7342 xmlRelaxNGNextValue(ctxt);
7343
7344 break;
7345 }
7346 case XML_RELAXNG_CHOICE: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007347 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007348 xmlChar *oldvalue;
7349
7350 oldflags = ctxt->flags;
7351 ctxt->flags |= FLAGS_IGNORABLE;
7352
7353 oldvalue = ctxt->state->value;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007354 while (list != NULL) {
7355 ret = xmlRelaxNGValidateValue(ctxt, list);
7356 if (ret == 0) {
7357 break;
7358 }
7359 ctxt->state->value = oldvalue;
7360 list = list->next;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007361 }
7362 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007363 if (ret != 0) {
7364 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7365 xmlRelaxNGDumpValidError(ctxt);
7366 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007367 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007368 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007369 if (ret == 0)
7370 xmlRelaxNGNextValue(ctxt);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007371 break;
7372 }
7373 case XML_RELAXNG_LIST: {
Daniel Veillardfd573f12003-03-16 17:52:32 +00007374 xmlRelaxNGDefinePtr list = define->content;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007375 xmlChar *oldvalue, *oldend, *val, *cur;
Daniel Veillard416589a2003-02-17 17:25:42 +00007376#ifdef DEBUG_LIST
7377 int nb_values = 0;
7378#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007379
7380 oldvalue = ctxt->state->value;
7381 oldend = ctxt->state->endvalue;
7382
7383 val = xmlStrdup(oldvalue);
7384 if (val == NULL) {
Daniel Veillardd4310742003-02-18 21:12:46 +00007385 val = xmlStrdup(BAD_CAST "");
7386 }
7387 if (val == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00007388 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007389 return(-1);
7390 }
7391 cur = val;
7392 while (*cur != 0) {
Daniel Veillard416589a2003-02-17 17:25:42 +00007393 if (IS_BLANK(*cur)) {
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007394 *cur = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00007395 cur++;
7396#ifdef DEBUG_LIST
7397 nb_values++;
7398#endif
7399 while (IS_BLANK(*cur))
7400 *cur++ = 0;
7401 } else
7402 cur++;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007403 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007404#ifdef DEBUG_LIST
7405 xmlGenericError(xmlGenericErrorContext,
7406 "list value: '%s' found %d items\n", oldvalue, nb_values);
7407 nb_values = 0;
7408#endif
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007409 ctxt->state->endvalue = cur;
7410 cur = val;
7411 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007412
Daniel Veillardfd573f12003-03-16 17:52:32 +00007413 ctxt->state->value = cur;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007414
Daniel Veillardfd573f12003-03-16 17:52:32 +00007415 while (list != NULL) {
7416 if (ctxt->state->value == ctxt->state->endvalue)
7417 ctxt->state->value = NULL;
7418 ret = xmlRelaxNGValidateValue(ctxt, list);
7419 if (ret != 0) {
7420#ifdef DEBUG_LIST
7421 xmlGenericError(xmlGenericErrorContext,
7422 "Failed to validate value: '%s' with %d rule\n",
7423 ctxt->state->value, nb_values);
7424#endif
7425 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00007426 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007427#ifdef DEBUG_LIST
7428 nb_values++;
7429#endif
7430 list = list->next;
7431 }
7432
7433 if ((ret == 0) && (ctxt->state->value != NULL) &&
7434 (ctxt->state->value != ctxt->state->endvalue)) {
7435 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA, ctxt->state->value);
7436 ret = -1;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007437 }
7438 xmlFree(val);
7439 ctxt->state->value = oldvalue;
7440 ctxt->state->endvalue = oldend;
7441 break;
7442 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007443 case XML_RELAXNG_ONEORMORE:
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007444 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7445 if (ret != 0) {
7446 break;
7447 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007448 /* no break on purpose */
7449 case XML_RELAXNG_ZEROORMORE: {
7450 xmlChar *cur, *temp;
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007451
7452 oldflags = ctxt->flags;
7453 ctxt->flags |= FLAGS_IGNORABLE;
7454 cur = ctxt->state->value;
7455 temp = NULL;
7456 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
7457 (temp != cur)) {
7458 temp = cur;
7459 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
7460 if (ret != 0) {
7461 ctxt->state->value = temp;
7462 ret = 0;
7463 break;
7464 }
7465 cur = ctxt->state->value;
7466 }
7467 ctxt->flags = oldflags;
Daniel Veillard42f12e92003-03-07 18:32:59 +00007468 if (ret != 0) {
7469 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
7470 xmlRelaxNGDumpValidError(ctxt);
7471 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007472 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
Daniel Veillard42f12e92003-03-07 18:32:59 +00007473 }
Daniel Veillardc6e997c2003-01-27 12:35:42 +00007474 break;
7475 }
Daniel Veillard416589a2003-02-17 17:25:42 +00007476 case XML_RELAXNG_EXCEPT: {
7477 xmlRelaxNGDefinePtr list;
7478
7479 list = define->content;
7480 while (list != NULL) {
7481 ret = xmlRelaxNGValidateValue(ctxt, list);
7482 if (ret == 0) {
7483 ret = -1;
7484 break;
7485 } else
7486 ret = 0;
7487 list = list->next;
7488 }
7489 break;
7490 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007491 case XML_RELAXNG_DEF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00007492 case XML_RELAXNG_GROUP: {
7493 xmlRelaxNGDefinePtr list;
7494
7495 list = define->content;
7496 while (list != NULL) {
7497 ret = xmlRelaxNGValidateValue(ctxt, list);
7498 if (ret != 0) {
7499 ret = -1;
7500 break;
7501 } else
7502 ret = 0;
7503 list = list->next;
7504 }
Daniel Veillardd4310742003-02-18 21:12:46 +00007505 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007506 }
Daniel Veillard463a5472003-02-27 21:30:32 +00007507 case XML_RELAXNG_REF:
7508 case XML_RELAXNG_PARENTREF:
7509 ret = xmlRelaxNGValidateValue(ctxt, define->content);
7510 break;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007511 default:
7512 TODO
7513 ret = -1;
7514 }
7515 return(ret);
7516}
7517
7518/**
7519 * xmlRelaxNGValidateValueContent:
7520 * @ctxt: a Relax-NG validation context
7521 * @defines: the list of definitions to verify
7522 *
7523 * Validate the given definitions for the current value
7524 *
7525 * Returns 0 if the validation succeeded or an error code.
7526 */
7527static int
7528xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
7529 xmlRelaxNGDefinePtr defines) {
7530 int ret = 0;
7531
7532 while (defines != NULL) {
7533 ret = xmlRelaxNGValidateValue(ctxt, defines);
7534 if (ret != 0)
7535 break;
7536 defines = defines->next;
7537 }
7538 return(ret);
7539}
7540
7541/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007542 * xmlRelaxNGAttributeMatch:
7543 * @ctxt: a Relax-NG validation context
7544 * @define: the definition to check
7545 * @prop: the attribute
7546 *
7547 * Check if the attribute matches the definition nameClass
7548 *
7549 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
7550 */
7551static int
7552xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
7553 xmlRelaxNGDefinePtr define,
7554 xmlAttrPtr prop) {
7555 int ret;
7556
7557 if (define->name != NULL) {
7558 if (!xmlStrEqual(define->name, prop->name))
7559 return(0);
7560 }
7561 if (define->ns != NULL) {
7562 if (define->ns[0] == 0) {
7563 if (prop->ns != NULL)
7564 return(0);
7565 } else {
7566 if ((prop->ns == NULL) ||
7567 (!xmlStrEqual(define->ns, prop->ns->href)))
7568 return(0);
7569 }
7570 }
7571 if (define->nameClass == NULL)
7572 return(1);
7573 define = define->nameClass;
7574 if (define->type == XML_RELAXNG_EXCEPT) {
7575 xmlRelaxNGDefinePtr list;
7576
7577 list = define->content;
7578 while (list != NULL) {
7579 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
7580 if (ret == 1)
7581 return(0);
7582 if (ret < 0)
7583 return(ret);
7584 list = list->next;
7585 }
7586 } else {
7587 TODO
7588 }
7589 return(1);
7590}
7591
7592/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00007593 * xmlRelaxNGValidateAttribute:
7594 * @ctxt: a Relax-NG validation context
7595 * @define: the definition to verify
7596 *
7597 * Validate the given attribute definition for that node
7598 *
7599 * Returns 0 if the validation succeeded or an error code.
7600 */
7601static int
7602xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
7603 xmlRelaxNGDefinePtr define) {
7604 int ret = 0, i;
7605 xmlChar *value, *oldvalue;
7606 xmlAttrPtr prop = NULL, tmp;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007607 xmlNodePtr oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007608
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007609 if (ctxt->state->nbAttrLeft <= 0)
7610 return(-1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00007611 if (define->name != NULL) {
7612 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7613 tmp = ctxt->state->attrs[i];
7614 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
7615 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
7616 (tmp->ns == NULL)) ||
7617 ((tmp->ns != NULL) &&
7618 (xmlStrEqual(define->ns, tmp->ns->href)))) {
7619 prop = tmp;
7620 break;
7621 }
7622 }
7623 }
7624 if (prop != NULL) {
7625 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7626 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007627 oldseq = ctxt->state->seq;
7628 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007629 ctxt->state->value = value;
Daniel Veillard231d7912003-02-09 14:22:17 +00007630 ctxt->state->endvalue = NULL;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007631 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007632 if (ctxt->state->value != NULL)
7633 value = ctxt->state->value;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007634 if (value != NULL)
7635 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007636 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007637 ctxt->state->seq = oldseq;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007638 if (ret == 0) {
7639 /*
7640 * flag the attribute as processed
7641 */
7642 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007643 ctxt->state->nbAttrLeft--;
Daniel Veillard6eadf632003-01-23 18:29:16 +00007644 }
7645 } else {
7646 ret = -1;
7647 }
7648#ifdef DEBUG
7649 xmlGenericError(xmlGenericErrorContext,
7650 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
7651#endif
7652 } else {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007653 for (i = 0;i < ctxt->state->nbAttrs;i++) {
7654 tmp = ctxt->state->attrs[i];
Daniel Veillard144fae12003-02-03 13:17:57 +00007655 if ((tmp != NULL) &&
Daniel Veillardfd573f12003-03-16 17:52:32 +00007656 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007657 prop = tmp;
7658 break;
7659 }
7660 }
7661 if (prop != NULL) {
7662 value = xmlNodeListGetString(prop->doc, prop->children, 1);
7663 oldvalue = ctxt->state->value;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007664 oldseq = ctxt->state->seq;
7665 ctxt->state->seq = (xmlNodePtr) prop;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007666 ctxt->state->value = value;
7667 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
Daniel Veillard231d7912003-02-09 14:22:17 +00007668 if (ctxt->state->value != NULL)
7669 value = ctxt->state->value;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007670 if (value != NULL)
7671 xmlFree(value);
Daniel Veillard231d7912003-02-09 14:22:17 +00007672 ctxt->state->value = oldvalue;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00007673 ctxt->state->seq = oldseq;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007674 if (ret == 0) {
7675 /*
7676 * flag the attribute as processed
7677 */
7678 ctxt->state->attrs[i] = NULL;
Daniel Veillard1ed7f362003-02-03 10:57:45 +00007679 ctxt->state->nbAttrLeft--;
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007680 }
7681 } else {
7682 ret = -1;
7683 }
7684#ifdef DEBUG
Daniel Veillard144fae12003-02-03 13:17:57 +00007685 if (define->ns != NULL) {
7686 xmlGenericError(xmlGenericErrorContext,
7687 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
7688 define->ns, ret);
7689 } else {
7690 xmlGenericError(xmlGenericErrorContext,
7691 "xmlRelaxNGValidateAttribute(anyName): %d\n",
7692 ret);
7693 }
Daniel Veillard3b2e4e12003-02-03 08:52:58 +00007694#endif
Daniel Veillard6eadf632003-01-23 18:29:16 +00007695 }
7696
7697 return(ret);
7698}
7699
7700/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007701 * xmlRelaxNGValidateAttributeList:
7702 * @ctxt: a Relax-NG validation context
7703 * @define: the list of definition to verify
7704 *
7705 * Validate the given node against the list of attribute definitions
7706 *
7707 * Returns 0 if the validation succeeded or an error code.
7708 */
7709static int
7710xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
7711 xmlRelaxNGDefinePtr defines) {
7712 int ret = 0;
7713 while (defines != NULL) {
7714 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
7715 ret = -1;
7716 defines = defines->next;
7717 }
7718 return(ret);
7719}
7720
7721/**
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007722 * xmlRelaxNGNodeMatchesList:
7723 * @node: the node
7724 * @list: a NULL terminated array of definitions
7725 *
7726 * Check if a node can be matched by one of the definitions
7727 *
7728 * Returns 1 if matches 0 otherwise
7729 */
7730static int
7731xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
7732 xmlRelaxNGDefinePtr cur;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007733 int i = 0, tmp;
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007734
7735 if ((node == NULL) || (list == NULL))
7736 return(0);
7737
7738 cur = list[i++];
7739 while (cur != NULL) {
7740 if ((node->type == XML_ELEMENT_NODE) &&
7741 (cur->type == XML_RELAXNG_ELEMENT)) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00007742 tmp = xmlRelaxNGElementMatch(NULL, cur, node);
7743 if (tmp == 1)
7744 return(1);
Daniel Veillard39eb88b2003-03-11 11:21:28 +00007745 } else if (((node->type == XML_TEXT_NODE) ||
7746 (node->type == XML_CDATA_SECTION_NODE)) &&
Daniel Veillard76fc5ed2003-01-28 20:58:15 +00007747 (cur->type == XML_RELAXNG_TEXT)) {
7748 return(1);
7749 }
7750 cur = list[i++];
7751 }
7752 return(0);
7753}
7754
7755/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00007756 * xmlRelaxNGValidateInterleave:
7757 * @ctxt: a Relax-NG validation context
7758 * @define: the definition to verify
7759 *
7760 * Validate an interleave definition for a node.
7761 *
7762 * Returns 0 if the validation succeeded or an error code.
7763 */
7764static int
7765xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
7766 xmlRelaxNGDefinePtr define) {
7767 int ret = 0, i, nbgroups, left;
7768 int errNr = ctxt->errNr;
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007769 int oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007770
7771 xmlRelaxNGValidStatePtr oldstate;
7772 xmlRelaxNGPartitionPtr partitions;
7773 xmlRelaxNGInterleaveGroupPtr group = NULL;
7774 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
7775 xmlNodePtr *list = NULL, *lasts = NULL;
7776
7777 if (define->data != NULL) {
7778 partitions = (xmlRelaxNGPartitionPtr) define->data;
7779 nbgroups = partitions->nbgroups;
7780 left = nbgroups;
7781 } else {
7782 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA);
7783 return(-1);
7784 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007785 /*
7786 * Optimizations for MIXED
7787 */
7788 oldflags = ctxt->flags;
Daniel Veillarde063f482003-03-21 16:53:17 +00007789 if (define->dflags & IS_MIXED) {
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007790 ctxt->flags |= FLAGS_MIXED_CONTENT;
7791 if (nbgroups == 2) {
7792 /*
7793 * this is a pure <mixed> case
7794 */
7795 if (ctxt->state != NULL)
7796 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7797 ctxt->state->seq);
7798 if (partitions->groups[0]->rule->type == XML_RELAXNG_TEXT)
7799 ret = xmlRelaxNGValidateDefinition(ctxt,
7800 partitions->groups[1]->rule);
7801 else
7802 ret = xmlRelaxNGValidateDefinition(ctxt,
7803 partitions->groups[0]->rule);
7804 if (ret == 0) {
7805 if (ctxt->state != NULL)
7806 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt,
7807 ctxt->state->seq);
7808 }
7809 ctxt->flags = oldflags;
7810 return(ret);
7811 }
7812 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007813
7814 /*
7815 * Build arrays to store the first and last node of the chain
7816 * pertaining to each group
7817 */
7818 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7819 if (list == NULL) {
7820 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7821 return(-1);
7822 }
7823 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
7824 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
7825 if (lasts == NULL) {
7826 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
7827 return(-1);
7828 }
7829 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
7830
7831 /*
7832 * Walk the sequence of children finding the right group and
7833 * sorting them in sequences.
7834 */
7835 cur = ctxt->state->seq;
7836 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7837 start = cur;
7838 while (cur != NULL) {
7839 ctxt->state->seq = cur;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00007840 if ((partitions->triage != NULL) &&
7841 (partitions->flags & IS_DETERMINIST)) {
7842 void *tmp = NULL;
7843
7844 if ((cur->type == XML_TEXT_NODE) ||
7845 (cur->type == XML_CDATA_SECTION_NODE)) {
7846 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#text",
7847 NULL);
7848 } else if (cur->type == XML_ELEMENT_NODE) {
7849 if (cur->ns != NULL) {
7850 tmp = xmlHashLookup2(partitions->triage, cur->name,
7851 cur->ns->href);
7852 if (tmp == NULL)
7853 tmp = xmlHashLookup2(partitions->triage,
7854 BAD_CAST "#any", cur->ns->href);
7855 } else
7856 tmp = xmlHashLookup2(partitions->triage, cur->name, NULL);
7857 if (tmp == NULL)
7858 tmp = xmlHashLookup2(partitions->triage, BAD_CAST "#any",
7859 NULL);
7860 }
7861
7862 if (tmp == NULL) {
7863 i = nbgroups;
7864 } else {
7865 i = ((long) tmp) - 1;
7866 if (partitions->flags & IS_NEEDCHECK) {
7867 group = partitions->groups[i];
7868 if (!xmlRelaxNGNodeMatchesList(cur, group->defs))
7869 i = nbgroups;
7870 }
7871 }
7872 } else {
7873 for (i = 0;i < nbgroups;i++) {
7874 group = partitions->groups[i];
7875 if (group == NULL)
7876 continue;
7877 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
7878 break;
7879 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00007880 }
7881 /*
7882 * We break as soon as an element not matched is found
7883 */
7884 if (i >= nbgroups) {
7885 break;
7886 }
7887 if (lasts[i] != NULL) {
7888 lasts[i]->next = cur;
7889 lasts[i] = cur;
7890 } else {
7891 list[i] = cur;
7892 lasts[i] = cur;
7893 }
7894 if (cur->next != NULL)
7895 lastchg = cur->next;
7896 else
7897 lastchg = cur;
7898 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
7899 }
7900 if (ret != 0) {
7901 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7902 ret = -1;
7903 goto done;
7904 }
7905 lastelem = cur;
7906 oldstate = ctxt->state;
7907 for (i = 0;i < nbgroups;i++) {
7908 ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
7909 group = partitions->groups[i];
7910 if (lasts[i] != NULL) {
7911 last = lasts[i]->next;
7912 lasts[i]->next = NULL;
7913 }
7914 ctxt->state->seq = list[i];
7915 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
7916 if (ret != 0)
7917 break;
7918 if (ctxt->state != NULL) {
7919 cur = ctxt->state->seq;
7920 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
Daniel Veillard798024a2003-03-19 10:36:09 +00007921 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007922 oldstate = ctxt->state;
7923 ctxt->state = NULL;
7924 if (cur != NULL) {
7925 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7926 ret = -1;
7927 ctxt->state = oldstate;
7928 goto done;
7929 }
7930 } else if (ctxt->states != NULL) {
7931 int j;
7932 int found = 0;
7933
7934 for (j = 0;j < ctxt->states->nbState;j++) {
7935 cur = ctxt->states->tabState[j]->seq;
7936 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
7937 if (cur == NULL) {
7938 found = 1;
7939 break;
7940 }
7941 }
7942 if (ctxt->states->nbState > 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007943 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007944 oldstate = ctxt->states->tabState[ctxt->states->nbState - 1];
7945 }
7946 for (j = 0;j < ctxt->states->nbState - 1;j++) {
Daniel Veillard798024a2003-03-19 10:36:09 +00007947 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[j]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007948 }
7949 xmlRelaxNGFreeStates(ctxt, ctxt->states);
7950 ctxt->states = NULL;
7951 if (found == 0) {
7952 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
7953 ret = -1;
7954 ctxt->state = oldstate;
7955 goto done;
7956 }
7957 } else {
7958 ret = -1;
7959 break;
7960 }
7961 if (lasts[i] != NULL) {
7962 lasts[i]->next = last;
7963 }
7964 }
7965 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00007966 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007967 ctxt->state = oldstate;
7968 ctxt->state->seq = lastelem;
7969 if (ret != 0) {
7970 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ);
7971 ret = -1;
7972 goto done;
7973 }
7974
7975done:
Daniel Veillard249d7bb2003-03-19 21:02:29 +00007976 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00007977 /*
7978 * builds the next links chain from the prev one
7979 */
7980 cur = lastchg;
7981 while (cur != NULL) {
7982 if ((cur == start) || (cur->prev == NULL))
7983 break;
7984 cur->prev->next = cur;
7985 cur = cur->prev;
7986 }
7987 if (ret == 0) {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00007988 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00007989 }
7990
7991 xmlFree(list);
7992 xmlFree(lasts);
7993 return(ret);
7994}
7995
7996/**
7997 * xmlRelaxNGValidateDefinitionList:
7998 * @ctxt: a Relax-NG validation context
7999 * @define: the list of definition to verify
8000 *
8001 * Validate the given node content against the (list) of definitions
8002 *
8003 * Returns 0 if the validation succeeded or an error code.
8004 */
8005static int
8006xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt,
8007 xmlRelaxNGDefinePtr defines) {
8008 int ret = 0, res;
8009
8010
Daniel Veillard952379b2003-03-17 15:37:12 +00008011 if (defines == NULL) {
8012 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL, BAD_CAST "NULL definition list");
8013 return(-1);
8014 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008015 while (defines != NULL) {
8016 if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
8017 res = xmlRelaxNGValidateDefinition(ctxt, defines);
8018 if (res < 0)
8019 ret = -1;
8020 } else {
8021 VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
8022 return(-1);
8023 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008024 if (res == -1) /* continues on -2 */
Daniel Veillardfd573f12003-03-16 17:52:32 +00008025 break;
8026 defines = defines->next;
8027 }
8028
8029 return(ret);
8030}
8031
8032/**
8033 * xmlRelaxNGElementMatch:
Daniel Veillard416589a2003-02-17 17:25:42 +00008034 * @ctxt: a Relax-NG validation context
8035 * @define: the definition to check
Daniel Veillardfd573f12003-03-16 17:52:32 +00008036 * @elem: the element
Daniel Veillard416589a2003-02-17 17:25:42 +00008037 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008038 * Check if the element matches the definition nameClass
Daniel Veillard416589a2003-02-17 17:25:42 +00008039 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008040 * Returns 1 if the element matches, 0 if no, or -1 in case of error
Daniel Veillard416589a2003-02-17 17:25:42 +00008041 */
8042static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008043xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
8044 xmlRelaxNGDefinePtr define,
8045 xmlNodePtr elem) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008046 int ret = 0, oldflags = 0;
Daniel Veillard416589a2003-02-17 17:25:42 +00008047
Daniel Veillardfd573f12003-03-16 17:52:32 +00008048 if (define->name != NULL) {
8049 if (!xmlStrEqual(elem->name, define->name)) {
8050 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME, define->name, elem->name);
8051 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008052 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00008053 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008054 if ((define->ns != NULL) && (define->ns[0] != 0)) {
8055 if (elem->ns == NULL) {
8056 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS,
8057 elem->name);
8058 return(0);
8059 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
8060 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS,
8061 elem->name, define->ns);
8062 return(0);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008063 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008064 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
8065 (define->name == NULL)) {
8066 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8067 elem->name);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008068 return(0);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008069 } else if ((elem->ns != NULL) && (define->name != NULL)) {
8070 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS,
8071 define->name);
8072 return(0);
8073 }
8074
8075 if (define->nameClass == NULL)
8076 return(1);
8077
8078 define = define->nameClass;
8079 if (define->type == XML_RELAXNG_EXCEPT) {
8080 xmlRelaxNGDefinePtr list;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008081 if (ctxt != NULL) {
8082 oldflags = ctxt->flags;
8083 ctxt->flags |= FLAGS_IGNORABLE;
8084 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008085
8086 list = define->content;
8087 while (list != NULL) {
8088 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8089 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008090 if (ctxt != NULL)
8091 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008092 return(0);
8093 }
8094 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008095 if (ctxt != NULL)
8096 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008097 return(ret);
8098 }
8099 list = list->next;
8100 }
8101 ret = 1;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008102 if (ctxt != NULL) {
8103 ctxt->flags = oldflags;
8104 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008105 } else if (define->type == XML_RELAXNG_CHOICE) {
8106 xmlRelaxNGDefinePtr list;
8107
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008108 if (ctxt != NULL) {
8109 oldflags = ctxt->flags;
8110 ctxt->flags |= FLAGS_IGNORABLE;
8111 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008112
8113 list = define->nameClass;
8114 while (list != NULL) {
8115 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
8116 if (ret == 1) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008117 if (ctxt != NULL)
8118 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008119 return(1);
8120 }
8121 if (ret < 0) {
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008122 if (ctxt != NULL)
8123 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008124 return(ret);
8125 }
8126 list = list->next;
8127 }
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008128 if (ctxt != NULL) {
8129 if (ret != 0) {
8130 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8131 xmlRelaxNGDumpValidError(ctxt);
8132 } else {
8133 if (ctxt->errNr > 0) xmlRelaxNGPopErrors(ctxt, 0);
8134 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008135 }
8136 ret = 0;
Daniel Veillard0e3d3ce2003-03-21 12:43:18 +00008137 if (ctxt != NULL) {
8138 ctxt->flags = oldflags;
8139 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008140 } else {
8141 TODO
8142 ret = -1;
8143 }
8144 return(ret);
8145}
8146
8147/**
8148 * xmlRelaxNGValidateElementEnd:
8149 * @ctxt: a Relax-NG validation context
8150 *
8151 * Validate the end of the element, implements check that
8152 * there is nothing left not consumed in the element content
8153 * or in the attribute list.
8154 *
8155 * Returns 0 if the validation succeeded or an error code.
8156 */
8157static int
8158xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt) {
8159 int ret = 0, i;
8160 xmlRelaxNGValidStatePtr state;
8161
8162 state = ctxt->state;
8163 if (state->seq != NULL) {
8164 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
8165 if (state->seq != NULL) {
8166 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT,
8167 state->node->name, state->seq->name);
8168 ret = -1;
8169 }
8170 }
8171 for (i = 0;i < state->nbAttrs;i++) {
8172 if (state->attrs[i] != NULL) {
8173 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR,
8174 state->attrs[i]->name, state->node->name);
8175 ret = -1;
8176 }
8177 }
8178 return(ret);
8179}
8180
8181/**
8182 * xmlRelaxNGValidateState:
8183 * @ctxt: a Relax-NG validation context
8184 * @define: the definition to verify
8185 *
8186 * Validate the current state against the definition
8187 *
8188 * Returns 0 if the validation succeeded or an error code.
8189 */
8190static int
8191xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt,
8192 xmlRelaxNGDefinePtr define) {
8193 xmlNodePtr node;
8194 int ret = 0, i, tmp, oldflags, errNr;
Daniel Veillardbbb78b52003-03-21 01:24:45 +00008195 xmlRelaxNGValidStatePtr oldstate = NULL, state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008196
8197 if (define == NULL) {
8198 VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
8199 return(-1);
8200 }
8201
8202 if (ctxt->state != NULL) {
8203 node = ctxt->state->seq;
8204 } else {
8205 node = NULL;
8206 }
8207#ifdef DEBUG
8208 for (i = 0;i < ctxt->depth;i++)
8209 xmlGenericError(xmlGenericErrorContext, " ");
8210 xmlGenericError(xmlGenericErrorContext,
8211 "Start validating %s ", xmlRelaxNGDefName(define));
8212 if (define->name != NULL)
8213 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8214 if ((node != NULL) && (node->name != NULL))
8215 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
8216 else
8217 xmlGenericError(xmlGenericErrorContext, "\n");
8218#endif
8219 ctxt->depth++;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008220 switch (define->type) {
8221 case XML_RELAXNG_EMPTY:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008222 node = xmlRelaxNGSkipIgnored(ctxt, node);
8223 ret = 0;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008224 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008225 case XML_RELAXNG_NOT_ALLOWED:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008226 ret = -1;
8227 break;
8228 case XML_RELAXNG_TEXT:
8229 while ((node != NULL) &&
8230 ((node->type == XML_TEXT_NODE) ||
8231 (node->type == XML_COMMENT_NODE) ||
8232 (node->type == XML_PI_NODE) ||
8233 (node->type == XML_CDATA_SECTION_NODE)))
8234 node = node->next;
8235 ctxt->state->seq = node;
8236 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008237 case XML_RELAXNG_ELEMENT:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008238 errNr = ctxt->errNr;
8239 node = xmlRelaxNGSkipIgnored(ctxt, node);
8240 if (node == NULL) {
8241 VALID_ERR2(XML_RELAXNG_ERR_NOELEM, define->name);
8242 ret = -1;
8243 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8244 xmlRelaxNGDumpValidError(ctxt);
8245 break;
8246 }
8247 if (node->type != XML_ELEMENT_NODE) {
8248 VALID_ERR(XML_RELAXNG_ERR_NOTELEM);
8249 ret = -1;
8250 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8251 xmlRelaxNGDumpValidError(ctxt);
8252 break;
8253 }
8254 /*
8255 * This node was already validated successfully against
8256 * this definition.
8257 */
8258 if (node->_private == define) {
8259 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillard580ced82003-03-21 21:22:48 +00008260 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008261 if (ctxt->errNr != 0) {
8262 while ((ctxt->err != NULL) &&
8263 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8264 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008265 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8266 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008267 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8268 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8269 xmlRelaxNGValidErrorPop(ctxt);
8270 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008271 break;
8272 }
8273
8274 ret = xmlRelaxNGElementMatch(ctxt, define, node);
8275 if (ret <= 0) {
8276 ret = -1;
8277 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8278 xmlRelaxNGDumpValidError(ctxt);
8279 break;
8280 }
8281 ret = 0;
8282 if (ctxt->errNr != 0) {
Daniel Veillard580ced82003-03-21 21:22:48 +00008283 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008284 while ((ctxt->err != NULL) &&
8285 (((ctxt->err->err == XML_RELAXNG_ERR_ELEMNAME) &&
8286 (xmlStrEqual(ctxt->err->arg2, node->name))) ||
Daniel Veillard580ced82003-03-21 21:22:48 +00008287 ((ctxt->err->err == XML_RELAXNG_ERR_ELEMEXTRANS) &&
8288 (xmlStrEqual(ctxt->err->arg1, node->name))) ||
Daniel Veillardfd573f12003-03-16 17:52:32 +00008289 (ctxt->err->err == XML_RELAXNG_ERR_NOELEM) ||
8290 (ctxt->err->err == XML_RELAXNG_ERR_NOTELEM)))
8291 xmlRelaxNGValidErrorPop(ctxt);
8292 }
8293 errNr = ctxt->errNr;
8294
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008295 oldflags = ctxt->flags;
8296 if (ctxt->flags & FLAGS_MIXED_CONTENT) {
8297 ctxt->flags -= FLAGS_MIXED_CONTENT;
8298 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008299 state = xmlRelaxNGNewValidState(ctxt, node);
8300 if (state == NULL) {
8301 ret = -1;
8302 if ((ctxt->flags & FLAGS_IGNORABLE) == 0)
8303 xmlRelaxNGDumpValidError(ctxt);
8304 break;
8305 }
8306
8307 oldstate = ctxt->state;
8308 ctxt->state = state;
8309 if (define->attrs != NULL) {
8310 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
8311 if (tmp != 0) {
8312 ret = -1;
8313 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
8314 }
8315 }
8316 if (define->content != NULL) {
8317 tmp = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8318 if (tmp != 0) {
8319 ret = -1;
8320 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID, node->name);
8321 }
8322 }
8323 if (ctxt->states != NULL) {
8324 tmp = -1;
8325
Daniel Veillardfd573f12003-03-16 17:52:32 +00008326 ctxt->flags |= FLAGS_IGNORABLE;
8327
8328 for (i = 0;i < ctxt->states->nbState;i++) {
8329 state = ctxt->states->tabState[i];
8330 ctxt->state = state;
8331
8332 if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
8333 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008334 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008335 }
8336 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8337 ctxt->flags = oldflags;
8338 ctxt->states = NULL;
8339 if ((ret == 0) && (tmp == -1))
8340 ret = -1;
8341 } else {
8342 state = ctxt->state;
8343 if (ret == 0)
8344 ret = xmlRelaxNGValidateElementEnd(ctxt);
Daniel Veillard798024a2003-03-19 10:36:09 +00008345 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008346 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008347 if (ret == 0) {
8348 node->_private = define;
8349 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00008350 ctxt->flags = oldflags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008351 ctxt->state = oldstate;
8352 if (oldstate != NULL)
8353 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008354 if (ret != 0) {
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008355 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008356 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008357 ret = 0;
8358 } else {
8359 ret = -2;
8360 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008361 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008362 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008363 }
8364
8365#ifdef DEBUG
8366 xmlGenericError(xmlGenericErrorContext,
8367 "xmlRelaxNGValidateDefinition(): validated %s : %d",
8368 node->name, ret);
8369 if (oldstate == NULL)
8370 xmlGenericError(xmlGenericErrorContext, ": no state\n");
8371 else if (oldstate->seq == NULL)
8372 xmlGenericError(xmlGenericErrorContext, ": done\n");
8373 else if (oldstate->seq->type == XML_ELEMENT_NODE)
8374 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
8375 oldstate->seq->name);
8376 else
8377 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
8378 oldstate->seq->name, oldstate->seq->type);
8379#endif
8380 break;
8381 case XML_RELAXNG_OPTIONAL: {
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008382 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008383 oldflags = ctxt->flags;
8384 ctxt->flags |= FLAGS_IGNORABLE;
8385 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8386 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8387 if (ret != 0) {
8388 if (ctxt->state != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00008389 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008390 ctxt->state = oldstate;
8391 ctxt->flags = oldflags;
8392 ret = 0;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008393 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008394 break;
8395 }
8396 if (ctxt->states != NULL) {
8397 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8398 } else {
8399 ctxt->states = xmlRelaxNGNewStates(ctxt, 1);
8400 if (ctxt->states == NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008401 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008402 ctxt->flags = oldflags;
8403 ret = -1;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008404 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008405 break;
8406 }
8407 xmlRelaxNGAddStates(ctxt, ctxt->states, oldstate);
8408 xmlRelaxNGAddStates(ctxt, ctxt->states, ctxt->state);
8409 ctxt->state = NULL;
8410 }
8411 ctxt->flags = oldflags;
8412 ret = 0;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008413 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008414 break;
8415 }
8416 case XML_RELAXNG_ONEORMORE:
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008417 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008418 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
8419 if (ret != 0) {
8420 break;
8421 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008422 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008423 /* no break on purpose */
8424 case XML_RELAXNG_ZEROORMORE: {
8425 int progress;
8426 xmlRelaxNGStatesPtr states = NULL, res = NULL;
8427 int base, j;
8428
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008429 errNr = ctxt->errNr;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008430 res = xmlRelaxNGNewStates(ctxt, 1);
8431 if (res == NULL) {
8432 ret = -1;
8433 break;
8434 }
8435 /*
8436 * All the input states are also exit states
8437 */
8438 if (ctxt->state != NULL) {
8439 xmlRelaxNGAddStates(ctxt, res,
8440 xmlRelaxNGCopyValidState(ctxt, ctxt->state));
8441 } else {
8442 for (j = 0;j < ctxt->states->nbState;j++) {
8443 xmlRelaxNGAddStates(ctxt, res,
8444 xmlRelaxNGCopyValidState(ctxt,
8445 ctxt->states->tabState[j]));
8446 }
8447 }
8448 oldflags = ctxt->flags;
8449 ctxt->flags |= FLAGS_IGNORABLE;
8450 do {
8451 progress = 0;
8452 base = res->nbState;
8453
8454 if (ctxt->states != NULL) {
8455 states = ctxt->states;
8456 for (i = 0;i < states->nbState;i++) {
8457 ctxt->state = states->tabState[i];
8458 ctxt->states = NULL;
8459 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8460 define->content);
8461 if (ret == 0) {
8462 if (ctxt->state != NULL) {
8463 tmp = xmlRelaxNGAddStates(ctxt, res,
8464 ctxt->state);
8465 ctxt->state = NULL;
8466 if (tmp == 1)
8467 progress = 1;
8468 } else if (ctxt->states != NULL) {
8469 for (j = 0;j < ctxt->states->nbState;j++) {
8470 tmp = xmlRelaxNGAddStates(ctxt, res,
8471 ctxt->states->tabState[j]);
8472 if (tmp == 1)
8473 progress = 1;
8474 }
8475 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8476 ctxt->states = NULL;
8477 }
8478 } else {
8479 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008480 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008481 ctxt->state = NULL;
8482 }
8483 }
8484 }
8485 } else {
8486 ret = xmlRelaxNGValidateDefinitionList(ctxt,
8487 define->content);
8488 if (ret != 0) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008489 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008490 ctxt->state = NULL;
8491 } else {
8492 base = res->nbState;
8493 if (ctxt->state != NULL) {
8494 tmp = xmlRelaxNGAddStates(ctxt, res,
8495 ctxt->state);
8496 ctxt->state = NULL;
8497 if (tmp == 1)
8498 progress = 1;
8499 } else if (ctxt->states != NULL) {
8500 for (j = 0;j < ctxt->states->nbState;j++) {
8501 tmp = xmlRelaxNGAddStates(ctxt, res,
8502 ctxt->states->tabState[j]);
8503 if (tmp == 1)
8504 progress = 1;
8505 }
8506 if (states == NULL) {
8507 states = ctxt->states;
8508 } else {
8509 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8510 }
8511 ctxt->states = NULL;
8512 }
8513 }
8514 }
8515 if (progress) {
8516 /*
8517 * Collect all the new nodes added at that step
8518 * and make them the new node set
8519 */
8520 if (res->nbState - base == 1) {
8521 ctxt->state = xmlRelaxNGCopyValidState(ctxt,
8522 res->tabState[base]);
8523 } else {
8524 if (states == NULL) {
8525 xmlRelaxNGNewStates(ctxt, res->nbState - base);
8526 }
8527 states->nbState = 0;
8528 for (i = base;i < res->nbState;i++)
8529 xmlRelaxNGAddStates(ctxt, states,
8530 xmlRelaxNGCopyValidState(ctxt,
8531 res->tabState[i]));
8532 ctxt->states = states;
8533 }
8534 }
8535 } while (progress == 1);
8536 if (states != NULL) {
8537 xmlRelaxNGFreeStates(ctxt, states);
8538 }
8539 ctxt->states = res;
8540 ctxt->flags = oldflags;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008541 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008542 ret = 0;
8543 break;
8544 }
8545 case XML_RELAXNG_CHOICE: {
Daniel Veillard580ced82003-03-21 21:22:48 +00008546 xmlRelaxNGDefinePtr list = NULL;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008547 xmlRelaxNGStatesPtr states = NULL;
8548
Daniel Veillarde063f482003-03-21 16:53:17 +00008549 node = xmlRelaxNGSkipIgnored(ctxt, node);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008550
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008551 errNr = ctxt->errNr;
Daniel Veillarde063f482003-03-21 16:53:17 +00008552 if ((define->dflags & IS_TRIABLE) && (define->data != NULL)) {
8553 xmlHashTablePtr triage = (xmlHashTablePtr) define->data;
8554
8555 /*
8556 * Something we can optimize cleanly there is only one
8557 * possble branch out !
8558 */
8559 if (node == NULL) {
8560 ret = -1;
8561 break;
8562 }
8563 if ((node->type == XML_TEXT_NODE) ||
8564 (node->type == XML_CDATA_SECTION_NODE)) {
8565 list = xmlHashLookup2(triage, BAD_CAST "#text", NULL);
8566 } else if (node->type == XML_ELEMENT_NODE) {
8567 if (node->ns != NULL) {
8568 list = xmlHashLookup2(triage, node->name,
8569 node->ns->href);
8570 if (list == NULL)
8571 list = xmlHashLookup2(triage, BAD_CAST "#any",
8572 node->ns->href);
8573 } else
8574 list = xmlHashLookup2(triage, node->name, NULL);
8575 if (list == NULL)
8576 list = xmlHashLookup2(triage, BAD_CAST "#any", NULL);
8577 }
8578 if (list == NULL) {
8579 ret = -1;
8580 break;
8581 }
8582 ret = xmlRelaxNGValidateDefinition(ctxt, list);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008583 if (ret == 0) {
8584 }
Daniel Veillarde063f482003-03-21 16:53:17 +00008585 break;
8586 }
8587
8588 list = define->content;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008589 oldflags = ctxt->flags;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008590 ctxt->flags |= FLAGS_IGNORABLE;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008591
8592 while (list != NULL) {
8593 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
8594 ret = xmlRelaxNGValidateDefinition(ctxt, list);
8595 if (ret == 0) {
8596 if (states == NULL) {
8597 states = xmlRelaxNGNewStates(ctxt, 1);
8598 }
8599 if (ctxt->state != NULL) {
8600 xmlRelaxNGAddStates(ctxt, states, ctxt->state);
8601 } else if (ctxt->states != NULL) {
8602 for (i = 0;i < ctxt->states->nbState;i++) {
8603 xmlRelaxNGAddStates(ctxt, states,
8604 ctxt->states->tabState[i]);
8605 }
8606 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8607 ctxt->states = NULL;
8608 }
8609 } else {
Daniel Veillard798024a2003-03-19 10:36:09 +00008610 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008611 }
8612 ctxt->state = oldstate;
8613 list = list->next;
8614 }
8615 if (states != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008616 xmlRelaxNGFreeValidState(ctxt,oldstate);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008617 ctxt->states = states;
8618 ctxt->state = NULL;
8619 ret = 0;
8620 } else {
8621 ctxt->states = NULL;
8622 }
8623 ctxt->flags = oldflags;
8624 if (ret != 0) {
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008625 if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008626 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008627 }
8628 } else {
Daniel Veillard28c52ab2003-03-18 11:39:17 +00008629 if (ctxt->errNr > errNr) xmlRelaxNGPopErrors(ctxt, errNr);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008630 }
8631 break;
8632 }
8633 case XML_RELAXNG_DEF:
8634 case XML_RELAXNG_GROUP:
8635 ret = xmlRelaxNGValidateDefinitionList(ctxt, define->content);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008636 break;
8637 case XML_RELAXNG_INTERLEAVE:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008638 ret = xmlRelaxNGValidateInterleave(ctxt, define);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008639 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008640 case XML_RELAXNG_ATTRIBUTE:
8641 ret = xmlRelaxNGValidateAttribute(ctxt, define);
8642 break;
8643 case XML_RELAXNG_NOOP:
8644 case XML_RELAXNG_REF:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008645 case XML_RELAXNG_EXTERNALREF:
Daniel Veillardfd573f12003-03-16 17:52:32 +00008646 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8647 break;
Daniel Veillard952379b2003-03-17 15:37:12 +00008648 case XML_RELAXNG_PARENTREF:
8649 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
8650 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008651 case XML_RELAXNG_DATATYPE: {
8652 xmlNodePtr child;
8653 xmlChar *content = NULL;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008654
Daniel Veillardfd573f12003-03-16 17:52:32 +00008655 child = node;
8656 while (child != NULL) {
8657 if (child->type == XML_ELEMENT_NODE) {
8658 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM,
8659 node->parent->name);
8660 ret = -1;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008661 break;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008662 } else if ((child->type == XML_TEXT_NODE) ||
8663 (child->type == XML_CDATA_SECTION_NODE)) {
8664 content = xmlStrcat(content, child->content);
8665 }
8666 /* TODO: handle entities ... */
8667 child = child->next;
8668 }
8669 if (ret == -1) {
8670 if (content != NULL)
8671 xmlFree(content);
8672 break;
8673 }
8674 if (content == NULL) {
8675 content = xmlStrdup(BAD_CAST "");
8676 if (content == NULL) {
8677 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8678 ret = -1;
8679 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008680 }
8681 }
Daniel Veillardc3da18a2003-03-18 00:31:04 +00008682 ret = xmlRelaxNGValidateDatatype(ctxt, content, define,
8683 ctxt->state->seq);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008684 if (ret == -1) {
8685 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE, define->name);
8686 } else if (ret == 0) {
8687 ctxt->state->seq = NULL;
8688 }
8689 if (content != NULL)
8690 xmlFree(content);
8691 break;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008692 }
Daniel Veillardfd573f12003-03-16 17:52:32 +00008693 case XML_RELAXNG_VALUE: {
8694 xmlChar *content = NULL;
8695 xmlChar *oldvalue;
8696 xmlNodePtr child;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008697
Daniel Veillardfd573f12003-03-16 17:52:32 +00008698 child = node;
8699 while (child != NULL) {
8700 if (child->type == XML_ELEMENT_NODE) {
8701 VALID_ERR2(XML_RELAXNG_ERR_VALELEM,
8702 node->parent->name);
8703 ret = -1;
8704 break;
8705 } else if ((child->type == XML_TEXT_NODE) ||
8706 (child->type == XML_CDATA_SECTION_NODE)) {
8707 content = xmlStrcat(content, child->content);
8708 }
8709 /* TODO: handle entities ... */
8710 child = child->next;
8711 }
8712 if (ret == -1) {
8713 if (content != NULL)
8714 xmlFree(content);
8715 break;
8716 }
8717 if (content == NULL) {
8718 content = xmlStrdup(BAD_CAST "");
8719 if (content == NULL) {
8720 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8721 ret = -1;
8722 break;
8723 }
8724 }
8725 oldvalue = ctxt->state->value;
8726 ctxt->state->value = content;
8727 ret = xmlRelaxNGValidateValue(ctxt, define);
8728 ctxt->state->value = oldvalue;
8729 if (ret == -1) {
8730 VALID_ERR2(XML_RELAXNG_ERR_VALUE, define->name);
8731 } else if (ret == 0) {
8732 ctxt->state->seq = NULL;
8733 }
8734 if (content != NULL)
8735 xmlFree(content);
8736 break;
8737 }
8738 case XML_RELAXNG_LIST: {
8739 xmlChar *content;
8740 xmlNodePtr child;
8741 xmlChar *oldvalue, *oldendvalue;
8742 int len;
8743
8744 /*
8745 * Make sure it's only text nodes
8746 */
8747
8748 content = NULL;
8749 child = node;
8750 while (child != NULL) {
8751 if (child->type == XML_ELEMENT_NODE) {
8752 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM,
8753 node->parent->name);
8754 ret = -1;
8755 break;
8756 } else if ((child->type == XML_TEXT_NODE) ||
8757 (child->type == XML_CDATA_SECTION_NODE)) {
8758 content = xmlStrcat(content, child->content);
8759 }
8760 /* TODO: handle entities ... */
8761 child = child->next;
8762 }
8763 if (ret == -1) {
8764 if (content != NULL)
8765 xmlFree(content);
8766 break;
8767 }
8768 if (content == NULL) {
8769 content = xmlStrdup(BAD_CAST "");
8770 if (content == NULL) {
8771 VALID_ERR(XML_RELAXNG_ERR_MEMORY);
8772 ret = -1;
8773 break;
8774 }
8775 }
8776 len = xmlStrlen(content);
8777 oldvalue = ctxt->state->value;
8778 oldendvalue = ctxt->state->endvalue;
8779 ctxt->state->value = content;
8780 ctxt->state->endvalue = content + len;
8781 ret = xmlRelaxNGValidateValue(ctxt, define);
8782 ctxt->state->value = oldvalue;
8783 ctxt->state->endvalue = oldendvalue;
8784 if (ret == -1) {
8785 VALID_ERR(XML_RELAXNG_ERR_LIST);
8786 } else if ((ret == 0) && (node != NULL)) {
8787 ctxt->state->seq = node->next;
8788 }
8789 if (content != NULL)
8790 xmlFree(content);
8791 break;
8792 }
8793 case XML_RELAXNG_START:
8794 case XML_RELAXNG_EXCEPT:
8795 case XML_RELAXNG_PARAM:
8796 TODO
8797 ret = -1;
8798 break;
8799 }
8800 ctxt->depth--;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008801#ifdef DEBUG
Daniel Veillardfd573f12003-03-16 17:52:32 +00008802 for (i = 0;i < ctxt->depth;i++)
8803 xmlGenericError(xmlGenericErrorContext, " ");
8804 xmlGenericError(xmlGenericErrorContext,
8805 "Validating %s ", xmlRelaxNGDefName(define));
8806 if (define->name != NULL)
8807 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
8808 if (ret == 0)
8809 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
8810 else
8811 xmlGenericError(xmlGenericErrorContext, "failed\n");
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008812#endif
Daniel Veillardfd573f12003-03-16 17:52:32 +00008813 return(ret);
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008814}
8815
8816/**
Daniel Veillardfd573f12003-03-16 17:52:32 +00008817 * xmlRelaxNGValidateDefinition:
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008818 * @ctxt: a Relax-NG validation context
8819 * @define: the definition to verify
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008820 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008821 * Validate the current node lists against the definition
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008822 *
Daniel Veillardfd573f12003-03-16 17:52:32 +00008823 * Returns 0 if the validation succeeded or an error code.
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008824 */
8825static int
Daniel Veillardfd573f12003-03-16 17:52:32 +00008826xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
8827 xmlRelaxNGDefinePtr define) {
8828 xmlRelaxNGStatesPtr states, res;
8829 int i, j, k, ret, oldflags;
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008830
Daniel Veillardfd573f12003-03-16 17:52:32 +00008831 /*
8832 * We should NOT have both ctxt->state and ctxt->states
8833 */
8834 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8835 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008836 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008837 ctxt->state = NULL;
8838 }
8839
8840 if ((ctxt->states == NULL) || (ctxt->states->nbState == 1)) {
8841 if (ctxt->states != NULL) {
8842 ctxt->state = ctxt->states->tabState[0];
8843 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8844 ctxt->states = NULL;
8845 }
8846 ret = xmlRelaxNGValidateState(ctxt, define);
8847 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8848 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008849 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008850 ctxt->state = NULL;
8851 }
8852 if ((ctxt->states != NULL) && (ctxt->states->nbState == 1)) {
8853 ctxt->state = ctxt->states->tabState[0];
8854 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8855 ctxt->states = NULL;
8856 }
8857 return(ret);
8858 }
8859
8860 states = ctxt->states;
8861 ctxt->states = NULL;
8862 res = NULL;
8863 j = 0;
8864 oldflags = ctxt->flags;
8865 ctxt->flags |= FLAGS_IGNORABLE;
8866 for (i = 0;i < states->nbState;i++) {
8867 ctxt->state = states->tabState[i];
8868 ctxt->states = NULL;
8869 ret = xmlRelaxNGValidateState(ctxt, define);
8870 /*
8871 * We should NOT have both ctxt->state and ctxt->states
8872 */
8873 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8874 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008875 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008876 ctxt->state = NULL;
8877 }
8878 if (ret == 0) {
8879 if (ctxt->states == NULL) {
8880 if (res != NULL) {
8881 /* add the state to the container */
8882 xmlRelaxNGAddStates(ctxt, res, ctxt->state);
8883 ctxt->state = NULL;
8884 } else {
8885 /* add the state directly in states */
8886 states->tabState[j++] = ctxt->state;
8887 ctxt->state = NULL;
8888 }
8889 } else {
8890 if (res == NULL) {
8891 /* make it the new container and copy other results */
8892 res = ctxt->states;
8893 ctxt->states = NULL;
8894 for (k = 0;k < j;k++)
8895 xmlRelaxNGAddStates(ctxt, res, states->tabState[k]);
8896 } else {
8897 /* add all the new results to res and reff the container */
8898 for (k = 0;k < ctxt->states->nbState;k++)
8899 xmlRelaxNGAddStates(ctxt, res,
8900 ctxt->states->tabState[k]);
8901 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8902 ctxt->states = NULL;
8903 }
8904 }
8905 } else {
8906 if (ctxt->state != NULL) {
Daniel Veillard798024a2003-03-19 10:36:09 +00008907 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008908 ctxt->state = NULL;
8909 } else if (ctxt->states != NULL) {
8910 for (k = 0;k < ctxt->states->nbState;k++)
Daniel Veillard798024a2003-03-19 10:36:09 +00008911 xmlRelaxNGFreeValidState(ctxt,ctxt->states->tabState[k]);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008912 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8913 ctxt->states = NULL;
8914 }
8915 }
8916 }
8917 ctxt->flags = oldflags;
8918 if (res != NULL) {
8919 xmlRelaxNGFreeStates(ctxt, states);
8920 ctxt->states = res;
8921 ret = 0;
8922 } else if (j > 1) {
8923 states->nbState = j;
8924 ctxt->states = states;
8925 ret =0;
8926 } else if (j == 1) {
8927 ctxt->state = states->tabState[0];
8928 xmlRelaxNGFreeStates(ctxt, states);
8929 ret = 0;
8930 } else {
8931 ret = -1;
8932 xmlRelaxNGFreeStates(ctxt, states);
8933 if (ctxt->states != NULL) {
8934 xmlRelaxNGFreeStates(ctxt, ctxt->states);
8935 ctxt->states = NULL;
8936 }
8937 }
8938 if ((ctxt->state != NULL) && (ctxt->states != NULL)) {
8939 TODO
Daniel Veillard798024a2003-03-19 10:36:09 +00008940 xmlRelaxNGFreeValidState(ctxt,ctxt->state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008941 ctxt->state = NULL;
8942 }
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008943 return(ret);
8944}
8945
Daniel Veillard1564e6e2003-03-15 21:30:25 +00008946/**
Daniel Veillard6eadf632003-01-23 18:29:16 +00008947 * xmlRelaxNGValidateDocument:
8948 * @ctxt: a Relax-NG validation context
8949 * @doc: the document
8950 *
8951 * Validate the given document
8952 *
8953 * Returns 0 if the validation succeeded or an error code.
8954 */
8955static int
8956xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
8957 int ret;
8958 xmlRelaxNGPtr schema;
8959 xmlRelaxNGGrammarPtr grammar;
8960 xmlRelaxNGValidStatePtr state;
Daniel Veillardfd573f12003-03-16 17:52:32 +00008961 xmlNodePtr node;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008962
8963 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
8964 return(-1);
8965
Daniel Veillarda507fbf2003-03-31 16:09:37 +00008966 ctxt->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008967 schema = ctxt->schema;
8968 grammar = schema->topgrammar;
8969 if (grammar == NULL) {
Daniel Veillard42f12e92003-03-07 18:32:59 +00008970 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR);
Daniel Veillard6eadf632003-01-23 18:29:16 +00008971 return(-1);
8972 }
8973 state = xmlRelaxNGNewValidState(ctxt, NULL);
8974 ctxt->state = state;
8975 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008976 if ((ctxt->state != NULL) && (state->seq != NULL)) {
8977 state = ctxt->state;
Daniel Veillard6eadf632003-01-23 18:29:16 +00008978 node = state->seq;
8979 node = xmlRelaxNGSkipIgnored(ctxt, node);
8980 if (node != NULL) {
Daniel Veillardfd573f12003-03-16 17:52:32 +00008981 if (ret != -1) {
8982 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
8983 ret = -1;
8984 }
8985 }
8986 } else if (ctxt->states != NULL) {
8987 int i;
8988 int tmp = -1;
8989
8990 for (i = 0;i < ctxt->states->nbState;i++) {
8991 state = ctxt->states->tabState[i];
8992 node = state->seq;
8993 node = xmlRelaxNGSkipIgnored(ctxt, node);
8994 if (node == NULL)
8995 tmp = 0;
Daniel Veillard798024a2003-03-19 10:36:09 +00008996 xmlRelaxNGFreeValidState(ctxt,state);
Daniel Veillardfd573f12003-03-16 17:52:32 +00008997 }
8998 if (tmp == -1) {
8999 if (ret != -1) {
9000 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA);
9001 ret = -1;
9002 }
Daniel Veillard6eadf632003-01-23 18:29:16 +00009003 }
9004 }
Daniel Veillardbbb78b52003-03-21 01:24:45 +00009005 if (ctxt->state != NULL) {
9006 xmlRelaxNGFreeValidState(ctxt, ctxt->state);
9007 ctxt->state = NULL;
9008 }
Daniel Veillard580ced82003-03-21 21:22:48 +00009009 if (ret != 0)
Daniel Veillardfd573f12003-03-16 17:52:32 +00009010 xmlRelaxNGDumpValidError(ctxt);
Daniel Veillard580ced82003-03-21 21:22:48 +00009011#ifdef DEBUG
9012 else if (ctxt->errNr != 0) {
9013 ctxt->error(ctxt->userData, "%d Extra error messages left on stack !\n",
9014 ctxt->errNr);
9015 xmlRelaxNGDumpValidError(ctxt);
9016 }
9017#endif
Daniel Veillardc3da18a2003-03-18 00:31:04 +00009018 if (ctxt->idref == 1) {
9019 xmlValidCtxt vctxt;
9020
9021 memset(&vctxt, 0, sizeof(xmlValidCtxt));
9022 vctxt.valid = 1;
9023 vctxt.error = ctxt->error;
9024 vctxt.warning = ctxt->warning;
9025 vctxt.userData = ctxt->userData;
9026
9027 if (xmlValidateDocumentFinal(&vctxt, doc) != 1)
9028 ret = -1;
9029 }
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009030 if ((ret == 0) && (ctxt->errNo != XML_RELAXNG_OK))
9031 ret = -1;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009032
9033 return(ret);
9034}
9035
Daniel Veillardfd573f12003-03-16 17:52:32 +00009036/************************************************************************
9037 * *
9038 * Validation interfaces *
9039 * *
9040 ************************************************************************/
Daniel Veillard6eadf632003-01-23 18:29:16 +00009041/**
9042 * xmlRelaxNGNewValidCtxt:
9043 * @schema: a precompiled XML RelaxNGs
9044 *
9045 * Create an XML RelaxNGs validation context based on the given schema
9046 *
9047 * Returns the validation context or NULL in case of error
9048 */
9049xmlRelaxNGValidCtxtPtr
9050xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
9051 xmlRelaxNGValidCtxtPtr ret;
9052
9053 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
9054 if (ret == NULL) {
9055 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardfd573f12003-03-16 17:52:32 +00009056 "Failed to allocate new schema validation context\n");
Daniel Veillard6eadf632003-01-23 18:29:16 +00009057 return (NULL);
9058 }
9059 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
9060 ret->schema = schema;
Daniel Veillard1703c5f2003-02-10 14:28:44 +00009061 ret->error = xmlGenericError;
9062 ret->userData = xmlGenericErrorContext;
Daniel Veillard42f12e92003-03-07 18:32:59 +00009063 ret->errNr = 0;
9064 ret->errMax = 0;
9065 ret->err = NULL;
9066 ret->errTab = NULL;
Daniel Veillardc3da18a2003-03-18 00:31:04 +00009067 ret->idref = schema->idref;
Daniel Veillard798024a2003-03-19 10:36:09 +00009068 ret->states = NULL;
9069 ret->freeState = NULL;
9070 ret->freeStates = NULL;
Daniel Veillarda507fbf2003-03-31 16:09:37 +00009071 ret->errNo = XML_RELAXNG_OK;
Daniel Veillard6eadf632003-01-23 18:29:16 +00009072 return (ret);
9073}
9074
9075/**
9076 * xmlRelaxNGFreeValidCtxt:
9077 * @ctxt: the schema validation context
9078 *
9079 * Free the resources associated to the schema validation context
9080 */
9081void
9082xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
Daniel Veillard798024a2003-03-19 10:36:09 +00009083 int k;
9084
Daniel Veillard6eadf632003-01-23 18:29:16 +00009085 if (ctxt == NULL)
9086 return;
Daniel Veillardfd573f12003-03-16 17:52:32 +00009087 if (ctxt->states != NULL)
Daniel Veillard798024a2003-03-19 10:36:09 +00009088 xmlRelaxNGFreeStates(NULL, ctxt->states);
9089 if (ctxt->freeState != NULL) {
9090 for (k = 0;k < ctxt->freeState->nbState;k++) {
9091 xmlRelaxNGFreeValidState(NULL, ctxt->freeState->tabState[k]);
9092 }
9093 xmlRelaxNGFreeStates(NULL, ctxt->freeState);
9094 }
Daniel Veillard798024a2003-03-19 10:36:09 +00009095 if (ctxt->freeStates != NULL) {
9096 for (k = 0;k < ctxt->freeStatesNr;k++) {
9097 xmlRelaxNGFreeStates(NULL, ctxt->freeStates[k]);
9098 }
9099 xmlFree(ctxt->freeStates);
9100 }
Daniel Veillard42f12e92003-03-07 18:32:59 +00009101 if (ctxt->errTab != NULL)
9102 xmlFree(ctxt->errTab);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009103 xmlFree(ctxt);
9104}
9105
9106/**
9107 * xmlRelaxNGSetValidErrors:
9108 * @ctxt: a Relax-NG validation context
9109 * @err: the error function
9110 * @warn: the warning function
9111 * @ctx: the functions context
9112 *
9113 * Set the error and warning callback informations
9114 */
9115void
9116xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
9117 xmlRelaxNGValidityErrorFunc err,
9118 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
9119 if (ctxt == NULL)
9120 return;
9121 ctxt->error = err;
9122 ctxt->warning = warn;
9123 ctxt->userData = ctx;
9124}
9125
9126/**
9127 * xmlRelaxNGValidateDoc:
9128 * @ctxt: a Relax-NG validation context
9129 * @doc: a parsed document tree
9130 *
9131 * Validate a document tree in memory.
9132 *
9133 * Returns 0 if the document is valid, a positive error code
9134 * number otherwise and -1 in case of internal or API error.
9135 */
9136int
9137xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
9138 int ret;
9139
9140 if ((ctxt == NULL) || (doc == NULL))
9141 return(-1);
9142
9143 ctxt->doc = doc;
9144
9145 ret = xmlRelaxNGValidateDocument(ctxt, doc);
Daniel Veillard71531f32003-02-05 13:19:53 +00009146 /*
9147 * TODO: build error codes
9148 */
9149 if (ret == -1)
9150 return(1);
Daniel Veillard6eadf632003-01-23 18:29:16 +00009151 return(ret);
9152}
9153
9154#endif /* LIBXML_SCHEMAS_ENABLED */
9155