| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1 | /* | 
|  | 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 Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 9 | /** | 
|  | 10 | * TODO: | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 11 | * - error reporting | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 12 | * - simplification of the resulting compiled trees: | 
|  | 13 | *    - NOT_ALLOWED | 
|  | 14 | *    - EMPTY | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 15 | * - handle namespace declarations as attributes. | 
| Daniel Veillard | f4b4f98 | 2003-02-13 11:02:08 +0000 | [diff] [blame] | 16 | * - add support for DTD compatibility spec | 
|  | 17 | *   http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 18 | */ | 
|  | 19 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 20 | #define IN_LIBXML | 
|  | 21 | #include "libxml.h" | 
|  | 22 |  | 
|  | 23 | #ifdef LIBXML_SCHEMAS_ENABLED | 
|  | 24 |  | 
|  | 25 | #include <string.h> | 
|  | 26 | #include <stdio.h> | 
|  | 27 | #include <libxml/xmlmemory.h> | 
|  | 28 | #include <libxml/parser.h> | 
|  | 29 | #include <libxml/parserInternals.h> | 
|  | 30 | #include <libxml/hash.h> | 
|  | 31 | #include <libxml/uri.h> | 
|  | 32 |  | 
|  | 33 | #include <libxml/relaxng.h> | 
|  | 34 |  | 
|  | 35 | #include <libxml/xmlschemastypes.h> | 
|  | 36 | #include <libxml/xmlautomata.h> | 
|  | 37 | #include <libxml/xmlregexp.h> | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 38 | #include <libxml/xmlschemastypes.h> | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 39 |  | 
|  | 40 | /* | 
|  | 41 | * The Relax-NG namespace | 
|  | 42 | */ | 
|  | 43 | static const xmlChar *xmlRelaxNGNs = (const xmlChar *) | 
|  | 44 | "http://relaxng.org/ns/structure/1.0"; | 
|  | 45 |  | 
|  | 46 | #define IS_RELAXNG(node, type)						\ | 
|  | 47 | ((node != NULL) && (node->ns != NULL) &&				\ | 
|  | 48 | (xmlStrEqual(node->name, (const xmlChar *) type)) &&		\ | 
|  | 49 | (xmlStrEqual(node->ns->href, xmlRelaxNGNs))) | 
|  | 50 |  | 
|  | 51 |  | 
| Daniel Veillard | 71531f3 | 2003-02-05 13:19:53 +0000 | [diff] [blame] | 52 | /* #define DEBUG 1 */                /* very verbose output */ | 
|  | 53 | /* #define DEBUG_CONTENT 1 */ | 
|  | 54 | /* #define DEBUG_TYPE 1 */ | 
|  | 55 | /* #define DEBUG_VALID 1 */ | 
| Daniel Veillard | e5b110b | 2003-02-04 14:43:39 +0000 | [diff] [blame] | 56 | /* #define DEBUG_INTERLEAVE 1 */ | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 57 | /* #define DEBUG_LIST 1 */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 58 |  | 
|  | 59 | #define UNBOUNDED (1 << 30) | 
|  | 60 | #define TODO 								\ | 
|  | 61 | xmlGenericError(xmlGenericErrorContext,				\ | 
|  | 62 | "Unimplemented block at %s:%d\n",				\ | 
|  | 63 | __FILE__, __LINE__); | 
|  | 64 |  | 
|  | 65 | typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema; | 
|  | 66 | typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr; | 
|  | 67 |  | 
|  | 68 | typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine; | 
|  | 69 | typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr; | 
|  | 70 |  | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 71 | typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument; | 
|  | 72 | typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr; | 
|  | 73 |  | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 74 | typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude; | 
|  | 75 | typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr; | 
|  | 76 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 77 | typedef enum { | 
|  | 78 | XML_RELAXNG_COMBINE_UNDEFINED = 0,	/* undefined */ | 
|  | 79 | XML_RELAXNG_COMBINE_CHOICE,		/* choice */ | 
|  | 80 | XML_RELAXNG_COMBINE_INTERLEAVE	/* interleave */ | 
|  | 81 | } xmlRelaxNGCombine; | 
|  | 82 |  | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 83 | typedef enum { | 
|  | 84 | XML_RELAXNG_CONTENT_ERROR = -1, | 
|  | 85 | XML_RELAXNG_CONTENT_EMPTY = 0, | 
|  | 86 | XML_RELAXNG_CONTENT_SIMPLE, | 
|  | 87 | XML_RELAXNG_CONTENT_COMPLEX | 
|  | 88 | } xmlRelaxNGContentType; | 
|  | 89 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 90 | typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar; | 
|  | 91 | typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr; | 
|  | 92 |  | 
|  | 93 | struct _xmlRelaxNGGrammar { | 
|  | 94 | xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */ | 
|  | 95 | xmlRelaxNGGrammarPtr children;/* the children grammar if any */ | 
|  | 96 | xmlRelaxNGGrammarPtr next;	/* the next grammar if any */ | 
|  | 97 | xmlRelaxNGDefinePtr start;	/* <start> content */ | 
|  | 98 | xmlRelaxNGCombine combine;	/* the default combine value */ | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 99 | xmlRelaxNGDefinePtr startList;/* list of <start> definitions */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 100 | xmlHashTablePtr defs;	/* define* */ | 
|  | 101 | xmlHashTablePtr refs;	/* references */ | 
|  | 102 | }; | 
|  | 103 |  | 
|  | 104 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 105 | typedef enum { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 106 | XML_RELAXNG_NOOP = -1,	/* a no operation from simplification  */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 107 | XML_RELAXNG_EMPTY = 0,	/* an empty pattern */ | 
|  | 108 | XML_RELAXNG_NOT_ALLOWED,    /* not allowed top */ | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 109 | XML_RELAXNG_EXCEPT,    	/* except present in nameclass defs */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 110 | XML_RELAXNG_TEXT,		/* textual content */ | 
|  | 111 | XML_RELAXNG_ELEMENT,	/* an element */ | 
|  | 112 | XML_RELAXNG_DATATYPE,	/* extenal data type definition */ | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 113 | XML_RELAXNG_PARAM,		/* extenal data type parameter */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 114 | XML_RELAXNG_VALUE,		/* value from an extenal data type definition */ | 
|  | 115 | XML_RELAXNG_LIST,		/* a list of patterns */ | 
|  | 116 | XML_RELAXNG_ATTRIBUTE,	/* an attrbute following a pattern */ | 
|  | 117 | XML_RELAXNG_DEF,		/* a definition */ | 
|  | 118 | XML_RELAXNG_REF,		/* reference to a definition */ | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 119 | XML_RELAXNG_EXTERNALREF,	/* reference to an external def */ | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 120 | XML_RELAXNG_PARENTREF,	/* reference to a def in the parent grammar */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 121 | XML_RELAXNG_OPTIONAL,	/* optional patterns */ | 
|  | 122 | XML_RELAXNG_ZEROORMORE,	/* zero or more non empty patterns */ | 
|  | 123 | XML_RELAXNG_ONEORMORE,	/* one or more non empty patterns */ | 
|  | 124 | XML_RELAXNG_CHOICE,		/* a choice between non empty patterns */ | 
|  | 125 | XML_RELAXNG_GROUP,		/* a pair/group of non empty patterns */ | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 126 | XML_RELAXNG_INTERLEAVE,	/* interleaving choice of non-empty patterns */ | 
|  | 127 | XML_RELAXNG_START		/* Used to keep track of starts on grammars */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 128 | } xmlRelaxNGType; | 
|  | 129 |  | 
|  | 130 | struct _xmlRelaxNGDefine { | 
|  | 131 | xmlRelaxNGType type;	/* the type of definition */ | 
|  | 132 | xmlNodePtr	   node;	/* the node in the source */ | 
|  | 133 | xmlChar       *name;	/* the element local name if present */ | 
|  | 134 | xmlChar       *ns;		/* the namespace local name if present */ | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 135 | xmlChar       *value;	/* value when available */ | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 136 | void          *data;	/* data lib or specific pointer */ | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 137 | int            depth;       /* used for the cycle detection */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 138 | xmlRelaxNGDefinePtr content;/* the expected content */ | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 139 | xmlRelaxNGDefinePtr parent;	/* the parent definition, if any */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 140 | xmlRelaxNGDefinePtr next;	/* list within grouping sequences */ | 
|  | 141 | xmlRelaxNGDefinePtr attrs;	/* list of attributes for elements */ | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 142 | xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 143 | xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */ | 
|  | 144 | }; | 
|  | 145 |  | 
|  | 146 | /** | 
|  | 147 | * _xmlRelaxNG: | 
|  | 148 | * | 
|  | 149 | * A RelaxNGs definition | 
|  | 150 | */ | 
|  | 151 | struct _xmlRelaxNG { | 
|  | 152 | xmlRelaxNGGrammarPtr topgrammar; | 
|  | 153 | xmlDocPtr doc; | 
|  | 154 |  | 
|  | 155 | xmlHashTablePtr defs;	/* define */ | 
|  | 156 | xmlHashTablePtr refs;	/* references */ | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 157 | xmlHashTablePtr documents;  /* all the documents loaded */ | 
|  | 158 | xmlHashTablePtr includes;   /* all the includes loaded */ | 
|  | 159 | int                  defNr; /* number of defines used */ | 
|  | 160 | xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 161 | void *_private;	/* unused by the library for users or bindings */ | 
|  | 162 | }; | 
|  | 163 |  | 
|  | 164 | typedef enum { | 
|  | 165 | XML_RELAXNG_ERR_OK		= 0, | 
|  | 166 | XML_RELAXNG_ERR_NOROOT	= 1, | 
|  | 167 | XML_RELAXNG_ERR_ | 
|  | 168 | } xmlRelaxNGValidError; | 
|  | 169 |  | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 170 | #define XML_RELAXNG_IN_ATTRIBUTE	(1 << 0) | 
|  | 171 | #define XML_RELAXNG_IN_ONEORMORE	(1 << 1) | 
|  | 172 | #define XML_RELAXNG_IN_LIST		(1 << 2) | 
|  | 173 | #define XML_RELAXNG_IN_DATAEXCEPT	(1 << 3) | 
|  | 174 | #define XML_RELAXNG_IN_START		(1 << 4) | 
|  | 175 | #define XML_RELAXNG_IN_OOMGROUP		(1 << 5) | 
|  | 176 | #define XML_RELAXNG_IN_OOMINTERLEAVE	(1 << 6) | 
|  | 177 | #define XML_RELAXNG_IN_EXTERNALREF	(1 << 7) | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 178 | #define XML_RELAXNG_IN_ANYEXCEPT	(1 << 8) | 
|  | 179 | #define XML_RELAXNG_IN_NSEXCEPT		(1 << 9) | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 180 |  | 
|  | 181 | struct _xmlRelaxNGParserCtxt { | 
|  | 182 | void *userData;			/* user specific data block */ | 
|  | 183 | xmlRelaxNGValidityErrorFunc error;	/* the callback in case of errors */ | 
|  | 184 | xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */ | 
|  | 185 | xmlRelaxNGValidError err; | 
|  | 186 |  | 
|  | 187 | xmlRelaxNGPtr      schema;        /* The schema in use */ | 
|  | 188 | xmlRelaxNGGrammarPtr grammar;     /* the current grammar */ | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 189 | xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 190 | int                flags;         /* parser flags */ | 
|  | 191 | int                nbErrors;      /* number of errors at parse time */ | 
|  | 192 | int                nbWarnings;    /* number of warnings at parse time */ | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 193 | const xmlChar     *define;        /* the current define scope */ | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 194 | xmlRelaxNGDefinePtr def;          /* the current define */ | 
|  | 195 |  | 
|  | 196 | int                nbInterleaves; | 
|  | 197 | xmlHashTablePtr    interleaves;   /* keep track of all the interleaves */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 198 |  | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 199 | xmlHashTablePtr    documents;     /* all the documents loaded */ | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 200 | xmlHashTablePtr    includes;      /* all the includes loaded */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 201 | xmlChar	      *URL; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 202 | xmlDocPtr          document; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 203 |  | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 204 | int                  defNr;       /* number of defines used */ | 
|  | 205 | int                  defMax;      /* number of defines aloocated */ | 
|  | 206 | xmlRelaxNGDefinePtr *defTab;      /* pointer to the allocated definitions */ | 
|  | 207 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 208 | const char     *buffer; | 
|  | 209 | int               size; | 
|  | 210 |  | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 211 | /* the document stack */ | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 212 | xmlRelaxNGDocumentPtr doc;        /* Current parsed external ref */ | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 213 | int                   docNr;      /* Depth of the parsing stack */ | 
|  | 214 | int                   docMax;     /* Max depth of the parsing stack */ | 
|  | 215 | xmlRelaxNGDocumentPtr *docTab;    /* array of docs */ | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 216 |  | 
|  | 217 | /* the include stack */ | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 218 | xmlRelaxNGIncludePtr  inc;        /* Current parsed include */ | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 219 | int                   incNr;      /* Depth of the include parsing stack */ | 
|  | 220 | int                   incMax;     /* Max depth of the parsing stack */ | 
|  | 221 | xmlRelaxNGIncludePtr *incTab;     /* array of incs */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 222 | }; | 
|  | 223 |  | 
|  | 224 | #define FLAGS_IGNORABLE		1 | 
|  | 225 | #define FLAGS_NEGATIVE		2 | 
|  | 226 |  | 
|  | 227 | /** | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 228 | * xmlRelaxNGInterleaveGroup: | 
|  | 229 | * | 
|  | 230 | * A RelaxNGs partition set associated to lists of definitions | 
|  | 231 | */ | 
|  | 232 | typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup; | 
|  | 233 | typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr; | 
|  | 234 | struct _xmlRelaxNGInterleaveGroup { | 
|  | 235 | xmlRelaxNGDefinePtr  rule;	/* the rule to satisfy */ | 
|  | 236 | xmlRelaxNGDefinePtr *defs;	/* the array of element definitions */ | 
|  | 237 | }; | 
|  | 238 |  | 
|  | 239 | /** | 
|  | 240 | * xmlRelaxNGPartitions: | 
|  | 241 | * | 
|  | 242 | * A RelaxNGs partition associated to an interleave group | 
|  | 243 | */ | 
|  | 244 | typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition; | 
|  | 245 | typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr; | 
|  | 246 | struct _xmlRelaxNGPartition { | 
|  | 247 | int nbgroups;		/* number of groups in the partitions */ | 
|  | 248 | xmlRelaxNGInterleaveGroupPtr *groups; | 
|  | 249 | }; | 
|  | 250 |  | 
|  | 251 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 252 | * xmlRelaxNGValidState: | 
|  | 253 | * | 
|  | 254 | * A RelaxNGs validation state | 
|  | 255 | */ | 
|  | 256 | #define MAX_ATTR 20 | 
|  | 257 | typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState; | 
|  | 258 | typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr; | 
|  | 259 | struct _xmlRelaxNGValidState { | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 260 | xmlNodePtr   node;		/* the current node */ | 
|  | 261 | xmlNodePtr    seq;		/* the sequence of children left to validate */ | 
|  | 262 | int       nbAttrs;		/* the number of attributes */ | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 263 | int    nbAttrLeft;		/* the number of attributes left to validate */ | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 264 | xmlChar    *value;		/* the value when operating on string */ | 
|  | 265 | xmlChar *endvalue;		/* the end value when operating on string */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 266 | xmlAttrPtr attrs[1];	/* the array of attributes */ | 
|  | 267 | }; | 
|  | 268 |  | 
|  | 269 | /** | 
|  | 270 | * xmlRelaxNGValidCtxt: | 
|  | 271 | * | 
|  | 272 | * A RelaxNGs validation context | 
|  | 273 | */ | 
|  | 274 |  | 
|  | 275 | struct _xmlRelaxNGValidCtxt { | 
|  | 276 | void *userData;			/* user specific data block */ | 
|  | 277 | xmlRelaxNGValidityErrorFunc error;	/* the callback in case of errors */ | 
|  | 278 | xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */ | 
|  | 279 |  | 
|  | 280 | xmlRelaxNGPtr           schema;	/* The schema in use */ | 
|  | 281 | xmlDocPtr               doc;	/* the document being validated */ | 
|  | 282 | xmlRelaxNGValidStatePtr state;	/* the current validation state */ | 
|  | 283 | int                     flags;	/* validation flags */ | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 284 | int                     depth;	/* validation depth */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 285 | }; | 
|  | 286 |  | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 287 | /** | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 288 | * xmlRelaxNGInclude: | 
|  | 289 | * | 
|  | 290 | * Structure associated to a RelaxNGs document element | 
|  | 291 | */ | 
|  | 292 | struct _xmlRelaxNGInclude { | 
|  | 293 | xmlChar   *href;		/* the normalized href value */ | 
|  | 294 | xmlDocPtr  doc;		/* the associated XML document */ | 
|  | 295 | xmlRelaxNGDefinePtr content;/* the definitions */ | 
|  | 296 | xmlRelaxNGPtr	schema; /* the schema */ | 
|  | 297 | }; | 
|  | 298 |  | 
|  | 299 | /** | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 300 | * xmlRelaxNGDocument: | 
|  | 301 | * | 
|  | 302 | * Structure associated to a RelaxNGs document element | 
|  | 303 | */ | 
|  | 304 | struct _xmlRelaxNGDocument { | 
|  | 305 | xmlChar   *href;		/* the normalized href value */ | 
|  | 306 | xmlDocPtr  doc;		/* the associated XML document */ | 
|  | 307 | xmlRelaxNGDefinePtr content;/* the definitions */ | 
|  | 308 | xmlRelaxNGPtr	schema; /* the schema */ | 
|  | 309 | }; | 
|  | 310 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 311 | /************************************************************************ | 
|  | 312 | * 									* | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 313 | * 		Preliminary type checking interfaces			* | 
|  | 314 | * 									* | 
|  | 315 | ************************************************************************/ | 
|  | 316 | /** | 
|  | 317 | * xmlRelaxNGTypeHave: | 
|  | 318 | * @data:  data needed for the library | 
|  | 319 | * @type:  the type name | 
|  | 320 | * @value:  the value to check | 
|  | 321 | * | 
|  | 322 | * Function provided by a type library to check if a type is exported | 
|  | 323 | * | 
|  | 324 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 325 | */ | 
|  | 326 | typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type); | 
|  | 327 |  | 
|  | 328 | /** | 
|  | 329 | * xmlRelaxNGTypeCheck: | 
|  | 330 | * @data:  data needed for the library | 
|  | 331 | * @type:  the type name | 
|  | 332 | * @value:  the value to check | 
|  | 333 | * | 
|  | 334 | * Function provided by a type library to check if a value match a type | 
|  | 335 | * | 
|  | 336 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 337 | */ | 
|  | 338 | typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type, | 
|  | 339 | const xmlChar *value); | 
|  | 340 |  | 
|  | 341 | /** | 
|  | 342 | * xmlRelaxNGTypeCompare: | 
|  | 343 | * @data:  data needed for the library | 
|  | 344 | * @type:  the type name | 
|  | 345 | * @value1:  the first value | 
|  | 346 | * @value2:  the second value | 
|  | 347 | * | 
|  | 348 | * Function provided by a type library to compare two values accordingly | 
|  | 349 | * to a type. | 
|  | 350 | * | 
|  | 351 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 352 | */ | 
|  | 353 | typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type, | 
|  | 354 | const xmlChar *value1, | 
|  | 355 | const xmlChar *value2); | 
|  | 356 | typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary; | 
|  | 357 | typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr; | 
|  | 358 | struct _xmlRelaxNGTypeLibrary { | 
|  | 359 | const xmlChar     *namespace;	/* the datatypeLibrary value */ | 
|  | 360 | void                   *data;	/* data needed for the library */ | 
|  | 361 | xmlRelaxNGTypeHave      have;	/* the export function */ | 
|  | 362 | xmlRelaxNGTypeCheck    check;	/* the checking function */ | 
|  | 363 | xmlRelaxNGTypeCompare   comp;	/* the compare function */ | 
|  | 364 | }; | 
|  | 365 |  | 
|  | 366 | /************************************************************************ | 
|  | 367 | * 									* | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 368 | * 			Allocation functions				* | 
|  | 369 | * 									* | 
|  | 370 | ************************************************************************/ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 371 | static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar); | 
|  | 372 | static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define); | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 373 | static void xmlRelaxNGNormExtSpace(xmlChar *value); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 374 |  | 
|  | 375 | /** | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 376 | * xmlRelaxNGFreeDocument: | 
|  | 377 | * @docu:  a document structure | 
|  | 378 | * | 
|  | 379 | * Deallocate a RelaxNG document structure. | 
|  | 380 | */ | 
|  | 381 | static void | 
|  | 382 | xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu) | 
|  | 383 | { | 
|  | 384 | if (docu == NULL) | 
|  | 385 | return; | 
|  | 386 |  | 
|  | 387 | if (docu->href != NULL) | 
|  | 388 | xmlFree(docu->href); | 
|  | 389 | if (docu->doc != NULL) | 
|  | 390 | xmlFreeDoc(docu->doc); | 
|  | 391 | if (docu->schema != NULL) | 
|  | 392 | xmlRelaxNGFree(docu->schema); | 
|  | 393 | xmlFree(docu); | 
|  | 394 | } | 
|  | 395 |  | 
|  | 396 | /** | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 397 | * xmlRelaxNGFreeInclude: | 
|  | 398 | * @incl:  a include structure | 
|  | 399 | * | 
|  | 400 | * Deallocate a RelaxNG include structure. | 
|  | 401 | */ | 
|  | 402 | static void | 
|  | 403 | xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl) | 
|  | 404 | { | 
|  | 405 | if (incl == NULL) | 
|  | 406 | return; | 
|  | 407 |  | 
|  | 408 | if (incl->href != NULL) | 
|  | 409 | xmlFree(incl->href); | 
|  | 410 | if (incl->doc != NULL) | 
|  | 411 | xmlFreeDoc(incl->doc); | 
|  | 412 | if (incl->schema != NULL) | 
|  | 413 | xmlRelaxNGFree(incl->schema); | 
|  | 414 | xmlFree(incl); | 
|  | 415 | } | 
|  | 416 |  | 
|  | 417 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 418 | * xmlRelaxNGNewRelaxNG: | 
|  | 419 | * @ctxt:  a Relax-NG validation context (optional) | 
|  | 420 | * | 
|  | 421 | * Allocate a new RelaxNG structure. | 
|  | 422 | * | 
|  | 423 | * Returns the newly allocated structure or NULL in case or error | 
|  | 424 | */ | 
|  | 425 | static xmlRelaxNGPtr | 
|  | 426 | xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt) | 
|  | 427 | { | 
|  | 428 | xmlRelaxNGPtr ret; | 
|  | 429 |  | 
|  | 430 | ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG)); | 
|  | 431 | if (ret == NULL) { | 
|  | 432 | if ((ctxt != NULL) && (ctxt->error != NULL)) | 
|  | 433 | ctxt->error(ctxt->userData, "Out of memory\n"); | 
|  | 434 | ctxt->nbErrors++; | 
|  | 435 | return (NULL); | 
|  | 436 | } | 
|  | 437 | memset(ret, 0, sizeof(xmlRelaxNG)); | 
|  | 438 |  | 
|  | 439 | return (ret); | 
|  | 440 | } | 
|  | 441 |  | 
|  | 442 | /** | 
|  | 443 | * xmlRelaxNGFree: | 
|  | 444 | * @schema:  a schema structure | 
|  | 445 | * | 
|  | 446 | * Deallocate a RelaxNG structure. | 
|  | 447 | */ | 
|  | 448 | void | 
|  | 449 | xmlRelaxNGFree(xmlRelaxNGPtr schema) | 
|  | 450 | { | 
|  | 451 | if (schema == NULL) | 
|  | 452 | return; | 
|  | 453 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 454 | if (schema->topgrammar != NULL) | 
|  | 455 | xmlRelaxNGFreeGrammar(schema->topgrammar); | 
|  | 456 | if (schema->doc != NULL) | 
|  | 457 | xmlFreeDoc(schema->doc); | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 458 | if (schema->documents != NULL) | 
|  | 459 | xmlHashFree(schema->documents, (xmlHashDeallocator) | 
|  | 460 | xmlRelaxNGFreeDocument); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 461 | if (schema->includes != NULL) | 
|  | 462 | xmlHashFree(schema->includes, (xmlHashDeallocator) | 
|  | 463 | xmlRelaxNGFreeInclude); | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 464 | if (schema->defTab != NULL) { | 
|  | 465 | int i; | 
|  | 466 |  | 
|  | 467 | for (i = 0;i < schema->defNr;i++) | 
|  | 468 | xmlRelaxNGFreeDefine(schema->defTab[i]); | 
|  | 469 | xmlFree(schema->defTab); | 
|  | 470 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 471 |  | 
|  | 472 | xmlFree(schema); | 
|  | 473 | } | 
|  | 474 |  | 
|  | 475 | /** | 
|  | 476 | * xmlRelaxNGNewGrammar: | 
|  | 477 | * @ctxt:  a Relax-NG validation context (optional) | 
|  | 478 | * | 
|  | 479 | * Allocate a new RelaxNG grammar. | 
|  | 480 | * | 
|  | 481 | * Returns the newly allocated structure or NULL in case or error | 
|  | 482 | */ | 
|  | 483 | static xmlRelaxNGGrammarPtr | 
|  | 484 | xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt) | 
|  | 485 | { | 
|  | 486 | xmlRelaxNGGrammarPtr ret; | 
|  | 487 |  | 
|  | 488 | ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar)); | 
|  | 489 | if (ret == NULL) { | 
|  | 490 | if ((ctxt != NULL) && (ctxt->error != NULL)) | 
|  | 491 | ctxt->error(ctxt->userData, "Out of memory\n"); | 
|  | 492 | ctxt->nbErrors++; | 
|  | 493 | return (NULL); | 
|  | 494 | } | 
|  | 495 | memset(ret, 0, sizeof(xmlRelaxNGGrammar)); | 
|  | 496 |  | 
|  | 497 | return (ret); | 
|  | 498 | } | 
|  | 499 |  | 
|  | 500 | /** | 
|  | 501 | * xmlRelaxNGFreeGrammar: | 
|  | 502 | * @grammar:  a grammar structure | 
|  | 503 | * | 
|  | 504 | * Deallocate a RelaxNG grammar structure. | 
|  | 505 | */ | 
|  | 506 | static void | 
|  | 507 | xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar) | 
|  | 508 | { | 
|  | 509 | if (grammar == NULL) | 
|  | 510 | return; | 
|  | 511 |  | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 512 | if (grammar->next != NULL) { | 
|  | 513 | xmlRelaxNGFreeGrammar(grammar->next); | 
|  | 514 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 515 | if (grammar->refs != NULL) { | 
|  | 516 | xmlHashFree(grammar->refs, NULL); | 
|  | 517 | } | 
|  | 518 | if (grammar->defs != NULL) { | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 519 | xmlHashFree(grammar->defs, NULL); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 520 | } | 
|  | 521 |  | 
|  | 522 | xmlFree(grammar); | 
|  | 523 | } | 
|  | 524 |  | 
|  | 525 | /** | 
|  | 526 | * xmlRelaxNGNewDefine: | 
|  | 527 | * @ctxt:  a Relax-NG validation context | 
|  | 528 | * @node:  the node in the input document. | 
|  | 529 | * | 
|  | 530 | * Allocate a new RelaxNG define. | 
|  | 531 | * | 
|  | 532 | * Returns the newly allocated structure or NULL in case or error | 
|  | 533 | */ | 
|  | 534 | static xmlRelaxNGDefinePtr | 
|  | 535 | xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) | 
|  | 536 | { | 
|  | 537 | xmlRelaxNGDefinePtr ret; | 
|  | 538 |  | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 539 | if (ctxt->defMax == 0) { | 
|  | 540 | ctxt->defMax = 16; | 
|  | 541 | ctxt->defNr = 0; | 
|  | 542 | ctxt->defTab = (xmlRelaxNGDefinePtr *) | 
|  | 543 | xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr)); | 
|  | 544 | if (ctxt->defTab == NULL) { | 
|  | 545 | if ((ctxt != NULL) && (ctxt->error != NULL)) | 
|  | 546 | ctxt->error(ctxt->userData, "Out of memory\n"); | 
|  | 547 | ctxt->nbErrors++; | 
|  | 548 | return (NULL); | 
|  | 549 | } | 
|  | 550 | } else if (ctxt->defMax <= ctxt->defNr) { | 
|  | 551 | xmlRelaxNGDefinePtr *tmp; | 
|  | 552 | ctxt->defMax *= 2; | 
|  | 553 | tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab, | 
|  | 554 | ctxt->defMax * sizeof(xmlRelaxNGDefinePtr)); | 
|  | 555 | if (tmp == NULL) { | 
|  | 556 | if ((ctxt != NULL) && (ctxt->error != NULL)) | 
|  | 557 | ctxt->error(ctxt->userData, "Out of memory\n"); | 
|  | 558 | ctxt->nbErrors++; | 
|  | 559 | return (NULL); | 
|  | 560 | } | 
|  | 561 | ctxt->defTab = tmp; | 
|  | 562 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 563 | ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine)); | 
|  | 564 | if (ret == NULL) { | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 565 | if ((ctxt != NULL) && (ctxt->error != NULL)) | 
|  | 566 | ctxt->error(ctxt->userData, "Out of memory\n"); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 567 | ctxt->nbErrors++; | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 568 | return(NULL); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 569 | } | 
|  | 570 | memset(ret, 0, sizeof(xmlRelaxNGDefine)); | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 571 | ctxt->defTab[ctxt->defNr++] = ret; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 572 | ret->node = node; | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 573 | ret->depth = -1; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 574 | return (ret); | 
|  | 575 | } | 
|  | 576 |  | 
|  | 577 | /** | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 578 | * xmlRelaxNGFreePartition: | 
|  | 579 | * @partitions:  a partition set structure | 
|  | 580 | * | 
|  | 581 | * Deallocate RelaxNG partition set structures. | 
|  | 582 | */ | 
|  | 583 | static void | 
|  | 584 | xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) { | 
|  | 585 | xmlRelaxNGInterleaveGroupPtr group; | 
|  | 586 | int j; | 
|  | 587 |  | 
|  | 588 | if (partitions != NULL) { | 
|  | 589 | if (partitions->groups != NULL) { | 
|  | 590 | for (j = 0;j < partitions->nbgroups;j++) { | 
|  | 591 | group = partitions->groups[j]; | 
|  | 592 | if (group != NULL) { | 
|  | 593 | if (group->defs != NULL) | 
|  | 594 | xmlFree(group->defs); | 
|  | 595 | xmlFree(group); | 
|  | 596 | } | 
|  | 597 | } | 
|  | 598 | xmlFree(partitions->groups); | 
|  | 599 | } | 
|  | 600 | xmlFree(partitions); | 
|  | 601 | } | 
|  | 602 | } | 
|  | 603 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 604 | * xmlRelaxNGFreeDefine: | 
|  | 605 | * @define:  a define structure | 
|  | 606 | * | 
|  | 607 | * Deallocate a RelaxNG define structure. | 
|  | 608 | */ | 
|  | 609 | static void | 
|  | 610 | xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define) | 
|  | 611 | { | 
|  | 612 | if (define == NULL) | 
|  | 613 | return; | 
|  | 614 |  | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 615 | if ((define->data != NULL) && | 
|  | 616 | (define->type == XML_RELAXNG_INTERLEAVE)) | 
|  | 617 | xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 618 | if (define->name != NULL) | 
|  | 619 | xmlFree(define->name); | 
|  | 620 | if (define->ns != NULL) | 
|  | 621 | xmlFree(define->ns); | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 622 | if (define->value != NULL) | 
|  | 623 | xmlFree(define->value); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 624 | xmlFree(define); | 
|  | 625 | } | 
|  | 626 |  | 
|  | 627 | /** | 
|  | 628 | * xmlRelaxNGNewValidState: | 
|  | 629 | * @ctxt:  a Relax-NG validation context | 
|  | 630 | * @node:  the current node or NULL for the document | 
|  | 631 | * | 
|  | 632 | * Allocate a new RelaxNG validation state | 
|  | 633 | * | 
|  | 634 | * Returns the newly allocated structure or NULL in case or error | 
|  | 635 | */ | 
|  | 636 | static xmlRelaxNGValidStatePtr | 
|  | 637 | xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node) | 
|  | 638 | { | 
|  | 639 | xmlRelaxNGValidStatePtr ret; | 
|  | 640 | xmlAttrPtr attr; | 
|  | 641 | xmlAttrPtr attrs[MAX_ATTR]; | 
|  | 642 | int nbAttrs = 0; | 
|  | 643 | xmlNodePtr root = NULL; | 
|  | 644 |  | 
|  | 645 | if (node == NULL) { | 
|  | 646 | root = xmlDocGetRootElement(ctxt->doc); | 
|  | 647 | if (root == NULL) | 
|  | 648 | return(NULL); | 
|  | 649 | } else { | 
|  | 650 | attr = node->properties; | 
|  | 651 | while (attr != NULL) { | 
|  | 652 | if (nbAttrs < MAX_ATTR) | 
|  | 653 | attrs[nbAttrs++] = attr; | 
|  | 654 | else | 
|  | 655 | nbAttrs++; | 
|  | 656 | attr = attr->next; | 
|  | 657 | } | 
|  | 658 | } | 
|  | 659 |  | 
|  | 660 | if (nbAttrs < MAX_ATTR) | 
|  | 661 | attrs[nbAttrs] = NULL; | 
|  | 662 | ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState) + | 
|  | 663 | nbAttrs * sizeof(xmlAttrPtr)); | 
|  | 664 | if (ret == NULL) { | 
|  | 665 | if ((ctxt != NULL) && (ctxt->error != NULL)) | 
|  | 666 | ctxt->error(ctxt->userData, "Out of memory\n"); | 
|  | 667 | return (NULL); | 
|  | 668 | } | 
| Daniel Veillard | e5b110b | 2003-02-04 14:43:39 +0000 | [diff] [blame] | 669 | ret->value = NULL; | 
|  | 670 | ret->endvalue = NULL; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 671 | if (node == NULL) { | 
|  | 672 | ret->node = (xmlNodePtr) ctxt->doc; | 
|  | 673 | ret->seq = root; | 
|  | 674 | ret->nbAttrs = 0; | 
|  | 675 | } else { | 
|  | 676 | ret->node = node; | 
|  | 677 | ret->seq = node->children; | 
|  | 678 | ret->nbAttrs = nbAttrs; | 
|  | 679 | if (nbAttrs > 0) { | 
|  | 680 | if (nbAttrs < MAX_ATTR) { | 
|  | 681 | memcpy(&(ret->attrs[0]), attrs, | 
|  | 682 | sizeof(xmlAttrPtr) * (nbAttrs + 1)); | 
|  | 683 | } else { | 
|  | 684 | attr = node->properties; | 
|  | 685 | nbAttrs = 0; | 
|  | 686 | while (attr != NULL) { | 
|  | 687 | ret->attrs[nbAttrs++] = attr; | 
|  | 688 | attr = attr->next; | 
|  | 689 | } | 
|  | 690 | ret->attrs[nbAttrs] = NULL; | 
|  | 691 | } | 
|  | 692 | } | 
|  | 693 | } | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 694 | ret->nbAttrLeft = ret->nbAttrs; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 695 | return (ret); | 
|  | 696 | } | 
|  | 697 |  | 
|  | 698 | /** | 
|  | 699 | * xmlRelaxNGCopyValidState: | 
|  | 700 | * @ctxt:  a Relax-NG validation context | 
|  | 701 | * @state:  a validation state | 
|  | 702 | * | 
|  | 703 | * Copy the validation state | 
|  | 704 | * | 
|  | 705 | * Returns the newly allocated structure or NULL in case or error | 
|  | 706 | */ | 
|  | 707 | static xmlRelaxNGValidStatePtr | 
|  | 708 | xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 709 | xmlRelaxNGValidStatePtr state) | 
|  | 710 | { | 
|  | 711 | xmlRelaxNGValidStatePtr ret; | 
|  | 712 | unsigned int size; | 
|  | 713 |  | 
|  | 714 | if (state == NULL) | 
|  | 715 | return(NULL); | 
|  | 716 |  | 
|  | 717 | size = sizeof(xmlRelaxNGValidState) + | 
|  | 718 | state->nbAttrs * sizeof(xmlAttrPtr); | 
|  | 719 | ret = (xmlRelaxNGValidStatePtr) xmlMalloc(size); | 
|  | 720 | if (ret == NULL) { | 
|  | 721 | if ((ctxt != NULL) && (ctxt->error != NULL)) | 
|  | 722 | ctxt->error(ctxt->userData, "Out of memory\n"); | 
|  | 723 | return (NULL); | 
|  | 724 | } | 
|  | 725 | memcpy(ret, state, size); | 
|  | 726 | return(ret); | 
|  | 727 | } | 
|  | 728 |  | 
|  | 729 | /** | 
| Daniel Veillard | ce14fa5 | 2003-02-19 17:32:48 +0000 | [diff] [blame] | 730 | * xmlRelaxNGEqualValidState: | 
|  | 731 | * @ctxt:  a Relax-NG validation context | 
|  | 732 | * @state1:  a validation state | 
|  | 733 | * @state2:  a validation state | 
|  | 734 | * | 
|  | 735 | * Compare the validation states for equality | 
|  | 736 | * | 
|  | 737 | * Returns 1 if equald, 0 otherwise | 
|  | 738 | */ | 
|  | 739 | static int | 
|  | 740 | xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
|  | 741 | xmlRelaxNGValidStatePtr state1, | 
|  | 742 | xmlRelaxNGValidStatePtr state2) | 
|  | 743 | { | 
|  | 744 | int i; | 
|  | 745 |  | 
|  | 746 | if ((state1 == NULL) || (state2 == NULL)) | 
|  | 747 | return(0); | 
|  | 748 | if (state1 == state2) | 
|  | 749 | return(1); | 
|  | 750 | if (state1->node != state2->node) | 
|  | 751 | return(0); | 
|  | 752 | if (state1->seq != state2->seq) | 
|  | 753 | return(0); | 
|  | 754 | if (state1->nbAttrLeft != state2->nbAttrLeft) | 
|  | 755 | return(0); | 
|  | 756 | if (state1->nbAttrs != state2->nbAttrs) | 
|  | 757 | return(0); | 
|  | 758 | if (state1->endvalue != state2->endvalue) | 
|  | 759 | return(0); | 
|  | 760 | if ((state1->value != state2->value) && | 
|  | 761 | (!xmlStrEqual(state1->value, state2->value))) | 
|  | 762 | return(0); | 
|  | 763 | for (i = 0;i < state1->nbAttrs;i++) { | 
|  | 764 | if (state1->attrs[i] != state2->attrs[i]) | 
|  | 765 | return(0); | 
|  | 766 | } | 
|  | 767 | return(1); | 
|  | 768 | } | 
|  | 769 |  | 
|  | 770 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 771 | * xmlRelaxNGFreeValidState: | 
|  | 772 | * @state:  a validation state structure | 
|  | 773 | * | 
|  | 774 | * Deallocate a RelaxNG validation state structure. | 
|  | 775 | */ | 
|  | 776 | static void | 
|  | 777 | xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state) | 
|  | 778 | { | 
|  | 779 | if (state == NULL) | 
|  | 780 | return; | 
|  | 781 |  | 
|  | 782 | xmlFree(state); | 
|  | 783 | } | 
|  | 784 |  | 
|  | 785 | /************************************************************************ | 
|  | 786 | * 									* | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 787 | * 			Document functions					* | 
|  | 788 | * 									* | 
|  | 789 | ************************************************************************/ | 
|  | 790 | static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 791 | xmlDocPtr doc); | 
|  | 792 |  | 
|  | 793 | /** | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 794 | * xmlRelaxNGIncludePush: | 
|  | 795 | * @ctxt:  the parser context | 
|  | 796 | * @value:  the element doc | 
|  | 797 | * | 
|  | 798 | * Pushes a new include on top of the include stack | 
|  | 799 | * | 
|  | 800 | * Returns 0 in case of error, the index in the stack otherwise | 
|  | 801 | */ | 
|  | 802 | static int | 
|  | 803 | xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 804 | xmlRelaxNGIncludePtr value) | 
|  | 805 | { | 
|  | 806 | if (ctxt->incTab == NULL) { | 
|  | 807 | ctxt->incMax = 4; | 
|  | 808 | ctxt->incNr = 0; | 
|  | 809 | ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc( | 
|  | 810 | ctxt->incMax * sizeof(ctxt->incTab[0])); | 
|  | 811 | if (ctxt->incTab == NULL) { | 
|  | 812 | xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); | 
|  | 813 | return (0); | 
|  | 814 | } | 
|  | 815 | } | 
|  | 816 | if (ctxt->incNr >= ctxt->incMax) { | 
|  | 817 | ctxt->incMax *= 2; | 
|  | 818 | ctxt->incTab = | 
|  | 819 | (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab, | 
|  | 820 | ctxt->incMax * | 
|  | 821 | sizeof(ctxt->incTab[0])); | 
|  | 822 | if (ctxt->incTab == NULL) { | 
|  | 823 | xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); | 
|  | 824 | return (0); | 
|  | 825 | } | 
|  | 826 | } | 
|  | 827 | ctxt->incTab[ctxt->incNr] = value; | 
|  | 828 | ctxt->inc = value; | 
|  | 829 | return (ctxt->incNr++); | 
|  | 830 | } | 
|  | 831 |  | 
|  | 832 | /** | 
|  | 833 | * xmlRelaxNGIncludePop: | 
|  | 834 | * @ctxt: the parser context | 
|  | 835 | * | 
|  | 836 | * Pops the top include from the include stack | 
|  | 837 | * | 
|  | 838 | * Returns the include just removed | 
|  | 839 | */ | 
|  | 840 | static xmlRelaxNGIncludePtr | 
|  | 841 | xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt) | 
|  | 842 | { | 
|  | 843 | xmlRelaxNGIncludePtr ret; | 
|  | 844 |  | 
|  | 845 | if (ctxt->incNr <= 0) | 
|  | 846 | return (0); | 
|  | 847 | ctxt->incNr--; | 
|  | 848 | if (ctxt->incNr > 0) | 
|  | 849 | ctxt->inc = ctxt->incTab[ctxt->incNr - 1]; | 
|  | 850 | else | 
|  | 851 | ctxt->inc = NULL; | 
|  | 852 | ret = ctxt->incTab[ctxt->incNr]; | 
|  | 853 | ctxt->incTab[ctxt->incNr] = 0; | 
|  | 854 | return (ret); | 
|  | 855 | } | 
|  | 856 |  | 
|  | 857 | /** | 
|  | 858 | * xmlRelaxNGLoadInclude: | 
|  | 859 | * @ctxt: the parser context | 
|  | 860 | * @URL:  the normalized URL | 
|  | 861 | * @node: the include node. | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 862 | * @ns:  the namespace passed from the context. | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 863 | * | 
|  | 864 | * First lookup if the document is already loaded into the parser context, | 
|  | 865 | * check against recursion. If not found the resource is loaded and | 
|  | 866 | * the content is preprocessed before being returned back to the caller. | 
|  | 867 | * | 
|  | 868 | * Returns the xmlRelaxNGIncludePtr or NULL in case of error | 
|  | 869 | */ | 
|  | 870 | static xmlRelaxNGIncludePtr | 
|  | 871 | xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL, | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 872 | xmlNodePtr node, const xmlChar *ns) { | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 873 | xmlRelaxNGIncludePtr ret = NULL; | 
|  | 874 | xmlDocPtr doc; | 
|  | 875 | int i; | 
|  | 876 | xmlNodePtr root, tmp, tmp2, cur; | 
|  | 877 |  | 
|  | 878 | /* | 
|  | 879 | * check against recursion in the stack | 
|  | 880 | */ | 
|  | 881 | for (i = 0;i < ctxt->incNr;i++) { | 
|  | 882 | if (xmlStrEqual(ctxt->incTab[i]->href, URL)) { | 
|  | 883 | if (ctxt->error != NULL) | 
|  | 884 | ctxt->error(ctxt->userData, | 
|  | 885 | "Detected an externalRef recursion for %s\n", | 
|  | 886 | URL); | 
|  | 887 | ctxt->nbErrors++; | 
|  | 888 | return(NULL); | 
|  | 889 | } | 
|  | 890 | } | 
|  | 891 |  | 
|  | 892 | /* | 
|  | 893 | * Lookup in the hash table | 
|  | 894 | */ | 
|  | 895 | if (ctxt->includes == NULL) { | 
|  | 896 | ctxt->includes = xmlHashCreate(10); | 
|  | 897 | if (ctxt->includes == NULL) { | 
|  | 898 | if (ctxt->error != NULL) | 
|  | 899 | ctxt->error(ctxt->userData, | 
|  | 900 | "Failed to allocate hash table for document\n"); | 
|  | 901 | ctxt->nbErrors++; | 
|  | 902 | return(NULL); | 
|  | 903 | } | 
|  | 904 | } else { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 905 | if (ns == NULL) | 
|  | 906 | ret = xmlHashLookup2(ctxt->includes, BAD_CAST "", URL); | 
|  | 907 | else | 
|  | 908 | ret = xmlHashLookup2(ctxt->includes, ns, URL); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 909 | if (ret != NULL) | 
|  | 910 | return(ret); | 
|  | 911 | } | 
|  | 912 |  | 
|  | 913 |  | 
|  | 914 | /* | 
|  | 915 | * load the document | 
|  | 916 | */ | 
|  | 917 | doc = xmlParseFile((const char *) URL); | 
|  | 918 | if (doc == NULL) { | 
|  | 919 | if (ctxt->error != NULL) | 
|  | 920 | ctxt->error(ctxt->userData, | 
|  | 921 | "xmlRelaxNG: could not load %s\n", URL); | 
|  | 922 | ctxt->nbErrors++; | 
|  | 923 | return (NULL); | 
|  | 924 | } | 
|  | 925 |  | 
|  | 926 | /* | 
|  | 927 | * Allocate the document structures and register it first. | 
|  | 928 | */ | 
|  | 929 | ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude)); | 
|  | 930 | if (ret == NULL) { | 
|  | 931 | if (ctxt->error != NULL) | 
|  | 932 | ctxt->error(ctxt->userData, | 
|  | 933 | "xmlRelaxNG: allocate memory for doc %s\n", URL); | 
|  | 934 | ctxt->nbErrors++; | 
|  | 935 | xmlFreeDoc(doc); | 
|  | 936 | return (NULL); | 
|  | 937 | } | 
|  | 938 | memset(ret, 0, sizeof(xmlRelaxNGInclude)); | 
|  | 939 | ret->doc = doc; | 
|  | 940 | ret->href = xmlStrdup(URL); | 
|  | 941 |  | 
|  | 942 | /* | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 943 | * transmit the ns if needed | 
|  | 944 | */ | 
|  | 945 | if (ns != NULL) { | 
|  | 946 | root = xmlDocGetRootElement(doc); | 
|  | 947 | if (root != NULL) { | 
|  | 948 | if (xmlHasProp(root, BAD_CAST"ns") == NULL) { | 
|  | 949 | xmlSetProp(root, BAD_CAST"ns", ns); | 
|  | 950 | } | 
|  | 951 | } | 
|  | 952 | } | 
|  | 953 |  | 
|  | 954 | /* | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 955 | * push it on the stack and register it in the hash table | 
|  | 956 | */ | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 957 | if (ns == NULL) | 
|  | 958 | xmlHashAddEntry2(ctxt->includes, BAD_CAST "", URL, ret); | 
|  | 959 | else | 
|  | 960 | xmlHashAddEntry2(ctxt->includes, ns, URL, ret); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 961 | xmlRelaxNGIncludePush(ctxt, ret); | 
|  | 962 |  | 
|  | 963 | /* | 
|  | 964 | * Some preprocessing of the document content, this include recursing | 
|  | 965 | * in the include stack. | 
|  | 966 | */ | 
|  | 967 | doc = xmlRelaxNGCleanupDoc(ctxt, doc); | 
|  | 968 | if (doc == NULL) { | 
|  | 969 | /* xmlFreeDoc(ctxt->include); */ | 
|  | 970 | ctxt->inc = NULL; | 
|  | 971 | return(NULL); | 
|  | 972 | } | 
|  | 973 |  | 
|  | 974 | /* | 
|  | 975 | * Pop up the include from the stack | 
|  | 976 | */ | 
|  | 977 | xmlRelaxNGIncludePop(ctxt); | 
|  | 978 |  | 
|  | 979 | /* | 
|  | 980 | * Check that the top element is a grammar | 
|  | 981 | */ | 
|  | 982 | root = xmlDocGetRootElement(doc); | 
|  | 983 | if (root == NULL) { | 
|  | 984 | if (ctxt->error != NULL) | 
|  | 985 | ctxt->error(ctxt->userData, | 
|  | 986 | "xmlRelaxNG: included document is empty %s\n", URL); | 
|  | 987 | ctxt->nbErrors++; | 
|  | 988 | xmlFreeDoc(doc); | 
|  | 989 | return (NULL); | 
|  | 990 | } | 
|  | 991 | if (!IS_RELAXNG(root, "grammar")) { | 
|  | 992 | if (ctxt->error != NULL) | 
|  | 993 | ctxt->error(ctxt->userData, | 
|  | 994 | "xmlRelaxNG: included document %s root is not a grammar\n", | 
|  | 995 | URL); | 
|  | 996 | ctxt->nbErrors++; | 
|  | 997 | xmlFreeDoc(doc); | 
|  | 998 | return (NULL); | 
|  | 999 | } | 
|  | 1000 |  | 
|  | 1001 | /* | 
|  | 1002 | * Elimination of redefined rules in the include. | 
|  | 1003 | */ | 
|  | 1004 | cur = node->children; | 
|  | 1005 | while (cur != NULL) { | 
|  | 1006 | if (IS_RELAXNG(cur, "start")) { | 
|  | 1007 | int found = 0; | 
|  | 1008 |  | 
|  | 1009 | tmp = root->children; | 
|  | 1010 | while (tmp != NULL) { | 
|  | 1011 | tmp2 = tmp->next; | 
|  | 1012 | if (IS_RELAXNG(tmp, "start")) { | 
|  | 1013 | found = 1; | 
|  | 1014 | xmlUnlinkNode(tmp); | 
|  | 1015 | xmlFreeNode(tmp); | 
|  | 1016 | } | 
|  | 1017 | tmp = tmp2; | 
|  | 1018 | } | 
|  | 1019 | if (!found) { | 
|  | 1020 | if (ctxt->error != NULL) | 
|  | 1021 | ctxt->error(ctxt->userData, | 
|  | 1022 | "xmlRelaxNG: include %s has a start but not the included grammar\n", | 
|  | 1023 | URL); | 
|  | 1024 | ctxt->nbErrors++; | 
|  | 1025 | } | 
|  | 1026 | } else if (IS_RELAXNG(cur, "define")) { | 
|  | 1027 | xmlChar *name, *name2; | 
|  | 1028 |  | 
|  | 1029 | name = xmlGetProp(cur, BAD_CAST "name"); | 
|  | 1030 | if (name == NULL) { | 
|  | 1031 | if (ctxt->error != NULL) | 
|  | 1032 | ctxt->error(ctxt->userData, | 
|  | 1033 | "xmlRelaxNG: include %s has define without name\n", | 
|  | 1034 | URL); | 
|  | 1035 | ctxt->nbErrors++; | 
|  | 1036 | } else { | 
|  | 1037 | int found = 0; | 
|  | 1038 |  | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 1039 | xmlRelaxNGNormExtSpace(name); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 1040 | tmp = root->children; | 
|  | 1041 | while (tmp != NULL) { | 
|  | 1042 | tmp2 = tmp->next; | 
|  | 1043 | if (IS_RELAXNG(tmp, "define")) { | 
|  | 1044 | name2 = xmlGetProp(tmp, BAD_CAST "name"); | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 1045 | xmlRelaxNGNormExtSpace(name2); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 1046 | if (name2 != NULL) { | 
|  | 1047 | if (xmlStrEqual(name, name2)) { | 
|  | 1048 | found = 1; | 
|  | 1049 | xmlUnlinkNode(tmp); | 
|  | 1050 | xmlFreeNode(tmp); | 
|  | 1051 | } | 
|  | 1052 | xmlFree(name2); | 
|  | 1053 | } | 
|  | 1054 | } | 
|  | 1055 | tmp = tmp2; | 
|  | 1056 | } | 
|  | 1057 | if (!found) { | 
|  | 1058 | if (ctxt->error != NULL) | 
|  | 1059 | ctxt->error(ctxt->userData, | 
|  | 1060 | "xmlRelaxNG: include %s has a define %s but not the included grammar\n", | 
|  | 1061 | URL, name); | 
|  | 1062 | ctxt->nbErrors++; | 
|  | 1063 | } | 
|  | 1064 | xmlFree(name); | 
|  | 1065 | } | 
|  | 1066 | } | 
|  | 1067 | cur = cur->next; | 
|  | 1068 | } | 
|  | 1069 |  | 
|  | 1070 |  | 
|  | 1071 | return(ret); | 
|  | 1072 | } | 
|  | 1073 |  | 
|  | 1074 | /** | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 1075 | * xmlRelaxNGDocumentPush: | 
|  | 1076 | * @ctxt:  the parser context | 
|  | 1077 | * @value:  the element doc | 
|  | 1078 | * | 
|  | 1079 | * Pushes a new doc on top of the doc stack | 
|  | 1080 | * | 
|  | 1081 | * Returns 0 in case of error, the index in the stack otherwise | 
|  | 1082 | */ | 
|  | 1083 | static int | 
|  | 1084 | xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 1085 | xmlRelaxNGDocumentPtr value) | 
|  | 1086 | { | 
|  | 1087 | if (ctxt->docTab == NULL) { | 
|  | 1088 | ctxt->docMax = 4; | 
|  | 1089 | ctxt->docNr = 0; | 
|  | 1090 | ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc( | 
|  | 1091 | ctxt->docMax * sizeof(ctxt->docTab[0])); | 
|  | 1092 | if (ctxt->docTab == NULL) { | 
|  | 1093 | xmlGenericError(xmlGenericErrorContext, "malloc failed !\n"); | 
|  | 1094 | return (0); | 
|  | 1095 | } | 
|  | 1096 | } | 
|  | 1097 | if (ctxt->docNr >= ctxt->docMax) { | 
|  | 1098 | ctxt->docMax *= 2; | 
|  | 1099 | ctxt->docTab = | 
|  | 1100 | (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab, | 
|  | 1101 | ctxt->docMax * | 
|  | 1102 | sizeof(ctxt->docTab[0])); | 
|  | 1103 | if (ctxt->docTab == NULL) { | 
|  | 1104 | xmlGenericError(xmlGenericErrorContext, "realloc failed !\n"); | 
|  | 1105 | return (0); | 
|  | 1106 | } | 
|  | 1107 | } | 
|  | 1108 | ctxt->docTab[ctxt->docNr] = value; | 
|  | 1109 | ctxt->doc = value; | 
|  | 1110 | return (ctxt->docNr++); | 
|  | 1111 | } | 
|  | 1112 |  | 
|  | 1113 | /** | 
|  | 1114 | * xmlRelaxNGDocumentPop: | 
|  | 1115 | * @ctxt: the parser context | 
|  | 1116 | * | 
|  | 1117 | * Pops the top doc from the doc stack | 
|  | 1118 | * | 
|  | 1119 | * Returns the doc just removed | 
|  | 1120 | */ | 
|  | 1121 | static xmlRelaxNGDocumentPtr | 
|  | 1122 | xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt) | 
|  | 1123 | { | 
|  | 1124 | xmlRelaxNGDocumentPtr ret; | 
|  | 1125 |  | 
|  | 1126 | if (ctxt->docNr <= 0) | 
|  | 1127 | return (0); | 
|  | 1128 | ctxt->docNr--; | 
|  | 1129 | if (ctxt->docNr > 0) | 
|  | 1130 | ctxt->doc = ctxt->docTab[ctxt->docNr - 1]; | 
|  | 1131 | else | 
|  | 1132 | ctxt->doc = NULL; | 
|  | 1133 | ret = ctxt->docTab[ctxt->docNr]; | 
|  | 1134 | ctxt->docTab[ctxt->docNr] = 0; | 
|  | 1135 | return (ret); | 
|  | 1136 | } | 
|  | 1137 |  | 
|  | 1138 | /** | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 1139 | * xmlRelaxNGLoadExternalRef: | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 1140 | * @ctxt: the parser context | 
|  | 1141 | * @URL:  the normalized URL | 
|  | 1142 | * @ns:  the inherited ns if any | 
|  | 1143 | * | 
|  | 1144 | * First lookup if the document is already loaded into the parser context, | 
|  | 1145 | * check against recursion. If not found the resource is loaded and | 
|  | 1146 | * the content is preprocessed before being returned back to the caller. | 
|  | 1147 | * | 
|  | 1148 | * Returns the xmlRelaxNGDocumentPtr or NULL in case of error | 
|  | 1149 | */ | 
|  | 1150 | static xmlRelaxNGDocumentPtr | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 1151 | xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL, | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 1152 | const xmlChar *ns) { | 
|  | 1153 | xmlRelaxNGDocumentPtr ret = NULL; | 
|  | 1154 | xmlDocPtr doc; | 
|  | 1155 | xmlNodePtr root; | 
|  | 1156 | int i; | 
|  | 1157 |  | 
|  | 1158 | /* | 
|  | 1159 | * check against recursion in the stack | 
|  | 1160 | */ | 
|  | 1161 | for (i = 0;i < ctxt->docNr;i++) { | 
|  | 1162 | if (xmlStrEqual(ctxt->docTab[i]->href, URL)) { | 
|  | 1163 | if (ctxt->error != NULL) | 
|  | 1164 | ctxt->error(ctxt->userData, | 
|  | 1165 | "Detected an externalRef recursion for %s\n", | 
|  | 1166 | URL); | 
|  | 1167 | ctxt->nbErrors++; | 
|  | 1168 | return(NULL); | 
|  | 1169 | } | 
|  | 1170 | } | 
|  | 1171 |  | 
|  | 1172 | /* | 
|  | 1173 | * Lookup in the hash table | 
|  | 1174 | */ | 
|  | 1175 | if (ctxt->documents == NULL) { | 
|  | 1176 | ctxt->documents = xmlHashCreate(10); | 
|  | 1177 | if (ctxt->documents == NULL) { | 
|  | 1178 | if (ctxt->error != NULL) | 
|  | 1179 | ctxt->error(ctxt->userData, | 
|  | 1180 | "Failed to allocate hash table for document\n"); | 
|  | 1181 | ctxt->nbErrors++; | 
|  | 1182 | return(NULL); | 
|  | 1183 | } | 
|  | 1184 | } else { | 
|  | 1185 | if (ns == NULL) | 
|  | 1186 | ret = xmlHashLookup2(ctxt->documents, BAD_CAST "", URL); | 
|  | 1187 | else | 
|  | 1188 | ret = xmlHashLookup2(ctxt->documents, ns, URL); | 
|  | 1189 | if (ret != NULL) | 
|  | 1190 | return(ret); | 
|  | 1191 | } | 
|  | 1192 |  | 
|  | 1193 |  | 
|  | 1194 | /* | 
|  | 1195 | * load the document | 
|  | 1196 | */ | 
|  | 1197 | doc = xmlParseFile((const char *) URL); | 
|  | 1198 | if (doc == NULL) { | 
|  | 1199 | if (ctxt->error != NULL) | 
|  | 1200 | ctxt->error(ctxt->userData, | 
|  | 1201 | "xmlRelaxNG: could not load %s\n", URL); | 
|  | 1202 | ctxt->nbErrors++; | 
|  | 1203 | return (NULL); | 
|  | 1204 | } | 
|  | 1205 |  | 
|  | 1206 | /* | 
|  | 1207 | * Allocate the document structures and register it first. | 
|  | 1208 | */ | 
|  | 1209 | ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument)); | 
|  | 1210 | if (ret == NULL) { | 
|  | 1211 | if (ctxt->error != NULL) | 
|  | 1212 | ctxt->error(ctxt->userData, | 
|  | 1213 | "xmlRelaxNG: allocate memory for doc %s\n", URL); | 
|  | 1214 | ctxt->nbErrors++; | 
|  | 1215 | xmlFreeDoc(doc); | 
|  | 1216 | return (NULL); | 
|  | 1217 | } | 
|  | 1218 | memset(ret, 0, sizeof(xmlRelaxNGDocument)); | 
|  | 1219 | ret->doc = doc; | 
|  | 1220 | ret->href = xmlStrdup(URL); | 
|  | 1221 |  | 
|  | 1222 | /* | 
|  | 1223 | * transmit the ns if needed | 
|  | 1224 | */ | 
|  | 1225 | if (ns != NULL) { | 
|  | 1226 | root = xmlDocGetRootElement(doc); | 
|  | 1227 | if (root != NULL) { | 
|  | 1228 | if (xmlHasProp(root, BAD_CAST"ns") == NULL) { | 
|  | 1229 | xmlSetProp(root, BAD_CAST"ns", ns); | 
|  | 1230 | } | 
|  | 1231 | } | 
|  | 1232 | } | 
|  | 1233 |  | 
|  | 1234 | /* | 
|  | 1235 | * push it on the stack and register it in the hash table | 
|  | 1236 | */ | 
|  | 1237 | if (ns == NULL) | 
|  | 1238 | xmlHashAddEntry2(ctxt->documents, BAD_CAST "", URL, ret); | 
|  | 1239 | else | 
|  | 1240 | xmlHashAddEntry2(ctxt->documents, ns, URL, ret); | 
|  | 1241 | xmlRelaxNGDocumentPush(ctxt, ret); | 
|  | 1242 |  | 
|  | 1243 | /* | 
|  | 1244 | * Some preprocessing of the document content | 
|  | 1245 | */ | 
|  | 1246 | doc = xmlRelaxNGCleanupDoc(ctxt, doc); | 
|  | 1247 | if (doc == NULL) { | 
|  | 1248 | xmlFreeDoc(ctxt->document); | 
|  | 1249 | ctxt->doc = NULL; | 
|  | 1250 | return(NULL); | 
|  | 1251 | } | 
|  | 1252 |  | 
|  | 1253 | xmlRelaxNGDocumentPop(ctxt); | 
|  | 1254 |  | 
|  | 1255 | return(ret); | 
|  | 1256 | } | 
|  | 1257 |  | 
|  | 1258 | /************************************************************************ | 
|  | 1259 | * 									* | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1260 | * 			Error functions					* | 
|  | 1261 | * 									* | 
|  | 1262 | ************************************************************************/ | 
|  | 1263 |  | 
|  | 1264 | #define VALID_CTXT() 							\ | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 1265 | if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))			\ | 
|  | 1266 | xmlGenericError(xmlGenericErrorContext,			\ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1267 | "error detected at %s:%d\n",				\ | 
|  | 1268 | __FILE__, __LINE__); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 1269 |  | 
|  | 1270 | #define VALID_ERROR(a)							\ | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 1271 | if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))			\ | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 1272 | if (ctxt->error != NULL) ctxt->error(ctxt->userData, a) | 
|  | 1273 | #define VALID_ERROR2(a, b)						\ | 
|  | 1274 | if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))			\ | 
|  | 1275 | if (ctxt->error != NULL) ctxt->error(ctxt->userData, a, b) | 
|  | 1276 | #define VALID_ERROR3(a, b, c)						\ | 
|  | 1277 | if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2))			\ | 
|  | 1278 | if (ctxt->error != NULL) ctxt->error(ctxt->userData, a, b, c) | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1279 |  | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 1280 | #ifdef DEBUG | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 1281 | static const char * | 
|  | 1282 | xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) { | 
|  | 1283 | if (def == NULL) | 
|  | 1284 | return("none"); | 
|  | 1285 | switch(def->type) { | 
|  | 1286 | case XML_RELAXNG_EMPTY: return("empty"); | 
|  | 1287 | case XML_RELAXNG_NOT_ALLOWED: return("notAllowed"); | 
|  | 1288 | case XML_RELAXNG_EXCEPT: return("except"); | 
|  | 1289 | case XML_RELAXNG_TEXT: return("text"); | 
|  | 1290 | case XML_RELAXNG_ELEMENT: return("element"); | 
|  | 1291 | case XML_RELAXNG_DATATYPE: return("datatype"); | 
|  | 1292 | case XML_RELAXNG_VALUE: return("value"); | 
|  | 1293 | case XML_RELAXNG_LIST: return("list"); | 
|  | 1294 | case XML_RELAXNG_ATTRIBUTE: return("attribute"); | 
|  | 1295 | case XML_RELAXNG_DEF: return("def"); | 
|  | 1296 | case XML_RELAXNG_REF: return("ref"); | 
|  | 1297 | case XML_RELAXNG_EXTERNALREF: return("externalRef"); | 
|  | 1298 | case XML_RELAXNG_PARENTREF: return("parentRef"); | 
|  | 1299 | case XML_RELAXNG_OPTIONAL: return("optional"); | 
|  | 1300 | case XML_RELAXNG_ZEROORMORE: return("zeroOrMore"); | 
|  | 1301 | case XML_RELAXNG_ONEORMORE: return("oneOrMore"); | 
|  | 1302 | case XML_RELAXNG_CHOICE: return("choice"); | 
|  | 1303 | case XML_RELAXNG_GROUP: return("group"); | 
|  | 1304 | case XML_RELAXNG_INTERLEAVE: return("interleave"); | 
|  | 1305 | case XML_RELAXNG_START: return("start"); | 
|  | 1306 | } | 
|  | 1307 | return("unknown"); | 
|  | 1308 | } | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 1309 | #endif | 
|  | 1310 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1311 | #if 0 | 
|  | 1312 | /** | 
|  | 1313 | * xmlRelaxNGErrorContext: | 
|  | 1314 | * @ctxt:  the parsing context | 
|  | 1315 | * @schema:  the schema being built | 
|  | 1316 | * @node:  the node being processed | 
|  | 1317 | * @child:  the child being processed | 
|  | 1318 | * | 
|  | 1319 | * Dump a RelaxNGType structure | 
|  | 1320 | */ | 
|  | 1321 | static void | 
|  | 1322 | xmlRelaxNGErrorContext(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGPtr schema, | 
|  | 1323 | xmlNodePtr node, xmlNodePtr child) | 
|  | 1324 | { | 
|  | 1325 | int line = 0; | 
|  | 1326 | const xmlChar *file = NULL; | 
|  | 1327 | const xmlChar *name = NULL; | 
|  | 1328 | const char *type = "error"; | 
|  | 1329 |  | 
|  | 1330 | if ((ctxt == NULL) || (ctxt->error == NULL)) | 
|  | 1331 | return; | 
|  | 1332 |  | 
|  | 1333 | if (child != NULL) | 
|  | 1334 | node = child; | 
|  | 1335 |  | 
|  | 1336 | if (node != NULL)  { | 
|  | 1337 | if ((node->type == XML_DOCUMENT_NODE) || | 
|  | 1338 | (node->type == XML_HTML_DOCUMENT_NODE)) { | 
|  | 1339 | xmlDocPtr doc = (xmlDocPtr) node; | 
|  | 1340 |  | 
|  | 1341 | file = doc->URL; | 
|  | 1342 | } else { | 
|  | 1343 | /* | 
|  | 1344 | * Try to find contextual informations to report | 
|  | 1345 | */ | 
|  | 1346 | if (node->type == XML_ELEMENT_NODE) { | 
|  | 1347 | line = (int) node->content; | 
|  | 1348 | } else if ((node->prev != NULL) && | 
|  | 1349 | (node->prev->type == XML_ELEMENT_NODE)) { | 
|  | 1350 | line = (int) node->prev->content; | 
|  | 1351 | } else if ((node->parent != NULL) && | 
|  | 1352 | (node->parent->type == XML_ELEMENT_NODE)) { | 
|  | 1353 | line = (int) node->parent->content; | 
|  | 1354 | } | 
|  | 1355 | if ((node->doc != NULL) && (node->doc->URL != NULL)) | 
|  | 1356 | file = node->doc->URL; | 
|  | 1357 | if (node->name != NULL) | 
|  | 1358 | name = node->name; | 
|  | 1359 | } | 
|  | 1360 | } | 
|  | 1361 |  | 
|  | 1362 | if (ctxt != NULL) | 
|  | 1363 | type = "compilation error"; | 
|  | 1364 | else if (schema != NULL) | 
|  | 1365 | type = "runtime error"; | 
|  | 1366 |  | 
|  | 1367 | if ((file != NULL) && (line != 0) && (name != NULL)) | 
|  | 1368 | ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n", | 
|  | 1369 | type, file, line, name); | 
|  | 1370 | else if ((file != NULL) && (name != NULL)) | 
|  | 1371 | ctxt->error(ctxt->userData, "%s: file %s element %s\n", | 
|  | 1372 | type, file, name); | 
|  | 1373 | else if ((file != NULL) && (line != 0)) | 
|  | 1374 | ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line); | 
|  | 1375 | else if (file != NULL) | 
|  | 1376 | ctxt->error(ctxt->userData, "%s: file %s\n", type, file); | 
|  | 1377 | else if (name != NULL) | 
|  | 1378 | ctxt->error(ctxt->userData, "%s: element %s\n", type, name); | 
|  | 1379 | else | 
|  | 1380 | ctxt->error(ctxt->userData, "%s\n", type); | 
|  | 1381 | } | 
|  | 1382 | #endif | 
|  | 1383 |  | 
|  | 1384 | /************************************************************************ | 
|  | 1385 | * 									* | 
|  | 1386 | * 			Type library hooks				* | 
|  | 1387 | * 									* | 
|  | 1388 | ************************************************************************/ | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 1389 | static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 1390 | const xmlChar *str); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1391 |  | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1392 | /** | 
|  | 1393 | * xmlRelaxNGSchemaTypeHave: | 
|  | 1394 | * @data:  data needed for the library | 
|  | 1395 | * @type:  the type name | 
|  | 1396 | * | 
|  | 1397 | * Check if the given type is provided by | 
|  | 1398 | * the W3C XMLSchema Datatype library. | 
|  | 1399 | * | 
|  | 1400 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 1401 | */ | 
|  | 1402 | static int | 
|  | 1403 | xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED, | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 1404 | const xmlChar *type) { | 
|  | 1405 | xmlSchemaTypePtr typ; | 
|  | 1406 |  | 
|  | 1407 | if (type == NULL) | 
|  | 1408 | return(-1); | 
|  | 1409 | typ = xmlSchemaGetPredefinedType(type, | 
|  | 1410 | BAD_CAST "http://www.w3.org/2001/XMLSchema"); | 
|  | 1411 | if (typ == NULL) | 
|  | 1412 | return(0); | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1413 | return(1); | 
|  | 1414 | } | 
|  | 1415 |  | 
|  | 1416 | /** | 
|  | 1417 | * xmlRelaxNGSchemaTypeCheck: | 
|  | 1418 | * @data:  data needed for the library | 
|  | 1419 | * @type:  the type name | 
|  | 1420 | * @value:  the value to check | 
|  | 1421 | * | 
|  | 1422 | * Check if the given type and value are validated by | 
|  | 1423 | * the W3C XMLSchema Datatype library. | 
|  | 1424 | * | 
|  | 1425 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 1426 | */ | 
|  | 1427 | static int | 
|  | 1428 | xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED, | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 1429 | const xmlChar *type, | 
|  | 1430 | const xmlChar *value) { | 
|  | 1431 | xmlSchemaTypePtr typ; | 
|  | 1432 | int ret; | 
|  | 1433 |  | 
|  | 1434 | /* | 
|  | 1435 | * TODO: the type should be cached ab provided back, interface subject | 
|  | 1436 | * to changes. | 
|  | 1437 | * TODO: handle facets, may require an additional interface and keep | 
|  | 1438 | * the value returned from the validation. | 
|  | 1439 | */ | 
|  | 1440 | if ((type == NULL) || (value == NULL)) | 
|  | 1441 | return(-1); | 
|  | 1442 | typ = xmlSchemaGetPredefinedType(type, | 
|  | 1443 | BAD_CAST "http://www.w3.org/2001/XMLSchema"); | 
|  | 1444 | if (typ == NULL) | 
|  | 1445 | return(-1); | 
|  | 1446 | ret = xmlSchemaValidatePredefinedType(typ, value, NULL); | 
|  | 1447 | if (ret == 0) | 
|  | 1448 | return(1); | 
|  | 1449 | if (ret > 0) | 
|  | 1450 | return(0); | 
|  | 1451 | return(-1); | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1452 | } | 
|  | 1453 |  | 
|  | 1454 | /** | 
|  | 1455 | * xmlRelaxNGSchemaTypeCompare: | 
|  | 1456 | * @data:  data needed for the library | 
|  | 1457 | * @type:  the type name | 
|  | 1458 | * @value1:  the first value | 
|  | 1459 | * @value2:  the second value | 
|  | 1460 | * | 
|  | 1461 | * Compare two values accordingly a type from the W3C XMLSchema | 
|  | 1462 | * Datatype library. | 
|  | 1463 | * | 
|  | 1464 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 1465 | */ | 
|  | 1466 | static int | 
|  | 1467 | xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED, | 
|  | 1468 | const xmlChar *type ATTRIBUTE_UNUSED, | 
|  | 1469 | const xmlChar *value1 ATTRIBUTE_UNUSED, | 
|  | 1470 | const xmlChar *value2 ATTRIBUTE_UNUSED) { | 
|  | 1471 | TODO | 
|  | 1472 | return(1); | 
|  | 1473 | } | 
|  | 1474 |  | 
|  | 1475 | /** | 
|  | 1476 | * xmlRelaxNGDefaultTypeHave: | 
|  | 1477 | * @data:  data needed for the library | 
|  | 1478 | * @type:  the type name | 
|  | 1479 | * | 
|  | 1480 | * Check if the given type is provided by | 
|  | 1481 | * the default datatype library. | 
|  | 1482 | * | 
|  | 1483 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 1484 | */ | 
|  | 1485 | static int | 
|  | 1486 | xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) { | 
|  | 1487 | if (type == NULL) | 
|  | 1488 | return(-1); | 
|  | 1489 | if (xmlStrEqual(type, BAD_CAST "string")) | 
|  | 1490 | return(1); | 
|  | 1491 | if (xmlStrEqual(type, BAD_CAST "token")) | 
|  | 1492 | return(1); | 
|  | 1493 | return(0); | 
|  | 1494 | } | 
|  | 1495 |  | 
|  | 1496 | /** | 
|  | 1497 | * xmlRelaxNGDefaultTypeCheck: | 
|  | 1498 | * @data:  data needed for the library | 
|  | 1499 | * @type:  the type name | 
|  | 1500 | * @value:  the value to check | 
|  | 1501 | * | 
|  | 1502 | * Check if the given type and value are validated by | 
|  | 1503 | * the default datatype library. | 
|  | 1504 | * | 
|  | 1505 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 1506 | */ | 
|  | 1507 | static int | 
|  | 1508 | xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED, | 
|  | 1509 | const xmlChar *type ATTRIBUTE_UNUSED, | 
|  | 1510 | const xmlChar *value ATTRIBUTE_UNUSED) { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 1511 | if (value == NULL) | 
|  | 1512 | return(-1); | 
|  | 1513 | if (xmlStrEqual(type, BAD_CAST "string")) | 
|  | 1514 | return(1); | 
|  | 1515 | if (xmlStrEqual(type, BAD_CAST "token")) { | 
|  | 1516 | #if 0 | 
|  | 1517 | const xmlChar *cur = value; | 
|  | 1518 |  | 
|  | 1519 | while (*cur != 0) { | 
|  | 1520 | if (!IS_BLANK(*cur)) | 
|  | 1521 | return(1); | 
|  | 1522 | cur++; | 
|  | 1523 | } | 
|  | 1524 | #endif | 
|  | 1525 | return(1); | 
|  | 1526 | } | 
|  | 1527 |  | 
|  | 1528 | return(0); | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1529 | } | 
|  | 1530 |  | 
|  | 1531 | /** | 
|  | 1532 | * xmlRelaxNGDefaultTypeCompare: | 
|  | 1533 | * @data:  data needed for the library | 
|  | 1534 | * @type:  the type name | 
|  | 1535 | * @value1:  the first value | 
|  | 1536 | * @value2:  the second value | 
|  | 1537 | * | 
|  | 1538 | * Compare two values accordingly a type from the default | 
|  | 1539 | * datatype library. | 
|  | 1540 | * | 
|  | 1541 | * Returns 1 if yes, 0 if no and -1 in case of error. | 
|  | 1542 | */ | 
|  | 1543 | static int | 
|  | 1544 | xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED, | 
|  | 1545 | const xmlChar *type ATTRIBUTE_UNUSED, | 
|  | 1546 | const xmlChar *value1 ATTRIBUTE_UNUSED, | 
|  | 1547 | const xmlChar *value2 ATTRIBUTE_UNUSED) { | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 1548 | int ret = -1; | 
|  | 1549 |  | 
|  | 1550 | if (xmlStrEqual(type, BAD_CAST "string")) { | 
|  | 1551 | ret = xmlStrEqual(value1, value2); | 
|  | 1552 | } else if (xmlStrEqual(type, BAD_CAST "token")) { | 
|  | 1553 | if (!xmlStrEqual(value1, value2)) { | 
|  | 1554 | xmlChar *nval, *nvalue; | 
|  | 1555 |  | 
|  | 1556 | /* | 
|  | 1557 | * TODO: trivial optimizations are possible by | 
|  | 1558 | * computing at compile-time | 
|  | 1559 | */ | 
|  | 1560 | nval = xmlRelaxNGNormalize(NULL, value1); | 
|  | 1561 | nvalue = xmlRelaxNGNormalize(NULL, value2); | 
|  | 1562 |  | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 1563 | if ((nval == NULL) || (nvalue == NULL)) | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 1564 | ret = -1; | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 1565 | else if (xmlStrEqual(nval, nvalue)) | 
|  | 1566 | ret = 1; | 
|  | 1567 | else | 
|  | 1568 | ret = 0; | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 1569 | if (nval != NULL) | 
|  | 1570 | xmlFree(nval); | 
|  | 1571 | if (nvalue != NULL) | 
|  | 1572 | xmlFree(nvalue); | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 1573 | } else | 
|  | 1574 | ret = 1; | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 1575 | } | 
|  | 1576 | return(ret); | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1577 | } | 
|  | 1578 |  | 
|  | 1579 | static int xmlRelaxNGTypeInitialized = 0; | 
|  | 1580 | static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL; | 
|  | 1581 |  | 
|  | 1582 | /** | 
|  | 1583 | * xmlRelaxNGFreeTypeLibrary: | 
|  | 1584 | * @lib:  the type library structure | 
|  | 1585 | * @namespace:  the URI bound to the library | 
|  | 1586 | * | 
|  | 1587 | * Free the structure associated to the type library | 
|  | 1588 | */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1589 | static void | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1590 | xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib, | 
|  | 1591 | const xmlChar *namespace ATTRIBUTE_UNUSED) { | 
|  | 1592 | if (lib == NULL) | 
|  | 1593 | return; | 
|  | 1594 | if (lib->namespace != NULL) | 
|  | 1595 | xmlFree((xmlChar *)lib->namespace); | 
|  | 1596 | xmlFree(lib); | 
|  | 1597 | } | 
|  | 1598 |  | 
|  | 1599 | /** | 
|  | 1600 | * xmlRelaxNGRegisterTypeLibrary: | 
|  | 1601 | * @namespace:  the URI bound to the library | 
|  | 1602 | * @data:  data associated to the library | 
|  | 1603 | * @have:  the provide function | 
|  | 1604 | * @check:  the checking function | 
|  | 1605 | * @comp:  the comparison function | 
|  | 1606 | * | 
|  | 1607 | * Register a new type library | 
|  | 1608 | * | 
|  | 1609 | * Returns 0 in case of success and -1 in case of error. | 
|  | 1610 | */ | 
|  | 1611 | static int | 
|  | 1612 | xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data, | 
|  | 1613 | xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check, | 
|  | 1614 | xmlRelaxNGTypeCompare comp) { | 
|  | 1615 | xmlRelaxNGTypeLibraryPtr lib; | 
|  | 1616 | int ret; | 
|  | 1617 |  | 
|  | 1618 | if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) || | 
|  | 1619 | (check == NULL) || (comp == NULL)) | 
|  | 1620 | return(-1); | 
|  | 1621 | if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) { | 
|  | 1622 | xmlGenericError(xmlGenericErrorContext, | 
|  | 1623 | "Relax-NG types library '%s' already registered\n", | 
|  | 1624 | namespace); | 
|  | 1625 | return(-1); | 
|  | 1626 | } | 
|  | 1627 | lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary)); | 
|  | 1628 | if (lib == NULL) { | 
|  | 1629 | xmlGenericError(xmlGenericErrorContext, | 
|  | 1630 | "Relax-NG types library '%s' malloc() failed\n", | 
|  | 1631 | namespace); | 
|  | 1632 | return (-1); | 
|  | 1633 | } | 
|  | 1634 | memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary)); | 
|  | 1635 | lib->namespace = xmlStrdup(namespace); | 
|  | 1636 | lib->data = data; | 
|  | 1637 | lib->have = have; | 
|  | 1638 | lib->comp = comp; | 
|  | 1639 | lib->check = check; | 
|  | 1640 | ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib); | 
|  | 1641 | if (ret < 0) { | 
|  | 1642 | xmlGenericError(xmlGenericErrorContext, | 
|  | 1643 | "Relax-NG types library failed to register '%s'\n", | 
|  | 1644 | namespace); | 
|  | 1645 | xmlRelaxNGFreeTypeLibrary(lib, namespace); | 
|  | 1646 | return(-1); | 
|  | 1647 | } | 
|  | 1648 | return(0); | 
|  | 1649 | } | 
|  | 1650 |  | 
|  | 1651 | /** | 
|  | 1652 | * xmlRelaxNGInitTypes: | 
|  | 1653 | * | 
|  | 1654 | * Initilize the default type libraries. | 
|  | 1655 | * | 
|  | 1656 | * Returns 0 in case of success and -1 in case of error. | 
|  | 1657 | */ | 
|  | 1658 | static int | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1659 | xmlRelaxNGInitTypes(void) { | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1660 | if (xmlRelaxNGTypeInitialized != 0) | 
|  | 1661 | return(0); | 
|  | 1662 | xmlRelaxNGRegisteredTypes = xmlHashCreate(10); | 
|  | 1663 | if (xmlRelaxNGRegisteredTypes == NULL) { | 
|  | 1664 | xmlGenericError(xmlGenericErrorContext, | 
|  | 1665 | "Failed to allocate sh table for Relax-NG types\n"); | 
|  | 1666 | return(-1); | 
|  | 1667 | } | 
|  | 1668 | xmlRelaxNGRegisterTypeLibrary( | 
|  | 1669 | BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes", | 
|  | 1670 | NULL, | 
|  | 1671 | xmlRelaxNGSchemaTypeHave, | 
|  | 1672 | xmlRelaxNGSchemaTypeCheck, | 
|  | 1673 | xmlRelaxNGSchemaTypeCompare); | 
|  | 1674 | xmlRelaxNGRegisterTypeLibrary( | 
|  | 1675 | xmlRelaxNGNs, | 
|  | 1676 | NULL, | 
|  | 1677 | xmlRelaxNGDefaultTypeHave, | 
|  | 1678 | xmlRelaxNGDefaultTypeCheck, | 
|  | 1679 | xmlRelaxNGDefaultTypeCompare); | 
|  | 1680 | xmlRelaxNGTypeInitialized = 1; | 
|  | 1681 | return(0); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1682 | } | 
|  | 1683 |  | 
|  | 1684 | /** | 
|  | 1685 | * xmlRelaxNGCleanupTypes: | 
|  | 1686 | * | 
|  | 1687 | * Cleanup the default Schemas type library associated to RelaxNG | 
|  | 1688 | */ | 
|  | 1689 | void | 
|  | 1690 | xmlRelaxNGCleanupTypes(void) { | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1691 | if (xmlRelaxNGTypeInitialized == 0) | 
|  | 1692 | return; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1693 | xmlSchemaCleanupTypes(); | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1694 | xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator) | 
|  | 1695 | xmlRelaxNGFreeTypeLibrary); | 
|  | 1696 | xmlRelaxNGTypeInitialized = 0; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1697 | } | 
|  | 1698 |  | 
|  | 1699 | /************************************************************************ | 
|  | 1700 | * 									* | 
|  | 1701 | * 			Parsing functions				* | 
|  | 1702 | * 									* | 
|  | 1703 | ************************************************************************/ | 
|  | 1704 |  | 
|  | 1705 | static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute( | 
|  | 1706 | xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node); | 
|  | 1707 | static xmlRelaxNGDefinePtr xmlRelaxNGParseElement( | 
|  | 1708 | xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node); | 
|  | 1709 | static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns( | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 1710 | xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group); | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 1711 | static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern( | 
|  | 1712 | xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node); | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 1713 | static xmlRelaxNGPtr xmlRelaxNGParseDocument( | 
|  | 1714 | xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node); | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 1715 | static int xmlRelaxNGParseGrammarContent( | 
|  | 1716 | xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes); | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 1717 | static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass( | 
|  | 1718 | xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, | 
|  | 1719 | xmlRelaxNGDefinePtr def); | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 1720 | static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar( | 
|  | 1721 | xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1722 |  | 
|  | 1723 |  | 
|  | 1724 | #define IS_BLANK_NODE(n)						\ | 
|  | 1725 | (((n)->type == XML_TEXT_NODE) && (xmlRelaxNGIsBlank((n)->content))) | 
|  | 1726 |  | 
|  | 1727 | /** | 
|  | 1728 | * xmlRelaxNGIsBlank: | 
|  | 1729 | * @str:  a string | 
|  | 1730 | * | 
|  | 1731 | * Check if a string is ignorable c.f. 4.2. Whitespace | 
|  | 1732 | * | 
|  | 1733 | * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise | 
|  | 1734 | */ | 
|  | 1735 | static int | 
|  | 1736 | xmlRelaxNGIsBlank(xmlChar *str) { | 
|  | 1737 | if (str == NULL) | 
|  | 1738 | return(1); | 
|  | 1739 | while (*str != 0) { | 
|  | 1740 | if (!(IS_BLANK(*str))) return(0); | 
|  | 1741 | str++; | 
|  | 1742 | } | 
|  | 1743 | return(1); | 
|  | 1744 | } | 
|  | 1745 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1746 | /** | 
|  | 1747 | * xmlRelaxNGGetDataTypeLibrary: | 
|  | 1748 | * @ctxt:  a Relax-NG parser context | 
|  | 1749 | * @node:  the current data or value element | 
|  | 1750 | * | 
|  | 1751 | * Applies algorithm from 4.3. datatypeLibrary attribute | 
|  | 1752 | * | 
|  | 1753 | * Returns the datatypeLibary value or NULL if not found | 
|  | 1754 | */ | 
|  | 1755 | static xmlChar * | 
|  | 1756 | xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
|  | 1757 | xmlNodePtr node) { | 
|  | 1758 | xmlChar *ret, *escape; | 
|  | 1759 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1760 | if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) { | 
|  | 1761 | ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); | 
|  | 1762 | if (ret != NULL) { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 1763 | if (ret[0] == 0) { | 
|  | 1764 | xmlFree(ret); | 
|  | 1765 | return(NULL); | 
|  | 1766 | } | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1767 | escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1768 | if (escape == NULL) { | 
|  | 1769 | return(ret); | 
|  | 1770 | } | 
|  | 1771 | xmlFree(ret); | 
|  | 1772 | return(escape); | 
|  | 1773 | } | 
|  | 1774 | } | 
|  | 1775 | node = node->parent; | 
|  | 1776 | while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) { | 
| Daniel Veillard | e5b110b | 2003-02-04 14:43:39 +0000 | [diff] [blame] | 1777 | ret = xmlGetProp(node, BAD_CAST "datatypeLibrary"); | 
|  | 1778 | if (ret != NULL) { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 1779 | if (ret[0] == 0) { | 
|  | 1780 | xmlFree(ret); | 
|  | 1781 | return(NULL); | 
|  | 1782 | } | 
| Daniel Veillard | e5b110b | 2003-02-04 14:43:39 +0000 | [diff] [blame] | 1783 | escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?"); | 
|  | 1784 | if (escape == NULL) { | 
|  | 1785 | return(ret); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1786 | } | 
| Daniel Veillard | e5b110b | 2003-02-04 14:43:39 +0000 | [diff] [blame] | 1787 | xmlFree(ret); | 
|  | 1788 | return(escape); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 1789 | } | 
|  | 1790 | node = node->parent; | 
|  | 1791 | } | 
|  | 1792 | return(NULL); | 
|  | 1793 | } | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1794 |  | 
|  | 1795 | /** | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 1796 | * xmlRelaxNGParseValue: | 
|  | 1797 | * @ctxt:  a Relax-NG parser context | 
|  | 1798 | * @node:  the data node. | 
|  | 1799 | * | 
|  | 1800 | * parse the content of a RelaxNG value node. | 
|  | 1801 | * | 
|  | 1802 | * Returns the definition pointer or NULL in case of error | 
|  | 1803 | */ | 
|  | 1804 | static xmlRelaxNGDefinePtr | 
|  | 1805 | xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 1806 | xmlRelaxNGDefinePtr def = NULL; | 
|  | 1807 | xmlRelaxNGTypeLibraryPtr lib; | 
|  | 1808 | xmlChar *type; | 
|  | 1809 | xmlChar *library; | 
|  | 1810 | int tmp; | 
|  | 1811 |  | 
|  | 1812 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 1813 | if (def == NULL) | 
|  | 1814 | return(NULL); | 
|  | 1815 | def->type = XML_RELAXNG_VALUE; | 
|  | 1816 |  | 
|  | 1817 | type = xmlGetProp(node, BAD_CAST "type"); | 
|  | 1818 | if (type != NULL) { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 1819 | xmlRelaxNGNormExtSpace(type); | 
|  | 1820 | if (xmlValidateNCName(type, 0)) { | 
|  | 1821 | if (ctxt->error != NULL) | 
|  | 1822 | ctxt->error(ctxt->userData, | 
|  | 1823 | "value type '%s' is not an NCName\n", | 
|  | 1824 | type); | 
|  | 1825 | ctxt->nbErrors++; | 
|  | 1826 | } | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 1827 | library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); | 
|  | 1828 | if (library == NULL) | 
|  | 1829 | library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); | 
|  | 1830 |  | 
|  | 1831 | def->name = type; | 
|  | 1832 | def->ns = library; | 
|  | 1833 |  | 
|  | 1834 | lib = (xmlRelaxNGTypeLibraryPtr) | 
|  | 1835 | xmlHashLookup(xmlRelaxNGRegisteredTypes, library); | 
|  | 1836 | if (lib == NULL) { | 
|  | 1837 | if (ctxt->error != NULL) | 
|  | 1838 | ctxt->error(ctxt->userData, | 
|  | 1839 | "Use of unregistered type library '%s'\n", | 
|  | 1840 | library); | 
|  | 1841 | ctxt->nbErrors++; | 
|  | 1842 | def->data = NULL; | 
|  | 1843 | } else { | 
|  | 1844 | def->data = lib; | 
|  | 1845 | if (lib->have == NULL) { | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 1846 | if (ctxt->error != NULL) | 
|  | 1847 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 1848 | "Internal error with type library '%s': no 'have'\n", | 
|  | 1849 | library); | 
|  | 1850 | ctxt->nbErrors++; | 
|  | 1851 | } else { | 
|  | 1852 | tmp = lib->have(lib->data, def->name); | 
|  | 1853 | if (tmp != 1) { | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 1854 | if (ctxt->error != NULL) | 
|  | 1855 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 1856 | "Error type '%s' is not exported by type library '%s'\n", | 
|  | 1857 | def->name, library); | 
|  | 1858 | ctxt->nbErrors++; | 
|  | 1859 | } | 
|  | 1860 | } | 
|  | 1861 | } | 
|  | 1862 | } | 
|  | 1863 | if (node->children == NULL) { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 1864 | def->value = xmlStrdup(BAD_CAST ""); | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 1865 | } else if ((node->children->type != XML_TEXT_NODE) || | 
|  | 1866 | (node->children->next != NULL)) { | 
|  | 1867 | if (ctxt->error != NULL) | 
|  | 1868 | ctxt->error(ctxt->userData, | 
|  | 1869 | "Expecting a single text value for <value>content\n"); | 
|  | 1870 | ctxt->nbErrors++; | 
|  | 1871 | } else { | 
|  | 1872 | def->value = xmlNodeGetContent(node); | 
|  | 1873 | if (def->value == NULL) { | 
|  | 1874 | if (ctxt->error != NULL) | 
|  | 1875 | ctxt->error(ctxt->userData, | 
|  | 1876 | "Element <value> has no content\n"); | 
|  | 1877 | ctxt->nbErrors++; | 
|  | 1878 | } | 
|  | 1879 | } | 
|  | 1880 | /* TODO check ahead of time that the value is okay per the type */ | 
|  | 1881 | return(def); | 
|  | 1882 | } | 
|  | 1883 |  | 
|  | 1884 | /** | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1885 | * xmlRelaxNGParseData: | 
|  | 1886 | * @ctxt:  a Relax-NG parser context | 
|  | 1887 | * @node:  the data node. | 
|  | 1888 | * | 
|  | 1889 | * parse the content of a RelaxNG data node. | 
|  | 1890 | * | 
|  | 1891 | * Returns the definition pointer or NULL in case of error | 
|  | 1892 | */ | 
|  | 1893 | static xmlRelaxNGDefinePtr | 
|  | 1894 | xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 1895 | xmlRelaxNGDefinePtr def = NULL, except, last = NULL; | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 1896 | xmlRelaxNGDefinePtr param, lastparam = NULL; | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1897 | xmlRelaxNGTypeLibraryPtr lib; | 
|  | 1898 | xmlChar *type; | 
|  | 1899 | xmlChar *library; | 
|  | 1900 | xmlNodePtr content; | 
|  | 1901 | int tmp; | 
|  | 1902 |  | 
|  | 1903 | type = xmlGetProp(node, BAD_CAST "type"); | 
|  | 1904 | if (type == NULL) { | 
|  | 1905 | if (ctxt->error != NULL) | 
|  | 1906 | ctxt->error(ctxt->userData, | 
|  | 1907 | "data has no type\n"); | 
|  | 1908 | ctxt->nbErrors++; | 
|  | 1909 | return(NULL); | 
|  | 1910 | } | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 1911 | xmlRelaxNGNormExtSpace(type); | 
|  | 1912 | if (xmlValidateNCName(type, 0)) { | 
|  | 1913 | if (ctxt->error != NULL) | 
|  | 1914 | ctxt->error(ctxt->userData, | 
|  | 1915 | "data type '%s' is not an NCName\n", | 
|  | 1916 | type); | 
|  | 1917 | ctxt->nbErrors++; | 
|  | 1918 | } | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1919 | library = xmlRelaxNGGetDataTypeLibrary(ctxt, node); | 
|  | 1920 | if (library == NULL) | 
|  | 1921 | library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0"); | 
|  | 1922 |  | 
|  | 1923 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 1924 | if (def == NULL) { | 
|  | 1925 | xmlFree(type); | 
|  | 1926 | return(NULL); | 
|  | 1927 | } | 
|  | 1928 | def->type = XML_RELAXNG_DATATYPE; | 
|  | 1929 | def->name = type; | 
|  | 1930 | def->ns = library; | 
|  | 1931 |  | 
|  | 1932 | lib = (xmlRelaxNGTypeLibraryPtr) | 
|  | 1933 | xmlHashLookup(xmlRelaxNGRegisteredTypes, library); | 
|  | 1934 | if (lib == NULL) { | 
|  | 1935 | if (ctxt->error != NULL) | 
|  | 1936 | ctxt->error(ctxt->userData, | 
|  | 1937 | "Use of unregistered type library '%s'\n", | 
|  | 1938 | library); | 
|  | 1939 | ctxt->nbErrors++; | 
|  | 1940 | def->data = NULL; | 
|  | 1941 | } else { | 
|  | 1942 | def->data = lib; | 
|  | 1943 | if (lib->have == NULL) { | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 1944 | if (ctxt->error != NULL) | 
|  | 1945 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1946 | "Internal error with type library '%s': no 'have'\n", | 
|  | 1947 | library); | 
|  | 1948 | ctxt->nbErrors++; | 
|  | 1949 | } else { | 
|  | 1950 | tmp = lib->have(lib->data, def->name); | 
|  | 1951 | if (tmp != 1) { | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 1952 | if (ctxt->error != NULL) | 
|  | 1953 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1954 | "Error type '%s' is not exported by type library '%s'\n", | 
|  | 1955 | def->name, library); | 
|  | 1956 | ctxt->nbErrors++; | 
|  | 1957 | } | 
|  | 1958 | } | 
|  | 1959 | } | 
|  | 1960 | content = node->children; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 1961 |  | 
|  | 1962 | /* | 
|  | 1963 | * Handle optional params | 
|  | 1964 | */ | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 1965 | while (content != NULL) { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 1966 | if (!xmlStrEqual(content->name, BAD_CAST "param")) | 
|  | 1967 | break; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 1968 | if (xmlStrEqual(library, | 
|  | 1969 | BAD_CAST"http://relaxng.org/ns/structure/1.0")) { | 
|  | 1970 | if (ctxt->error != NULL) | 
|  | 1971 | ctxt->error(ctxt->userData, | 
|  | 1972 | "Type library '%s' does not allow type parameters\n", | 
|  | 1973 | library); | 
|  | 1974 | ctxt->nbErrors++; | 
|  | 1975 | content = content->next; | 
|  | 1976 | while ((content != NULL) && | 
|  | 1977 | (xmlStrEqual(content->name, BAD_CAST "param"))) | 
|  | 1978 | content = content->next; | 
|  | 1979 | } else { | 
|  | 1980 | param = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 1981 | if (param != NULL) { | 
|  | 1982 | param->type = XML_RELAXNG_PARAM; | 
|  | 1983 | param->name = xmlGetProp(content, BAD_CAST "name"); | 
|  | 1984 | if (param->name == NULL) { | 
|  | 1985 | if (ctxt->error != NULL) | 
|  | 1986 | ctxt->error(ctxt->userData, | 
|  | 1987 | "param has no name\n"); | 
|  | 1988 | ctxt->nbErrors++; | 
|  | 1989 | } | 
|  | 1990 | param->value = xmlNodeGetContent(content); | 
|  | 1991 | if (lastparam == NULL) { | 
|  | 1992 | def->attrs = lastparam = param; | 
|  | 1993 | } else { | 
|  | 1994 | lastparam->next = param; | 
|  | 1995 | lastparam = param; | 
|  | 1996 | } | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 1997 | } | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 1998 | content = content->next; | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 1999 | } | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 2000 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 2001 | /* | 
|  | 2002 | * Handle optional except | 
|  | 2003 | */ | 
|  | 2004 | if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) { | 
|  | 2005 | xmlNodePtr child; | 
|  | 2006 | xmlRelaxNGDefinePtr tmp2, last2 = NULL; | 
|  | 2007 |  | 
|  | 2008 | except = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2009 | if (except == NULL) { | 
|  | 2010 | return(def); | 
|  | 2011 | } | 
|  | 2012 | except->type = XML_RELAXNG_EXCEPT; | 
|  | 2013 | child = content->children; | 
|  | 2014 | if (last == NULL) { | 
|  | 2015 | def->content = except; | 
|  | 2016 | } else { | 
|  | 2017 | last->next = except; | 
|  | 2018 | } | 
|  | 2019 | if (child == NULL) { | 
|  | 2020 | if (ctxt->error != NULL) | 
|  | 2021 | ctxt->error(ctxt->userData, | 
|  | 2022 | "except has no content\n"); | 
|  | 2023 | ctxt->nbErrors++; | 
|  | 2024 | } | 
|  | 2025 | while (child != NULL) { | 
|  | 2026 | tmp2 = xmlRelaxNGParsePattern(ctxt, child); | 
|  | 2027 | if (tmp2 != NULL) { | 
|  | 2028 | if (last2 == NULL) { | 
|  | 2029 | except->content = last2 = tmp2; | 
|  | 2030 | } else { | 
|  | 2031 | last2->next = tmp2; | 
|  | 2032 | last2 = tmp2; | 
|  | 2033 | } | 
|  | 2034 | } | 
|  | 2035 | child = child->next; | 
|  | 2036 | } | 
|  | 2037 | content = content->next; | 
|  | 2038 | } | 
|  | 2039 | /* | 
|  | 2040 | * Check there is no unhandled data | 
|  | 2041 | */ | 
|  | 2042 | if (content != NULL) { | 
|  | 2043 | if (ctxt->error != NULL) | 
|  | 2044 | ctxt->error(ctxt->userData, | 
|  | 2045 | "Element data has unexpected content %s\n", content->name); | 
|  | 2046 | ctxt->nbErrors++; | 
|  | 2047 | } | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 2048 |  | 
|  | 2049 | return(def); | 
|  | 2050 | } | 
|  | 2051 |  | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2052 | /** | 
|  | 2053 | * xmlRelaxNGCompareElemDefLists: | 
|  | 2054 | * @ctxt:  a Relax-NG parser context | 
|  | 2055 | * @defs1:  the first list of element defs | 
|  | 2056 | * @defs2:  the second list of element defs | 
|  | 2057 | * | 
|  | 2058 | * Compare the 2 lists of element definitions. The comparison is | 
|  | 2059 | * that if both lists do not accept the same QNames, it returns 1 | 
|  | 2060 | * If the 2 lists can accept the same QName the comparison returns 0 | 
|  | 2061 | * | 
|  | 2062 | * Returns 1 disttinct, 0 if equal | 
|  | 2063 | */ | 
|  | 2064 | static int | 
|  | 2065 | xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
|  | 2066 | xmlRelaxNGDefinePtr *def1, | 
|  | 2067 | xmlRelaxNGDefinePtr *def2) { | 
|  | 2068 | xmlRelaxNGDefinePtr *basedef2 = def2; | 
|  | 2069 |  | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 2070 | if ((def1 == NULL) || (def2 == NULL)) | 
|  | 2071 | return(1); | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2072 | if ((*def1 == NULL) || (*def2 == NULL)) | 
|  | 2073 | return(1); | 
|  | 2074 | while (*def1 != NULL) { | 
|  | 2075 | while ((*def2) != NULL) { | 
|  | 2076 | if ((*def1)->name == NULL) { | 
|  | 2077 | if (xmlStrEqual((*def2)->ns, (*def1)->ns)) | 
|  | 2078 | return(0); | 
|  | 2079 | } else if ((*def2)->name == NULL) { | 
|  | 2080 | if (xmlStrEqual((*def2)->ns, (*def1)->ns)) | 
|  | 2081 | return(0); | 
|  | 2082 | } else if (xmlStrEqual((*def1)->name, (*def2)->name)) { | 
|  | 2083 | if (xmlStrEqual((*def2)->ns, (*def1)->ns)) | 
|  | 2084 | return(0); | 
|  | 2085 | } | 
|  | 2086 | def2++; | 
|  | 2087 | } | 
|  | 2088 | def2 = basedef2; | 
|  | 2089 | def1++; | 
|  | 2090 | } | 
|  | 2091 | return(1); | 
|  | 2092 | } | 
|  | 2093 |  | 
|  | 2094 | /** | 
|  | 2095 | * xmlRelaxNGGetElements: | 
|  | 2096 | * @ctxt:  a Relax-NG parser context | 
|  | 2097 | * @def:  the interleave definition | 
|  | 2098 | * | 
|  | 2099 | * Compute the list of top elements a definition can generate | 
|  | 2100 | * | 
|  | 2101 | * Returns a list of elements or NULL if none was found. | 
|  | 2102 | */ | 
|  | 2103 | static xmlRelaxNGDefinePtr * | 
|  | 2104 | xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 2105 | xmlRelaxNGDefinePtr def) { | 
|  | 2106 | xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp; | 
|  | 2107 | int len = 0; | 
|  | 2108 | int max = 0; | 
|  | 2109 |  | 
|  | 2110 | parent = NULL; | 
|  | 2111 | cur = def; | 
|  | 2112 | while (cur != NULL) { | 
| Daniel Veillard | b08c981 | 2003-01-28 23:09:49 +0000 | [diff] [blame] | 2113 | if ((cur->type == XML_RELAXNG_ELEMENT) || | 
|  | 2114 | (cur->type == XML_RELAXNG_TEXT)) { | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2115 | if (ret == NULL) { | 
|  | 2116 | max = 10; | 
|  | 2117 | ret = (xmlRelaxNGDefinePtr *) | 
|  | 2118 | xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr)); | 
|  | 2119 | if (ret == NULL) { | 
|  | 2120 | if (ctxt->error != NULL) | 
|  | 2121 | ctxt->error(ctxt->userData, | 
|  | 2122 | "Out of memory in element search\n"); | 
|  | 2123 | ctxt->nbErrors++; | 
|  | 2124 | return(NULL); | 
|  | 2125 | } | 
|  | 2126 | } else if (max <= len) { | 
|  | 2127 | max *= 2; | 
|  | 2128 | ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr)); | 
|  | 2129 | if (ret == NULL) { | 
|  | 2130 | if (ctxt->error != NULL) | 
|  | 2131 | ctxt->error(ctxt->userData, | 
|  | 2132 | "Out of memory in element search\n"); | 
|  | 2133 | ctxt->nbErrors++; | 
|  | 2134 | return(NULL); | 
|  | 2135 | } | 
|  | 2136 | } | 
| Daniel Veillard | b08c981 | 2003-01-28 23:09:49 +0000 | [diff] [blame] | 2137 | ret[len++] = cur; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2138 | ret[len] = NULL; | 
|  | 2139 | } else if ((cur->type == XML_RELAXNG_CHOICE) || | 
|  | 2140 | (cur->type == XML_RELAXNG_INTERLEAVE) || | 
|  | 2141 | (cur->type == XML_RELAXNG_GROUP) || | 
|  | 2142 | (cur->type == XML_RELAXNG_ONEORMORE) || | 
| Daniel Veillard | b08c981 | 2003-01-28 23:09:49 +0000 | [diff] [blame] | 2143 | (cur->type == XML_RELAXNG_ZEROORMORE) || | 
|  | 2144 | (cur->type == XML_RELAXNG_OPTIONAL) || | 
|  | 2145 | (cur->type == XML_RELAXNG_REF) || | 
|  | 2146 | (cur->type == XML_RELAXNG_DEF)) { | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2147 | /* | 
|  | 2148 | * Don't go within elements or attributes or string values. | 
|  | 2149 | * Just gather the element top list | 
|  | 2150 | */ | 
|  | 2151 | if (cur->content != NULL) { | 
|  | 2152 | parent = cur; | 
|  | 2153 | cur = cur->content; | 
|  | 2154 | tmp = cur; | 
|  | 2155 | while (tmp != NULL) { | 
|  | 2156 | tmp->parent = parent; | 
|  | 2157 | tmp = tmp->next; | 
|  | 2158 | } | 
|  | 2159 | continue; | 
|  | 2160 | } | 
|  | 2161 | } | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 2162 | if (cur == def) | 
|  | 2163 | return(ret); | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2164 | if (cur->next != NULL) { | 
|  | 2165 | cur = cur->next; | 
|  | 2166 | continue; | 
|  | 2167 | } | 
|  | 2168 | do { | 
|  | 2169 | cur = cur->parent; | 
|  | 2170 | if (cur == NULL) break; | 
|  | 2171 | if (cur == def) return(ret); | 
|  | 2172 | if (cur->next != NULL) { | 
|  | 2173 | cur = cur->next; | 
|  | 2174 | break; | 
|  | 2175 | } | 
|  | 2176 | } while (cur != NULL); | 
|  | 2177 | } | 
|  | 2178 | return(ret); | 
|  | 2179 | } | 
|  | 2180 |  | 
|  | 2181 | /** | 
|  | 2182 | * xmlRelaxNGComputeInterleaves: | 
|  | 2183 | * @def:  the interleave definition | 
|  | 2184 | * @ctxt:  a Relax-NG parser context | 
|  | 2185 | * @node:  the data node. | 
|  | 2186 | * | 
|  | 2187 | * A lot of work for preprocessing interleave definitions | 
|  | 2188 | * is potentially needed to get a decent execution speed at runtime | 
|  | 2189 | *   - trying to get a total order on the element nodes generated | 
|  | 2190 | *     by the interleaves, order the list of interleave definitions | 
|  | 2191 | *     following that order. | 
|  | 2192 | *   - if <text/> is used to handle mixed content, it is better to | 
|  | 2193 | *     flag this in the define and simplify the runtime checking | 
|  | 2194 | *     algorithm | 
|  | 2195 | */ | 
|  | 2196 | static void | 
|  | 2197 | xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def, | 
|  | 2198 | xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 2199 | xmlChar *name ATTRIBUTE_UNUSED) { | 
|  | 2200 | xmlRelaxNGDefinePtr cur; | 
|  | 2201 |  | 
|  | 2202 | xmlRelaxNGDefinePtr *list = NULL; | 
|  | 2203 | xmlRelaxNGPartitionPtr partitions = NULL; | 
|  | 2204 | xmlRelaxNGInterleaveGroupPtr *groups = NULL; | 
|  | 2205 | xmlRelaxNGInterleaveGroupPtr group; | 
|  | 2206 | int i,j,ret; | 
|  | 2207 | int nbgroups = 0; | 
|  | 2208 | int nbchild = 0; | 
|  | 2209 |  | 
|  | 2210 | #ifdef DEBUG_INTERLEAVE | 
|  | 2211 | xmlGenericError(xmlGenericErrorContext, | 
|  | 2212 | "xmlRelaxNGComputeInterleaves(%s)\n", | 
|  | 2213 | name); | 
|  | 2214 | #endif | 
|  | 2215 | cur = def->content; | 
|  | 2216 | while (cur != NULL) { | 
|  | 2217 | nbchild++; | 
|  | 2218 | cur = cur->next; | 
|  | 2219 | } | 
|  | 2220 |  | 
|  | 2221 | #ifdef DEBUG_INTERLEAVE | 
|  | 2222 | xmlGenericError(xmlGenericErrorContext, "  %d child\n", nbchild); | 
|  | 2223 | #endif | 
|  | 2224 | groups = (xmlRelaxNGInterleaveGroupPtr *) | 
|  | 2225 | xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr)); | 
|  | 2226 | if (groups == NULL) | 
|  | 2227 | goto error; | 
|  | 2228 | cur = def->content; | 
|  | 2229 | while (cur != NULL) { | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 2230 | groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr) | 
|  | 2231 | xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup)); | 
|  | 2232 | if (groups[nbgroups] == NULL) | 
|  | 2233 | goto error; | 
|  | 2234 | groups[nbgroups]->rule = cur; | 
|  | 2235 | groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur); | 
|  | 2236 | nbgroups++; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2237 | cur = cur->next; | 
|  | 2238 | } | 
|  | 2239 | list = NULL; | 
|  | 2240 | #ifdef DEBUG_INTERLEAVE | 
|  | 2241 | xmlGenericError(xmlGenericErrorContext, "  %d groups\n", nbgroups); | 
|  | 2242 | #endif | 
|  | 2243 |  | 
|  | 2244 | /* | 
|  | 2245 | * Let's check that all rules makes a partitions according to 7.4 | 
|  | 2246 | */ | 
|  | 2247 | partitions = (xmlRelaxNGPartitionPtr) | 
|  | 2248 | xmlMalloc(sizeof(xmlRelaxNGPartition)); | 
|  | 2249 | if (partitions == NULL) | 
|  | 2250 | goto error; | 
|  | 2251 | partitions->nbgroups = nbgroups; | 
|  | 2252 | for (i = 0;i < nbgroups;i++) { | 
|  | 2253 | group = groups[i]; | 
|  | 2254 | for (j = i+1;j < nbgroups;j++) { | 
|  | 2255 | if (groups[j] == NULL) | 
|  | 2256 | continue; | 
|  | 2257 | ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs, | 
|  | 2258 | groups[j]->defs); | 
|  | 2259 | if (ret == 0) { | 
|  | 2260 | if (ctxt->error != NULL) | 
|  | 2261 | ctxt->error(ctxt->userData, | 
|  | 2262 | "Element or text conflicts in interleave\n"); | 
|  | 2263 | ctxt->nbErrors++; | 
|  | 2264 | } | 
|  | 2265 | } | 
|  | 2266 | } | 
|  | 2267 | partitions->groups = groups; | 
|  | 2268 |  | 
|  | 2269 | /* | 
|  | 2270 | * Free Up the child list, and save the partition list back in the def | 
|  | 2271 | */ | 
|  | 2272 | def->data = partitions; | 
|  | 2273 | return; | 
|  | 2274 |  | 
|  | 2275 | error: | 
|  | 2276 | if (ctxt->error != NULL) | 
|  | 2277 | ctxt->error(ctxt->userData, | 
|  | 2278 | "Out of memory in interleave computation\n"); | 
|  | 2279 | ctxt->nbErrors++; | 
|  | 2280 | if (list == NULL) | 
|  | 2281 | xmlFree(list); | 
|  | 2282 | if (groups != NULL) { | 
|  | 2283 | for (i = 0;i < nbgroups;i++) | 
|  | 2284 | if (groups[i] != NULL) { | 
|  | 2285 | if (groups[i]->defs != NULL) | 
|  | 2286 | xmlFree(groups[i]->defs); | 
|  | 2287 | xmlFree(groups[i]); | 
|  | 2288 | } | 
|  | 2289 | xmlFree(groups); | 
|  | 2290 | } | 
|  | 2291 | xmlRelaxNGFreePartition(partitions); | 
|  | 2292 | } | 
|  | 2293 |  | 
|  | 2294 | /** | 
|  | 2295 | * xmlRelaxNGParseInterleave: | 
|  | 2296 | * @ctxt:  a Relax-NG parser context | 
|  | 2297 | * @node:  the data node. | 
|  | 2298 | * | 
|  | 2299 | * parse the content of a RelaxNG interleave node. | 
|  | 2300 | * | 
|  | 2301 | * Returns the definition pointer or NULL in case of error | 
|  | 2302 | */ | 
|  | 2303 | static xmlRelaxNGDefinePtr | 
|  | 2304 | xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 2305 | xmlRelaxNGDefinePtr def = NULL; | 
|  | 2306 | xmlRelaxNGDefinePtr last = NULL, cur; | 
|  | 2307 | xmlNodePtr child; | 
|  | 2308 |  | 
|  | 2309 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2310 | if (def == NULL) { | 
|  | 2311 | return(NULL); | 
|  | 2312 | } | 
|  | 2313 | def->type = XML_RELAXNG_INTERLEAVE; | 
|  | 2314 |  | 
|  | 2315 | if (ctxt->interleaves == NULL) | 
|  | 2316 | ctxt->interleaves = xmlHashCreate(10); | 
|  | 2317 | if (ctxt->interleaves == NULL) { | 
|  | 2318 | if (ctxt->error != NULL) | 
|  | 2319 | ctxt->error(ctxt->userData, | 
|  | 2320 | "Failed to create interleaves hash table\n"); | 
|  | 2321 | ctxt->nbErrors++; | 
|  | 2322 | } else { | 
|  | 2323 | char name[32]; | 
|  | 2324 |  | 
|  | 2325 | snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++); | 
|  | 2326 | if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) { | 
|  | 2327 | if (ctxt->error != NULL) | 
|  | 2328 | ctxt->error(ctxt->userData, | 
|  | 2329 | "Failed to add %s to hash table\n", name); | 
|  | 2330 | ctxt->nbErrors++; | 
|  | 2331 | } | 
|  | 2332 | } | 
|  | 2333 | child = node->children; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2334 | if (child == NULL) { | 
|  | 2335 | if (ctxt->error != NULL) | 
|  | 2336 | ctxt->error(ctxt->userData, "Element interleave is empty\n"); | 
|  | 2337 | ctxt->nbErrors++; | 
|  | 2338 | } | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2339 | while (child != NULL) { | 
|  | 2340 | if (IS_RELAXNG(child, "element")) { | 
|  | 2341 | cur = xmlRelaxNGParseElement(ctxt, child); | 
|  | 2342 | } else { | 
|  | 2343 | cur = xmlRelaxNGParsePattern(ctxt, child); | 
|  | 2344 | } | 
|  | 2345 | if (cur != NULL) { | 
|  | 2346 | cur->parent = def; | 
|  | 2347 | if (last == NULL) { | 
|  | 2348 | def->content = last = cur; | 
|  | 2349 | } else { | 
|  | 2350 | last->next = cur; | 
|  | 2351 | last = cur; | 
|  | 2352 | } | 
|  | 2353 | } | 
|  | 2354 | child = child->next; | 
|  | 2355 | } | 
|  | 2356 |  | 
|  | 2357 | return(def); | 
|  | 2358 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2359 |  | 
|  | 2360 | /** | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 2361 | * xmlRelaxNGParseInclude: | 
|  | 2362 | * @ctxt:  a Relax-NG parser context | 
|  | 2363 | * @node:  the include node | 
|  | 2364 | * | 
|  | 2365 | * Integrate the content of an include node in the current grammar | 
|  | 2366 | * | 
|  | 2367 | * Returns 0 in case of success or -1 in case of error | 
|  | 2368 | */ | 
|  | 2369 | static int | 
|  | 2370 | xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 2371 | xmlRelaxNGIncludePtr incl; | 
|  | 2372 | xmlNodePtr root; | 
|  | 2373 | int ret = 0, tmp; | 
|  | 2374 |  | 
|  | 2375 | incl = node->_private; | 
|  | 2376 | if (incl == NULL) { | 
|  | 2377 | if (ctxt->error != NULL) | 
|  | 2378 | ctxt->error(ctxt->userData, | 
|  | 2379 | "Include node has no data\n"); | 
|  | 2380 | ctxt->nbErrors++; | 
|  | 2381 | return(-1); | 
|  | 2382 | } | 
|  | 2383 | root = xmlDocGetRootElement(incl->doc); | 
|  | 2384 | if (root == NULL) { | 
|  | 2385 | if (ctxt->error != NULL) | 
|  | 2386 | ctxt->error(ctxt->userData, | 
|  | 2387 | "Include document is empty\n"); | 
|  | 2388 | ctxt->nbErrors++; | 
|  | 2389 | return(-1); | 
|  | 2390 | } | 
|  | 2391 | if (!xmlStrEqual(root->name, BAD_CAST "grammar")) { | 
|  | 2392 | if (ctxt->error != NULL) | 
|  | 2393 | ctxt->error(ctxt->userData, | 
|  | 2394 | "Include document root is not a grammar\n"); | 
|  | 2395 | ctxt->nbErrors++; | 
|  | 2396 | return(-1); | 
|  | 2397 | } | 
|  | 2398 |  | 
|  | 2399 | /* | 
|  | 2400 | * Merge the definition from both the include and the internal list | 
|  | 2401 | */ | 
|  | 2402 | if (root->children != NULL) { | 
|  | 2403 | tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children); | 
|  | 2404 | if (tmp != 0) | 
|  | 2405 | ret = -1; | 
|  | 2406 | } | 
|  | 2407 | if (node->children != NULL) { | 
|  | 2408 | tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children); | 
|  | 2409 | if (tmp != 0) | 
|  | 2410 | ret = -1; | 
|  | 2411 | } | 
|  | 2412 | return(ret); | 
|  | 2413 | } | 
|  | 2414 |  | 
|  | 2415 | /** | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2416 | * xmlRelaxNGParseDefine: | 
|  | 2417 | * @ctxt:  a Relax-NG parser context | 
|  | 2418 | * @node:  the define node | 
|  | 2419 | * | 
|  | 2420 | * parse the content of a RelaxNG define element node. | 
|  | 2421 | * | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 2422 | * Returns 0 in case of success or -1 in case of error | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2423 | */ | 
|  | 2424 | static int | 
|  | 2425 | xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 2426 | xmlChar *name; | 
|  | 2427 | int ret = 0, tmp; | 
|  | 2428 | xmlRelaxNGDefinePtr def; | 
|  | 2429 | const xmlChar *olddefine; | 
|  | 2430 |  | 
|  | 2431 | name = xmlGetProp(node, BAD_CAST "name"); | 
|  | 2432 | if (name == NULL) { | 
|  | 2433 | if (ctxt->error != NULL) | 
|  | 2434 | ctxt->error(ctxt->userData, | 
|  | 2435 | "define has no name\n"); | 
|  | 2436 | ctxt->nbErrors++; | 
|  | 2437 | } else { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2438 | xmlRelaxNGNormExtSpace(name); | 
|  | 2439 | if (xmlValidateNCName(name, 0)) { | 
|  | 2440 | if (ctxt->error != NULL) | 
|  | 2441 | ctxt->error(ctxt->userData, | 
|  | 2442 | "define name '%s' is not an NCName\n", | 
|  | 2443 | name); | 
|  | 2444 | ctxt->nbErrors++; | 
|  | 2445 | } | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2446 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2447 | if (def == NULL) { | 
|  | 2448 | xmlFree(name); | 
|  | 2449 | return(-1); | 
|  | 2450 | } | 
|  | 2451 | def->type = XML_RELAXNG_DEF; | 
|  | 2452 | def->name = name; | 
|  | 2453 | if (node->children == NULL) { | 
|  | 2454 | if (ctxt->error != NULL) | 
|  | 2455 | ctxt->error(ctxt->userData, | 
|  | 2456 | "define has no children\n"); | 
|  | 2457 | ctxt->nbErrors++; | 
|  | 2458 | } else { | 
|  | 2459 | olddefine = ctxt->define; | 
|  | 2460 | ctxt->define = name; | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 2461 | def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0); | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2462 | ctxt->define = olddefine; | 
|  | 2463 | } | 
|  | 2464 | if (ctxt->grammar->defs == NULL) | 
|  | 2465 | ctxt->grammar->defs = xmlHashCreate(10); | 
|  | 2466 | if (ctxt->grammar->defs == NULL) { | 
|  | 2467 | if (ctxt->error != NULL) | 
|  | 2468 | ctxt->error(ctxt->userData, | 
|  | 2469 | "Could not create definition hash\n"); | 
|  | 2470 | ctxt->nbErrors++; | 
|  | 2471 | ret = -1; | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2472 | } else { | 
|  | 2473 | tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def); | 
|  | 2474 | if (tmp < 0) { | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 2475 | xmlRelaxNGDefinePtr prev; | 
|  | 2476 |  | 
|  | 2477 | prev = xmlHashLookup(ctxt->grammar->defs, name); | 
|  | 2478 | if (prev == NULL) { | 
|  | 2479 | if (ctxt->error != NULL) | 
|  | 2480 | ctxt->error(ctxt->userData, | 
|  | 2481 | "Internal error on define aggregation of %s\n", | 
|  | 2482 | name); | 
|  | 2483 | ctxt->nbErrors++; | 
|  | 2484 | ret = -1; | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 2485 | } else { | 
|  | 2486 | while (prev->nextHash != NULL) | 
|  | 2487 | prev = prev->nextHash; | 
|  | 2488 | prev->nextHash = def; | 
|  | 2489 | } | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2490 | } | 
|  | 2491 | } | 
|  | 2492 | } | 
|  | 2493 | return(ret); | 
|  | 2494 | } | 
|  | 2495 |  | 
|  | 2496 | /** | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 2497 | * xmlRelaxNGProcessExternalRef: | 
|  | 2498 | * @ctxt: the parser context | 
|  | 2499 | * @node:  the externlRef node | 
|  | 2500 | * | 
|  | 2501 | * Process and compile an externlRef node | 
|  | 2502 | * | 
|  | 2503 | * Returns the xmlRelaxNGDefinePtr or NULL in case of error | 
|  | 2504 | */ | 
|  | 2505 | static xmlRelaxNGDefinePtr | 
|  | 2506 | xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 2507 | xmlRelaxNGDocumentPtr docu; | 
|  | 2508 | xmlNodePtr root, tmp; | 
|  | 2509 | xmlChar *ns; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 2510 | int newNs = 0, oldflags; | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 2511 | xmlRelaxNGDefinePtr def; | 
|  | 2512 |  | 
|  | 2513 | docu = node->_private; | 
|  | 2514 | if (docu != NULL) { | 
|  | 2515 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2516 | if (def == NULL) | 
|  | 2517 | return(NULL); | 
|  | 2518 | def->type = XML_RELAXNG_EXTERNALREF; | 
|  | 2519 |  | 
|  | 2520 | if (docu->content == NULL) { | 
|  | 2521 | /* | 
|  | 2522 | * Then do the parsing for good | 
|  | 2523 | */ | 
|  | 2524 | root = xmlDocGetRootElement(docu->doc); | 
|  | 2525 | if (root == NULL) { | 
|  | 2526 | if (ctxt->error != NULL) | 
|  | 2527 | ctxt->error(ctxt->userData, | 
|  | 2528 | "xmlRelaxNGParse: %s is empty\n", | 
|  | 2529 | ctxt->URL); | 
|  | 2530 | ctxt->nbErrors++; | 
|  | 2531 | return (NULL); | 
|  | 2532 | } | 
|  | 2533 | /* | 
|  | 2534 | * ns transmission rules | 
|  | 2535 | */ | 
|  | 2536 | ns = xmlGetProp(root, BAD_CAST "ns"); | 
|  | 2537 | if (ns == NULL) { | 
|  | 2538 | tmp = node; | 
|  | 2539 | while ((tmp != NULL) && | 
|  | 2540 | (tmp->type == XML_ELEMENT_NODE)) { | 
|  | 2541 | ns = xmlGetProp(tmp, BAD_CAST "ns"); | 
|  | 2542 | if (ns != NULL) { | 
|  | 2543 | break; | 
|  | 2544 | } | 
|  | 2545 | tmp = tmp->parent; | 
|  | 2546 | } | 
|  | 2547 | if (ns != NULL) { | 
|  | 2548 | xmlSetProp(root, BAD_CAST "ns", ns); | 
|  | 2549 | newNs = 1; | 
|  | 2550 | xmlFree(ns); | 
|  | 2551 | } | 
|  | 2552 | } else { | 
|  | 2553 | xmlFree(ns); | 
|  | 2554 | } | 
|  | 2555 |  | 
|  | 2556 | /* | 
|  | 2557 | * Parsing to get a precompiled schemas. | 
|  | 2558 | */ | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 2559 | oldflags = ctxt->flags; | 
|  | 2560 | ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF; | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 2561 | docu->schema = xmlRelaxNGParseDocument(ctxt, root); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 2562 | ctxt->flags = oldflags; | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 2563 | if ((docu->schema != NULL) && | 
|  | 2564 | (docu->schema->topgrammar != NULL)) { | 
|  | 2565 | docu->content = docu->schema->topgrammar->start; | 
|  | 2566 | } | 
|  | 2567 |  | 
|  | 2568 | /* | 
|  | 2569 | * the externalRef may be reused in a different ns context | 
|  | 2570 | */ | 
|  | 2571 | if (newNs == 1) { | 
|  | 2572 | xmlUnsetProp(root, BAD_CAST "ns"); | 
|  | 2573 | } | 
|  | 2574 | } | 
|  | 2575 | def->content = docu->content; | 
|  | 2576 | } else { | 
|  | 2577 | def = NULL; | 
|  | 2578 | } | 
|  | 2579 | return(def); | 
|  | 2580 | } | 
|  | 2581 |  | 
|  | 2582 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2583 | * xmlRelaxNGParsePattern: | 
|  | 2584 | * @ctxt:  a Relax-NG parser context | 
|  | 2585 | * @node:  the pattern node. | 
|  | 2586 | * | 
|  | 2587 | * parse the content of a RelaxNG pattern node. | 
|  | 2588 | * | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2589 | * Returns the definition pointer or NULL in case of error or if no | 
|  | 2590 | *     pattern is generated. | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2591 | */ | 
|  | 2592 | static xmlRelaxNGDefinePtr | 
|  | 2593 | xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 2594 | xmlRelaxNGDefinePtr def = NULL; | 
|  | 2595 |  | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2596 | if (node == NULL) { | 
|  | 2597 | return(NULL); | 
|  | 2598 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2599 | if (IS_RELAXNG(node, "element")) { | 
|  | 2600 | def = xmlRelaxNGParseElement(ctxt, node); | 
|  | 2601 | } else if (IS_RELAXNG(node, "attribute")) { | 
|  | 2602 | def = xmlRelaxNGParseAttribute(ctxt, node); | 
|  | 2603 | } else if (IS_RELAXNG(node, "empty")) { | 
|  | 2604 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2605 | if (def == NULL) | 
|  | 2606 | return(NULL); | 
|  | 2607 | def->type = XML_RELAXNG_EMPTY; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2608 | if (node->children != NULL) { | 
|  | 2609 | if (ctxt->error != NULL) | 
|  | 2610 | ctxt->error(ctxt->userData, "empty: had a child node\n"); | 
|  | 2611 | ctxt->nbErrors++; | 
|  | 2612 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2613 | } else if (IS_RELAXNG(node, "text")) { | 
|  | 2614 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2615 | if (def == NULL) | 
|  | 2616 | return(NULL); | 
|  | 2617 | def->type = XML_RELAXNG_TEXT; | 
|  | 2618 | if (node->children != NULL) { | 
|  | 2619 | if (ctxt->error != NULL) | 
|  | 2620 | ctxt->error(ctxt->userData, "text: had a child node\n"); | 
|  | 2621 | ctxt->nbErrors++; | 
|  | 2622 | } | 
|  | 2623 | } else if (IS_RELAXNG(node, "zeroOrMore")) { | 
|  | 2624 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2625 | if (def == NULL) | 
|  | 2626 | return(NULL); | 
|  | 2627 | def->type = XML_RELAXNG_ZEROORMORE; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2628 | if (node->children == NULL) { | 
|  | 2629 | if (ctxt->error != NULL) | 
|  | 2630 | ctxt->error(ctxt->userData, | 
|  | 2631 | "Element %s is empty\n", node->name); | 
|  | 2632 | ctxt->nbErrors++; | 
|  | 2633 | } else { | 
|  | 2634 | def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1); | 
|  | 2635 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2636 | } else if (IS_RELAXNG(node, "oneOrMore")) { | 
|  | 2637 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2638 | if (def == NULL) | 
|  | 2639 | return(NULL); | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 2640 | def->type = XML_RELAXNG_ONEORMORE; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2641 | if (node->children == NULL) { | 
|  | 2642 | if (ctxt->error != NULL) | 
|  | 2643 | ctxt->error(ctxt->userData, | 
|  | 2644 | "Element %s is empty\n", node->name); | 
|  | 2645 | ctxt->nbErrors++; | 
|  | 2646 | } else { | 
|  | 2647 | def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1); | 
|  | 2648 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2649 | } else if (IS_RELAXNG(node, "optional")) { | 
|  | 2650 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2651 | if (def == NULL) | 
|  | 2652 | return(NULL); | 
|  | 2653 | def->type = XML_RELAXNG_OPTIONAL; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2654 | if (node->children == NULL) { | 
|  | 2655 | if (ctxt->error != NULL) | 
|  | 2656 | ctxt->error(ctxt->userData, | 
|  | 2657 | "Element %s is empty\n", node->name); | 
|  | 2658 | ctxt->nbErrors++; | 
|  | 2659 | } else { | 
|  | 2660 | def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1); | 
|  | 2661 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2662 | } else if (IS_RELAXNG(node, "choice")) { | 
|  | 2663 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2664 | if (def == NULL) | 
|  | 2665 | return(NULL); | 
|  | 2666 | def->type = XML_RELAXNG_CHOICE; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2667 | if (node->children == NULL) { | 
|  | 2668 | if (ctxt->error != NULL) | 
|  | 2669 | ctxt->error(ctxt->userData, | 
|  | 2670 | "Element %s is empty\n", node->name); | 
|  | 2671 | ctxt->nbErrors++; | 
|  | 2672 | } else { | 
|  | 2673 | def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0); | 
|  | 2674 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2675 | } else if (IS_RELAXNG(node, "group")) { | 
|  | 2676 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2677 | if (def == NULL) | 
|  | 2678 | return(NULL); | 
|  | 2679 | def->type = XML_RELAXNG_GROUP; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2680 | if (node->children == NULL) { | 
|  | 2681 | if (ctxt->error != NULL) | 
|  | 2682 | ctxt->error(ctxt->userData, | 
|  | 2683 | "Element %s is empty\n", node->name); | 
|  | 2684 | ctxt->nbErrors++; | 
|  | 2685 | } else { | 
|  | 2686 | def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0); | 
|  | 2687 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2688 | } else if (IS_RELAXNG(node, "ref")) { | 
|  | 2689 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2690 | if (def == NULL) | 
|  | 2691 | return(NULL); | 
|  | 2692 | def->type = XML_RELAXNG_REF; | 
|  | 2693 | def->name = xmlGetProp(node, BAD_CAST "name"); | 
|  | 2694 | if (def->name == NULL) { | 
|  | 2695 | if (ctxt->error != NULL) | 
|  | 2696 | ctxt->error(ctxt->userData, | 
|  | 2697 | "ref has no name\n"); | 
|  | 2698 | ctxt->nbErrors++; | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2699 | } else { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2700 | xmlRelaxNGNormExtSpace(def->name); | 
|  | 2701 | if (xmlValidateNCName(def->name, 0)) { | 
|  | 2702 | if (ctxt->error != NULL) | 
|  | 2703 | ctxt->error(ctxt->userData, | 
|  | 2704 | "ref name '%s' is not an NCName\n", | 
|  | 2705 | def->name); | 
|  | 2706 | ctxt->nbErrors++; | 
|  | 2707 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2708 | } | 
|  | 2709 | if (node->children != NULL) { | 
|  | 2710 | if (ctxt->error != NULL) | 
|  | 2711 | ctxt->error(ctxt->userData, | 
|  | 2712 | "ref is not empty\n"); | 
|  | 2713 | ctxt->nbErrors++; | 
|  | 2714 | } | 
|  | 2715 | if (ctxt->grammar->refs == NULL) | 
|  | 2716 | ctxt->grammar->refs = xmlHashCreate(10); | 
|  | 2717 | if (ctxt->grammar->refs == NULL) { | 
|  | 2718 | if (ctxt->error != NULL) | 
|  | 2719 | ctxt->error(ctxt->userData, | 
|  | 2720 | "Could not create references hash\n"); | 
|  | 2721 | ctxt->nbErrors++; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2722 | def = NULL; | 
|  | 2723 | } else { | 
|  | 2724 | int tmp; | 
|  | 2725 |  | 
|  | 2726 | tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def); | 
|  | 2727 | if (tmp < 0) { | 
|  | 2728 | xmlRelaxNGDefinePtr prev; | 
|  | 2729 |  | 
|  | 2730 | prev = (xmlRelaxNGDefinePtr) | 
|  | 2731 | xmlHashLookup(ctxt->grammar->refs, def->name); | 
|  | 2732 | if (prev == NULL) { | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 2733 | if (def->name != NULL) { | 
|  | 2734 | if (ctxt->error != NULL) | 
|  | 2735 | ctxt->error(ctxt->userData, | 
|  | 2736 | "Error refs definitions '%s'\n", | 
|  | 2737 | def->name); | 
|  | 2738 | } else { | 
|  | 2739 | if (ctxt->error != NULL) | 
|  | 2740 | ctxt->error(ctxt->userData, | 
|  | 2741 | "Error refs definitions\n"); | 
|  | 2742 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2743 | ctxt->nbErrors++; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2744 | def = NULL; | 
|  | 2745 | } else { | 
|  | 2746 | def->nextHash = prev->nextHash; | 
|  | 2747 | prev->nextHash = def; | 
|  | 2748 | } | 
|  | 2749 | } | 
|  | 2750 | } | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 2751 | } else if (IS_RELAXNG(node, "data")) { | 
|  | 2752 | def = xmlRelaxNGParseData(ctxt, node); | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2753 | #if 0 | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 2754 | } else if (IS_RELAXNG(node, "define")) { | 
|  | 2755 | xmlRelaxNGParseDefine(ctxt, node); | 
|  | 2756 | def = NULL; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2757 | #endif | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 2758 | } else if (IS_RELAXNG(node, "value")) { | 
|  | 2759 | def = xmlRelaxNGParseValue(ctxt, node); | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 2760 | } else if (IS_RELAXNG(node, "list")) { | 
|  | 2761 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2762 | if (def == NULL) | 
|  | 2763 | return(NULL); | 
|  | 2764 | def->type = XML_RELAXNG_LIST; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2765 | if (node->children == NULL) { | 
|  | 2766 | if (ctxt->error != NULL) | 
|  | 2767 | ctxt->error(ctxt->userData, | 
|  | 2768 | "Element %s is empty\n", node->name); | 
|  | 2769 | ctxt->nbErrors++; | 
|  | 2770 | } else { | 
|  | 2771 | def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0); | 
|  | 2772 | } | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2773 | } else if (IS_RELAXNG(node, "interleave")) { | 
|  | 2774 | def = xmlRelaxNGParseInterleave(ctxt, node); | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 2775 | } else if (IS_RELAXNG(node, "externalRef")) { | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 2776 | def = xmlRelaxNGProcessExternalRef(ctxt, node); | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 2777 | } else if (IS_RELAXNG(node, "notAllowed")) { | 
|  | 2778 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2779 | if (def == NULL) | 
|  | 2780 | return(NULL); | 
|  | 2781 | def->type = XML_RELAXNG_NOT_ALLOWED; | 
|  | 2782 | if (node->children != NULL) { | 
|  | 2783 | if (ctxt->error != NULL) | 
|  | 2784 | ctxt->error(ctxt->userData, | 
|  | 2785 | "xmlRelaxNGParse: notAllowed element is not empty\n"); | 
|  | 2786 | ctxt->nbErrors++; | 
|  | 2787 | } | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 2788 | } else if (IS_RELAXNG(node, "grammar")) { | 
|  | 2789 | xmlRelaxNGGrammarPtr grammar, old; | 
|  | 2790 | xmlRelaxNGGrammarPtr oldparent; | 
|  | 2791 |  | 
|  | 2792 | oldparent = ctxt->parentgrammar; | 
|  | 2793 | old = ctxt->grammar; | 
|  | 2794 | ctxt->parentgrammar = old; | 
|  | 2795 | grammar = xmlRelaxNGParseGrammar(ctxt, node->children); | 
|  | 2796 | if (old != NULL) { | 
|  | 2797 | ctxt->grammar = old; | 
|  | 2798 | ctxt->parentgrammar = oldparent; | 
|  | 2799 | if (grammar != NULL) { | 
|  | 2800 | grammar->next = old->next; | 
|  | 2801 | old->next = grammar; | 
|  | 2802 | } | 
|  | 2803 | } | 
|  | 2804 | if (grammar != NULL) | 
|  | 2805 | def = grammar->start; | 
|  | 2806 | else | 
|  | 2807 | def = NULL; | 
|  | 2808 | } else if (IS_RELAXNG(node, "parentRef")) { | 
|  | 2809 | if (ctxt->parentgrammar == NULL) { | 
|  | 2810 | if (ctxt->error != NULL) | 
|  | 2811 | ctxt->error(ctxt->userData, | 
|  | 2812 | "Use of parentRef without a parent grammar\n"); | 
|  | 2813 | ctxt->nbErrors++; | 
|  | 2814 | return(NULL); | 
|  | 2815 | } | 
|  | 2816 | def = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2817 | if (def == NULL) | 
|  | 2818 | return(NULL); | 
|  | 2819 | def->type = XML_RELAXNG_PARENTREF; | 
|  | 2820 | def->name = xmlGetProp(node, BAD_CAST "name"); | 
|  | 2821 | if (def->name == NULL) { | 
|  | 2822 | if (ctxt->error != NULL) | 
|  | 2823 | ctxt->error(ctxt->userData, | 
|  | 2824 | "parentRef has no name\n"); | 
|  | 2825 | ctxt->nbErrors++; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2826 | } else { | 
|  | 2827 | xmlRelaxNGNormExtSpace(def->name); | 
|  | 2828 | if (xmlValidateNCName(def->name, 0)) { | 
|  | 2829 | if (ctxt->error != NULL) | 
|  | 2830 | ctxt->error(ctxt->userData, | 
|  | 2831 | "parentRef name '%s' is not an NCName\n", | 
|  | 2832 | def->name); | 
|  | 2833 | ctxt->nbErrors++; | 
|  | 2834 | } | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 2835 | } | 
|  | 2836 | if (node->children != NULL) { | 
|  | 2837 | if (ctxt->error != NULL) | 
|  | 2838 | ctxt->error(ctxt->userData, | 
|  | 2839 | "parentRef is not empty\n"); | 
|  | 2840 | ctxt->nbErrors++; | 
|  | 2841 | } | 
|  | 2842 | if (ctxt->parentgrammar->refs == NULL) | 
|  | 2843 | ctxt->parentgrammar->refs = xmlHashCreate(10); | 
|  | 2844 | if (ctxt->parentgrammar->refs == NULL) { | 
|  | 2845 | if (ctxt->error != NULL) | 
|  | 2846 | ctxt->error(ctxt->userData, | 
|  | 2847 | "Could not create references hash\n"); | 
|  | 2848 | ctxt->nbErrors++; | 
|  | 2849 | def = NULL; | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2850 | } else if (def->name != NULL) { | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 2851 | int tmp; | 
|  | 2852 |  | 
|  | 2853 | tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def); | 
|  | 2854 | if (tmp < 0) { | 
|  | 2855 | xmlRelaxNGDefinePtr prev; | 
|  | 2856 |  | 
|  | 2857 | prev = (xmlRelaxNGDefinePtr) | 
|  | 2858 | xmlHashLookup(ctxt->parentgrammar->refs, def->name); | 
|  | 2859 | if (prev == NULL) { | 
|  | 2860 | if (ctxt->error != NULL) | 
|  | 2861 | ctxt->error(ctxt->userData, | 
|  | 2862 | "Internal error parentRef definitions '%s'\n", | 
|  | 2863 | def->name); | 
|  | 2864 | ctxt->nbErrors++; | 
|  | 2865 | def = NULL; | 
|  | 2866 | } else { | 
|  | 2867 | def->nextHash = prev->nextHash; | 
|  | 2868 | prev->nextHash = def; | 
|  | 2869 | } | 
|  | 2870 | } | 
|  | 2871 | } | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2872 | } else if (IS_RELAXNG(node, "mixed")) { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 2873 | if (node->children == NULL) { | 
|  | 2874 | if (ctxt->error != NULL) | 
|  | 2875 | ctxt->error(ctxt->userData, | 
|  | 2876 | "Mixed is empty\n"); | 
|  | 2877 | ctxt->nbErrors++; | 
|  | 2878 | def = NULL; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 2879 | } else { | 
|  | 2880 | def = xmlRelaxNGParseInterleave(ctxt, node); | 
|  | 2881 | if (def != NULL) { | 
|  | 2882 | xmlRelaxNGDefinePtr tmp; | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 2883 |  | 
|  | 2884 | if ((def->content != NULL) && (def->content->next != NULL)) { | 
|  | 2885 | tmp = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2886 | if (tmp != NULL) { | 
|  | 2887 | tmp->type = XML_RELAXNG_GROUP; | 
|  | 2888 | tmp->content = def->content; | 
|  | 2889 | def->content = tmp; | 
|  | 2890 | } | 
|  | 2891 | } | 
|  | 2892 |  | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 2893 | tmp = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2894 | if (tmp == NULL) | 
|  | 2895 | return(def); | 
|  | 2896 | tmp->type = XML_RELAXNG_TEXT; | 
|  | 2897 | tmp->next = def->content; | 
|  | 2898 | def->content = tmp; | 
|  | 2899 | } | 
|  | 2900 | } | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2901 | } else { | 
|  | 2902 | if (ctxt->error != NULL) | 
|  | 2903 | ctxt->error(ctxt->userData, | 
|  | 2904 | "Unexpected node %s is not a pattern\n", | 
|  | 2905 | node->name); | 
|  | 2906 | ctxt->nbErrors++; | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 2907 | def = NULL; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2908 | } | 
|  | 2909 | return(def); | 
|  | 2910 | } | 
|  | 2911 |  | 
|  | 2912 | /** | 
|  | 2913 | * xmlRelaxNGParseAttribute: | 
|  | 2914 | * @ctxt:  a Relax-NG parser context | 
|  | 2915 | * @node:  the element node | 
|  | 2916 | * | 
|  | 2917 | * parse the content of a RelaxNG attribute node. | 
|  | 2918 | * | 
|  | 2919 | * Returns the definition pointer or NULL in case of error. | 
|  | 2920 | */ | 
|  | 2921 | static xmlRelaxNGDefinePtr | 
|  | 2922 | xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2923 | xmlRelaxNGDefinePtr ret, cur; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2924 | xmlNodePtr child; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2925 | int old_flags; | 
|  | 2926 |  | 
|  | 2927 | ret = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 2928 | if (ret == NULL) | 
|  | 2929 | return(NULL); | 
|  | 2930 | ret->type = XML_RELAXNG_ATTRIBUTE; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2931 | ret->parent = ctxt->def; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2932 | child = node->children; | 
|  | 2933 | if (child == NULL) { | 
|  | 2934 | if (ctxt->error != NULL) | 
|  | 2935 | ctxt->error(ctxt->userData, | 
|  | 2936 | "xmlRelaxNGParseattribute: attribute has no children\n"); | 
|  | 2937 | ctxt->nbErrors++; | 
|  | 2938 | return(ret); | 
|  | 2939 | } | 
|  | 2940 | old_flags = ctxt->flags; | 
|  | 2941 | ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE; | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 2942 | cur = xmlRelaxNGParseNameClass(ctxt, child, ret); | 
|  | 2943 | if (cur != NULL) | 
|  | 2944 | child = child->next; | 
|  | 2945 |  | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2946 | if (child != NULL) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2947 | cur = xmlRelaxNGParsePattern(ctxt, child); | 
|  | 2948 | if (cur != NULL) { | 
|  | 2949 | switch (cur->type) { | 
|  | 2950 | case XML_RELAXNG_EMPTY: | 
|  | 2951 | case XML_RELAXNG_NOT_ALLOWED: | 
|  | 2952 | case XML_RELAXNG_TEXT: | 
|  | 2953 | case XML_RELAXNG_ELEMENT: | 
|  | 2954 | case XML_RELAXNG_DATATYPE: | 
|  | 2955 | case XML_RELAXNG_VALUE: | 
|  | 2956 | case XML_RELAXNG_LIST: | 
|  | 2957 | case XML_RELAXNG_REF: | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 2958 | case XML_RELAXNG_PARENTREF: | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 2959 | case XML_RELAXNG_EXTERNALREF: | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2960 | case XML_RELAXNG_DEF: | 
|  | 2961 | case XML_RELAXNG_ONEORMORE: | 
|  | 2962 | case XML_RELAXNG_ZEROORMORE: | 
|  | 2963 | case XML_RELAXNG_OPTIONAL: | 
|  | 2964 | case XML_RELAXNG_CHOICE: | 
|  | 2965 | case XML_RELAXNG_GROUP: | 
|  | 2966 | case XML_RELAXNG_INTERLEAVE: | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 2967 | case XML_RELAXNG_ATTRIBUTE: | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2968 | ret->content = cur; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 2969 | cur->parent = ret; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2970 | break; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 2971 | case XML_RELAXNG_START: | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 2972 | case XML_RELAXNG_PARAM: | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 2973 | case XML_RELAXNG_EXCEPT: | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2974 | if (ctxt->error != NULL) | 
|  | 2975 | ctxt->error(ctxt->userData, | 
|  | 2976 | "attribute has invalid content\n"); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 2977 | ctxt->nbErrors++; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 2978 | break; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 2979 | case XML_RELAXNG_NOOP: | 
|  | 2980 | TODO | 
|  | 2981 | if (ctxt->error != NULL) | 
|  | 2982 | ctxt->error(ctxt->userData, | 
|  | 2983 | "Internal error, noop found\n"); | 
|  | 2984 | ctxt->nbErrors++; | 
|  | 2985 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2986 | } | 
|  | 2987 | } | 
|  | 2988 | child = child->next; | 
|  | 2989 | } | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 2990 | if (child != NULL) { | 
|  | 2991 | if (ctxt->error != NULL) | 
|  | 2992 | ctxt->error(ctxt->userData, "attribute has multiple children\n"); | 
|  | 2993 | ctxt->nbErrors++; | 
|  | 2994 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 2995 | ctxt->flags = old_flags; | 
|  | 2996 | return(ret); | 
|  | 2997 | } | 
|  | 2998 |  | 
|  | 2999 | /** | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3000 | * xmlRelaxNGParseExceptNameClass: | 
|  | 3001 | * @ctxt:  a Relax-NG parser context | 
|  | 3002 | * @node:  the except node | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 3003 | * @attr:  1 if within an attribute, 0 if within an element | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3004 | * | 
|  | 3005 | * parse the content of a RelaxNG nameClass node. | 
|  | 3006 | * | 
|  | 3007 | * Returns the definition pointer or NULL in case of error. | 
|  | 3008 | */ | 
|  | 3009 | static xmlRelaxNGDefinePtr | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 3010 | xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 3011 | xmlNodePtr node, int attr) { | 
|  | 3012 | xmlRelaxNGDefinePtr ret, cur, last = NULL; | 
|  | 3013 | xmlNodePtr child; | 
|  | 3014 |  | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3015 | if (!IS_RELAXNG(node, "except")) { | 
|  | 3016 | if (ctxt->error != NULL) | 
|  | 3017 | ctxt->error(ctxt->userData, | 
|  | 3018 | "Expecting an except node\n"); | 
|  | 3019 | ctxt->nbErrors++; | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 3020 | return(NULL); | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3021 | } | 
|  | 3022 | if (node->next != NULL) { | 
|  | 3023 | if (ctxt->error != NULL) | 
|  | 3024 | ctxt->error(ctxt->userData, | 
|  | 3025 | "exceptNameClass allows only a single except node\n"); | 
|  | 3026 | ctxt->nbErrors++; | 
|  | 3027 | } | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 3028 | if (node->children == NULL) { | 
|  | 3029 | if (ctxt->error != NULL) | 
|  | 3030 | ctxt->error(ctxt->userData, | 
|  | 3031 | "except has no content\n"); | 
|  | 3032 | ctxt->nbErrors++; | 
|  | 3033 | return(NULL); | 
|  | 3034 | } | 
|  | 3035 |  | 
|  | 3036 | ret = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 3037 | if (ret == NULL) | 
|  | 3038 | return(NULL); | 
|  | 3039 | ret->type = XML_RELAXNG_EXCEPT; | 
|  | 3040 | child = node->children; | 
|  | 3041 | while (child != NULL) { | 
|  | 3042 | cur = xmlRelaxNGNewDefine(ctxt, child); | 
|  | 3043 | if (cur == NULL) | 
|  | 3044 | break; | 
|  | 3045 | if (attr) | 
|  | 3046 | cur->type = XML_RELAXNG_ATTRIBUTE; | 
|  | 3047 | else | 
|  | 3048 | cur->type = XML_RELAXNG_ELEMENT; | 
|  | 3049 |  | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 3050 | if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) { | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 3051 | if (last == NULL) { | 
|  | 3052 | ret->content = cur; | 
|  | 3053 | } else { | 
|  | 3054 | last->next = cur; | 
|  | 3055 | } | 
|  | 3056 | last = cur; | 
|  | 3057 | } | 
|  | 3058 | child = child->next; | 
|  | 3059 | } | 
|  | 3060 |  | 
|  | 3061 | return(ret); | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3062 | } | 
|  | 3063 |  | 
|  | 3064 | /** | 
|  | 3065 | * xmlRelaxNGParseNameClass: | 
|  | 3066 | * @ctxt:  a Relax-NG parser context | 
|  | 3067 | * @node:  the nameClass node | 
|  | 3068 | * @def:  the current definition | 
|  | 3069 | * | 
|  | 3070 | * parse the content of a RelaxNG nameClass node. | 
|  | 3071 | * | 
|  | 3072 | * Returns the definition pointer or NULL in case of error. | 
|  | 3073 | */ | 
|  | 3074 | static xmlRelaxNGDefinePtr | 
|  | 3075 | xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node, | 
|  | 3076 | xmlRelaxNGDefinePtr def) { | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 3077 | xmlRelaxNGDefinePtr ret, tmp; | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3078 | xmlChar *val; | 
|  | 3079 |  | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 3080 | ret = def; | 
|  | 3081 | if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName"))  || | 
|  | 3082 | (IS_RELAXNG(node, "nsName"))) { | 
|  | 3083 | if ((def->type != XML_RELAXNG_ELEMENT) && | 
|  | 3084 | (def->type != XML_RELAXNG_ATTRIBUTE)) { | 
|  | 3085 | ret = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 3086 | if (ret == NULL) | 
|  | 3087 | return(NULL); | 
|  | 3088 | ret->parent = def; | 
|  | 3089 | if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) | 
|  | 3090 | ret->type = XML_RELAXNG_ATTRIBUTE; | 
|  | 3091 | else | 
|  | 3092 | ret->type = XML_RELAXNG_ELEMENT; | 
|  | 3093 | } | 
|  | 3094 | } | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3095 | if (IS_RELAXNG(node, "name")) { | 
|  | 3096 | val = xmlNodeGetContent(node); | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3097 | xmlRelaxNGNormExtSpace(val); | 
|  | 3098 | if (xmlValidateNCName(val, 0)) { | 
|  | 3099 | if (ctxt->error != NULL) { | 
|  | 3100 | if (node->parent != NULL) | 
|  | 3101 | ctxt->error(ctxt->userData, | 
|  | 3102 | "Element %s name '%s' is not an NCName\n", | 
|  | 3103 | node->parent->name, val); | 
|  | 3104 | else | 
|  | 3105 | ctxt->error(ctxt->userData, | 
|  | 3106 | "name '%s' is not an NCName\n", | 
|  | 3107 | val); | 
|  | 3108 | } | 
|  | 3109 | ctxt->nbErrors++; | 
|  | 3110 | } | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3111 | ret->name = val; | 
|  | 3112 | val = xmlGetProp(node, BAD_CAST "ns"); | 
|  | 3113 | ret->ns = val; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 3114 | if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && | 
|  | 3115 | (val != NULL) && | 
|  | 3116 | (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) { | 
|  | 3117 | ctxt->error(ctxt->userData, | 
|  | 3118 | "Attribute with namespace '%s' is not allowed\n", | 
|  | 3119 | val); | 
|  | 3120 | ctxt->nbErrors++; | 
|  | 3121 | } | 
|  | 3122 | if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && | 
|  | 3123 | (val != NULL) && | 
|  | 3124 | (val[0] == 0) && | 
|  | 3125 | (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) { | 
|  | 3126 | ctxt->error(ctxt->userData, | 
|  | 3127 | "Attribute with QName 'xmlns' is not allowed\n", | 
|  | 3128 | val); | 
|  | 3129 | ctxt->nbErrors++; | 
|  | 3130 | } | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3131 | } else if (IS_RELAXNG(node, "anyName")) { | 
|  | 3132 | ret->name = NULL; | 
|  | 3133 | ret->ns = NULL; | 
|  | 3134 | if (node->children != NULL) { | 
|  | 3135 | ret->nameClass = | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 3136 | xmlRelaxNGParseExceptNameClass(ctxt, node->children, | 
|  | 3137 | (def->type == XML_RELAXNG_ATTRIBUTE)); | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3138 | } | 
|  | 3139 | } else if (IS_RELAXNG(node, "nsName")) { | 
|  | 3140 | ret->name = NULL; | 
|  | 3141 | ret->ns = xmlGetProp(node, BAD_CAST "ns"); | 
|  | 3142 | if (ret->ns == NULL) { | 
|  | 3143 | if (ctxt->error != NULL) | 
|  | 3144 | ctxt->error(ctxt->userData, | 
|  | 3145 | "nsName has no ns attribute\n"); | 
|  | 3146 | ctxt->nbErrors++; | 
|  | 3147 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 3148 | if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) && | 
|  | 3149 | (ret->ns != NULL) && | 
|  | 3150 | (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) { | 
|  | 3151 | ctxt->error(ctxt->userData, | 
|  | 3152 | "Attribute with namespace '%s' is not allowed\n", | 
|  | 3153 | ret->ns); | 
|  | 3154 | ctxt->nbErrors++; | 
|  | 3155 | } | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3156 | if (node->children != NULL) { | 
|  | 3157 | ret->nameClass = | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 3158 | xmlRelaxNGParseExceptNameClass(ctxt, node->children, | 
|  | 3159 | (def->type == XML_RELAXNG_ATTRIBUTE)); | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3160 | } | 
|  | 3161 | } else if (IS_RELAXNG(node, "choice")) { | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 3162 | xmlNodePtr child; | 
|  | 3163 | xmlRelaxNGDefinePtr last = NULL; | 
|  | 3164 |  | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 3165 | ret = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 3166 | if (ret == NULL) | 
|  | 3167 | return(NULL); | 
|  | 3168 | ret->parent = def; | 
|  | 3169 | ret->type = XML_RELAXNG_CHOICE; | 
|  | 3170 |  | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3171 | if (node->children == NULL) { | 
|  | 3172 | if (ctxt->error != NULL) | 
|  | 3173 | ctxt->error(ctxt->userData, | 
|  | 3174 | "Element choice is empty\n"); | 
|  | 3175 | ctxt->nbErrors++; | 
|  | 3176 | } else { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3177 |  | 
|  | 3178 | child = node->children; | 
|  | 3179 | while (child != NULL) { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 3180 | tmp = xmlRelaxNGParseNameClass(ctxt, child, ret); | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3181 | if (tmp != NULL) { | 
|  | 3182 | if (last == NULL) { | 
|  | 3183 | last = ret->nameClass = tmp; | 
|  | 3184 | } else { | 
|  | 3185 | last->next = tmp; | 
|  | 3186 | last = tmp; | 
|  | 3187 | } | 
|  | 3188 | } | 
|  | 3189 | child = child->next; | 
|  | 3190 | } | 
|  | 3191 | } | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3192 | } else { | 
|  | 3193 | if (ctxt->error != NULL) | 
|  | 3194 | ctxt->error(ctxt->userData, | 
|  | 3195 | "expecting name, anyName, nsName or choice : got %s\n", | 
|  | 3196 | node->name); | 
|  | 3197 | ctxt->nbErrors++; | 
|  | 3198 | return(NULL); | 
|  | 3199 | } | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 3200 | if (ret != def) { | 
|  | 3201 | if (def->nameClass == NULL) { | 
|  | 3202 | def->nameClass = ret; | 
|  | 3203 | } else { | 
|  | 3204 | tmp = def->nameClass; | 
|  | 3205 | while (tmp->next != NULL) { | 
|  | 3206 | tmp = tmp->next; | 
|  | 3207 | } | 
|  | 3208 | tmp->next = ret; | 
|  | 3209 | } | 
|  | 3210 | } | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3211 | return(ret); | 
|  | 3212 | } | 
|  | 3213 |  | 
|  | 3214 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3215 | * xmlRelaxNGParseElement: | 
|  | 3216 | * @ctxt:  a Relax-NG parser context | 
|  | 3217 | * @node:  the element node | 
|  | 3218 | * | 
|  | 3219 | * parse the content of a RelaxNG element node. | 
|  | 3220 | * | 
|  | 3221 | * Returns the definition pointer or NULL in case of error. | 
|  | 3222 | */ | 
|  | 3223 | static xmlRelaxNGDefinePtr | 
|  | 3224 | xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 3225 | xmlRelaxNGDefinePtr ret, cur, last; | 
|  | 3226 | xmlNodePtr child; | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 3227 | const xmlChar *olddefine; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3228 |  | 
|  | 3229 | ret = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 3230 | if (ret == NULL) | 
|  | 3231 | return(NULL); | 
|  | 3232 | ret->type = XML_RELAXNG_ELEMENT; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 3233 | ret->parent = ctxt->def; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3234 | child = node->children; | 
|  | 3235 | if (child == NULL) { | 
|  | 3236 | if (ctxt->error != NULL) | 
|  | 3237 | ctxt->error(ctxt->userData, | 
|  | 3238 | "xmlRelaxNGParseElement: element has no children\n"); | 
|  | 3239 | ctxt->nbErrors++; | 
|  | 3240 | return(ret); | 
|  | 3241 | } | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 3242 | cur = xmlRelaxNGParseNameClass(ctxt, child, ret); | 
|  | 3243 | if (cur != NULL) | 
|  | 3244 | child = child->next; | 
|  | 3245 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3246 | if (child == NULL) { | 
|  | 3247 | if (ctxt->error != NULL) | 
|  | 3248 | ctxt->error(ctxt->userData, | 
|  | 3249 | "xmlRelaxNGParseElement: element has no content\n"); | 
|  | 3250 | ctxt->nbErrors++; | 
|  | 3251 | return(ret); | 
|  | 3252 | } | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 3253 | olddefine = ctxt->define; | 
|  | 3254 | ctxt->define = NULL; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3255 | last = NULL; | 
|  | 3256 | while (child != NULL) { | 
|  | 3257 | cur = xmlRelaxNGParsePattern(ctxt, child); | 
|  | 3258 | if (cur != NULL) { | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 3259 | cur->parent = ret; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3260 | switch (cur->type) { | 
|  | 3261 | case XML_RELAXNG_EMPTY: | 
|  | 3262 | case XML_RELAXNG_NOT_ALLOWED: | 
|  | 3263 | case XML_RELAXNG_TEXT: | 
|  | 3264 | case XML_RELAXNG_ELEMENT: | 
|  | 3265 | case XML_RELAXNG_DATATYPE: | 
|  | 3266 | case XML_RELAXNG_VALUE: | 
|  | 3267 | case XML_RELAXNG_LIST: | 
|  | 3268 | case XML_RELAXNG_REF: | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 3269 | case XML_RELAXNG_PARENTREF: | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 3270 | case XML_RELAXNG_EXTERNALREF: | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3271 | case XML_RELAXNG_DEF: | 
|  | 3272 | case XML_RELAXNG_ZEROORMORE: | 
|  | 3273 | case XML_RELAXNG_ONEORMORE: | 
|  | 3274 | case XML_RELAXNG_OPTIONAL: | 
|  | 3275 | case XML_RELAXNG_CHOICE: | 
|  | 3276 | case XML_RELAXNG_GROUP: | 
|  | 3277 | case XML_RELAXNG_INTERLEAVE: | 
|  | 3278 | if (last == NULL) { | 
|  | 3279 | ret->content = last = cur; | 
|  | 3280 | } else { | 
|  | 3281 | if ((last->type == XML_RELAXNG_ELEMENT) && | 
|  | 3282 | (ret->content == last)) { | 
|  | 3283 | ret->content = xmlRelaxNGNewDefine(ctxt, node); | 
|  | 3284 | if (ret->content != NULL) { | 
|  | 3285 | ret->content->type = XML_RELAXNG_GROUP; | 
|  | 3286 | ret->content->content = last; | 
|  | 3287 | } else { | 
|  | 3288 | ret->content = last; | 
|  | 3289 | } | 
|  | 3290 | } | 
|  | 3291 | last->next = cur; | 
|  | 3292 | last = cur; | 
|  | 3293 | } | 
|  | 3294 | break; | 
|  | 3295 | case XML_RELAXNG_ATTRIBUTE: | 
|  | 3296 | cur->next = ret->attrs; | 
|  | 3297 | ret->attrs = cur; | 
|  | 3298 | break; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 3299 | case XML_RELAXNG_START: | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 3300 | case XML_RELAXNG_PARAM: | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 3301 | case XML_RELAXNG_EXCEPT: | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 3302 | TODO | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 3303 | ctxt->nbErrors++; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 3304 | break; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3305 | case XML_RELAXNG_NOOP: | 
|  | 3306 | TODO | 
|  | 3307 | if (ctxt->error != NULL) | 
|  | 3308 | ctxt->error(ctxt->userData, | 
|  | 3309 | "Internal error, noop found\n"); | 
|  | 3310 | ctxt->nbErrors++; | 
|  | 3311 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3312 | } | 
|  | 3313 | } | 
|  | 3314 | child = child->next; | 
|  | 3315 | } | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 3316 | ctxt->define = olddefine; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3317 | return(ret); | 
|  | 3318 | } | 
|  | 3319 |  | 
|  | 3320 | /** | 
|  | 3321 | * xmlRelaxNGParsePatterns: | 
|  | 3322 | * @ctxt:  a Relax-NG parser context | 
|  | 3323 | * @nodes:  list of nodes | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 3324 | * @group:  use an implicit <group> for elements | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3325 | * | 
|  | 3326 | * parse the content of a RelaxNG start node. | 
|  | 3327 | * | 
|  | 3328 | * Returns the definition pointer or NULL in case of error. | 
|  | 3329 | */ | 
|  | 3330 | static xmlRelaxNGDefinePtr | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 3331 | xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, | 
|  | 3332 | int group) { | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 3333 | xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3334 |  | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 3335 | parent = ctxt->def; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3336 | while (nodes != NULL) { | 
|  | 3337 | if (IS_RELAXNG(nodes, "element")) { | 
|  | 3338 | cur = xmlRelaxNGParseElement(ctxt, nodes); | 
|  | 3339 | if (def == NULL) { | 
|  | 3340 | def = last = cur; | 
|  | 3341 | } else { | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 3342 | if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) && | 
|  | 3343 | (def == last)) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3344 | def = xmlRelaxNGNewDefine(ctxt, nodes); | 
|  | 3345 | def->type = XML_RELAXNG_GROUP; | 
|  | 3346 | def->content = last; | 
|  | 3347 | } | 
|  | 3348 | last->next = cur; | 
|  | 3349 | last = cur; | 
|  | 3350 | } | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 3351 | cur->parent = parent; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3352 | } else { | 
|  | 3353 | cur = xmlRelaxNGParsePattern(ctxt, nodes); | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 3354 | if (cur != NULL) { | 
|  | 3355 | if (def == NULL) { | 
|  | 3356 | def = last = cur; | 
|  | 3357 | } else { | 
|  | 3358 | last->next = cur; | 
|  | 3359 | last = cur; | 
|  | 3360 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3361 | } | 
|  | 3362 | } | 
|  | 3363 | nodes = nodes->next; | 
|  | 3364 | } | 
|  | 3365 | return(def); | 
|  | 3366 | } | 
|  | 3367 |  | 
|  | 3368 | /** | 
|  | 3369 | * xmlRelaxNGParseStart: | 
|  | 3370 | * @ctxt:  a Relax-NG parser context | 
|  | 3371 | * @nodes:  start children nodes | 
|  | 3372 | * | 
|  | 3373 | * parse the content of a RelaxNG start node. | 
|  | 3374 | * | 
|  | 3375 | * Returns 0 in case of success, -1 in case of error | 
|  | 3376 | */ | 
|  | 3377 | static int | 
|  | 3378 | xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) { | 
|  | 3379 | int ret = 0; | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 3380 | xmlRelaxNGDefinePtr def = NULL, last; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3381 |  | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3382 | if (nodes == NULL) { | 
|  | 3383 | if (ctxt->error != NULL) | 
|  | 3384 | ctxt->error(ctxt->userData, | 
|  | 3385 | "start has no children\n"); | 
|  | 3386 | ctxt->nbErrors++; | 
|  | 3387 | return(-1); | 
|  | 3388 | } | 
|  | 3389 | if (IS_RELAXNG(nodes, "empty")) { | 
|  | 3390 | def = xmlRelaxNGNewDefine(ctxt, nodes); | 
|  | 3391 | if (def == NULL) | 
|  | 3392 | return(-1); | 
|  | 3393 | def->type = XML_RELAXNG_EMPTY; | 
|  | 3394 | if (nodes->children != NULL) { | 
|  | 3395 | if (ctxt->error != NULL) | 
|  | 3396 | ctxt->error(ctxt->userData, "element empty is not empty\n"); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 3397 | ctxt->nbErrors++; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3398 | } | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3399 | } else if (IS_RELAXNG(nodes, "notAllowed")) { | 
|  | 3400 | def = xmlRelaxNGNewDefine(ctxt, nodes); | 
|  | 3401 | if (def == NULL) | 
|  | 3402 | return(-1); | 
|  | 3403 | def->type = XML_RELAXNG_NOT_ALLOWED; | 
|  | 3404 | if (nodes->children != NULL) { | 
|  | 3405 | if (ctxt->error != NULL) | 
|  | 3406 | ctxt->error(ctxt->userData, | 
|  | 3407 | "element notAllowed is not empty\n"); | 
|  | 3408 | ctxt->nbErrors++; | 
|  | 3409 | } | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3410 | } else { | 
|  | 3411 | def = xmlRelaxNGParsePatterns(ctxt, nodes, 1); | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 3412 | } | 
|  | 3413 | if (ctxt->grammar->start != NULL) { | 
|  | 3414 | last = ctxt->grammar->start; | 
|  | 3415 | while (last->next != NULL) | 
|  | 3416 | last = last->next; | 
|  | 3417 | last->next = def; | 
|  | 3418 | } else { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3419 | ctxt->grammar->start = def; | 
|  | 3420 | } | 
|  | 3421 | nodes = nodes->next; | 
|  | 3422 | if (nodes != NULL) { | 
|  | 3423 | if (ctxt->error != NULL) | 
|  | 3424 | ctxt->error(ctxt->userData, | 
|  | 3425 | "start more than one children\n"); | 
|  | 3426 | ctxt->nbErrors++; | 
|  | 3427 | return(-1); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3428 | } | 
|  | 3429 | return(ret); | 
|  | 3430 | } | 
|  | 3431 |  | 
|  | 3432 | /** | 
|  | 3433 | * xmlRelaxNGParseGrammarContent: | 
|  | 3434 | * @ctxt:  a Relax-NG parser context | 
|  | 3435 | * @nodes:  grammar children nodes | 
|  | 3436 | * | 
|  | 3437 | * parse the content of a RelaxNG grammar node. | 
|  | 3438 | * | 
|  | 3439 | * Returns 0 in case of success, -1 in case of error | 
|  | 3440 | */ | 
|  | 3441 | static int | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 3442 | xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3443 | { | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 3444 | int ret = 0, tmp; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3445 |  | 
|  | 3446 | if (nodes == NULL) { | 
|  | 3447 | if (ctxt->error != NULL) | 
|  | 3448 | ctxt->error(ctxt->userData, | 
|  | 3449 | "grammar has no children\n"); | 
|  | 3450 | ctxt->nbErrors++; | 
|  | 3451 | return(-1); | 
|  | 3452 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3453 | while (nodes != NULL) { | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 3454 | if (IS_RELAXNG(nodes, "start")) { | 
|  | 3455 | if (nodes->children == NULL) { | 
|  | 3456 | if (ctxt->error != NULL) | 
|  | 3457 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 3458 | "start has no children\n"); | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 3459 | ctxt->nbErrors++; | 
|  | 3460 | } else { | 
|  | 3461 | tmp = xmlRelaxNGParseStart(ctxt, nodes->children); | 
|  | 3462 | if (tmp != 0) | 
|  | 3463 | ret = -1; | 
|  | 3464 | } | 
|  | 3465 | } else if (IS_RELAXNG(nodes, "define")) { | 
|  | 3466 | tmp = xmlRelaxNGParseDefine(ctxt, nodes); | 
|  | 3467 | if (tmp != 0) | 
|  | 3468 | ret = -1; | 
|  | 3469 | } else if (IS_RELAXNG(nodes, "include")) { | 
|  | 3470 | tmp = xmlRelaxNGParseInclude(ctxt, nodes); | 
|  | 3471 | if (tmp != 0) | 
|  | 3472 | ret = -1; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3473 | } else { | 
|  | 3474 | if (ctxt->error != NULL) | 
|  | 3475 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 3476 | "grammar has unexpected child %s\n", nodes->name); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3477 | ctxt->nbErrors++; | 
|  | 3478 | ret = -1; | 
|  | 3479 | } | 
|  | 3480 | nodes = nodes->next; | 
|  | 3481 | } | 
|  | 3482 | return (ret); | 
|  | 3483 | } | 
|  | 3484 |  | 
|  | 3485 | /** | 
|  | 3486 | * xmlRelaxNGCheckReference: | 
|  | 3487 | * @ref:  the ref | 
|  | 3488 | * @ctxt:  a Relax-NG parser context | 
|  | 3489 | * @name:  the name associated to the defines | 
|  | 3490 | * | 
|  | 3491 | * Applies the 4.17. combine attribute rule for all the define | 
|  | 3492 | * element of a given grammar using the same name. | 
|  | 3493 | */ | 
|  | 3494 | static void | 
|  | 3495 | xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref, | 
|  | 3496 | xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) { | 
|  | 3497 | xmlRelaxNGGrammarPtr grammar; | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 3498 | xmlRelaxNGDefinePtr def, cur; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3499 |  | 
|  | 3500 | grammar = ctxt->grammar; | 
|  | 3501 | if (grammar == NULL) { | 
|  | 3502 | if (ctxt->error != NULL) | 
|  | 3503 | ctxt->error(ctxt->userData, | 
|  | 3504 | "Internal error: no grammar in CheckReference %s\n", | 
|  | 3505 | name); | 
|  | 3506 | ctxt->nbErrors++; | 
|  | 3507 | return; | 
|  | 3508 | } | 
|  | 3509 | if (ref->content != NULL) { | 
|  | 3510 | if (ctxt->error != NULL) | 
|  | 3511 | ctxt->error(ctxt->userData, | 
|  | 3512 | "Internal error: reference has content in CheckReference %s\n", | 
|  | 3513 | name); | 
|  | 3514 | ctxt->nbErrors++; | 
|  | 3515 | return; | 
|  | 3516 | } | 
|  | 3517 | if (grammar->defs != NULL) { | 
|  | 3518 | def = xmlHashLookup(grammar->defs, name); | 
|  | 3519 | if (def != NULL) { | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 3520 | cur = ref; | 
|  | 3521 | while (cur != NULL) { | 
|  | 3522 | cur->content = def; | 
|  | 3523 | cur = cur->nextHash; | 
|  | 3524 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3525 | } else { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 3526 | if (ctxt->error != NULL) | 
|  | 3527 | ctxt->error(ctxt->userData, | 
|  | 3528 | "Reference %s has no matching definition\n", | 
|  | 3529 | name); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 3530 | ctxt->nbErrors++; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3531 | } | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 3532 | } else { | 
|  | 3533 | if (ctxt->error != NULL) | 
|  | 3534 | ctxt->error(ctxt->userData, | 
|  | 3535 | "Reference %s has no matching definition\n", | 
|  | 3536 | name); | 
|  | 3537 | ctxt->nbErrors++; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3538 | } | 
|  | 3539 | /* | 
|  | 3540 | * TODO: make a closure and verify there is no loop ! | 
|  | 3541 | */ | 
|  | 3542 | } | 
|  | 3543 |  | 
|  | 3544 | /** | 
|  | 3545 | * xmlRelaxNGCheckCombine: | 
|  | 3546 | * @define:  the define(s) list | 
|  | 3547 | * @ctxt:  a Relax-NG parser context | 
|  | 3548 | * @name:  the name associated to the defines | 
|  | 3549 | * | 
|  | 3550 | * Applies the 4.17. combine attribute rule for all the define | 
|  | 3551 | * element of a given grammar using the same name. | 
|  | 3552 | */ | 
|  | 3553 | static void | 
|  | 3554 | xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define, | 
|  | 3555 | xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) { | 
|  | 3556 | xmlChar *combine; | 
|  | 3557 | int choiceOrInterleave = -1; | 
|  | 3558 | int missing = 0; | 
|  | 3559 | xmlRelaxNGDefinePtr cur, last, tmp, tmp2; | 
|  | 3560 |  | 
|  | 3561 | if (define->nextHash == NULL) | 
|  | 3562 | return; | 
|  | 3563 | cur = define; | 
|  | 3564 | while (cur != NULL) { | 
|  | 3565 | combine = xmlGetProp(cur->node, BAD_CAST "combine"); | 
|  | 3566 | if (combine != NULL) { | 
|  | 3567 | if (xmlStrEqual(combine, BAD_CAST "choice")) { | 
|  | 3568 | if (choiceOrInterleave == -1) | 
|  | 3569 | choiceOrInterleave = 1; | 
|  | 3570 | else if (choiceOrInterleave == 0) { | 
|  | 3571 | if (ctxt->error != NULL) | 
|  | 3572 | ctxt->error(ctxt->userData, | 
|  | 3573 | "Defines for %s use both 'choice' and 'interleave'\n", | 
|  | 3574 | name); | 
|  | 3575 | ctxt->nbErrors++; | 
|  | 3576 | } | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 3577 | } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3578 | if (choiceOrInterleave == -1) | 
|  | 3579 | choiceOrInterleave = 0; | 
|  | 3580 | else if (choiceOrInterleave == 1) { | 
|  | 3581 | if (ctxt->error != NULL) | 
|  | 3582 | ctxt->error(ctxt->userData, | 
|  | 3583 | "Defines for %s use both 'choice' and 'interleave'\n", | 
|  | 3584 | name); | 
|  | 3585 | ctxt->nbErrors++; | 
|  | 3586 | } | 
|  | 3587 | } else { | 
|  | 3588 | if (ctxt->error != NULL) | 
|  | 3589 | ctxt->error(ctxt->userData, | 
|  | 3590 | "Defines for %s use unknown combine value '%s''\n", | 
|  | 3591 | name, combine); | 
|  | 3592 | ctxt->nbErrors++; | 
|  | 3593 | } | 
|  | 3594 | xmlFree(combine); | 
|  | 3595 | } else { | 
|  | 3596 | if (missing == 0) | 
|  | 3597 | missing = 1; | 
|  | 3598 | else { | 
|  | 3599 | if (ctxt->error != NULL) | 
|  | 3600 | ctxt->error(ctxt->userData, | 
|  | 3601 | "Some defines for %s lacks the combine attribute\n", | 
|  | 3602 | name); | 
|  | 3603 | ctxt->nbErrors++; | 
|  | 3604 | } | 
|  | 3605 | } | 
|  | 3606 |  | 
|  | 3607 | cur = cur->nextHash; | 
|  | 3608 | } | 
|  | 3609 | #ifdef DEBUG | 
|  | 3610 | xmlGenericError(xmlGenericErrorContext, | 
|  | 3611 | "xmlRelaxNGCheckCombine(): merging %s defines: %d\n", | 
|  | 3612 | name, choiceOrInterleave); | 
|  | 3613 | #endif | 
|  | 3614 | if (choiceOrInterleave == -1) | 
|  | 3615 | choiceOrInterleave = 0; | 
|  | 3616 | cur = xmlRelaxNGNewDefine(ctxt, define->node); | 
|  | 3617 | if (cur == NULL) | 
|  | 3618 | return; | 
|  | 3619 | if (choiceOrInterleave == 0) | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3620 | cur->type = XML_RELAXNG_INTERLEAVE; | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 3621 | else | 
|  | 3622 | cur->type = XML_RELAXNG_CHOICE; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3623 | tmp = define; | 
|  | 3624 | last = NULL; | 
|  | 3625 | while (tmp != NULL) { | 
|  | 3626 | if (tmp->content != NULL) { | 
|  | 3627 | if (tmp->content->next != NULL) { | 
|  | 3628 | /* | 
|  | 3629 | * we need first to create a wrapper. | 
|  | 3630 | */ | 
|  | 3631 | tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node); | 
|  | 3632 | if (tmp2 == NULL) | 
|  | 3633 | break; | 
|  | 3634 | tmp2->type = XML_RELAXNG_GROUP; | 
|  | 3635 | tmp2->content = tmp->content; | 
|  | 3636 | } else { | 
|  | 3637 | tmp2 = tmp->content; | 
|  | 3638 | } | 
|  | 3639 | if (last == NULL) { | 
|  | 3640 | cur->content = tmp2; | 
|  | 3641 | } else { | 
|  | 3642 | last->next = tmp2; | 
|  | 3643 | } | 
|  | 3644 | last = tmp2; | 
|  | 3645 | tmp->content = NULL; | 
|  | 3646 | } | 
|  | 3647 | tmp = tmp->nextHash; | 
|  | 3648 | } | 
|  | 3649 | define->content = cur; | 
| Daniel Veillard | 154877e | 2003-01-30 12:17:05 +0000 | [diff] [blame] | 3650 | if (choiceOrInterleave == 0) { | 
|  | 3651 | if (ctxt->interleaves == NULL) | 
|  | 3652 | ctxt->interleaves = xmlHashCreate(10); | 
|  | 3653 | if (ctxt->interleaves == NULL) { | 
|  | 3654 | if (ctxt->error != NULL) | 
|  | 3655 | ctxt->error(ctxt->userData, | 
|  | 3656 | "Failed to create interleaves hash table\n"); | 
|  | 3657 | ctxt->nbErrors++; | 
|  | 3658 | } else { | 
|  | 3659 | char tmpname[32]; | 
|  | 3660 |  | 
|  | 3661 | snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); | 
|  | 3662 | if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) { | 
|  | 3663 | if (ctxt->error != NULL) | 
|  | 3664 | ctxt->error(ctxt->userData, | 
|  | 3665 | "Failed to add %s to hash table\n", tmpname); | 
|  | 3666 | ctxt->nbErrors++; | 
|  | 3667 | } | 
|  | 3668 | } | 
|  | 3669 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3670 | } | 
|  | 3671 |  | 
|  | 3672 | /** | 
|  | 3673 | * xmlRelaxNGCombineStart: | 
|  | 3674 | * @ctxt:  a Relax-NG parser context | 
|  | 3675 | * @grammar:  the grammar | 
|  | 3676 | * | 
|  | 3677 | * Applies the 4.17. combine rule for all the start | 
|  | 3678 | * element of a given grammar. | 
|  | 3679 | */ | 
|  | 3680 | static void | 
|  | 3681 | xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 3682 | xmlRelaxNGGrammarPtr grammar) { | 
|  | 3683 | xmlRelaxNGDefinePtr starts; | 
|  | 3684 | xmlChar *combine; | 
|  | 3685 | int choiceOrInterleave = -1; | 
|  | 3686 | int missing = 0; | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 3687 | xmlRelaxNGDefinePtr cur; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3688 |  | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 3689 | starts = grammar->start; | 
|  | 3690 | if ((starts == NULL) || (starts->next == NULL)) | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3691 | return; | 
|  | 3692 | cur = starts; | 
|  | 3693 | while (cur != NULL) { | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 3694 | if ((cur->node == NULL) || (cur->node->parent == NULL) || | 
|  | 3695 | (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) { | 
|  | 3696 | combine = NULL; | 
|  | 3697 | if (ctxt->error != NULL) | 
|  | 3698 | ctxt->error(ctxt->userData, | 
|  | 3699 | "Internal error: start element not found\n"); | 
|  | 3700 | ctxt->nbErrors++; | 
|  | 3701 | } else { | 
|  | 3702 | combine = xmlGetProp(cur->node->parent, BAD_CAST "combine"); | 
|  | 3703 | } | 
|  | 3704 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3705 | if (combine != NULL) { | 
|  | 3706 | if (xmlStrEqual(combine, BAD_CAST "choice")) { | 
|  | 3707 | if (choiceOrInterleave == -1) | 
|  | 3708 | choiceOrInterleave = 1; | 
|  | 3709 | else if (choiceOrInterleave == 0) { | 
|  | 3710 | if (ctxt->error != NULL) | 
|  | 3711 | ctxt->error(ctxt->userData, | 
|  | 3712 | "<start> use both 'choice' and 'interleave'\n"); | 
|  | 3713 | ctxt->nbErrors++; | 
|  | 3714 | } | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 3715 | } else if (xmlStrEqual(combine, BAD_CAST "interleave")) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3716 | if (choiceOrInterleave == -1) | 
|  | 3717 | choiceOrInterleave = 0; | 
|  | 3718 | else if (choiceOrInterleave == 1) { | 
|  | 3719 | if (ctxt->error != NULL) | 
|  | 3720 | ctxt->error(ctxt->userData, | 
|  | 3721 | "<start> use both 'choice' and 'interleave'\n"); | 
|  | 3722 | ctxt->nbErrors++; | 
|  | 3723 | } | 
|  | 3724 | } else { | 
|  | 3725 | if (ctxt->error != NULL) | 
|  | 3726 | ctxt->error(ctxt->userData, | 
|  | 3727 | "<start> uses unknown combine value '%s''\n", combine); | 
|  | 3728 | ctxt->nbErrors++; | 
|  | 3729 | } | 
|  | 3730 | xmlFree(combine); | 
|  | 3731 | } else { | 
|  | 3732 | if (missing == 0) | 
|  | 3733 | missing = 1; | 
|  | 3734 | else { | 
|  | 3735 | if (ctxt->error != NULL) | 
|  | 3736 | ctxt->error(ctxt->userData, | 
|  | 3737 | "Some <start> elements lacks the combine attribute\n"); | 
|  | 3738 | ctxt->nbErrors++; | 
|  | 3739 | } | 
|  | 3740 | } | 
|  | 3741 |  | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 3742 | cur = cur->next; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3743 | } | 
|  | 3744 | #ifdef DEBUG | 
|  | 3745 | xmlGenericError(xmlGenericErrorContext, | 
|  | 3746 | "xmlRelaxNGCombineStart(): merging <start>: %d\n", | 
|  | 3747 | choiceOrInterleave); | 
|  | 3748 | #endif | 
|  | 3749 | if (choiceOrInterleave == -1) | 
|  | 3750 | choiceOrInterleave = 0; | 
|  | 3751 | cur = xmlRelaxNGNewDefine(ctxt, starts->node); | 
|  | 3752 | if (cur == NULL) | 
|  | 3753 | return; | 
|  | 3754 | if (choiceOrInterleave == 0) | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3755 | cur->type = XML_RELAXNG_INTERLEAVE; | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 3756 | else | 
|  | 3757 | cur->type = XML_RELAXNG_CHOICE; | 
|  | 3758 | cur->content = grammar->start; | 
|  | 3759 | grammar->start = cur; | 
|  | 3760 | if (choiceOrInterleave == 0) { | 
|  | 3761 | if (ctxt->interleaves == NULL) | 
|  | 3762 | ctxt->interleaves = xmlHashCreate(10); | 
|  | 3763 | if (ctxt->interleaves == NULL) { | 
|  | 3764 | if (ctxt->error != NULL) | 
|  | 3765 | ctxt->error(ctxt->userData, | 
|  | 3766 | "Failed to create interleaves hash table\n"); | 
|  | 3767 | ctxt->nbErrors++; | 
|  | 3768 | } else { | 
|  | 3769 | char tmpname[32]; | 
|  | 3770 |  | 
|  | 3771 | snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++); | 
|  | 3772 | if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) { | 
|  | 3773 | if (ctxt->error != NULL) | 
|  | 3774 | ctxt->error(ctxt->userData, | 
|  | 3775 | "Failed to add %s to hash table\n", tmpname); | 
|  | 3776 | ctxt->nbErrors++; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3777 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3778 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3779 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 3780 | } | 
|  | 3781 |  | 
|  | 3782 | /** | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 3783 | * xmlRelaxNGCheckCycles: | 
|  | 3784 | * @ctxt:  a Relax-NG parser context | 
|  | 3785 | * @nodes:  grammar children nodes | 
|  | 3786 | * @depth:  the counter | 
|  | 3787 | * | 
|  | 3788 | * Check for cycles. | 
|  | 3789 | * | 
|  | 3790 | * Returns 0 if check passed, and -1 in case of error | 
|  | 3791 | */ | 
|  | 3792 | static int | 
|  | 3793 | xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 3794 | xmlRelaxNGDefinePtr cur, int depth) { | 
|  | 3795 | int ret = 0; | 
|  | 3796 |  | 
|  | 3797 | while ((ret == 0) && (cur != NULL)) { | 
|  | 3798 | if ((cur->type == XML_RELAXNG_REF) || | 
|  | 3799 | (cur->type == XML_RELAXNG_PARENTREF)) { | 
|  | 3800 | if (cur->depth == -1) { | 
|  | 3801 | cur->depth = depth; | 
|  | 3802 | ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); | 
|  | 3803 | cur->depth = -2; | 
|  | 3804 | } else if (depth == cur->depth) { | 
|  | 3805 | if (ctxt->error != NULL) | 
|  | 3806 | ctxt->error(ctxt->userData, | 
|  | 3807 | "Detected a cycle in %s references\n", cur->name); | 
|  | 3808 | ctxt->nbErrors++; | 
|  | 3809 | return(-1); | 
|  | 3810 | } | 
|  | 3811 | } else if (cur->type == XML_RELAXNG_ELEMENT) { | 
|  | 3812 | ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1); | 
|  | 3813 | } else { | 
|  | 3814 | ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth); | 
|  | 3815 | } | 
|  | 3816 | cur = cur->next; | 
|  | 3817 | } | 
|  | 3818 | return(ret); | 
|  | 3819 | } | 
|  | 3820 |  | 
|  | 3821 | /** | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3822 | * xmlRelaxNGTryUnlink: | 
|  | 3823 | * @ctxt:  a Relax-NG parser context | 
|  | 3824 | * @cur:  the definition to unlink | 
|  | 3825 | * @parent:  the parent definition | 
|  | 3826 | * @prev:  the previous sibling definition | 
|  | 3827 | * | 
|  | 3828 | * Try to unlink a definition. If not possble make it a NOOP | 
|  | 3829 | * | 
|  | 3830 | * Returns the new prev definition | 
|  | 3831 | */ | 
|  | 3832 | static xmlRelaxNGDefinePtr | 
|  | 3833 | xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
|  | 3834 | xmlRelaxNGDefinePtr cur, | 
|  | 3835 | xmlRelaxNGDefinePtr parent, | 
|  | 3836 | xmlRelaxNGDefinePtr prev) { | 
|  | 3837 | if (prev != NULL) { | 
|  | 3838 | prev->next = cur->next; | 
|  | 3839 | } else { | 
|  | 3840 | if (parent != NULL) { | 
|  | 3841 | if (parent->content == cur) | 
|  | 3842 | parent->content = cur->next; | 
|  | 3843 | else if (parent->attrs == cur) | 
|  | 3844 | parent->attrs = cur->next; | 
|  | 3845 | else if (parent->nameClass == cur) | 
|  | 3846 | parent->nameClass = cur->next; | 
|  | 3847 | } else { | 
|  | 3848 | cur->type = XML_RELAXNG_NOOP; | 
|  | 3849 | prev = cur; | 
|  | 3850 | } | 
|  | 3851 | } | 
|  | 3852 | return(prev); | 
|  | 3853 | } | 
|  | 3854 |  | 
|  | 3855 | /** | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 3856 | * xmlRelaxNGSimplify: | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3857 | * @ctxt:  a Relax-NG parser context | 
|  | 3858 | * @nodes:  grammar children nodes | 
|  | 3859 | * | 
|  | 3860 | * Check for simplification of empty and notAllowed | 
|  | 3861 | */ | 
|  | 3862 | static void | 
|  | 3863 | xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 3864 | xmlRelaxNGDefinePtr cur, | 
|  | 3865 | xmlRelaxNGDefinePtr parent) { | 
|  | 3866 | xmlRelaxNGDefinePtr prev = NULL; | 
|  | 3867 |  | 
|  | 3868 | while (cur != NULL) { | 
|  | 3869 | if ((cur->type == XML_RELAXNG_REF) || | 
|  | 3870 | (cur->type == XML_RELAXNG_PARENTREF)) { | 
|  | 3871 | if (cur->depth != -3) { | 
|  | 3872 | cur->depth = -3; | 
|  | 3873 | xmlRelaxNGSimplify(ctxt, cur->content, cur); | 
|  | 3874 | } | 
|  | 3875 | } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3876 | cur->parent = parent; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3877 | if ((parent != NULL) && | 
|  | 3878 | ((parent->type == XML_RELAXNG_ATTRIBUTE) || | 
|  | 3879 | (parent->type == XML_RELAXNG_LIST) || | 
|  | 3880 | (parent->type == XML_RELAXNG_GROUP) || | 
|  | 3881 | (parent->type == XML_RELAXNG_INTERLEAVE) || | 
|  | 3882 | (parent->type == XML_RELAXNG_ONEORMORE) || | 
|  | 3883 | (parent->type == XML_RELAXNG_ZEROORMORE))) { | 
|  | 3884 | parent->type = XML_RELAXNG_NOT_ALLOWED; | 
|  | 3885 | break; | 
|  | 3886 | } | 
|  | 3887 | if ((parent != NULL) && | 
|  | 3888 | (parent->type == XML_RELAXNG_CHOICE)) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3889 | prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3890 | } else | 
|  | 3891 | prev = cur; | 
|  | 3892 | } else if (cur->type == XML_RELAXNG_EMPTY){ | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3893 | cur->parent = parent; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3894 | if ((parent != NULL) && | 
|  | 3895 | ((parent->type == XML_RELAXNG_ONEORMORE) || | 
|  | 3896 | (parent->type == XML_RELAXNG_ZEROORMORE))) { | 
|  | 3897 | parent->type = XML_RELAXNG_EMPTY; | 
|  | 3898 | break; | 
|  | 3899 | } | 
|  | 3900 | if ((parent != NULL) && | 
|  | 3901 | ((parent->type == XML_RELAXNG_GROUP) || | 
|  | 3902 | (parent->type == XML_RELAXNG_INTERLEAVE))) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3903 | prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3904 | } else | 
|  | 3905 | prev = cur; | 
|  | 3906 | } else { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3907 | cur->parent = parent; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3908 | if (cur->content != NULL) | 
|  | 3909 | xmlRelaxNGSimplify(ctxt, cur->content, cur); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3910 | if (cur->attrs != NULL) | 
|  | 3911 | xmlRelaxNGSimplify(ctxt, cur->attrs, cur); | 
|  | 3912 | if (cur->nameClass != NULL) | 
|  | 3913 | xmlRelaxNGSimplify(ctxt, cur->nameClass, cur); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3914 | /* | 
|  | 3915 | * This may result in a simplification | 
|  | 3916 | */ | 
|  | 3917 | if ((cur->type == XML_RELAXNG_GROUP) || | 
|  | 3918 | (cur->type == XML_RELAXNG_INTERLEAVE)) { | 
|  | 3919 | if (cur->content == NULL) | 
|  | 3920 | cur->type = XML_RELAXNG_EMPTY; | 
|  | 3921 | else if (cur->content->next == NULL) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3922 | if ((parent == NULL) && (prev == NULL)) { | 
|  | 3923 | cur->type = XML_RELAXNG_NOOP; | 
|  | 3924 | } else if (prev == NULL) { | 
|  | 3925 | parent->content = cur->content; | 
|  | 3926 | cur->content->next = cur->next; | 
|  | 3927 | cur = cur->content; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3928 | } else { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3929 | cur->content->next = cur->next; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3930 | prev->next = cur->content; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3931 | cur = cur->content; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3932 | } | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3933 | } | 
|  | 3934 | } | 
|  | 3935 | /* | 
|  | 3936 | * the current node may have been transformed back | 
|  | 3937 | */ | 
|  | 3938 | if ((cur->type == XML_RELAXNG_EXCEPT) && | 
|  | 3939 | (cur->content != NULL) && | 
|  | 3940 | (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3941 | prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3942 | } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) { | 
|  | 3943 | if ((parent != NULL) && | 
|  | 3944 | ((parent->type == XML_RELAXNG_ATTRIBUTE) || | 
|  | 3945 | (parent->type == XML_RELAXNG_LIST) || | 
|  | 3946 | (parent->type == XML_RELAXNG_GROUP) || | 
|  | 3947 | (parent->type == XML_RELAXNG_INTERLEAVE) || | 
|  | 3948 | (parent->type == XML_RELAXNG_ONEORMORE) || | 
|  | 3949 | (parent->type == XML_RELAXNG_ZEROORMORE))) { | 
|  | 3950 | parent->type = XML_RELAXNG_NOT_ALLOWED; | 
|  | 3951 | break; | 
|  | 3952 | } | 
|  | 3953 | if ((parent != NULL) && | 
|  | 3954 | (parent->type == XML_RELAXNG_CHOICE)) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3955 | prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3956 | } else | 
|  | 3957 | prev = cur; | 
|  | 3958 | } else if (cur->type == XML_RELAXNG_EMPTY){ | 
|  | 3959 | if ((parent != NULL) && | 
|  | 3960 | ((parent->type == XML_RELAXNG_ONEORMORE) || | 
|  | 3961 | (parent->type == XML_RELAXNG_ZEROORMORE))) { | 
|  | 3962 | parent->type = XML_RELAXNG_EMPTY; | 
|  | 3963 | break; | 
|  | 3964 | } | 
|  | 3965 | if ((parent != NULL) && | 
|  | 3966 | ((parent->type == XML_RELAXNG_GROUP) || | 
|  | 3967 | (parent->type == XML_RELAXNG_INTERLEAVE) || | 
|  | 3968 | (parent->type == XML_RELAXNG_CHOICE))) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 3969 | prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 3970 | } else | 
|  | 3971 | prev = cur; | 
|  | 3972 | } else { | 
|  | 3973 | prev = cur; | 
|  | 3974 | } | 
|  | 3975 | } | 
|  | 3976 | cur = cur->next; | 
|  | 3977 | } | 
|  | 3978 | } | 
|  | 3979 |  | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 3980 | /** | 
|  | 3981 | * xmlRelaxNGGroupContentType: | 
|  | 3982 | * @ct1:  the first content type | 
|  | 3983 | * @ct2:  the second content type | 
|  | 3984 | * | 
|  | 3985 | * Try to group 2 content types | 
|  | 3986 | * | 
|  | 3987 | * Returns the content type | 
|  | 3988 | */ | 
|  | 3989 | static xmlRelaxNGContentType | 
|  | 3990 | xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1, | 
|  | 3991 | xmlRelaxNGContentType ct2) { | 
|  | 3992 | if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || | 
|  | 3993 | (ct2 == XML_RELAXNG_CONTENT_ERROR)) | 
|  | 3994 | return(XML_RELAXNG_CONTENT_ERROR); | 
|  | 3995 | if (ct1 == XML_RELAXNG_CONTENT_EMPTY) | 
|  | 3996 | return(ct2); | 
|  | 3997 | if (ct2 == XML_RELAXNG_CONTENT_EMPTY) | 
|  | 3998 | return(ct1); | 
|  | 3999 | if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) && | 
|  | 4000 | (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) | 
|  | 4001 | return(XML_RELAXNG_CONTENT_COMPLEX); | 
|  | 4002 | return(XML_RELAXNG_CONTENT_ERROR); | 
|  | 4003 | } | 
|  | 4004 |  | 
|  | 4005 | /** | 
|  | 4006 | * xmlRelaxNGMaxContentType: | 
|  | 4007 | * @ct1:  the first content type | 
|  | 4008 | * @ct2:  the second content type | 
|  | 4009 | * | 
|  | 4010 | * Compute the max content-type | 
|  | 4011 | * | 
|  | 4012 | * Returns the content type | 
|  | 4013 | */ | 
|  | 4014 | static xmlRelaxNGContentType | 
|  | 4015 | xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1, | 
|  | 4016 | xmlRelaxNGContentType ct2) { | 
|  | 4017 | if ((ct1 == XML_RELAXNG_CONTENT_ERROR) || | 
|  | 4018 | (ct2 == XML_RELAXNG_CONTENT_ERROR)) | 
|  | 4019 | return(XML_RELAXNG_CONTENT_ERROR); | 
|  | 4020 | if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) || | 
|  | 4021 | (ct2 == XML_RELAXNG_CONTENT_SIMPLE)) | 
|  | 4022 | return(XML_RELAXNG_CONTENT_SIMPLE); | 
|  | 4023 | if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) || | 
|  | 4024 | (ct2 == XML_RELAXNG_CONTENT_COMPLEX)) | 
|  | 4025 | return(XML_RELAXNG_CONTENT_COMPLEX); | 
|  | 4026 | return(XML_RELAXNG_CONTENT_EMPTY); | 
|  | 4027 | } | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4028 |  | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4029 | /** | 
|  | 4030 | * xmlRelaxNGCheckRules: | 
|  | 4031 | * @ctxt:  a Relax-NG parser context | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4032 | * @cur:  the current definition | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4033 | * @flags:  some accumulated flags | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4034 | * @ptype:  the parent type | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4035 | * | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4036 | * Check for rules in section 7.1 and 7.2 | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4037 | * | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4038 | * Returns the content type of @cur | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4039 | */ | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4040 | static xmlRelaxNGContentType | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4041 | xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt, | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4042 | xmlRelaxNGDefinePtr cur, int flags, | 
|  | 4043 | xmlRelaxNGType ptype) { | 
|  | 4044 | int nflags = flags; | 
|  | 4045 | xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4046 |  | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4047 | while (cur != NULL) { | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4048 | ret = XML_RELAXNG_CONTENT_EMPTY; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4049 | if ((cur->type == XML_RELAXNG_REF) || | 
|  | 4050 | (cur->type == XML_RELAXNG_PARENTREF)) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4051 | if (flags & XML_RELAXNG_IN_LIST) { | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4052 | if (ctxt->error != NULL) | 
|  | 4053 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4054 | "Found forbidden pattern list//ref\n"); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4055 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4056 | } | 
|  | 4057 | if (flags & XML_RELAXNG_IN_ATTRIBUTE) { | 
|  | 4058 | if (ctxt->error != NULL) | 
|  | 4059 | ctxt->error(ctxt->userData, | 
|  | 4060 | "Found forbidden pattern attribute//ref\n"); | 
|  | 4061 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4062 | } | 
|  | 4063 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4064 | if (ctxt->error != NULL) | 
|  | 4065 | ctxt->error(ctxt->userData, | 
|  | 4066 | "Found forbidden pattern data/except//ref\n"); | 
|  | 4067 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4068 | } | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 4069 | if (cur->depth > -4) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4070 | cur->depth = -4; | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 4071 | ret = xmlRelaxNGCheckRules(ctxt, cur->content, | 
|  | 4072 | flags, cur->type); | 
|  | 4073 | cur->depth = ret - 15 ; | 
|  | 4074 | } else if (cur->depth == -4) { | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4075 | ret = XML_RELAXNG_CONTENT_COMPLEX; | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 4076 | } else { | 
|  | 4077 | ret = (xmlRelaxNGContentType) cur->depth + 15; | 
|  | 4078 | } | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4079 | } else if (cur->type == XML_RELAXNG_ELEMENT) { | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4080 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4081 | if (ctxt->error != NULL) | 
|  | 4082 | ctxt->error(ctxt->userData, | 
|  | 4083 | "Found forbidden pattern data/except//element(ref)\n"); | 
|  | 4084 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4085 | } | 
|  | 4086 | if (flags & XML_RELAXNG_IN_LIST) { | 
|  | 4087 | if (ctxt->error != NULL) | 
|  | 4088 | ctxt->error(ctxt->userData, | 
|  | 4089 | "Found forbidden pattern list//element(ref)\n"); | 
|  | 4090 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4091 | } | 
|  | 4092 | if (flags & XML_RELAXNG_IN_ATTRIBUTE) { | 
|  | 4093 | if (ctxt->error != NULL) | 
|  | 4094 | ctxt->error(ctxt->userData, | 
|  | 4095 | "Found forbidden pattern attribute//element(ref)\n"); | 
|  | 4096 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4097 | } | 
|  | 4098 | /* | 
|  | 4099 | * reset since in the simple form elements are only child | 
|  | 4100 | * of grammar/define | 
|  | 4101 | */ | 
|  | 4102 | nflags = 0; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4103 | ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type); | 
|  | 4104 | if (ret != XML_RELAXNG_CONTENT_EMPTY) { | 
|  | 4105 | if (ctxt->error != NULL) | 
|  | 4106 | ctxt->error(ctxt->userData, | 
|  | 4107 | "Element %s attributes have a content type error\n", | 
|  | 4108 | cur->name); | 
|  | 4109 | ctxt->nbErrors++; | 
|  | 4110 | } | 
|  | 4111 | ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); | 
|  | 4112 | if (ret == XML_RELAXNG_CONTENT_ERROR) { | 
|  | 4113 | if (ctxt->error != NULL) | 
|  | 4114 | ctxt->error(ctxt->userData, | 
|  | 4115 | "Element %s has a content type error\n", | 
|  | 4116 | cur->name); | 
|  | 4117 | ctxt->nbErrors++; | 
|  | 4118 | } else { | 
|  | 4119 | ret = XML_RELAXNG_CONTENT_COMPLEX; | 
|  | 4120 | } | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4121 | } else if (cur->type == XML_RELAXNG_ATTRIBUTE) { | 
|  | 4122 | if (flags & XML_RELAXNG_IN_ATTRIBUTE) { | 
|  | 4123 | if (ctxt->error != NULL) | 
|  | 4124 | ctxt->error(ctxt->userData, | 
|  | 4125 | "Found forbidden pattern attribute//attribute\n"); | 
|  | 4126 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4127 | } | 
|  | 4128 | if (flags & XML_RELAXNG_IN_LIST) { | 
|  | 4129 | if (ctxt->error != NULL) | 
|  | 4130 | ctxt->error(ctxt->userData, | 
|  | 4131 | "Found forbidden pattern list//attribute\n"); | 
|  | 4132 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4133 | } | 
|  | 4134 | if (flags & XML_RELAXNG_IN_OOMGROUP) { | 
|  | 4135 | if (ctxt->error != NULL) | 
|  | 4136 | ctxt->error(ctxt->userData, | 
|  | 4137 | "Found forbidden pattern oneOrMore//group//attribute\n"); | 
|  | 4138 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4139 | } | 
|  | 4140 | if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) { | 
|  | 4141 | if (ctxt->error != NULL) | 
|  | 4142 | ctxt->error(ctxt->userData, | 
|  | 4143 | "Found forbidden pattern oneOrMore//interleave//attribute\n"); | 
|  | 4144 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4145 | } | 
|  | 4146 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4147 | if (ctxt->error != NULL) | 
|  | 4148 | ctxt->error(ctxt->userData, | 
|  | 4149 | "Found forbidden pattern data/except//attribute\n"); | 
|  | 4150 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4151 | } | 
|  | 4152 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4153 | if (ctxt->error != NULL) | 
|  | 4154 | ctxt->error(ctxt->userData, | 
|  | 4155 | "Found forbidden pattern start//attribute\n"); | 
|  | 4156 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4157 | } | 
|  | 4158 | nflags = flags | XML_RELAXNG_IN_ATTRIBUTE; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4159 | xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); | 
|  | 4160 | ret = XML_RELAXNG_CONTENT_EMPTY; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4161 | } else if ((cur->type == XML_RELAXNG_ONEORMORE) || | 
|  | 4162 | (cur->type == XML_RELAXNG_ZEROORMORE)) { | 
|  | 4163 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4164 | if (ctxt->error != NULL) | 
|  | 4165 | ctxt->error(ctxt->userData, | 
|  | 4166 | "Found forbidden pattern data/except//oneOrMore\n"); | 
|  | 4167 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4168 | } | 
|  | 4169 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4170 | if (ctxt->error != NULL) | 
|  | 4171 | ctxt->error(ctxt->userData, | 
|  | 4172 | "Found forbidden pattern start//oneOrMore\n"); | 
|  | 4173 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4174 | } | 
|  | 4175 | nflags = flags | XML_RELAXNG_IN_ONEORMORE; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4176 | ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); | 
|  | 4177 | ret = xmlRelaxNGGroupContentType(ret, ret); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4178 | } else if (cur->type == XML_RELAXNG_LIST) { | 
|  | 4179 | if (flags & XML_RELAXNG_IN_LIST) { | 
|  | 4180 | if (ctxt->error != NULL) | 
|  | 4181 | ctxt->error(ctxt->userData, | 
|  | 4182 | "Found forbidden pattern list//list\n"); | 
|  | 4183 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4184 | } | 
|  | 4185 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4186 | if (ctxt->error != NULL) | 
|  | 4187 | ctxt->error(ctxt->userData, | 
|  | 4188 | "Found forbidden pattern data/except//list\n"); | 
|  | 4189 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4190 | } | 
|  | 4191 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4192 | if (ctxt->error != NULL) | 
|  | 4193 | ctxt->error(ctxt->userData, | 
|  | 4194 | "Found forbidden pattern start//list\n"); | 
|  | 4195 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4196 | } | 
|  | 4197 | nflags = flags | XML_RELAXNG_IN_LIST; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4198 | ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4199 | } else if (cur->type == XML_RELAXNG_GROUP) { | 
|  | 4200 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4201 | if (ctxt->error != NULL) | 
|  | 4202 | ctxt->error(ctxt->userData, | 
|  | 4203 | "Found forbidden pattern data/except//group\n"); | 
|  | 4204 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4205 | } | 
|  | 4206 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4207 | if (ctxt->error != NULL) | 
|  | 4208 | ctxt->error(ctxt->userData, | 
|  | 4209 | "Found forbidden pattern start//group\n"); | 
|  | 4210 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4211 | } | 
|  | 4212 | if (flags & XML_RELAXNG_IN_ONEORMORE) | 
|  | 4213 | nflags = flags | XML_RELAXNG_IN_OOMGROUP; | 
|  | 4214 | else | 
|  | 4215 | nflags = flags; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4216 | ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4217 | } else if (cur->type == XML_RELAXNG_INTERLEAVE) { | 
|  | 4218 | if (flags & XML_RELAXNG_IN_LIST) { | 
|  | 4219 | if (ctxt->error != NULL) | 
|  | 4220 | ctxt->error(ctxt->userData, | 
|  | 4221 | "Found forbidden pattern list//interleave\n"); | 
|  | 4222 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4223 | } | 
|  | 4224 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4225 | if (ctxt->error != NULL) | 
|  | 4226 | ctxt->error(ctxt->userData, | 
|  | 4227 | "Found forbidden pattern data/except//interleave\n"); | 
|  | 4228 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4229 | } | 
|  | 4230 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4231 | if (ctxt->error != NULL) | 
|  | 4232 | ctxt->error(ctxt->userData, | 
|  | 4233 | "Found forbidden pattern start//interleave\n"); | 
|  | 4234 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4235 | } | 
|  | 4236 | if (flags & XML_RELAXNG_IN_ONEORMORE) | 
|  | 4237 | nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE; | 
|  | 4238 | else | 
|  | 4239 | nflags = flags; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4240 | ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4241 | } else if (cur->type == XML_RELAXNG_EXCEPT) { | 
|  | 4242 | if ((cur->parent != NULL) && | 
|  | 4243 | (cur->parent->type == XML_RELAXNG_DATATYPE)) | 
|  | 4244 | nflags = flags | XML_RELAXNG_IN_DATAEXCEPT; | 
|  | 4245 | else | 
|  | 4246 | nflags = flags; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4247 | ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4248 | } else if (cur->type == XML_RELAXNG_DATATYPE) { | 
|  | 4249 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4250 | if (ctxt->error != NULL) | 
|  | 4251 | ctxt->error(ctxt->userData, | 
|  | 4252 | "Found forbidden pattern start//data\n"); | 
|  | 4253 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4254 | } | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4255 | xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); | 
|  | 4256 | ret = XML_RELAXNG_CONTENT_SIMPLE; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4257 | } else if (cur->type == XML_RELAXNG_VALUE) { | 
|  | 4258 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4259 | if (ctxt->error != NULL) | 
|  | 4260 | ctxt->error(ctxt->userData, | 
|  | 4261 | "Found forbidden pattern start//value\n"); | 
|  | 4262 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4263 | } | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4264 | xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); | 
|  | 4265 | ret = XML_RELAXNG_CONTENT_SIMPLE; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4266 | } else if (cur->type == XML_RELAXNG_TEXT) { | 
|  | 4267 | if (flags & XML_RELAXNG_IN_LIST) { | 
|  | 4268 | if (ctxt->error != NULL) | 
|  | 4269 | ctxt->error(ctxt->userData, | 
|  | 4270 | "Found forbidden pattern list//text\n"); | 
|  | 4271 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4272 | } | 
|  | 4273 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4274 | if (ctxt->error != NULL) | 
|  | 4275 | ctxt->error(ctxt->userData, | 
|  | 4276 | "Found forbidden pattern data/except//text\n"); | 
|  | 4277 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4278 | } | 
|  | 4279 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4280 | if (ctxt->error != NULL) | 
|  | 4281 | ctxt->error(ctxt->userData, | 
|  | 4282 | "Found forbidden pattern start//text\n"); | 
|  | 4283 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4284 | } | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4285 | ret = XML_RELAXNG_CONTENT_COMPLEX; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4286 | } else if (cur->type == XML_RELAXNG_EMPTY) { | 
|  | 4287 | if (flags & XML_RELAXNG_IN_DATAEXCEPT) { | 
|  | 4288 | if (ctxt->error != NULL) | 
|  | 4289 | ctxt->error(ctxt->userData, | 
|  | 4290 | "Found forbidden pattern data/except//empty\n"); | 
|  | 4291 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4292 | } | 
|  | 4293 | if (flags & XML_RELAXNG_IN_START) { | 
|  | 4294 | if (ctxt->error != NULL) | 
|  | 4295 | ctxt->error(ctxt->userData, | 
|  | 4296 | "Found forbidden pattern start//empty\n"); | 
|  | 4297 | ctxt->nbErrors++; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4298 | } | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4299 | ret = XML_RELAXNG_CONTENT_EMPTY; | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4300 | } else { | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4301 | ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4302 | } | 
|  | 4303 | cur = cur->next; | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4304 | if (ptype == XML_RELAXNG_GROUP) { | 
|  | 4305 | val = xmlRelaxNGGroupContentType(val, ret); | 
|  | 4306 | } else if (ptype == XML_RELAXNG_INTERLEAVE) { | 
|  | 4307 | tmp = xmlRelaxNGGroupContentType(val, ret); | 
|  | 4308 | if (tmp != XML_RELAXNG_CONTENT_ERROR) | 
|  | 4309 | tmp = xmlRelaxNGMaxContentType(val, ret); | 
|  | 4310 | } else if (ptype == XML_RELAXNG_CHOICE) { | 
|  | 4311 | val = xmlRelaxNGMaxContentType(val, ret); | 
|  | 4312 | } else if (ptype == XML_RELAXNG_LIST) { | 
|  | 4313 | val = XML_RELAXNG_CONTENT_SIMPLE; | 
|  | 4314 | } else if (ptype == XML_RELAXNG_EXCEPT) { | 
|  | 4315 | if (ret == XML_RELAXNG_CONTENT_ERROR) | 
|  | 4316 | val = XML_RELAXNG_CONTENT_ERROR; | 
|  | 4317 | else | 
|  | 4318 | val = XML_RELAXNG_CONTENT_SIMPLE; | 
|  | 4319 | } else { | 
|  | 4320 | val = xmlRelaxNGGroupContentType(val, ret); | 
|  | 4321 | } | 
|  | 4322 |  | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4323 | } | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4324 | return(val); | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4325 | } | 
| Daniel Veillard | 1c745ad | 2003-02-20 00:11:02 +0000 | [diff] [blame] | 4326 |  | 
|  | 4327 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4328 | * xmlRelaxNGParseGrammar: | 
|  | 4329 | * @ctxt:  a Relax-NG parser context | 
|  | 4330 | * @nodes:  grammar children nodes | 
|  | 4331 | * | 
|  | 4332 | * parse a Relax-NG <grammar> node | 
|  | 4333 | * | 
|  | 4334 | * Returns the internal xmlRelaxNGGrammarPtr built or | 
|  | 4335 | *         NULL in case of error | 
|  | 4336 | */ | 
|  | 4337 | static xmlRelaxNGGrammarPtr | 
|  | 4338 | xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) { | 
|  | 4339 | xmlRelaxNGGrammarPtr ret, tmp, old; | 
|  | 4340 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4341 | ret = xmlRelaxNGNewGrammar(ctxt); | 
|  | 4342 | if (ret == NULL) | 
|  | 4343 | return(NULL); | 
|  | 4344 |  | 
|  | 4345 | /* | 
|  | 4346 | * Link the new grammar in the tree | 
|  | 4347 | */ | 
|  | 4348 | ret->parent = ctxt->grammar; | 
|  | 4349 | if (ctxt->grammar != NULL) { | 
|  | 4350 | tmp = ctxt->grammar->children; | 
|  | 4351 | if (tmp == NULL) { | 
|  | 4352 | ctxt->grammar->children = ret; | 
|  | 4353 | } else { | 
|  | 4354 | while (tmp->next != NULL) | 
|  | 4355 | tmp = tmp->next; | 
|  | 4356 | tmp->next = ret; | 
|  | 4357 | } | 
|  | 4358 | } | 
|  | 4359 |  | 
|  | 4360 | old = ctxt->grammar; | 
|  | 4361 | ctxt->grammar = ret; | 
|  | 4362 | xmlRelaxNGParseGrammarContent(ctxt, nodes); | 
|  | 4363 | ctxt->grammar = ret; | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 4364 | if (ctxt->grammar == NULL) { | 
|  | 4365 | if (ctxt->error != NULL) | 
|  | 4366 | ctxt->error(ctxt->userData, | 
|  | 4367 | "Failed to parse <grammar> content\n"); | 
|  | 4368 | ctxt->nbErrors++; | 
|  | 4369 | } else if (ctxt->grammar->start == NULL) { | 
|  | 4370 | if (ctxt->error != NULL) | 
|  | 4371 | ctxt->error(ctxt->userData, | 
|  | 4372 | "Element <grammar> has no <start>\n"); | 
|  | 4373 | ctxt->nbErrors++; | 
|  | 4374 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4375 |  | 
|  | 4376 | /* | 
|  | 4377 | * Apply 4.17 mergingd rules to defines and starts | 
|  | 4378 | */ | 
|  | 4379 | xmlRelaxNGCombineStart(ctxt, ret); | 
|  | 4380 | if (ret->defs != NULL) { | 
|  | 4381 | xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine, | 
|  | 4382 | ctxt); | 
|  | 4383 | } | 
|  | 4384 |  | 
|  | 4385 | /* | 
|  | 4386 | * link together defines and refs in this grammar | 
|  | 4387 | */ | 
|  | 4388 | if (ret->refs != NULL) { | 
|  | 4389 | xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference, | 
|  | 4390 | ctxt); | 
|  | 4391 | } | 
|  | 4392 | ctxt->grammar = old; | 
|  | 4393 | return(ret); | 
|  | 4394 | } | 
|  | 4395 |  | 
|  | 4396 | /** | 
|  | 4397 | * xmlRelaxNGParseDocument: | 
|  | 4398 | * @ctxt:  a Relax-NG parser context | 
|  | 4399 | * @node:  the root node of the RelaxNG schema | 
|  | 4400 | * | 
|  | 4401 | * parse a Relax-NG definition resource and build an internal | 
|  | 4402 | * xmlRelaxNG struture which can be used to validate instances. | 
|  | 4403 | * | 
|  | 4404 | * Returns the internal XML RelaxNG structure built or | 
|  | 4405 | *         NULL in case of error | 
|  | 4406 | */ | 
|  | 4407 | static xmlRelaxNGPtr | 
|  | 4408 | xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 4409 | xmlRelaxNGPtr schema = NULL; | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 4410 | const xmlChar *olddefine; | 
| Daniel Veillard | e431a27 | 2003-01-29 23:02:33 +0000 | [diff] [blame] | 4411 | xmlRelaxNGGrammarPtr old; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4412 |  | 
|  | 4413 | if ((ctxt == NULL) || (node == NULL)) | 
|  | 4414 | return (NULL); | 
|  | 4415 |  | 
|  | 4416 | schema = xmlRelaxNGNewRelaxNG(ctxt); | 
|  | 4417 | if (schema == NULL) | 
|  | 4418 | return(NULL); | 
|  | 4419 |  | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 4420 | olddefine = ctxt->define; | 
|  | 4421 | ctxt->define = NULL; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4422 | if (IS_RELAXNG(node, "grammar")) { | 
|  | 4423 | schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children); | 
|  | 4424 | } else { | 
|  | 4425 | schema->topgrammar = xmlRelaxNGNewGrammar(ctxt); | 
|  | 4426 | if (schema->topgrammar == NULL) { | 
|  | 4427 | return(schema); | 
|  | 4428 | } | 
|  | 4429 | schema->topgrammar->parent = NULL; | 
| Daniel Veillard | e431a27 | 2003-01-29 23:02:33 +0000 | [diff] [blame] | 4430 | old = ctxt->grammar; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4431 | ctxt->grammar = schema->topgrammar; | 
|  | 4432 | xmlRelaxNGParseStart(ctxt, node); | 
| Daniel Veillard | e431a27 | 2003-01-29 23:02:33 +0000 | [diff] [blame] | 4433 | if (old != NULL) | 
|  | 4434 | ctxt->grammar = old; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4435 | } | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 4436 | ctxt->define = olddefine; | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 4437 | if (schema->topgrammar->start != NULL) { | 
|  | 4438 | xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4439 | if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) { | 
|  | 4440 | xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL); | 
|  | 4441 | while ((schema->topgrammar->start != NULL) && | 
|  | 4442 | (schema->topgrammar->start->type == XML_RELAXNG_NOOP) && | 
|  | 4443 | (schema->topgrammar->start->next != NULL)) | 
|  | 4444 | schema->topgrammar->start = schema->topgrammar->start->content; | 
|  | 4445 | xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start, | 
| Daniel Veillard | 4c5cf70 | 2003-02-21 15:40:34 +0000 | [diff] [blame] | 4446 | XML_RELAXNG_IN_START, XML_RELAXNG_NOOP); | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 4447 | } | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 4448 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4449 |  | 
|  | 4450 | #ifdef DEBUG | 
|  | 4451 | if (schema == NULL) | 
|  | 4452 | xmlGenericError(xmlGenericErrorContext, | 
|  | 4453 | "xmlRelaxNGParseDocument() failed\n"); | 
|  | 4454 | #endif | 
|  | 4455 |  | 
|  | 4456 | return (schema); | 
|  | 4457 | } | 
|  | 4458 |  | 
|  | 4459 | /************************************************************************ | 
|  | 4460 | * 									* | 
|  | 4461 | * 			Reading RelaxNGs				* | 
|  | 4462 | * 									* | 
|  | 4463 | ************************************************************************/ | 
|  | 4464 |  | 
|  | 4465 | /** | 
|  | 4466 | * xmlRelaxNGNewParserCtxt: | 
|  | 4467 | * @URL:  the location of the schema | 
|  | 4468 | * | 
|  | 4469 | * Create an XML RelaxNGs parse context for that file/resource expected | 
|  | 4470 | * to contain an XML RelaxNGs file. | 
|  | 4471 | * | 
|  | 4472 | * Returns the parser context or NULL in case of error | 
|  | 4473 | */ | 
|  | 4474 | xmlRelaxNGParserCtxtPtr | 
|  | 4475 | xmlRelaxNGNewParserCtxt(const char *URL) { | 
|  | 4476 | xmlRelaxNGParserCtxtPtr ret; | 
|  | 4477 |  | 
|  | 4478 | if (URL == NULL) | 
|  | 4479 | return(NULL); | 
|  | 4480 |  | 
|  | 4481 | ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); | 
|  | 4482 | if (ret == NULL) { | 
|  | 4483 | xmlGenericError(xmlGenericErrorContext, | 
|  | 4484 | "Failed to allocate new schama parser context for %s\n", URL); | 
|  | 4485 | return (NULL); | 
|  | 4486 | } | 
|  | 4487 | memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); | 
|  | 4488 | ret->URL = xmlStrdup((const xmlChar *)URL); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 4489 | ret->error = xmlGenericError; | 
|  | 4490 | ret->userData = xmlGenericErrorContext; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4491 | return (ret); | 
|  | 4492 | } | 
|  | 4493 |  | 
|  | 4494 | /** | 
|  | 4495 | * xmlRelaxNGNewMemParserCtxt: | 
|  | 4496 | * @buffer:  a pointer to a char array containing the schemas | 
|  | 4497 | * @size:  the size of the array | 
|  | 4498 | * | 
|  | 4499 | * Create an XML RelaxNGs parse context for that memory buffer expected | 
|  | 4500 | * to contain an XML RelaxNGs file. | 
|  | 4501 | * | 
|  | 4502 | * Returns the parser context or NULL in case of error | 
|  | 4503 | */ | 
|  | 4504 | xmlRelaxNGParserCtxtPtr | 
|  | 4505 | xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) { | 
|  | 4506 | xmlRelaxNGParserCtxtPtr ret; | 
|  | 4507 |  | 
|  | 4508 | if ((buffer == NULL) || (size <= 0)) | 
|  | 4509 | return(NULL); | 
|  | 4510 |  | 
|  | 4511 | ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt)); | 
|  | 4512 | if (ret == NULL) { | 
|  | 4513 | xmlGenericError(xmlGenericErrorContext, | 
|  | 4514 | "Failed to allocate new schama parser context\n"); | 
|  | 4515 | return (NULL); | 
|  | 4516 | } | 
|  | 4517 | memset(ret, 0, sizeof(xmlRelaxNGParserCtxt)); | 
|  | 4518 | ret->buffer = buffer; | 
|  | 4519 | ret->size = size; | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 4520 | ret->error = xmlGenericError; | 
|  | 4521 | ret->userData = xmlGenericErrorContext; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4522 | return (ret); | 
|  | 4523 | } | 
|  | 4524 |  | 
|  | 4525 | /** | 
|  | 4526 | * xmlRelaxNGFreeParserCtxt: | 
|  | 4527 | * @ctxt:  the schema parser context | 
|  | 4528 | * | 
|  | 4529 | * Free the resources associated to the schema parser context | 
|  | 4530 | */ | 
|  | 4531 | void | 
|  | 4532 | xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) { | 
|  | 4533 | if (ctxt == NULL) | 
|  | 4534 | return; | 
|  | 4535 | if (ctxt->URL != NULL) | 
|  | 4536 | xmlFree(ctxt->URL); | 
|  | 4537 | if (ctxt->doc != NULL) | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 4538 | xmlFreeDoc(ctxt->document); | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 4539 | if (ctxt->interleaves != NULL) | 
|  | 4540 | xmlHashFree(ctxt->interleaves, NULL); | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 4541 | if (ctxt->documents != NULL) | 
|  | 4542 | xmlHashFree(ctxt->documents, (xmlHashDeallocator) | 
|  | 4543 | xmlRelaxNGFreeDocument); | 
|  | 4544 | if (ctxt->docTab != NULL) | 
|  | 4545 | xmlFree(ctxt->docTab); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 4546 | if (ctxt->incTab != NULL) | 
|  | 4547 | xmlFree(ctxt->incTab); | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 4548 | if (ctxt->defTab != NULL) { | 
|  | 4549 | int i; | 
|  | 4550 |  | 
|  | 4551 | for (i = 0;i < ctxt->defNr;i++) | 
|  | 4552 | xmlRelaxNGFreeDefine(ctxt->defTab[i]); | 
|  | 4553 | xmlFree(ctxt->defTab); | 
|  | 4554 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4555 | xmlFree(ctxt); | 
|  | 4556 | } | 
|  | 4557 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4558 | /** | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 4559 | * xmlRelaxNGNormExtSpace: | 
|  | 4560 | * @value:  a value | 
|  | 4561 | * | 
|  | 4562 | * Removes the leading and ending spaces of the value | 
|  | 4563 | * The string is modified "in situ" | 
|  | 4564 | */ | 
|  | 4565 | static void | 
|  | 4566 | xmlRelaxNGNormExtSpace(xmlChar *value) { | 
|  | 4567 | xmlChar *start = value; | 
|  | 4568 | xmlChar *cur = value; | 
|  | 4569 | if (value == NULL) | 
|  | 4570 | return; | 
|  | 4571 |  | 
|  | 4572 | while (IS_BLANK(*cur)) cur++; | 
|  | 4573 | if (cur == start) { | 
|  | 4574 | do { | 
|  | 4575 | while ((*cur != 0) && (!IS_BLANK(*cur))) cur++; | 
|  | 4576 | if (*cur == 0) | 
|  | 4577 | return; | 
|  | 4578 | start = cur; | 
|  | 4579 | while (IS_BLANK(*cur)) cur++; | 
|  | 4580 | if (*cur == 0) { | 
|  | 4581 | *start = 0; | 
|  | 4582 | return; | 
|  | 4583 | } | 
|  | 4584 | } while (1); | 
|  | 4585 | } else { | 
|  | 4586 | do { | 
|  | 4587 | while ((*cur != 0) && (!IS_BLANK(*cur))) | 
|  | 4588 | *start++ = *cur++; | 
|  | 4589 | if (*cur == 0) { | 
|  | 4590 | *start = 0; | 
|  | 4591 | return; | 
|  | 4592 | } | 
|  | 4593 | /* don't try to normalize the inner spaces */ | 
|  | 4594 | while (IS_BLANK(*cur)) cur++; | 
|  | 4595 | *start++ = *cur++; | 
|  | 4596 | if (*cur == 0) { | 
|  | 4597 | *start = 0; | 
|  | 4598 | return; | 
|  | 4599 | } | 
|  | 4600 | } while (1); | 
|  | 4601 | } | 
|  | 4602 | } | 
|  | 4603 |  | 
|  | 4604 | /** | 
|  | 4605 | * xmlRelaxNGCheckAttributes: | 
|  | 4606 | * @ctxt:  a Relax-NG parser context | 
|  | 4607 | * @node:  a Relax-NG node | 
|  | 4608 | * | 
|  | 4609 | * Check all the attributes on the given node | 
|  | 4610 | */ | 
|  | 4611 | static void | 
|  | 4612 | xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) { | 
|  | 4613 | xmlAttrPtr cur, next; | 
|  | 4614 |  | 
|  | 4615 | cur = node->properties; | 
|  | 4616 | while (cur != NULL) { | 
|  | 4617 | next = cur->next; | 
|  | 4618 | if ((cur->ns == NULL) || | 
|  | 4619 | (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { | 
|  | 4620 | if (xmlStrEqual(cur->name, BAD_CAST "name")) { | 
|  | 4621 | if ((!xmlStrEqual(node->name, BAD_CAST "element")) && | 
|  | 4622 | (!xmlStrEqual(node->name, BAD_CAST "attribute")) && | 
|  | 4623 | (!xmlStrEqual(node->name, BAD_CAST "ref")) && | 
|  | 4624 | (!xmlStrEqual(node->name, BAD_CAST "parentRef")) && | 
| Daniel Veillard | 2df2de2 | 2003-02-17 23:34:33 +0000 | [diff] [blame] | 4625 | (!xmlStrEqual(node->name, BAD_CAST "param")) && | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 4626 | (!xmlStrEqual(node->name, BAD_CAST "define"))) { | 
|  | 4627 | if (ctxt->error != NULL) | 
|  | 4628 | ctxt->error(ctxt->userData, | 
|  | 4629 | "Attribute %s is not allowed on %s\n", | 
|  | 4630 | cur->name, node->name); | 
|  | 4631 | ctxt->nbErrors++; | 
|  | 4632 | } | 
|  | 4633 | } else if (xmlStrEqual(cur->name, BAD_CAST "type")) { | 
|  | 4634 | if ((!xmlStrEqual(node->name, BAD_CAST "value")) && | 
|  | 4635 | (!xmlStrEqual(node->name, BAD_CAST "data"))) { | 
|  | 4636 | if (ctxt->error != NULL) | 
|  | 4637 | ctxt->error(ctxt->userData, | 
|  | 4638 | "Attribute %s is not allowed on %s\n", | 
|  | 4639 | cur->name, node->name); | 
|  | 4640 | ctxt->nbErrors++; | 
|  | 4641 | } | 
|  | 4642 | } else if (xmlStrEqual(cur->name, BAD_CAST "href")) { | 
|  | 4643 | if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) && | 
|  | 4644 | (!xmlStrEqual(node->name, BAD_CAST "include"))) { | 
|  | 4645 | if (ctxt->error != NULL) | 
|  | 4646 | ctxt->error(ctxt->userData, | 
|  | 4647 | "Attribute %s is not allowed on %s\n", | 
|  | 4648 | cur->name, node->name); | 
|  | 4649 | ctxt->nbErrors++; | 
|  | 4650 | } | 
|  | 4651 | } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) { | 
|  | 4652 | if ((!xmlStrEqual(node->name, BAD_CAST "start")) && | 
|  | 4653 | (!xmlStrEqual(node->name, BAD_CAST "define"))) { | 
|  | 4654 | if (ctxt->error != NULL) | 
|  | 4655 | ctxt->error(ctxt->userData, | 
|  | 4656 | "Attribute %s is not allowed on %s\n", | 
|  | 4657 | cur->name, node->name); | 
|  | 4658 | ctxt->nbErrors++; | 
|  | 4659 | } | 
|  | 4660 | } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) { | 
|  | 4661 | xmlChar *val; | 
|  | 4662 | xmlURIPtr uri; | 
|  | 4663 |  | 
|  | 4664 | val = xmlNodeListGetString(node->doc, cur->children, 1); | 
|  | 4665 | if (val != NULL) { | 
|  | 4666 | if (val[0] != 0) { | 
|  | 4667 | uri = xmlParseURI((const char *) val); | 
|  | 4668 | if (uri == NULL) { | 
|  | 4669 | if (ctxt->error != NULL) | 
|  | 4670 | ctxt->error(ctxt->userData, | 
|  | 4671 | "Attribute %s contains invalid URI %s\n", | 
|  | 4672 | cur->name, val); | 
|  | 4673 | ctxt->nbErrors++; | 
|  | 4674 | } else { | 
|  | 4675 | if (uri->scheme == NULL) { | 
|  | 4676 | if (ctxt->error != NULL) | 
|  | 4677 | ctxt->error(ctxt->userData, | 
|  | 4678 | "Attribute %s URI %s is not absolute\n", | 
|  | 4679 | cur->name, val); | 
|  | 4680 | ctxt->nbErrors++; | 
|  | 4681 | } | 
|  | 4682 | if (uri->fragment != NULL) { | 
|  | 4683 | if (ctxt->error != NULL) | 
|  | 4684 | ctxt->error(ctxt->userData, | 
|  | 4685 | "Attribute %s URI %s has a fragment ID\n", | 
|  | 4686 | cur->name, val); | 
|  | 4687 | ctxt->nbErrors++; | 
|  | 4688 | } | 
|  | 4689 | xmlFreeURI(uri); | 
|  | 4690 | } | 
|  | 4691 | } | 
|  | 4692 | xmlFree(val); | 
|  | 4693 | } | 
|  | 4694 | } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) { | 
|  | 4695 | if (ctxt->error != NULL) | 
|  | 4696 | ctxt->error(ctxt->userData, | 
|  | 4697 | "Unknown attribute %s on %s\n", | 
|  | 4698 | cur->name, node->name); | 
|  | 4699 | ctxt->nbErrors++; | 
|  | 4700 | } | 
|  | 4701 | } | 
|  | 4702 | cur = next; | 
|  | 4703 | } | 
|  | 4704 | } | 
|  | 4705 |  | 
|  | 4706 | /** | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 4707 | * xmlRelaxNGCleanupTree: | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 4708 | * @ctxt:  a Relax-NG parser context | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 4709 | * @root:  an xmlNodePtr subtree | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4710 | * | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 4711 | * Cleanup the subtree from unwanted nodes for parsing, resolve | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 4712 | * Include and externalRef lookups. | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4713 | */ | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 4714 | static void | 
|  | 4715 | xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) { | 
|  | 4716 | xmlNodePtr cur, delete; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4717 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4718 | delete = NULL; | 
|  | 4719 | cur = root; | 
|  | 4720 | while (cur != NULL) { | 
|  | 4721 | if (delete != NULL) { | 
|  | 4722 | xmlUnlinkNode(delete); | 
|  | 4723 | xmlFreeNode(delete); | 
|  | 4724 | delete = NULL; | 
|  | 4725 | } | 
|  | 4726 | if (cur->type == XML_ELEMENT_NODE) { | 
|  | 4727 | /* | 
|  | 4728 | * Simplification 4.1. Annotations | 
|  | 4729 | */ | 
|  | 4730 | if ((cur->ns == NULL) || | 
|  | 4731 | (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 4732 | if ((cur->parent != NULL) && | 
|  | 4733 | (cur->parent->type == XML_ELEMENT_NODE) && | 
|  | 4734 | ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) || | 
|  | 4735 | (xmlStrEqual(cur->parent->name, BAD_CAST "value")) || | 
|  | 4736 | (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) { | 
|  | 4737 | if (ctxt->error != NULL) | 
|  | 4738 | ctxt->error(ctxt->userData, | 
|  | 4739 | "element %s doesn't allow foreign elements\n", | 
|  | 4740 | cur->parent->name); | 
|  | 4741 | ctxt->nbErrors++; | 
|  | 4742 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4743 | delete = cur; | 
|  | 4744 | goto skip_children; | 
|  | 4745 | } else { | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 4746 | xmlRelaxNGCleanupAttributes(ctxt, cur); | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 4747 | if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) { | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 4748 | xmlChar *href, *ns, *base, *URL; | 
|  | 4749 | xmlRelaxNGDocumentPtr docu; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 4750 | xmlNodePtr tmp; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 4751 |  | 
|  | 4752 | ns = xmlGetProp(cur, BAD_CAST "ns"); | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 4753 | if (ns == NULL) { | 
|  | 4754 | tmp = cur->parent; | 
|  | 4755 | while ((tmp != NULL) && | 
|  | 4756 | (tmp->type == XML_ELEMENT_NODE)) { | 
|  | 4757 | ns = xmlGetProp(tmp, BAD_CAST "ns"); | 
|  | 4758 | if (ns != NULL) | 
|  | 4759 | break; | 
|  | 4760 | tmp = tmp->parent; | 
|  | 4761 | } | 
|  | 4762 | } | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 4763 | href = xmlGetProp(cur, BAD_CAST "href"); | 
|  | 4764 | if (href == NULL) { | 
|  | 4765 | if (ctxt->error != NULL) | 
|  | 4766 | ctxt->error(ctxt->userData, | 
|  | 4767 | "xmlRelaxNGParse: externalRef has no href attribute\n"); | 
|  | 4768 | ctxt->nbErrors++; | 
|  | 4769 | delete = cur; | 
|  | 4770 | goto skip_children; | 
|  | 4771 | } | 
|  | 4772 | base = xmlNodeGetBase(cur->doc, cur); | 
|  | 4773 | URL = xmlBuildURI(href, base); | 
|  | 4774 | if (URL == NULL) { | 
|  | 4775 | if (ctxt->error != NULL) | 
|  | 4776 | ctxt->error(ctxt->userData, | 
|  | 4777 | "Failed to compute URL for externalRef %s\n", href); | 
|  | 4778 | ctxt->nbErrors++; | 
|  | 4779 | if (href != NULL) | 
|  | 4780 | xmlFree(href); | 
|  | 4781 | if (base != NULL) | 
|  | 4782 | xmlFree(base); | 
|  | 4783 | delete = cur; | 
|  | 4784 | goto skip_children; | 
|  | 4785 | } | 
|  | 4786 | if (href != NULL) | 
|  | 4787 | xmlFree(href); | 
|  | 4788 | if (base != NULL) | 
|  | 4789 | xmlFree(base); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 4790 | docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns); | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 4791 | if (docu == NULL) { | 
|  | 4792 | if (ctxt->error != NULL) | 
|  | 4793 | ctxt->error(ctxt->userData, | 
|  | 4794 | "Failed to load externalRef %s\n", URL); | 
|  | 4795 | ctxt->nbErrors++; | 
|  | 4796 | xmlFree(URL); | 
|  | 4797 | delete = cur; | 
|  | 4798 | goto skip_children; | 
|  | 4799 | } | 
|  | 4800 | xmlFree(URL); | 
|  | 4801 | cur->_private = docu; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4802 | } else if (xmlStrEqual(cur->name, BAD_CAST "include")) { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 4803 | xmlChar *href, *ns, *base, *URL; | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 4804 | xmlRelaxNGIncludePtr incl; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 4805 | xmlNodePtr tmp; | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 4806 |  | 
|  | 4807 | href = xmlGetProp(cur, BAD_CAST "href"); | 
|  | 4808 | if (href == NULL) { | 
|  | 4809 | if (ctxt->error != NULL) | 
|  | 4810 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 4811 | "xmlRelaxNGParse: include has no href attribute\n"); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 4812 | ctxt->nbErrors++; | 
|  | 4813 | delete = cur; | 
|  | 4814 | goto skip_children; | 
|  | 4815 | } | 
|  | 4816 | base = xmlNodeGetBase(cur->doc, cur); | 
|  | 4817 | URL = xmlBuildURI(href, base); | 
|  | 4818 | if (URL == NULL) { | 
|  | 4819 | if (ctxt->error != NULL) | 
|  | 4820 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 4821 | "Failed to compute URL for include %s\n", href); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 4822 | ctxt->nbErrors++; | 
|  | 4823 | if (href != NULL) | 
|  | 4824 | xmlFree(href); | 
|  | 4825 | if (base != NULL) | 
|  | 4826 | xmlFree(base); | 
|  | 4827 | delete = cur; | 
|  | 4828 | goto skip_children; | 
|  | 4829 | } | 
|  | 4830 | if (href != NULL) | 
|  | 4831 | xmlFree(href); | 
|  | 4832 | if (base != NULL) | 
|  | 4833 | xmlFree(base); | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 4834 | ns = xmlGetProp(cur, BAD_CAST "ns"); | 
|  | 4835 | if (ns == NULL) { | 
|  | 4836 | tmp = cur->parent; | 
|  | 4837 | while ((tmp != NULL) && | 
|  | 4838 | (tmp->type == XML_ELEMENT_NODE)) { | 
|  | 4839 | ns = xmlGetProp(tmp, BAD_CAST "ns"); | 
|  | 4840 | if (ns != NULL) | 
|  | 4841 | break; | 
|  | 4842 | tmp = tmp->parent; | 
|  | 4843 | } | 
|  | 4844 | } | 
|  | 4845 | incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns); | 
|  | 4846 | if (ns != NULL) | 
|  | 4847 | xmlFree(ns); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 4848 | if (incl == NULL) { | 
|  | 4849 | if (ctxt->error != NULL) | 
|  | 4850 | ctxt->error(ctxt->userData, | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 4851 | "Failed to load include %s\n", URL); | 
| Daniel Veillard | a9d912d | 2003-02-01 17:43:10 +0000 | [diff] [blame] | 4852 | ctxt->nbErrors++; | 
|  | 4853 | xmlFree(URL); | 
|  | 4854 | delete = cur; | 
|  | 4855 | goto skip_children; | 
|  | 4856 | } | 
|  | 4857 | xmlFree(URL); | 
|  | 4858 | cur->_private = incl; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4859 | } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) || | 
|  | 4860 | (xmlStrEqual(cur->name, BAD_CAST "attribute"))) { | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 4861 | xmlChar *name, *ns; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4862 | xmlNodePtr text = NULL; | 
|  | 4863 |  | 
|  | 4864 | /* | 
|  | 4865 | * Simplification 4.8. name attribute of element | 
|  | 4866 | * and attribute elements | 
|  | 4867 | */ | 
|  | 4868 | name = xmlGetProp(cur, BAD_CAST "name"); | 
|  | 4869 | if (name != NULL) { | 
|  | 4870 | if (cur->children == NULL) { | 
|  | 4871 | text = xmlNewChild(cur, cur->ns, BAD_CAST "name", | 
|  | 4872 | name); | 
|  | 4873 | } else { | 
|  | 4874 | xmlNodePtr node; | 
|  | 4875 | node = xmlNewNode(cur->ns, BAD_CAST "name"); | 
|  | 4876 | if (node != NULL) { | 
|  | 4877 | xmlAddPrevSibling(cur->children, node); | 
|  | 4878 | text = xmlNewText(name); | 
|  | 4879 | xmlAddChild(node, text); | 
|  | 4880 | text = node; | 
|  | 4881 | } | 
|  | 4882 | } | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 4883 | if (text == NULL) { | 
|  | 4884 | if (ctxt->error != NULL) | 
|  | 4885 | ctxt->error(ctxt->userData, | 
|  | 4886 | "Failed to create a name %s element\n", name); | 
|  | 4887 | ctxt->nbErrors++; | 
|  | 4888 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4889 | xmlUnsetProp(cur, BAD_CAST "name"); | 
|  | 4890 | xmlFree(name); | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 4891 | ns = xmlGetProp(cur, BAD_CAST "ns"); | 
|  | 4892 | if (ns != NULL) { | 
|  | 4893 | if (text != NULL) { | 
|  | 4894 | xmlSetProp(text, BAD_CAST "ns", ns); | 
|  | 4895 | /* xmlUnsetProp(cur, BAD_CAST "ns"); */ | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4896 | } | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 4897 | xmlFree(ns); | 
|  | 4898 | } else if (xmlStrEqual(cur->name, | 
|  | 4899 | BAD_CAST "attribute")) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4900 | xmlSetProp(text, BAD_CAST "ns", BAD_CAST ""); | 
|  | 4901 | } | 
|  | 4902 | } | 
|  | 4903 | } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) || | 
|  | 4904 | (xmlStrEqual(cur->name, BAD_CAST "nsName")) || | 
|  | 4905 | (xmlStrEqual(cur->name, BAD_CAST "value"))) { | 
|  | 4906 | /* | 
|  | 4907 | * Simplification 4.8. name attribute of element | 
|  | 4908 | * and attribute elements | 
|  | 4909 | */ | 
|  | 4910 | if (xmlHasProp(cur, BAD_CAST "ns") == NULL) { | 
|  | 4911 | xmlNodePtr node; | 
|  | 4912 | xmlChar *ns = NULL; | 
|  | 4913 |  | 
|  | 4914 | node = cur->parent; | 
|  | 4915 | while ((node != NULL) && | 
|  | 4916 | (node->type == XML_ELEMENT_NODE)) { | 
|  | 4917 | ns = xmlGetProp(node, BAD_CAST "ns"); | 
|  | 4918 | if (ns != NULL) { | 
|  | 4919 | break; | 
|  | 4920 | } | 
|  | 4921 | node = node->parent; | 
|  | 4922 | } | 
|  | 4923 | if (ns == NULL) { | 
|  | 4924 | xmlSetProp(cur, BAD_CAST "ns", BAD_CAST ""); | 
|  | 4925 | } else { | 
|  | 4926 | xmlSetProp(cur, BAD_CAST "ns", ns); | 
|  | 4927 | xmlFree(ns); | 
|  | 4928 | } | 
|  | 4929 | } | 
|  | 4930 | if (xmlStrEqual(cur->name, BAD_CAST "name")) { | 
|  | 4931 | xmlChar *name, *local, *prefix; | 
|  | 4932 |  | 
|  | 4933 | /* | 
|  | 4934 | * Simplification: 4.10. QNames | 
|  | 4935 | */ | 
|  | 4936 | name = xmlNodeGetContent(cur); | 
|  | 4937 | if (name != NULL) { | 
|  | 4938 | local = xmlSplitQName2(name, &prefix); | 
|  | 4939 | if (local != NULL) { | 
|  | 4940 | xmlNsPtr ns; | 
|  | 4941 |  | 
|  | 4942 | ns = xmlSearchNs(cur->doc, cur, prefix); | 
|  | 4943 | if (ns == NULL) { | 
|  | 4944 | if (ctxt->error != NULL) | 
|  | 4945 | ctxt->error(ctxt->userData, | 
|  | 4946 | "xmlRelaxNGParse: no namespace for prefix %s\n", prefix); | 
|  | 4947 | ctxt->nbErrors++; | 
|  | 4948 | } else { | 
|  | 4949 | xmlSetProp(cur, BAD_CAST "ns", ns->href); | 
|  | 4950 | xmlNodeSetContent(cur, local); | 
|  | 4951 | } | 
|  | 4952 | xmlFree(local); | 
|  | 4953 | xmlFree(prefix); | 
|  | 4954 | } | 
|  | 4955 | xmlFree(name); | 
|  | 4956 | } | 
|  | 4957 | } | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 4958 | if (xmlStrEqual(cur->name, BAD_CAST "nsName")) { | 
|  | 4959 | if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { | 
|  | 4960 | if (ctxt->error != NULL) | 
|  | 4961 | ctxt->error(ctxt->userData, | 
|  | 4962 | "Found nsName/except//nsName forbidden construct\n"); | 
|  | 4963 | ctxt->nbErrors++; | 
|  | 4964 | } | 
|  | 4965 | } | 
|  | 4966 | } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) && | 
|  | 4967 | (cur != root)) { | 
|  | 4968 | int oldflags = ctxt->flags; | 
|  | 4969 |  | 
|  | 4970 | if ((cur->parent != NULL) && | 
|  | 4971 | (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) { | 
|  | 4972 | ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT; | 
|  | 4973 | xmlRelaxNGCleanupTree(ctxt, cur); | 
|  | 4974 | ctxt->flags = oldflags; | 
|  | 4975 | goto skip_children; | 
|  | 4976 | } else if ((cur->parent != NULL) && | 
|  | 4977 | (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) { | 
|  | 4978 | ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT; | 
|  | 4979 | xmlRelaxNGCleanupTree(ctxt, cur); | 
|  | 4980 | ctxt->flags = oldflags; | 
|  | 4981 | goto skip_children; | 
|  | 4982 | } | 
|  | 4983 | } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) { | 
|  | 4984 | if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) { | 
|  | 4985 | if (ctxt->error != NULL) | 
|  | 4986 | ctxt->error(ctxt->userData, | 
|  | 4987 | "Found anyName/except//anyName forbidden construct\n"); | 
|  | 4988 | ctxt->nbErrors++; | 
|  | 4989 | } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) { | 
|  | 4990 | if (ctxt->error != NULL) | 
|  | 4991 | ctxt->error(ctxt->userData, | 
|  | 4992 | "Found nsName/except//anyName forbidden construct\n"); | 
|  | 4993 | ctxt->nbErrors++; | 
|  | 4994 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 4995 | } | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 4996 | /* | 
|  | 4997 | * Thisd is not an else since "include" is transformed | 
|  | 4998 | * into a div | 
|  | 4999 | */ | 
|  | 5000 | if (xmlStrEqual(cur->name, BAD_CAST "div")) { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5001 | xmlChar *ns; | 
|  | 5002 | xmlNodePtr child, ins, tmp; | 
|  | 5003 |  | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 5004 | /* | 
|  | 5005 | * implements rule 4.11 | 
|  | 5006 | */ | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5007 |  | 
|  | 5008 | ns = xmlGetProp(cur, BAD_CAST "ns"); | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 5009 |  | 
|  | 5010 | child = cur->children; | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 5011 | ins = cur; | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 5012 | while (child != NULL) { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5013 | if (ns != NULL) { | 
|  | 5014 | if (!xmlHasProp(child, BAD_CAST "ns")) { | 
|  | 5015 | xmlSetProp(child, BAD_CAST "ns", ns); | 
|  | 5016 | } | 
|  | 5017 | } | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 5018 | tmp = child->next; | 
|  | 5019 | xmlUnlinkNode(child); | 
|  | 5020 | ins = xmlAddNextSibling(ins, child); | 
|  | 5021 | child = tmp; | 
|  | 5022 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5023 | if (ns != NULL) | 
|  | 5024 | xmlFree(ns); | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 5025 | delete = cur; | 
|  | 5026 | goto skip_children; | 
|  | 5027 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5028 | } | 
|  | 5029 | } | 
|  | 5030 | /* | 
|  | 5031 | * Simplification 4.2 whitespaces | 
|  | 5032 | */ | 
|  | 5033 | else if (cur->type == XML_TEXT_NODE) { | 
|  | 5034 | if (IS_BLANK_NODE(cur)) { | 
|  | 5035 | if (cur->parent->type == XML_ELEMENT_NODE) { | 
|  | 5036 | if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) && | 
|  | 5037 | (!xmlStrEqual(cur->parent->name, BAD_CAST "param"))) | 
|  | 5038 | delete = cur; | 
|  | 5039 | } else { | 
|  | 5040 | delete = cur; | 
|  | 5041 | goto skip_children; | 
|  | 5042 | } | 
|  | 5043 | } | 
|  | 5044 | } else if (cur->type != XML_CDATA_SECTION_NODE) { | 
|  | 5045 | delete = cur; | 
|  | 5046 | goto skip_children; | 
|  | 5047 | } | 
|  | 5048 |  | 
|  | 5049 | /* | 
|  | 5050 | * Skip to next node | 
|  | 5051 | */ | 
|  | 5052 | if (cur->children != NULL) { | 
|  | 5053 | if ((cur->children->type != XML_ENTITY_DECL) && | 
|  | 5054 | (cur->children->type != XML_ENTITY_REF_NODE) && | 
|  | 5055 | (cur->children->type != XML_ENTITY_NODE)) { | 
|  | 5056 | cur = cur->children; | 
|  | 5057 | continue; | 
|  | 5058 | } | 
|  | 5059 | } | 
|  | 5060 | skip_children: | 
|  | 5061 | if (cur->next != NULL) { | 
|  | 5062 | cur = cur->next; | 
|  | 5063 | continue; | 
|  | 5064 | } | 
|  | 5065 |  | 
|  | 5066 | do { | 
|  | 5067 | cur = cur->parent; | 
|  | 5068 | if (cur == NULL) | 
|  | 5069 | break; | 
|  | 5070 | if (cur == root) { | 
|  | 5071 | cur = NULL; | 
|  | 5072 | break; | 
|  | 5073 | } | 
|  | 5074 | if (cur->next != NULL) { | 
|  | 5075 | cur = cur->next; | 
|  | 5076 | break; | 
|  | 5077 | } | 
|  | 5078 | } while (cur != NULL); | 
|  | 5079 | } | 
|  | 5080 | if (delete != NULL) { | 
|  | 5081 | xmlUnlinkNode(delete); | 
|  | 5082 | xmlFreeNode(delete); | 
|  | 5083 | delete = NULL; | 
|  | 5084 | } | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 5085 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5086 |  | 
| Daniel Veillard | c5312d7 | 2003-02-21 17:14:10 +0000 | [diff] [blame^] | 5087 | /** | 
|  | 5088 | * xmlRelaxNGCleanupDoc: | 
|  | 5089 | * @ctxt:  a Relax-NG parser context | 
|  | 5090 | * @doc:  an xmldocPtr document pointer | 
|  | 5091 | * | 
|  | 5092 | * Cleanup the document from unwanted nodes for parsing, resolve | 
|  | 5093 | * Include and externalRef lookups. | 
|  | 5094 | * | 
|  | 5095 | * Returns the cleaned up document or NULL in case of error | 
|  | 5096 | */ | 
|  | 5097 | static xmlDocPtr | 
|  | 5098 | xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) { | 
|  | 5099 | xmlNodePtr root; | 
|  | 5100 |  | 
|  | 5101 | /* | 
|  | 5102 | * Extract the root | 
|  | 5103 | */ | 
|  | 5104 | root = xmlDocGetRootElement(doc); | 
|  | 5105 | if (root == NULL) { | 
|  | 5106 | if (ctxt->error != NULL) | 
|  | 5107 | ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n", | 
|  | 5108 | ctxt->URL); | 
|  | 5109 | ctxt->nbErrors++; | 
|  | 5110 | return (NULL); | 
|  | 5111 | } | 
|  | 5112 | xmlRelaxNGCleanupTree(ctxt, root); | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 5113 | return(doc); | 
|  | 5114 | } | 
|  | 5115 |  | 
|  | 5116 | /** | 
|  | 5117 | * xmlRelaxNGParse: | 
|  | 5118 | * @ctxt:  a Relax-NG parser context | 
|  | 5119 | * | 
|  | 5120 | * parse a schema definition resource and build an internal | 
|  | 5121 | * XML Shema struture which can be used to validate instances. | 
|  | 5122 | * *WARNING* this interface is highly subject to change | 
|  | 5123 | * | 
|  | 5124 | * Returns the internal XML RelaxNG structure built from the resource or | 
|  | 5125 | *         NULL in case of error | 
|  | 5126 | */ | 
|  | 5127 | xmlRelaxNGPtr | 
|  | 5128 | xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt) | 
|  | 5129 | { | 
|  | 5130 | xmlRelaxNGPtr ret = NULL; | 
|  | 5131 | xmlDocPtr doc; | 
|  | 5132 | xmlNodePtr root; | 
|  | 5133 |  | 
|  | 5134 | xmlRelaxNGInitTypes(); | 
|  | 5135 |  | 
|  | 5136 | if (ctxt == NULL) | 
|  | 5137 | return (NULL); | 
|  | 5138 |  | 
|  | 5139 | /* | 
|  | 5140 | * First step is to parse the input document into an DOM/Infoset | 
|  | 5141 | */ | 
|  | 5142 | if (ctxt->URL != NULL) { | 
|  | 5143 | doc = xmlParseFile((const char *) ctxt->URL); | 
|  | 5144 | if (doc == NULL) { | 
|  | 5145 | if (ctxt->error != NULL) | 
|  | 5146 | ctxt->error(ctxt->userData, | 
|  | 5147 | "xmlRelaxNGParse: could not load %s\n", ctxt->URL); | 
|  | 5148 | ctxt->nbErrors++; | 
|  | 5149 | return (NULL); | 
|  | 5150 | } | 
|  | 5151 | } else if (ctxt->buffer != NULL) { | 
|  | 5152 | doc = xmlParseMemory(ctxt->buffer, ctxt->size); | 
|  | 5153 | if (doc == NULL) { | 
|  | 5154 | if (ctxt->error != NULL) | 
|  | 5155 | ctxt->error(ctxt->userData, | 
|  | 5156 | "xmlRelaxNGParse: could not parse schemas\n"); | 
|  | 5157 | ctxt->nbErrors++; | 
|  | 5158 | return (NULL); | 
|  | 5159 | } | 
|  | 5160 | doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); | 
|  | 5161 | ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer"); | 
|  | 5162 | } else { | 
|  | 5163 | if (ctxt->error != NULL) | 
|  | 5164 | ctxt->error(ctxt->userData, | 
|  | 5165 | "xmlRelaxNGParse: nothing to parse\n"); | 
|  | 5166 | ctxt->nbErrors++; | 
|  | 5167 | return (NULL); | 
|  | 5168 | } | 
|  | 5169 | ctxt->document = doc; | 
|  | 5170 |  | 
|  | 5171 | /* | 
|  | 5172 | * Some preprocessing of the document content | 
|  | 5173 | */ | 
|  | 5174 | doc = xmlRelaxNGCleanupDoc(ctxt, doc); | 
|  | 5175 | if (doc == NULL) { | 
|  | 5176 | xmlFreeDoc(ctxt->document); | 
|  | 5177 | ctxt->document = NULL; | 
|  | 5178 | return(NULL); | 
|  | 5179 | } | 
|  | 5180 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5181 | /* | 
|  | 5182 | * Then do the parsing for good | 
|  | 5183 | */ | 
|  | 5184 | root = xmlDocGetRootElement(doc); | 
|  | 5185 | if (root == NULL) { | 
|  | 5186 | if (ctxt->error != NULL) | 
|  | 5187 | ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n", | 
|  | 5188 | ctxt->URL); | 
|  | 5189 | ctxt->nbErrors++; | 
|  | 5190 | return (NULL); | 
|  | 5191 | } | 
|  | 5192 | ret = xmlRelaxNGParseDocument(ctxt, root); | 
|  | 5193 | if (ret == NULL) | 
|  | 5194 | return(NULL); | 
|  | 5195 |  | 
|  | 5196 | /* | 
|  | 5197 | * Check the ref/defines links | 
|  | 5198 | */ | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 5199 | /* | 
|  | 5200 | * try to preprocess interleaves | 
|  | 5201 | */ | 
|  | 5202 | if (ctxt->interleaves != NULL) { | 
|  | 5203 | xmlHashScan(ctxt->interleaves, | 
|  | 5204 | (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt); | 
|  | 5205 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5206 |  | 
|  | 5207 | /* | 
|  | 5208 | * if there was a parsing error return NULL | 
|  | 5209 | */ | 
|  | 5210 | if (ctxt->nbErrors > 0) { | 
|  | 5211 | xmlRelaxNGFree(ret); | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 5212 | ctxt->document = NULL; | 
|  | 5213 | xmlFreeDoc(doc); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5214 | return(NULL); | 
|  | 5215 | } | 
|  | 5216 |  | 
|  | 5217 | /* | 
|  | 5218 | * Transfer the pointer for cleanup at the schema level. | 
|  | 5219 | */ | 
|  | 5220 | ret->doc = doc; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 5221 | ctxt->document = NULL; | 
|  | 5222 | ret->documents = ctxt->documents; | 
|  | 5223 | ctxt->documents = NULL; | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 5224 | ret->includes = ctxt->includes; | 
|  | 5225 | ctxt->includes = NULL; | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 5226 | ret->defNr = ctxt->defNr; | 
|  | 5227 | ret->defTab = ctxt->defTab; | 
|  | 5228 | ctxt->defTab = NULL; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5229 |  | 
|  | 5230 | return (ret); | 
|  | 5231 | } | 
|  | 5232 |  | 
|  | 5233 | /** | 
|  | 5234 | * xmlRelaxNGSetParserErrors: | 
|  | 5235 | * @ctxt:  a Relax-NG validation context | 
|  | 5236 | * @err:  the error callback | 
|  | 5237 | * @warn:  the warning callback | 
|  | 5238 | * @ctx:  contextual data for the callbacks | 
|  | 5239 | * | 
|  | 5240 | * Set the callback functions used to handle errors for a validation context | 
|  | 5241 | */ | 
|  | 5242 | void | 
|  | 5243 | xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt, | 
|  | 5244 | xmlRelaxNGValidityErrorFunc err, | 
|  | 5245 | xmlRelaxNGValidityWarningFunc warn, void *ctx) { | 
|  | 5246 | if (ctxt == NULL) | 
|  | 5247 | return; | 
|  | 5248 | ctxt->error = err; | 
|  | 5249 | ctxt->warning = warn; | 
|  | 5250 | ctxt->userData = ctx; | 
|  | 5251 | } | 
|  | 5252 | /************************************************************************ | 
|  | 5253 | * 									* | 
|  | 5254 | * 			Dump back a compiled form			* | 
|  | 5255 | * 									* | 
|  | 5256 | ************************************************************************/ | 
|  | 5257 | static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define); | 
|  | 5258 |  | 
|  | 5259 | /** | 
|  | 5260 | * xmlRelaxNGDumpDefines: | 
|  | 5261 | * @output:  the file output | 
|  | 5262 | * @defines:  a list of define structures | 
|  | 5263 | * | 
|  | 5264 | * Dump a RelaxNG structure back | 
|  | 5265 | */ | 
|  | 5266 | static void | 
|  | 5267 | xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) { | 
|  | 5268 | while (defines != NULL) { | 
|  | 5269 | xmlRelaxNGDumpDefine(output, defines); | 
|  | 5270 | defines = defines->next; | 
|  | 5271 | } | 
|  | 5272 | } | 
|  | 5273 |  | 
|  | 5274 | /** | 
|  | 5275 | * xmlRelaxNGDumpDefine: | 
|  | 5276 | * @output:  the file output | 
|  | 5277 | * @define:  a define structure | 
|  | 5278 | * | 
|  | 5279 | * Dump a RelaxNG structure back | 
|  | 5280 | */ | 
|  | 5281 | static void | 
|  | 5282 | xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) { | 
|  | 5283 | if (define == NULL) | 
|  | 5284 | return; | 
|  | 5285 | switch(define->type) { | 
|  | 5286 | case XML_RELAXNG_EMPTY: | 
|  | 5287 | fprintf(output, "<empty/>\n"); | 
|  | 5288 | break; | 
|  | 5289 | case XML_RELAXNG_NOT_ALLOWED: | 
|  | 5290 | fprintf(output, "<notAllowed/>\n"); | 
|  | 5291 | break; | 
|  | 5292 | case XML_RELAXNG_TEXT: | 
|  | 5293 | fprintf(output, "<text/>\n"); | 
|  | 5294 | break; | 
|  | 5295 | case XML_RELAXNG_ELEMENT: | 
|  | 5296 | fprintf(output, "<element>\n"); | 
|  | 5297 | if (define->name != NULL) { | 
|  | 5298 | fprintf(output, "<name"); | 
|  | 5299 | if (define->ns != NULL) | 
|  | 5300 | fprintf(output, " ns=\"%s\"", define->ns); | 
|  | 5301 | fprintf(output, ">%s</name>\n", define->name); | 
|  | 5302 | } | 
|  | 5303 | xmlRelaxNGDumpDefines(output, define->attrs); | 
|  | 5304 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5305 | fprintf(output, "</element>\n"); | 
|  | 5306 | break; | 
|  | 5307 | case XML_RELAXNG_LIST: | 
|  | 5308 | fprintf(output, "<list>\n"); | 
|  | 5309 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5310 | fprintf(output, "</list>\n"); | 
|  | 5311 | break; | 
|  | 5312 | case XML_RELAXNG_ONEORMORE: | 
|  | 5313 | fprintf(output, "<oneOrMore>\n"); | 
|  | 5314 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5315 | fprintf(output, "</oneOrMore>\n"); | 
|  | 5316 | break; | 
|  | 5317 | case XML_RELAXNG_ZEROORMORE: | 
|  | 5318 | fprintf(output, "<zeroOrMore>\n"); | 
|  | 5319 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5320 | fprintf(output, "</zeroOrMore>\n"); | 
|  | 5321 | break; | 
|  | 5322 | case XML_RELAXNG_CHOICE: | 
|  | 5323 | fprintf(output, "<choice>\n"); | 
|  | 5324 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5325 | fprintf(output, "</choice>\n"); | 
|  | 5326 | break; | 
|  | 5327 | case XML_RELAXNG_GROUP: | 
|  | 5328 | fprintf(output, "<group>\n"); | 
|  | 5329 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5330 | fprintf(output, "</group>\n"); | 
|  | 5331 | break; | 
|  | 5332 | case XML_RELAXNG_INTERLEAVE: | 
|  | 5333 | fprintf(output, "<interleave>\n"); | 
|  | 5334 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5335 | fprintf(output, "</interleave>\n"); | 
|  | 5336 | break; | 
|  | 5337 | case XML_RELAXNG_OPTIONAL: | 
|  | 5338 | fprintf(output, "<optional>\n"); | 
|  | 5339 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5340 | fprintf(output, "</optional>\n"); | 
|  | 5341 | break; | 
|  | 5342 | case XML_RELAXNG_ATTRIBUTE: | 
|  | 5343 | fprintf(output, "<attribute>\n"); | 
|  | 5344 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5345 | fprintf(output, "</attribute>\n"); | 
|  | 5346 | break; | 
|  | 5347 | case XML_RELAXNG_DEF: | 
|  | 5348 | fprintf(output, "<define"); | 
|  | 5349 | if (define->name != NULL) | 
|  | 5350 | fprintf(output, " name=\"%s\"", define->name); | 
|  | 5351 | fprintf(output, ">\n"); | 
|  | 5352 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5353 | fprintf(output, "</define>\n"); | 
|  | 5354 | break; | 
|  | 5355 | case XML_RELAXNG_REF: | 
|  | 5356 | fprintf(output, "<ref"); | 
|  | 5357 | if (define->name != NULL) | 
|  | 5358 | fprintf(output, " name=\"%s\"", define->name); | 
|  | 5359 | fprintf(output, ">\n"); | 
|  | 5360 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5361 | fprintf(output, "</ref>\n"); | 
|  | 5362 | break; | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 5363 | case XML_RELAXNG_PARENTREF: | 
|  | 5364 | fprintf(output, "<parentRef"); | 
|  | 5365 | if (define->name != NULL) | 
|  | 5366 | fprintf(output, " name=\"%s\"", define->name); | 
|  | 5367 | fprintf(output, ">\n"); | 
|  | 5368 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5369 | fprintf(output, "</parentRef>\n"); | 
|  | 5370 | break; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 5371 | case XML_RELAXNG_EXTERNALREF: | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5372 | fprintf(output, "<externalRef>"); | 
| Daniel Veillard | e431a27 | 2003-01-29 23:02:33 +0000 | [diff] [blame] | 5373 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5374 | fprintf(output, "</externalRef>\n"); | 
|  | 5375 | break; | 
|  | 5376 | case XML_RELAXNG_DATATYPE: | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5377 | case XML_RELAXNG_VALUE: | 
|  | 5378 | TODO | 
|  | 5379 | break; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 5380 | case XML_RELAXNG_START: | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 5381 | case XML_RELAXNG_EXCEPT: | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 5382 | case XML_RELAXNG_PARAM: | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 5383 | TODO | 
|  | 5384 | break; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 5385 | case XML_RELAXNG_NOOP: | 
|  | 5386 | xmlRelaxNGDumpDefines(output, define->content); | 
|  | 5387 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5388 | } | 
|  | 5389 | } | 
|  | 5390 |  | 
|  | 5391 | /** | 
|  | 5392 | * xmlRelaxNGDumpGrammar: | 
|  | 5393 | * @output:  the file output | 
|  | 5394 | * @grammar:  a grammar structure | 
|  | 5395 | * @top:  is this a top grammar | 
|  | 5396 | * | 
|  | 5397 | * Dump a RelaxNG structure back | 
|  | 5398 | */ | 
|  | 5399 | static void | 
|  | 5400 | xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top) | 
|  | 5401 | { | 
|  | 5402 | if (grammar == NULL) | 
|  | 5403 | return; | 
|  | 5404 |  | 
|  | 5405 | fprintf(output, "<grammar"); | 
|  | 5406 | if (top) | 
|  | 5407 | fprintf(output, | 
|  | 5408 | " xmlns=\"http://relaxng.org/ns/structure/1.0\""); | 
|  | 5409 | switch(grammar->combine) { | 
|  | 5410 | case XML_RELAXNG_COMBINE_UNDEFINED: | 
|  | 5411 | break; | 
|  | 5412 | case XML_RELAXNG_COMBINE_CHOICE: | 
|  | 5413 | fprintf(output, " combine=\"choice\""); | 
|  | 5414 | break; | 
|  | 5415 | case XML_RELAXNG_COMBINE_INTERLEAVE: | 
|  | 5416 | fprintf(output, " combine=\"interleave\""); | 
|  | 5417 | break; | 
|  | 5418 | default: | 
|  | 5419 | fprintf(output, " <!-- invalid combine value -->"); | 
|  | 5420 | } | 
|  | 5421 | fprintf(output, ">\n"); | 
|  | 5422 | if (grammar->start == NULL) { | 
|  | 5423 | fprintf(output, " <!-- grammar had no start -->"); | 
|  | 5424 | } else { | 
|  | 5425 | fprintf(output, "<start>\n"); | 
|  | 5426 | xmlRelaxNGDumpDefine(output, grammar->start); | 
|  | 5427 | fprintf(output, "</start>\n"); | 
|  | 5428 | } | 
|  | 5429 | /* TODO ? Dump the defines ? */ | 
|  | 5430 | fprintf(output, "</grammar>\n"); | 
|  | 5431 | } | 
|  | 5432 |  | 
|  | 5433 | /** | 
|  | 5434 | * xmlRelaxNGDump: | 
|  | 5435 | * @output:  the file output | 
|  | 5436 | * @schema:  a schema structure | 
|  | 5437 | * | 
|  | 5438 | * Dump a RelaxNG structure back | 
|  | 5439 | */ | 
|  | 5440 | void | 
|  | 5441 | xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema) | 
|  | 5442 | { | 
|  | 5443 | if (schema == NULL) { | 
|  | 5444 | fprintf(output, "RelaxNG empty or failed to compile\n"); | 
|  | 5445 | return; | 
|  | 5446 | } | 
|  | 5447 | fprintf(output, "RelaxNG: "); | 
|  | 5448 | if (schema->doc == NULL) { | 
|  | 5449 | fprintf(output, "no document\n"); | 
|  | 5450 | } else if (schema->doc->URL != NULL) { | 
|  | 5451 | fprintf(output, "%s\n", schema->doc->URL); | 
|  | 5452 | } else { | 
|  | 5453 | fprintf(output, "\n"); | 
|  | 5454 | } | 
|  | 5455 | if (schema->topgrammar == NULL) { | 
|  | 5456 | fprintf(output, "RelaxNG has no top grammar\n"); | 
|  | 5457 | return; | 
|  | 5458 | } | 
|  | 5459 | xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1); | 
|  | 5460 | } | 
|  | 5461 |  | 
| Daniel Veillard | febcca4 | 2003-02-16 15:44:18 +0000 | [diff] [blame] | 5462 | /** | 
|  | 5463 | * xmlRelaxNGDumpTree: | 
|  | 5464 | * @output:  the file output | 
|  | 5465 | * @schema:  a schema structure | 
|  | 5466 | * | 
|  | 5467 | * Dump the transformed RelaxNG tree. | 
|  | 5468 | */ | 
|  | 5469 | void | 
|  | 5470 | xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema) | 
|  | 5471 | { | 
|  | 5472 | if (schema == NULL) { | 
|  | 5473 | fprintf(output, "RelaxNG empty or failed to compile\n"); | 
|  | 5474 | return; | 
|  | 5475 | } | 
|  | 5476 | if (schema->doc == NULL) { | 
|  | 5477 | fprintf(output, "no document\n"); | 
|  | 5478 | } else { | 
|  | 5479 | xmlDocDump(output, schema->doc); | 
|  | 5480 | } | 
|  | 5481 | } | 
|  | 5482 |  | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5483 | /************************************************************************ | 
|  | 5484 | * 									* | 
|  | 5485 | * 			Validation implementation			* | 
|  | 5486 | * 									* | 
|  | 5487 | ************************************************************************/ | 
|  | 5488 | static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 5489 | xmlRelaxNGDefinePtr define); | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5490 | static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 5491 | xmlRelaxNGDefinePtr define); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5492 |  | 
|  | 5493 | /** | 
|  | 5494 | * xmlRelaxNGSkipIgnored: | 
|  | 5495 | * @ctxt:  a schema validation context | 
|  | 5496 | * @node:  the top node. | 
|  | 5497 | * | 
|  | 5498 | * Skip ignorable nodes in that context | 
|  | 5499 | * | 
|  | 5500 | * Returns the new sibling or NULL in case of error. | 
|  | 5501 | */ | 
|  | 5502 | static xmlNodePtr | 
|  | 5503 | xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED, | 
|  | 5504 | xmlNodePtr node) { | 
|  | 5505 | /* | 
|  | 5506 | * TODO complete and handle entities | 
|  | 5507 | */ | 
|  | 5508 | while ((node != NULL) && | 
|  | 5509 | ((node->type == XML_COMMENT_NODE) || | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 5510 | (node->type == XML_PI_NODE) || | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5511 | ((node->type == XML_TEXT_NODE) && | 
|  | 5512 | (IS_BLANK_NODE(node))))) { | 
|  | 5513 | node = node->next; | 
|  | 5514 | } | 
|  | 5515 | return(node); | 
|  | 5516 | } | 
|  | 5517 |  | 
|  | 5518 | /** | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 5519 | * xmlRelaxNGNormalize: | 
|  | 5520 | * @ctxt:  a schema validation context | 
|  | 5521 | * @str:  the string to normalize | 
|  | 5522 | * | 
|  | 5523 | * Implements the  normalizeWhiteSpace( s ) function from | 
|  | 5524 | * section 6.2.9 of the spec | 
|  | 5525 | * | 
|  | 5526 | * Returns the new string or NULL in case of error. | 
|  | 5527 | */ | 
|  | 5528 | static xmlChar * | 
|  | 5529 | xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) { | 
|  | 5530 | xmlChar *ret, *p; | 
|  | 5531 | const xmlChar *tmp; | 
|  | 5532 | int len; | 
|  | 5533 |  | 
|  | 5534 | if (str == NULL) | 
|  | 5535 | return(NULL); | 
|  | 5536 | tmp = str; | 
|  | 5537 | while (*tmp != 0) tmp++; | 
|  | 5538 | len = tmp - str; | 
|  | 5539 |  | 
|  | 5540 | ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar)); | 
|  | 5541 | if (ret == NULL) { | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 5542 | if (ctxt != NULL) { | 
|  | 5543 | VALID_CTXT(); | 
|  | 5544 | VALID_ERROR("xmlRelaxNGNormalize: out of memory\n"); | 
|  | 5545 | } else { | 
|  | 5546 | xmlGenericError(xmlGenericErrorContext, | 
|  | 5547 | "xmlRelaxNGNormalize: out of memory\n"); | 
|  | 5548 | } | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 5549 | return(NULL); | 
|  | 5550 | } | 
|  | 5551 | p = ret; | 
|  | 5552 | while (IS_BLANK(*str)) str++; | 
|  | 5553 | while (*str != 0) { | 
|  | 5554 | if (IS_BLANK(*str)) { | 
|  | 5555 | while (IS_BLANK(*str)) str++; | 
|  | 5556 | if (*str == 0) | 
|  | 5557 | break; | 
|  | 5558 | *p++ = ' '; | 
|  | 5559 | } else | 
|  | 5560 | *p++ = *str++; | 
|  | 5561 | } | 
|  | 5562 | *p = 0; | 
|  | 5563 | return(ret); | 
|  | 5564 | } | 
|  | 5565 |  | 
|  | 5566 | /** | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 5567 | * xmlRelaxNGValidateDatatype: | 
|  | 5568 | * @ctxt:  a Relax-NG validation context | 
|  | 5569 | * @value:  the string value | 
|  | 5570 | * @type:  the datatype definition | 
|  | 5571 | * | 
|  | 5572 | * Validate the given value against the dataype | 
|  | 5573 | * | 
|  | 5574 | * Returns 0 if the validation succeeded or an error code. | 
|  | 5575 | */ | 
|  | 5576 | static int | 
|  | 5577 | xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value, | 
|  | 5578 | xmlRelaxNGDefinePtr define) { | 
|  | 5579 | int ret; | 
|  | 5580 | xmlRelaxNGTypeLibraryPtr lib; | 
|  | 5581 |  | 
|  | 5582 | if ((define == NULL) || (define->data == NULL)) { | 
|  | 5583 | return(-1); | 
|  | 5584 | } | 
|  | 5585 | lib = (xmlRelaxNGTypeLibraryPtr) define->data; | 
|  | 5586 | if (lib->check != NULL) | 
|  | 5587 | ret = lib->check(lib->data, define->name, value); | 
|  | 5588 | else | 
|  | 5589 | ret = -1; | 
|  | 5590 | if (ret < 0) { | 
|  | 5591 | VALID_CTXT(); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 5592 | VALID_ERROR2("Internal: failed to validate type %s\n", define->name); | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 5593 | return(-1); | 
|  | 5594 | } else if (ret == 1) { | 
|  | 5595 | ret = 0; | 
|  | 5596 | } else { | 
|  | 5597 | VALID_CTXT(); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 5598 | VALID_ERROR3("Type %s doesn't allow value %s\n", define->name, value); | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 5599 | return(-1); | 
|  | 5600 | ret = -1; | 
|  | 5601 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5602 | if ((ret == 0) && (define->content != NULL)) { | 
|  | 5603 | const xmlChar *oldvalue, *oldendvalue; | 
|  | 5604 |  | 
|  | 5605 | oldvalue = ctxt->state->value; | 
|  | 5606 | oldendvalue = ctxt->state->endvalue; | 
|  | 5607 | ctxt->state->value = (xmlChar *) value; | 
|  | 5608 | ctxt->state->endvalue = NULL; | 
|  | 5609 | ret = xmlRelaxNGValidateValue(ctxt, define->content); | 
|  | 5610 | ctxt->state->value = (xmlChar *) oldvalue; | 
|  | 5611 | ctxt->state->endvalue = (xmlChar *) oldendvalue; | 
|  | 5612 | } | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 5613 | return(ret); | 
|  | 5614 | } | 
|  | 5615 |  | 
|  | 5616 | /** | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5617 | * xmlRelaxNGNextValue: | 
|  | 5618 | * @ctxt:  a Relax-NG validation context | 
|  | 5619 | * | 
|  | 5620 | * Skip to the next value when validating within a list | 
|  | 5621 | * | 
|  | 5622 | * Returns 0 if the operation succeeded or an error code. | 
|  | 5623 | */ | 
|  | 5624 | static int | 
|  | 5625 | xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) { | 
|  | 5626 | xmlChar *cur; | 
|  | 5627 |  | 
|  | 5628 | cur = ctxt->state->value; | 
|  | 5629 | if ((cur == NULL) || (ctxt->state->endvalue == NULL)) { | 
|  | 5630 | ctxt->state->value = NULL; | 
| Daniel Veillard | e5b110b | 2003-02-04 14:43:39 +0000 | [diff] [blame] | 5631 | ctxt->state->endvalue = NULL; | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5632 | return(0); | 
|  | 5633 | } | 
|  | 5634 | while (*cur != 0) cur++; | 
|  | 5635 | while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++; | 
|  | 5636 | if (cur == ctxt->state->endvalue) | 
|  | 5637 | ctxt->state->value = NULL; | 
|  | 5638 | else | 
|  | 5639 | ctxt->state->value = cur; | 
|  | 5640 | return(0); | 
|  | 5641 | } | 
|  | 5642 |  | 
|  | 5643 | /** | 
|  | 5644 | * xmlRelaxNGValidateValueList: | 
|  | 5645 | * @ctxt:  a Relax-NG validation context | 
|  | 5646 | * @defines:  the list of definitions to verify | 
|  | 5647 | * | 
|  | 5648 | * Validate the given set of definitions for the current value | 
|  | 5649 | * | 
|  | 5650 | * Returns 0 if the validation succeeded or an error code. | 
|  | 5651 | */ | 
|  | 5652 | static int | 
|  | 5653 | xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 5654 | xmlRelaxNGDefinePtr defines) { | 
|  | 5655 | int ret = 0; | 
|  | 5656 |  | 
|  | 5657 | while (defines != NULL) { | 
|  | 5658 | ret = xmlRelaxNGValidateValue(ctxt, defines); | 
|  | 5659 | if (ret != 0) | 
|  | 5660 | break; | 
|  | 5661 | defines = defines->next; | 
|  | 5662 | } | 
|  | 5663 | return(ret); | 
|  | 5664 | } | 
|  | 5665 |  | 
|  | 5666 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5667 | * xmlRelaxNGValidateValue: | 
|  | 5668 | * @ctxt:  a Relax-NG validation context | 
|  | 5669 | * @define:  the definition to verify | 
|  | 5670 | * | 
|  | 5671 | * Validate the given definition for the current value | 
|  | 5672 | * | 
|  | 5673 | * Returns 0 if the validation succeeded or an error code. | 
|  | 5674 | */ | 
|  | 5675 | static int | 
|  | 5676 | xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 5677 | xmlRelaxNGDefinePtr define) { | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 5678 | int ret = 0, oldflags; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5679 | xmlChar *value; | 
|  | 5680 |  | 
|  | 5681 | value = ctxt->state->value; | 
|  | 5682 | switch (define->type) { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 5683 | case XML_RELAXNG_EMPTY: { | 
|  | 5684 | if ((value != NULL) && (value[0] != 0)) { | 
|  | 5685 | int idx = 0; | 
|  | 5686 |  | 
|  | 5687 | while (IS_BLANK(value[idx])) | 
|  | 5688 | idx++; | 
|  | 5689 | if (value[idx] != 0) | 
|  | 5690 | ret = -1; | 
|  | 5691 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5692 | break; | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 5693 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5694 | case XML_RELAXNG_TEXT: | 
|  | 5695 | break; | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 5696 | case XML_RELAXNG_VALUE: { | 
|  | 5697 | if (!xmlStrEqual(value, define->value)) { | 
|  | 5698 | if (define->name != NULL) { | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 5699 | xmlRelaxNGTypeLibraryPtr lib; | 
|  | 5700 |  | 
|  | 5701 | lib = (xmlRelaxNGTypeLibraryPtr) define->data; | 
|  | 5702 | if ((lib != NULL) && (lib->comp != NULL)) | 
|  | 5703 | ret = lib->comp(lib->data, define->name, value, | 
|  | 5704 | define->value); | 
|  | 5705 | else | 
|  | 5706 | ret = -1; | 
|  | 5707 | if (ret < 0) { | 
|  | 5708 | VALID_CTXT(); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 5709 | VALID_ERROR2("Internal: failed to compare type %s\n", | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 5710 | define->name); | 
|  | 5711 | return(-1); | 
|  | 5712 | } else if (ret == 1) { | 
|  | 5713 | ret = 0; | 
|  | 5714 | } else { | 
|  | 5715 | ret = -1; | 
|  | 5716 | } | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 5717 | } else { | 
|  | 5718 | xmlChar *nval, *nvalue; | 
|  | 5719 |  | 
|  | 5720 | /* | 
|  | 5721 | * TODO: trivial optimizations are possible by | 
|  | 5722 | * computing at compile-time | 
|  | 5723 | */ | 
|  | 5724 | nval = xmlRelaxNGNormalize(ctxt, define->value); | 
|  | 5725 | nvalue = xmlRelaxNGNormalize(ctxt, value); | 
|  | 5726 |  | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 5727 | if ((nval == NULL) || (nvalue == NULL) || | 
|  | 5728 | (!xmlStrEqual(nval, nvalue))) | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 5729 | ret = -1; | 
|  | 5730 | if (nval != NULL) | 
|  | 5731 | xmlFree(nval); | 
|  | 5732 | if (nvalue != NULL) | 
|  | 5733 | xmlFree(nvalue); | 
|  | 5734 | } | 
|  | 5735 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5736 | if (ret == 0) | 
|  | 5737 | xmlRelaxNGNextValue(ctxt); | 
| Daniel Veillard | edc9192 | 2003-01-26 00:52:04 +0000 | [diff] [blame] | 5738 | break; | 
|  | 5739 | } | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5740 | case XML_RELAXNG_DATATYPE: { | 
|  | 5741 | ret = xmlRelaxNGValidateDatatype(ctxt, value, define); | 
|  | 5742 | if (ret == 0) | 
|  | 5743 | xmlRelaxNGNextValue(ctxt); | 
|  | 5744 |  | 
|  | 5745 | break; | 
|  | 5746 | } | 
|  | 5747 | case XML_RELAXNG_CHOICE: { | 
|  | 5748 | xmlRelaxNGDefinePtr list = define->content; | 
|  | 5749 | xmlChar *oldvalue; | 
|  | 5750 |  | 
|  | 5751 | oldflags = ctxt->flags; | 
|  | 5752 | ctxt->flags |= FLAGS_IGNORABLE; | 
|  | 5753 |  | 
|  | 5754 | oldvalue = ctxt->state->value; | 
|  | 5755 | while (list != NULL) { | 
|  | 5756 | ret = xmlRelaxNGValidateValue(ctxt, list); | 
|  | 5757 | if (ret == 0) { | 
|  | 5758 | break; | 
|  | 5759 | } | 
|  | 5760 | ctxt->state->value = oldvalue; | 
|  | 5761 | list = list->next; | 
|  | 5762 | } | 
|  | 5763 | ctxt->flags = oldflags; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5764 | if (ret == 0) | 
|  | 5765 | xmlRelaxNGNextValue(ctxt); | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5766 | break; | 
|  | 5767 | } | 
|  | 5768 | case XML_RELAXNG_LIST: { | 
|  | 5769 | xmlRelaxNGDefinePtr list = define->content; | 
|  | 5770 | xmlChar *oldvalue, *oldend, *val, *cur; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5771 | #ifdef DEBUG_LIST | 
|  | 5772 | int nb_values = 0; | 
|  | 5773 | #endif | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5774 |  | 
|  | 5775 | oldvalue = ctxt->state->value; | 
|  | 5776 | oldend = ctxt->state->endvalue; | 
|  | 5777 |  | 
|  | 5778 | val = xmlStrdup(oldvalue); | 
|  | 5779 | if (val == NULL) { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 5780 | val = xmlStrdup(BAD_CAST ""); | 
|  | 5781 | } | 
|  | 5782 | if (val == NULL) { | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5783 | VALID_CTXT(); | 
|  | 5784 | VALID_ERROR("Internal: no state\n"); | 
|  | 5785 | return(-1); | 
|  | 5786 | } | 
|  | 5787 | cur = val; | 
|  | 5788 | while (*cur != 0) { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5789 | if (IS_BLANK(*cur)) { | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5790 | *cur = 0; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5791 | cur++; | 
|  | 5792 | #ifdef DEBUG_LIST | 
|  | 5793 | nb_values++; | 
|  | 5794 | #endif | 
|  | 5795 | while (IS_BLANK(*cur)) | 
|  | 5796 | *cur++ = 0; | 
|  | 5797 | } else | 
|  | 5798 | cur++; | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5799 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5800 | #ifdef DEBUG_LIST | 
|  | 5801 | xmlGenericError(xmlGenericErrorContext, | 
|  | 5802 | "list value: '%s' found %d items\n", oldvalue, nb_values); | 
|  | 5803 | nb_values = 0; | 
|  | 5804 | #endif | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5805 | ctxt->state->endvalue = cur; | 
|  | 5806 | cur = val; | 
|  | 5807 | while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++; | 
|  | 5808 |  | 
|  | 5809 | ctxt->state->value = cur; | 
|  | 5810 |  | 
|  | 5811 | while (list != NULL) { | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 5812 | if (ctxt->state->value == ctxt->state->endvalue) | 
|  | 5813 | ctxt->state->value = NULL; | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5814 | ret = xmlRelaxNGValidateValue(ctxt, list); | 
|  | 5815 | if (ret != 0) { | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5816 | #ifdef DEBUG_LIST | 
|  | 5817 | xmlGenericError(xmlGenericErrorContext, | 
|  | 5818 | "Failed to validate value: '%s' with %d rule\n", | 
|  | 5819 | ctxt->state->value, nb_values); | 
|  | 5820 | #endif | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5821 | break; | 
|  | 5822 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5823 | #ifdef DEBUG_LIST | 
|  | 5824 | nb_values++; | 
|  | 5825 | #endif | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5826 | list = list->next; | 
|  | 5827 | } | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 5828 |  | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5829 | if ((ret == 0) && (ctxt->state->value != NULL) && | 
|  | 5830 | (ctxt->state->value != ctxt->state->endvalue)) { | 
|  | 5831 | VALID_CTXT(); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 5832 | VALID_ERROR2("Extra data in list: %s\n", ctxt->state->value); | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 5833 | ret = -1; | 
|  | 5834 | } | 
|  | 5835 | xmlFree(val); | 
|  | 5836 | ctxt->state->value = oldvalue; | 
|  | 5837 | ctxt->state->endvalue = oldend; | 
|  | 5838 | break; | 
|  | 5839 | } | 
|  | 5840 | case XML_RELAXNG_ONEORMORE: | 
|  | 5841 | ret = xmlRelaxNGValidateValueList(ctxt, define->content); | 
|  | 5842 | if (ret != 0) { | 
|  | 5843 | break; | 
|  | 5844 | } | 
|  | 5845 | /* no break on purpose */ | 
|  | 5846 | case XML_RELAXNG_ZEROORMORE: { | 
|  | 5847 | xmlChar *cur, *temp; | 
|  | 5848 |  | 
|  | 5849 | oldflags = ctxt->flags; | 
|  | 5850 | ctxt->flags |= FLAGS_IGNORABLE; | 
|  | 5851 | cur = ctxt->state->value; | 
|  | 5852 | temp = NULL; | 
|  | 5853 | while ((cur != NULL) && (cur != ctxt->state->endvalue) && | 
|  | 5854 | (temp != cur)) { | 
|  | 5855 | temp = cur; | 
|  | 5856 | ret = xmlRelaxNGValidateValueList(ctxt, define->content); | 
|  | 5857 | if (ret != 0) { | 
|  | 5858 | ctxt->state->value = temp; | 
|  | 5859 | ret = 0; | 
|  | 5860 | break; | 
|  | 5861 | } | 
|  | 5862 | cur = ctxt->state->value; | 
|  | 5863 | } | 
|  | 5864 | ctxt->flags = oldflags; | 
|  | 5865 | break; | 
|  | 5866 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 5867 | case XML_RELAXNG_EXCEPT: { | 
|  | 5868 | xmlRelaxNGDefinePtr list; | 
|  | 5869 |  | 
|  | 5870 | list = define->content; | 
|  | 5871 | while (list != NULL) { | 
|  | 5872 | ret = xmlRelaxNGValidateValue(ctxt, list); | 
|  | 5873 | if (ret == 0) { | 
|  | 5874 | ret = -1; | 
|  | 5875 | break; | 
|  | 5876 | } else | 
|  | 5877 | ret = 0; | 
|  | 5878 | list = list->next; | 
|  | 5879 | } | 
|  | 5880 | break; | 
|  | 5881 | } | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 5882 | case XML_RELAXNG_GROUP: { | 
|  | 5883 | xmlRelaxNGDefinePtr list; | 
|  | 5884 |  | 
|  | 5885 | list = define->content; | 
|  | 5886 | while (list != NULL) { | 
|  | 5887 | ret = xmlRelaxNGValidateValue(ctxt, list); | 
|  | 5888 | if (ret != 0) { | 
|  | 5889 | ret = -1; | 
|  | 5890 | break; | 
|  | 5891 | } else | 
|  | 5892 | ret = 0; | 
|  | 5893 | list = list->next; | 
|  | 5894 | } | 
|  | 5895 | break; | 
|  | 5896 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5897 | default: | 
|  | 5898 | TODO | 
|  | 5899 | ret = -1; | 
|  | 5900 | } | 
|  | 5901 | return(ret); | 
|  | 5902 | } | 
|  | 5903 |  | 
|  | 5904 | /** | 
|  | 5905 | * xmlRelaxNGValidateValueContent: | 
|  | 5906 | * @ctxt:  a Relax-NG validation context | 
|  | 5907 | * @defines:  the list of definitions to verify | 
|  | 5908 | * | 
|  | 5909 | * Validate the given definitions for the current value | 
|  | 5910 | * | 
|  | 5911 | * Returns 0 if the validation succeeded or an error code. | 
|  | 5912 | */ | 
|  | 5913 | static int | 
|  | 5914 | xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 5915 | xmlRelaxNGDefinePtr defines) { | 
|  | 5916 | int ret = 0; | 
|  | 5917 |  | 
|  | 5918 | while (defines != NULL) { | 
|  | 5919 | ret = xmlRelaxNGValidateValue(ctxt, defines); | 
|  | 5920 | if (ret != 0) | 
|  | 5921 | break; | 
|  | 5922 | defines = defines->next; | 
|  | 5923 | } | 
|  | 5924 | return(ret); | 
|  | 5925 | } | 
|  | 5926 |  | 
|  | 5927 | /** | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 5928 | * xmlRelaxNGAttributeMatch: | 
|  | 5929 | * @ctxt:  a Relax-NG validation context | 
|  | 5930 | * @define:  the definition to check | 
|  | 5931 | * @prop:  the attribute | 
|  | 5932 | * | 
|  | 5933 | * Check if the attribute matches the definition nameClass | 
|  | 5934 | * | 
|  | 5935 | * Returns 1 if the attribute matches, 0 if no, or -1 in case of error | 
|  | 5936 | */ | 
|  | 5937 | static int | 
|  | 5938 | xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 5939 | xmlRelaxNGDefinePtr define, | 
|  | 5940 | xmlAttrPtr prop) { | 
|  | 5941 | int ret; | 
|  | 5942 |  | 
|  | 5943 | if (define->name != NULL) { | 
|  | 5944 | if (!xmlStrEqual(define->name, prop->name)) | 
|  | 5945 | return(0); | 
|  | 5946 | } | 
|  | 5947 | if (define->ns != NULL) { | 
|  | 5948 | if (define->ns[0] == 0) { | 
|  | 5949 | if (prop->ns != NULL) | 
|  | 5950 | return(0); | 
|  | 5951 | } else { | 
|  | 5952 | if ((prop->ns == NULL) || | 
|  | 5953 | (!xmlStrEqual(define->ns, prop->ns->href))) | 
|  | 5954 | return(0); | 
|  | 5955 | } | 
|  | 5956 | } | 
|  | 5957 | if (define->nameClass == NULL) | 
|  | 5958 | return(1); | 
|  | 5959 | define = define->nameClass; | 
|  | 5960 | if (define->type == XML_RELAXNG_EXCEPT) { | 
|  | 5961 | xmlRelaxNGDefinePtr list; | 
|  | 5962 |  | 
|  | 5963 | list = define->content; | 
|  | 5964 | while (list != NULL) { | 
|  | 5965 | ret = xmlRelaxNGAttributeMatch(ctxt, list, prop); | 
|  | 5966 | if (ret == 1) | 
|  | 5967 | return(0); | 
|  | 5968 | if (ret < 0) | 
|  | 5969 | return(ret); | 
|  | 5970 | list = list->next; | 
|  | 5971 | } | 
|  | 5972 | } else { | 
|  | 5973 | TODO | 
|  | 5974 | } | 
|  | 5975 | return(1); | 
|  | 5976 | } | 
|  | 5977 |  | 
|  | 5978 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5979 | * xmlRelaxNGValidateAttribute: | 
|  | 5980 | * @ctxt:  a Relax-NG validation context | 
|  | 5981 | * @define:  the definition to verify | 
|  | 5982 | * | 
|  | 5983 | * Validate the given attribute definition for that node | 
|  | 5984 | * | 
|  | 5985 | * Returns 0 if the validation succeeded or an error code. | 
|  | 5986 | */ | 
|  | 5987 | static int | 
|  | 5988 | xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 5989 | xmlRelaxNGDefinePtr define) { | 
|  | 5990 | int ret = 0, i; | 
|  | 5991 | xmlChar *value, *oldvalue; | 
|  | 5992 | xmlAttrPtr prop = NULL, tmp; | 
|  | 5993 |  | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 5994 | if (ctxt->state->nbAttrLeft <= 0) | 
|  | 5995 | return(-1); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 5996 | if (define->name != NULL) { | 
|  | 5997 | for (i = 0;i < ctxt->state->nbAttrs;i++) { | 
|  | 5998 | tmp = ctxt->state->attrs[i]; | 
|  | 5999 | if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) { | 
|  | 6000 | if ((((define->ns == NULL) || (define->ns[0] == 0)) && | 
|  | 6001 | (tmp->ns == NULL)) || | 
|  | 6002 | ((tmp->ns != NULL) && | 
|  | 6003 | (xmlStrEqual(define->ns, tmp->ns->href)))) { | 
|  | 6004 | prop = tmp; | 
|  | 6005 | break; | 
|  | 6006 | } | 
|  | 6007 | } | 
|  | 6008 | } | 
|  | 6009 | if (prop != NULL) { | 
|  | 6010 | value = xmlNodeListGetString(prop->doc, prop->children, 1); | 
|  | 6011 | oldvalue = ctxt->state->value; | 
|  | 6012 | ctxt->state->value = value; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6013 | ctxt->state->endvalue = NULL; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6014 | ret = xmlRelaxNGValidateValueContent(ctxt, define->content); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6015 | if (ctxt->state->value != NULL) | 
|  | 6016 | value = ctxt->state->value; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6017 | if (value != NULL) | 
|  | 6018 | xmlFree(value); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6019 | ctxt->state->value = oldvalue; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6020 | if (ret == 0) { | 
|  | 6021 | /* | 
|  | 6022 | * flag the attribute as processed | 
|  | 6023 | */ | 
|  | 6024 | ctxt->state->attrs[i] = NULL; | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 6025 | ctxt->state->nbAttrLeft--; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6026 | } | 
|  | 6027 | } else { | 
|  | 6028 | ret = -1; | 
|  | 6029 | } | 
|  | 6030 | #ifdef DEBUG | 
|  | 6031 | xmlGenericError(xmlGenericErrorContext, | 
|  | 6032 | "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret); | 
|  | 6033 | #endif | 
|  | 6034 | } else { | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 6035 | for (i = 0;i < ctxt->state->nbAttrs;i++) { | 
|  | 6036 | tmp = ctxt->state->attrs[i]; | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 6037 | if ((tmp != NULL) && | 
|  | 6038 | (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) { | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 6039 | prop = tmp; | 
|  | 6040 | break; | 
|  | 6041 | } | 
|  | 6042 | } | 
|  | 6043 | if (prop != NULL) { | 
|  | 6044 | value = xmlNodeListGetString(prop->doc, prop->children, 1); | 
|  | 6045 | oldvalue = ctxt->state->value; | 
|  | 6046 | ctxt->state->value = value; | 
|  | 6047 | ret = xmlRelaxNGValidateValueContent(ctxt, define->content); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6048 | if (ctxt->state->value != NULL) | 
|  | 6049 | value = ctxt->state->value; | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 6050 | if (value != NULL) | 
|  | 6051 | xmlFree(value); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6052 | ctxt->state->value = oldvalue; | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 6053 | if (ret == 0) { | 
|  | 6054 | /* | 
|  | 6055 | * flag the attribute as processed | 
|  | 6056 | */ | 
|  | 6057 | ctxt->state->attrs[i] = NULL; | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 6058 | ctxt->state->nbAttrLeft--; | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 6059 | } | 
|  | 6060 | } else { | 
|  | 6061 | ret = -1; | 
|  | 6062 | } | 
|  | 6063 | #ifdef DEBUG | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 6064 | if (define->ns != NULL) { | 
|  | 6065 | xmlGenericError(xmlGenericErrorContext, | 
|  | 6066 | "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n", | 
|  | 6067 | define->ns, ret); | 
|  | 6068 | } else { | 
|  | 6069 | xmlGenericError(xmlGenericErrorContext, | 
|  | 6070 | "xmlRelaxNGValidateAttribute(anyName): %d\n", | 
|  | 6071 | ret); | 
|  | 6072 | } | 
| Daniel Veillard | 3b2e4e1 | 2003-02-03 08:52:58 +0000 | [diff] [blame] | 6073 | #endif | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6074 | } | 
|  | 6075 |  | 
|  | 6076 | return(ret); | 
|  | 6077 | } | 
|  | 6078 |  | 
|  | 6079 | /** | 
|  | 6080 | * xmlRelaxNGValidateAttributeList: | 
|  | 6081 | * @ctxt:  a Relax-NG validation context | 
|  | 6082 | * @define:  the list of definition to verify | 
|  | 6083 | * | 
|  | 6084 | * Validate the given node against the list of attribute definitions | 
|  | 6085 | * | 
|  | 6086 | * Returns 0 if the validation succeeded or an error code. | 
|  | 6087 | */ | 
|  | 6088 | static int | 
|  | 6089 | xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 6090 | xmlRelaxNGDefinePtr defines) { | 
|  | 6091 | int ret = 0; | 
|  | 6092 | while (defines != NULL) { | 
|  | 6093 | if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0) | 
|  | 6094 | ret = -1; | 
|  | 6095 | defines = defines->next; | 
|  | 6096 | } | 
|  | 6097 | return(ret); | 
|  | 6098 | } | 
|  | 6099 |  | 
|  | 6100 | /** | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6101 | * xmlRelaxNGValidateTryPermutation: | 
|  | 6102 | * @ctxt:  a Relax-NG validation context | 
|  | 6103 | * @groups:  the array of groups | 
|  | 6104 | * @nbgroups:  the number of groups in the array | 
|  | 6105 | * @array:  the permutation to try | 
|  | 6106 | * @len:  the size of the set | 
|  | 6107 | * | 
|  | 6108 | * Try to validate a permutation for the group of definitions. | 
|  | 6109 | * | 
|  | 6110 | * Returns 0 if the validation succeeded or an error code. | 
|  | 6111 | */ | 
|  | 6112 | static int | 
|  | 6113 | xmlRelaxNGValidateTryPermutation(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 6114 | xmlRelaxNGDefinePtr rule, | 
|  | 6115 | xmlNodePtr *array, int len) { | 
|  | 6116 | int i, ret; | 
|  | 6117 |  | 
|  | 6118 | if (len > 0) { | 
|  | 6119 | /* | 
|  | 6120 | * One only need the next pointer set-up to do the validation | 
|  | 6121 | */ | 
|  | 6122 | for (i = 0;i < (len - 1);i++) | 
|  | 6123 | array[i]->next = array[i + 1]; | 
|  | 6124 | array[i]->next = NULL; | 
|  | 6125 |  | 
|  | 6126 | /* | 
|  | 6127 | * Now try to validate the sequence | 
|  | 6128 | */ | 
|  | 6129 | ctxt->state->seq = array[0]; | 
|  | 6130 | ret = xmlRelaxNGValidateDefinition(ctxt, rule); | 
|  | 6131 | } else { | 
|  | 6132 | ctxt->state->seq = NULL; | 
|  | 6133 | ret = xmlRelaxNGValidateDefinition(ctxt, rule); | 
|  | 6134 | } | 
|  | 6135 |  | 
|  | 6136 | /* | 
|  | 6137 | * the sequence must be fully consumed | 
|  | 6138 | */ | 
|  | 6139 | if (ctxt->state->seq != NULL) | 
|  | 6140 | return(-1); | 
|  | 6141 |  | 
|  | 6142 | return(ret); | 
|  | 6143 | } | 
|  | 6144 |  | 
|  | 6145 | /** | 
|  | 6146 | * xmlRelaxNGValidateWalkPermutations: | 
|  | 6147 | * @ctxt:  a Relax-NG validation context | 
|  | 6148 | * @groups:  the array of groups | 
|  | 6149 | * @nbgroups:  the number of groups in the array | 
|  | 6150 | * @nodes:  the set of nodes | 
|  | 6151 | * @array:  the current state of the parmutation | 
|  | 6152 | * @len:  the size of the set | 
|  | 6153 | * @level:  a pointer to the level variable | 
|  | 6154 | * @k:  the index in the array to fill | 
|  | 6155 | * | 
|  | 6156 | * Validate a set of nodes for a groups of definitions, will try the | 
|  | 6157 | * full set of permutations | 
|  | 6158 | * | 
|  | 6159 | * Returns 0 if the validation succeeded or an error code. | 
|  | 6160 | */ | 
|  | 6161 | static int | 
|  | 6162 | xmlRelaxNGValidateWalkPermutations(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 6163 | xmlRelaxNGDefinePtr rule, xmlNodePtr *nodes, | 
|  | 6164 | xmlNodePtr *array, int len, | 
|  | 6165 | int *level, int k) { | 
|  | 6166 | int i, ret; | 
|  | 6167 |  | 
|  | 6168 | if ((k >= 0) && (k < len)) | 
|  | 6169 | array[k] = nodes[*level]; | 
|  | 6170 | *level = *level + 1; | 
|  | 6171 | if (*level == len) { | 
|  | 6172 | ret = xmlRelaxNGValidateTryPermutation(ctxt, rule, array, len); | 
|  | 6173 | if (ret == 0) | 
|  | 6174 | return(0); | 
|  | 6175 | } else { | 
|  | 6176 | for (i = 0;i < len;i++) { | 
|  | 6177 | if (array[i] == NULL) { | 
|  | 6178 | ret = xmlRelaxNGValidateWalkPermutations(ctxt, rule, | 
|  | 6179 | nodes, array, len, level, i); | 
|  | 6180 | if (ret == 0) | 
|  | 6181 | return(0); | 
|  | 6182 | } | 
|  | 6183 | } | 
|  | 6184 | } | 
|  | 6185 | *level = *level - 1; | 
|  | 6186 | array[k] = NULL; | 
|  | 6187 | return(-1); | 
|  | 6188 | } | 
|  | 6189 |  | 
|  | 6190 | /** | 
|  | 6191 | * xmlRelaxNGNodeMatchesList: | 
|  | 6192 | * @node:  the node | 
|  | 6193 | * @list:  a NULL terminated array of definitions | 
|  | 6194 | * | 
|  | 6195 | * Check if a node can be matched by one of the definitions | 
|  | 6196 | * | 
|  | 6197 | * Returns 1 if matches 0 otherwise | 
|  | 6198 | */ | 
|  | 6199 | static int | 
|  | 6200 | xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) { | 
|  | 6201 | xmlRelaxNGDefinePtr cur; | 
|  | 6202 | int i = 0; | 
|  | 6203 |  | 
|  | 6204 | if ((node == NULL) || (list == NULL)) | 
|  | 6205 | return(0); | 
|  | 6206 |  | 
|  | 6207 | cur = list[i++]; | 
|  | 6208 | while (cur != NULL) { | 
|  | 6209 | if ((node->type == XML_ELEMENT_NODE) && | 
|  | 6210 | (cur->type == XML_RELAXNG_ELEMENT)) { | 
|  | 6211 | if (cur->name == NULL) { | 
|  | 6212 | if ((node->ns != NULL) && | 
|  | 6213 | (xmlStrEqual(node->ns->href, cur->ns))) | 
|  | 6214 | return(1); | 
|  | 6215 | } else if (xmlStrEqual(cur->name, node->name)) { | 
|  | 6216 | if ((cur->ns == NULL) || (cur->ns[0] == 0)) { | 
|  | 6217 | if (node->ns == NULL) | 
|  | 6218 | return(1); | 
|  | 6219 | } else { | 
|  | 6220 | if ((node->ns != NULL) && | 
|  | 6221 | (xmlStrEqual(node->ns->href, cur->ns))) | 
|  | 6222 | return(1); | 
|  | 6223 | } | 
|  | 6224 | } | 
|  | 6225 | } else if ((node->type == XML_TEXT_NODE) && | 
|  | 6226 | (cur->type == XML_RELAXNG_TEXT)) { | 
|  | 6227 | return(1); | 
|  | 6228 | } | 
|  | 6229 | cur = list[i++]; | 
|  | 6230 | } | 
|  | 6231 | return(0); | 
|  | 6232 | } | 
|  | 6233 |  | 
|  | 6234 | /** | 
|  | 6235 | * xmlRelaxNGValidatePartGroup: | 
|  | 6236 | * @ctxt:  a Relax-NG validation context | 
|  | 6237 | * @groups:  the array of groups | 
|  | 6238 | * @nbgroups:  the number of groups in the array | 
|  | 6239 | * @nodes:  the set of nodes | 
|  | 6240 | * @len:  the size of the set of nodes | 
|  | 6241 | * | 
|  | 6242 | * Validate a set of nodes for a groups of definitions | 
|  | 6243 | * | 
|  | 6244 | * Returns 0 if the validation succeeded or an error code. | 
|  | 6245 | */ | 
|  | 6246 | static int | 
|  | 6247 | xmlRelaxNGValidatePartGroup(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 6248 | xmlRelaxNGInterleaveGroupPtr *groups, | 
|  | 6249 | int nbgroups, xmlNodePtr *nodes, int len) { | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6250 | int level, ret = -1, i, j, k, top_j, max_j; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6251 | xmlNodePtr *array = NULL, *list, oldseq; | 
|  | 6252 | xmlRelaxNGInterleaveGroupPtr group; | 
|  | 6253 |  | 
|  | 6254 | list = (xmlNodePtr *) xmlMalloc(len * sizeof(xmlNodePtr)); | 
|  | 6255 | if (list == NULL) { | 
|  | 6256 | return(-1); | 
|  | 6257 | } | 
|  | 6258 | array = (xmlNodePtr *) xmlMalloc(len * sizeof(xmlNodePtr)); | 
|  | 6259 | if (array == NULL) { | 
|  | 6260 | xmlFree(list); | 
|  | 6261 | return(-1); | 
|  | 6262 | } | 
|  | 6263 | memset(array, 0, len * sizeof(xmlNodePtr)); | 
|  | 6264 |  | 
|  | 6265 | /* | 
|  | 6266 | * Partition the elements and validate the subsets. | 
|  | 6267 | */ | 
|  | 6268 | oldseq = ctxt->state->seq; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6269 | max_j = -1; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6270 | for (i = 0;i < nbgroups;i++) { | 
|  | 6271 | group = groups[i]; | 
|  | 6272 | if (group == NULL) | 
|  | 6273 | continue; | 
|  | 6274 | k = 0; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6275 | top_j = -1; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6276 | for (j = 0;j < len;j++) { | 
|  | 6277 | if (nodes[j] == NULL) | 
|  | 6278 | continue; | 
|  | 6279 | if (xmlRelaxNGNodeMatchesList(nodes[j], group->defs)) { | 
|  | 6280 | list[k++] = nodes[j]; | 
|  | 6281 | nodes[j] = NULL; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6282 | top_j = j; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6283 | } | 
|  | 6284 | } | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6285 | if (top_j > max_j) | 
|  | 6286 | max_j = top_j; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6287 | ctxt->state->seq = oldseq; | 
|  | 6288 | if (k > 1) { | 
|  | 6289 | memset(array, 0, k * sizeof(xmlNodePtr)); | 
| Daniel Veillard | b08c981 | 2003-01-28 23:09:49 +0000 | [diff] [blame] | 6290 | level = -1; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6291 | ret = xmlRelaxNGValidateWalkPermutations(ctxt, group->rule, | 
|  | 6292 | list, array, k, &level, -1); | 
|  | 6293 | } else { | 
|  | 6294 | ret = xmlRelaxNGValidateTryPermutation(ctxt, group->rule, list, k); | 
|  | 6295 | } | 
|  | 6296 | if (ret != 0) { | 
|  | 6297 | ctxt->state->seq = oldseq; | 
|  | 6298 | break; | 
|  | 6299 | } | 
|  | 6300 | } | 
|  | 6301 |  | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6302 | for (j = 0;j < max_j;j++) { | 
|  | 6303 | if (nodes[j] != NULL) { | 
|  | 6304 | TODO /* problem, one of the nodes didn't got a match */ | 
|  | 6305 | } | 
|  | 6306 | } | 
|  | 6307 | if (ret == 0) { | 
|  | 6308 | if (max_j + 1 < len) | 
|  | 6309 | ctxt->state->seq = nodes[max_j + 1]; | 
|  | 6310 | else | 
|  | 6311 | ctxt->state->seq = NULL; | 
|  | 6312 | } | 
|  | 6313 |  | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6314 | xmlFree(list); | 
|  | 6315 | xmlFree(array); | 
|  | 6316 | return(ret); | 
|  | 6317 | } | 
|  | 6318 |  | 
|  | 6319 | /** | 
|  | 6320 | * xmlRelaxNGValidateInterleave: | 
|  | 6321 | * @ctxt:  a Relax-NG validation context | 
|  | 6322 | * @define:  the definition to verify | 
|  | 6323 | * | 
|  | 6324 | * Validate an interleave definition for a node. | 
|  | 6325 | * | 
|  | 6326 | * Returns 0 if the validation succeeded or an error code. | 
|  | 6327 | */ | 
|  | 6328 | static int | 
|  | 6329 | xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 6330 | xmlRelaxNGDefinePtr define) { | 
|  | 6331 | int ret = 0, nbchildren, nbtot, i, j; | 
|  | 6332 | xmlRelaxNGPartitionPtr partitions; | 
|  | 6333 | xmlNodePtr *children = NULL; | 
|  | 6334 | xmlNodePtr *order = NULL; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6335 | xmlNodePtr cur, oldseq; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6336 |  | 
|  | 6337 | if (define->data != NULL) { | 
|  | 6338 | partitions = (xmlRelaxNGPartitionPtr) define->data; | 
|  | 6339 | } else { | 
|  | 6340 | VALID_CTXT(); | 
|  | 6341 | VALID_ERROR("Internal: interleave block has no data\n"); | 
|  | 6342 | return(-1); | 
|  | 6343 | } | 
|  | 6344 |  | 
|  | 6345 | /* | 
|  | 6346 | * Build the sequence of child and an array preserving the children | 
|  | 6347 | * initial order. | 
|  | 6348 | */ | 
|  | 6349 | cur = ctxt->state->seq; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6350 | oldseq = ctxt->state->seq; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6351 | nbchildren = 0; | 
|  | 6352 | nbtot = 0; | 
|  | 6353 | while (cur != NULL) { | 
|  | 6354 | if ((cur->type == XML_COMMENT_NODE) || | 
|  | 6355 | (cur->type == XML_PI_NODE) || | 
|  | 6356 | ((cur->type == XML_TEXT_NODE) && | 
|  | 6357 | (IS_BLANK_NODE(cur)))) { | 
|  | 6358 | nbtot++; | 
|  | 6359 | } else { | 
|  | 6360 | nbchildren++; | 
|  | 6361 | nbtot++; | 
|  | 6362 | } | 
|  | 6363 | cur = cur->next; | 
|  | 6364 | } | 
|  | 6365 | children = (xmlNodePtr *) xmlMalloc(nbchildren * sizeof(xmlNodePtr)); | 
|  | 6366 | if (children == NULL) | 
|  | 6367 | goto error; | 
|  | 6368 | order = (xmlNodePtr *) xmlMalloc(nbtot * sizeof(xmlNodePtr)); | 
|  | 6369 | if (order == NULL) | 
|  | 6370 | goto error; | 
|  | 6371 | cur = ctxt->state->seq; | 
|  | 6372 | i = 0; | 
|  | 6373 | j = 0; | 
|  | 6374 | while (cur != NULL) { | 
|  | 6375 | if ((cur->type == XML_COMMENT_NODE) || | 
|  | 6376 | (cur->type == XML_PI_NODE) || | 
|  | 6377 | ((cur->type == XML_TEXT_NODE) && | 
|  | 6378 | (IS_BLANK_NODE(cur)))) { | 
|  | 6379 | order[j++] = cur; | 
|  | 6380 | } else { | 
|  | 6381 | order[j++] = cur; | 
|  | 6382 | children[i++] = cur; | 
|  | 6383 | } | 
|  | 6384 | cur = cur->next; | 
|  | 6385 | } | 
|  | 6386 |  | 
|  | 6387 | /* TODO: retry with a maller set of child if there is a next... */ | 
|  | 6388 | ret = xmlRelaxNGValidatePartGroup(ctxt, partitions->groups, | 
|  | 6389 | partitions->nbgroups, children, nbchildren); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6390 | if (ret != 0) | 
|  | 6391 | ctxt->state->seq = oldseq; | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6392 |  | 
|  | 6393 | /* | 
|  | 6394 | * Cleanup: rebuid the child sequence and free the structure | 
|  | 6395 | */ | 
|  | 6396 | if (order != NULL) { | 
|  | 6397 | for (i = 0;i < nbtot;i++) { | 
|  | 6398 | if (i == 0) | 
|  | 6399 | order[i]->prev = NULL; | 
|  | 6400 | else | 
|  | 6401 | order[i]->prev = order[i - 1]; | 
|  | 6402 | if (i == nbtot - 1) | 
|  | 6403 | order[i]->next = NULL; | 
|  | 6404 | else | 
|  | 6405 | order[i]->next = order[i + 1]; | 
|  | 6406 | } | 
|  | 6407 | xmlFree(order); | 
|  | 6408 | } | 
|  | 6409 | if (children != NULL) | 
|  | 6410 | xmlFree(children); | 
|  | 6411 |  | 
|  | 6412 | return(ret); | 
|  | 6413 |  | 
|  | 6414 | error: | 
|  | 6415 | if (order != NULL) { | 
|  | 6416 | for (i = 0;i < nbtot;i++) { | 
|  | 6417 | if (i == 0) | 
|  | 6418 | order[i]->prev = NULL; | 
|  | 6419 | else | 
|  | 6420 | order[i]->prev = order[i - 1]; | 
|  | 6421 | if (i == nbtot - 1) | 
|  | 6422 | order[i]->next = NULL; | 
|  | 6423 | else | 
|  | 6424 | order[i]->next = order[i + 1]; | 
|  | 6425 | } | 
|  | 6426 | xmlFree(order); | 
|  | 6427 | } | 
|  | 6428 | if (children != NULL) | 
|  | 6429 | xmlFree(children); | 
|  | 6430 | return(-1); | 
|  | 6431 | } | 
|  | 6432 |  | 
|  | 6433 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6434 | * xmlRelaxNGValidateElementContent: | 
|  | 6435 | * @ctxt:  a Relax-NG validation context | 
|  | 6436 | * @define:  the list of definition to verify | 
|  | 6437 | * | 
|  | 6438 | * Validate the given node content against the (list) of definitions | 
|  | 6439 | * | 
|  | 6440 | * Returns 0 if the validation succeeded or an error code. | 
|  | 6441 | */ | 
|  | 6442 | static int | 
|  | 6443 | xmlRelaxNGValidateElementContent(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 6444 | xmlRelaxNGDefinePtr defines) { | 
|  | 6445 | int ret = 0, res; | 
|  | 6446 |  | 
|  | 6447 | if (ctxt->state == NULL) { | 
|  | 6448 | VALID_CTXT(); | 
|  | 6449 | VALID_ERROR("Internal: no state\n"); | 
|  | 6450 | return(-1); | 
|  | 6451 | } | 
|  | 6452 | while (defines != NULL) { | 
|  | 6453 | res = xmlRelaxNGValidateDefinition(ctxt, defines); | 
|  | 6454 | if (res < 0) | 
|  | 6455 | ret = -1; | 
|  | 6456 | defines = defines->next; | 
|  | 6457 | } | 
|  | 6458 |  | 
|  | 6459 | return(ret); | 
|  | 6460 | } | 
|  | 6461 |  | 
|  | 6462 | /** | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 6463 | * xmlRelaxNGElementMatch: | 
|  | 6464 | * @ctxt:  a Relax-NG validation context | 
|  | 6465 | * @define:  the definition to check | 
|  | 6466 | * @elem:  the element | 
|  | 6467 | * | 
|  | 6468 | * Check if the element matches the definition nameClass | 
|  | 6469 | * | 
|  | 6470 | * Returns 1 if the element matches, 0 if no, or -1 in case of error | 
|  | 6471 | */ | 
|  | 6472 | static int | 
|  | 6473 | xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 6474 | xmlRelaxNGDefinePtr define, | 
|  | 6475 | xmlNodePtr elem) { | 
|  | 6476 | int ret, oldflags; | 
|  | 6477 |  | 
|  | 6478 | if (define->name != NULL) { | 
|  | 6479 | if (!xmlStrEqual(elem->name, define->name)) { | 
|  | 6480 | VALID_CTXT(); | 
|  | 6481 | VALID_ERROR3("Expecting element %s, got %s\n", | 
|  | 6482 | define->name, elem->name); | 
|  | 6483 | return(0); | 
|  | 6484 | } | 
|  | 6485 | } | 
|  | 6486 | if ((define->ns != NULL) && (define->ns[0] != 0)) { | 
|  | 6487 | if (elem->ns == NULL) { | 
|  | 6488 | VALID_CTXT(); | 
|  | 6489 | VALID_ERROR2("Expecting a namespace for element %s\n", | 
|  | 6490 | elem->name); | 
|  | 6491 | return(0); | 
|  | 6492 | } else if (!xmlStrEqual(elem->ns->href, define->ns)) { | 
|  | 6493 | VALID_CTXT(); | 
|  | 6494 | VALID_ERROR3("Expecting element %s has wrong namespace: expecting %s\n", | 
|  | 6495 | elem->name, define->ns); | 
|  | 6496 | return(0); | 
|  | 6497 | } | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 6498 | } else if ((elem->ns != NULL) && (define->ns != NULL) && | 
|  | 6499 | (define->name == NULL)) { | 
|  | 6500 | VALID_CTXT(); | 
|  | 6501 | VALID_ERROR2("Expecting no namespace for element %s\n", | 
|  | 6502 | define->name); | 
|  | 6503 | return(0); | 
|  | 6504 | } else if ((elem->ns != NULL) && (define->name != NULL)) { | 
|  | 6505 | VALID_CTXT(); | 
|  | 6506 | VALID_ERROR2("Expecting no namespace for element %s\n", | 
|  | 6507 | define->name); | 
|  | 6508 | return(0); | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 6509 | } | 
|  | 6510 |  | 
|  | 6511 | if (define->nameClass == NULL) | 
|  | 6512 | return(1); | 
|  | 6513 |  | 
|  | 6514 | define = define->nameClass; | 
|  | 6515 | if (define->type == XML_RELAXNG_EXCEPT) { | 
|  | 6516 | xmlRelaxNGDefinePtr list; | 
|  | 6517 | oldflags = ctxt->flags; | 
|  | 6518 | ctxt->flags |= FLAGS_IGNORABLE; | 
|  | 6519 |  | 
|  | 6520 | list = define->content; | 
|  | 6521 | while (list != NULL) { | 
|  | 6522 | ret = xmlRelaxNGElementMatch(ctxt, list, elem); | 
|  | 6523 | if (ret == 1) { | 
|  | 6524 | ctxt->flags = oldflags; | 
|  | 6525 | return(0); | 
|  | 6526 | } | 
|  | 6527 | if (ret < 0) { | 
|  | 6528 | ctxt->flags = oldflags; | 
|  | 6529 | return(ret); | 
|  | 6530 | } | 
|  | 6531 | list = list->next; | 
|  | 6532 | } | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 6533 | ret = 1; | 
|  | 6534 | ctxt->flags = oldflags; | 
|  | 6535 | } else if (define->type == XML_RELAXNG_CHOICE) { | 
|  | 6536 | xmlRelaxNGDefinePtr list; | 
|  | 6537 | oldflags = ctxt->flags; | 
|  | 6538 | ctxt->flags |= FLAGS_IGNORABLE; | 
|  | 6539 |  | 
|  | 6540 | list = define->nameClass; | 
|  | 6541 | while (list != NULL) { | 
|  | 6542 | ret = xmlRelaxNGElementMatch(ctxt, list, elem); | 
|  | 6543 | if (ret == 1) { | 
|  | 6544 | ctxt->flags = oldflags; | 
|  | 6545 | return(1); | 
|  | 6546 | } | 
|  | 6547 | if (ret < 0) { | 
|  | 6548 | ctxt->flags = oldflags; | 
|  | 6549 | return(ret); | 
|  | 6550 | } | 
|  | 6551 | list = list->next; | 
|  | 6552 | } | 
|  | 6553 | ret = 0; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 6554 | ctxt->flags = oldflags; | 
|  | 6555 | } else { | 
|  | 6556 | TODO | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 6557 | ret = -1; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 6558 | } | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 6559 | return(ret); | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 6560 | } | 
|  | 6561 |  | 
|  | 6562 | /** | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6563 | * xmlRelaxNGValidateDefinition: | 
|  | 6564 | * @ctxt:  a Relax-NG validation context | 
|  | 6565 | * @define:  the definition to verify | 
|  | 6566 | * | 
|  | 6567 | * Validate the current node against the definition | 
|  | 6568 | * | 
|  | 6569 | * Returns 0 if the validation succeeded or an error code. | 
|  | 6570 | */ | 
|  | 6571 | static int | 
|  | 6572 | xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 6573 | xmlRelaxNGDefinePtr define) { | 
|  | 6574 | xmlNodePtr node; | 
|  | 6575 | int ret = 0, i, tmp, oldflags; | 
|  | 6576 | xmlRelaxNGValidStatePtr oldstate, state; | 
|  | 6577 |  | 
|  | 6578 | if (define == NULL) { | 
|  | 6579 | VALID_CTXT(); | 
|  | 6580 | VALID_ERROR("internal error: define == NULL\n"); | 
|  | 6581 | return(-1); | 
|  | 6582 | } | 
|  | 6583 | if (ctxt->state != NULL) { | 
|  | 6584 | node = ctxt->state->seq; | 
|  | 6585 | } else { | 
|  | 6586 | node = NULL; | 
|  | 6587 | } | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6588 | #ifdef DEBUG | 
|  | 6589 | for (i = 0;i < ctxt->depth;i++) | 
|  | 6590 | xmlGenericError(xmlGenericErrorContext, " "); | 
|  | 6591 | xmlGenericError(xmlGenericErrorContext, | 
|  | 6592 | "Start validating %s ", xmlRelaxNGDefName(define)); | 
|  | 6593 | if (define->name != NULL) | 
|  | 6594 | xmlGenericError(xmlGenericErrorContext, "%s ", define->name); | 
|  | 6595 | if ((node != NULL) && (node->name != NULL)) | 
|  | 6596 | xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name); | 
|  | 6597 | else | 
|  | 6598 | xmlGenericError(xmlGenericErrorContext, "\n"); | 
|  | 6599 | #endif | 
|  | 6600 | ctxt->depth++; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6601 | switch (define->type) { | 
|  | 6602 | case XML_RELAXNG_EMPTY: | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6603 | node = xmlRelaxNGSkipIgnored(ctxt, node); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6604 | if (node != NULL) { | 
|  | 6605 | VALID_CTXT(); | 
|  | 6606 | VALID_ERROR("Expecting an empty element\n"); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6607 | ret = -1; | 
|  | 6608 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6609 | } | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6610 | ret = 0; | 
|  | 6611 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6612 | case XML_RELAXNG_NOT_ALLOWED: | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6613 | ret = -1; | 
|  | 6614 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6615 | case XML_RELAXNG_TEXT: | 
| Daniel Veillard | ce14fa5 | 2003-02-19 17:32:48 +0000 | [diff] [blame] | 6616 | #if 0 | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6617 | if (node == NULL) { | 
|  | 6618 | ret = 0; | 
|  | 6619 | break; | 
|  | 6620 | } | 
| Daniel Veillard | ce14fa5 | 2003-02-19 17:32:48 +0000 | [diff] [blame] | 6621 | #endif | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6622 | while ((node != NULL) && | 
|  | 6623 | ((node->type == XML_TEXT_NODE) || | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 6624 | (node->type == XML_COMMENT_NODE) || | 
|  | 6625 | (node->type == XML_PI_NODE) || | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6626 | (node->type == XML_CDATA_SECTION_NODE))) | 
|  | 6627 | node = node->next; | 
| Daniel Veillard | ce14fa5 | 2003-02-19 17:32:48 +0000 | [diff] [blame] | 6628 | #if 0 | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 6629 | if (node == ctxt->state->seq) { | 
|  | 6630 | VALID_CTXT(); | 
|  | 6631 | VALID_ERROR("Expecting text content\n"); | 
|  | 6632 | ret = -1; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6633 | } | 
| Daniel Veillard | ce14fa5 | 2003-02-19 17:32:48 +0000 | [diff] [blame] | 6634 | #endif | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 6635 | ctxt->state->seq = node; | 
|  | 6636 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6637 | case XML_RELAXNG_ELEMENT: | 
|  | 6638 | node = xmlRelaxNGSkipIgnored(ctxt, node); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6639 | if (node == NULL) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6640 | VALID_CTXT(); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6641 | VALID_ERROR("Expecting an element, got empty\n"); | 
|  | 6642 | ret = -1; | 
|  | 6643 | break; | 
|  | 6644 | } | 
|  | 6645 | if (node->type != XML_ELEMENT_NODE) { | 
|  | 6646 | VALID_CTXT(); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 6647 | VALID_ERROR2("Expecting an element got %d type\n", node->type); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6648 | ret = -1; | 
|  | 6649 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6650 | } | 
| Daniel Veillard | e5b110b | 2003-02-04 14:43:39 +0000 | [diff] [blame] | 6651 | /* | 
|  | 6652 | * This node was already validated successfully against | 
|  | 6653 | * this definition. | 
|  | 6654 | */ | 
|  | 6655 | if (node->_private == define) | 
|  | 6656 | break; | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 6657 |  | 
|  | 6658 | ret = xmlRelaxNGElementMatch(ctxt, define, node); | 
|  | 6659 | if (ret <= 0) { | 
|  | 6660 | ret = -1; | 
|  | 6661 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6662 | } | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 6663 | ret = 0; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6664 |  | 
|  | 6665 | state = xmlRelaxNGNewValidState(ctxt, node); | 
|  | 6666 | if (state == NULL) { | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6667 | ret = -1; | 
|  | 6668 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6669 | } | 
|  | 6670 |  | 
|  | 6671 | oldstate = ctxt->state; | 
|  | 6672 | ctxt->state = state; | 
|  | 6673 | if (define->attrs != NULL) { | 
|  | 6674 | tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6675 | if (tmp != 0) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6676 | ret = -1; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6677 | #ifdef DEBUG | 
|  | 6678 | xmlGenericError(xmlGenericErrorContext, | 
|  | 6679 | "E: Element %s failed to validate attributes\n", | 
|  | 6680 | node->name); | 
|  | 6681 | #endif | 
|  | 6682 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6683 | } | 
|  | 6684 | if (define->content != NULL) { | 
|  | 6685 | tmp = xmlRelaxNGValidateElementContent(ctxt, define->content); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6686 | if (tmp != 0) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6687 | ret = -1; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6688 | #ifdef DEBUG | 
|  | 6689 | xmlGenericError(xmlGenericErrorContext, | 
|  | 6690 | "E: Element %s failed to validate element content\n", | 
|  | 6691 | node->name); | 
|  | 6692 | #endif | 
|  | 6693 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6694 | } | 
|  | 6695 | state = ctxt->state; | 
|  | 6696 | if (state->seq != NULL) { | 
|  | 6697 | state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq); | 
|  | 6698 | if (state->seq != NULL) { | 
|  | 6699 | VALID_CTXT(); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 6700 | VALID_ERROR3("Extra content for element %s: %s\n", | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 6701 | node->name, state->seq->name); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6702 | ret = -1; | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6703 | #ifdef DEBUG | 
|  | 6704 | xmlGenericError(xmlGenericErrorContext, | 
|  | 6705 | "E: Element %s has extra content: %s\n", | 
|  | 6706 | node->name, state->seq->name); | 
|  | 6707 | #endif | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6708 | } | 
|  | 6709 | } | 
|  | 6710 | for (i = 0;i < state->nbAttrs;i++) { | 
|  | 6711 | if (state->attrs[i] != NULL) { | 
|  | 6712 | VALID_CTXT(); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 6713 | VALID_ERROR3("Invalid attribute %s for element %s\n", | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6714 | state->attrs[i]->name, node->name); | 
|  | 6715 | ret = -1; | 
|  | 6716 | } | 
|  | 6717 | } | 
|  | 6718 | ctxt->state = oldstate; | 
|  | 6719 | xmlRelaxNGFreeValidState(state); | 
|  | 6720 | if (oldstate != NULL) | 
| Daniel Veillard | e5b110b | 2003-02-04 14:43:39 +0000 | [diff] [blame] | 6721 | oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next); | 
|  | 6722 | if (ret == 0) | 
|  | 6723 | node->_private = define; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6724 |  | 
|  | 6725 |  | 
|  | 6726 | #ifdef DEBUG | 
|  | 6727 | xmlGenericError(xmlGenericErrorContext, | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6728 | "xmlRelaxNGValidateDefinition(): validated %s : %d", | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6729 | node->name, ret); | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 6730 | if (oldstate == NULL) | 
|  | 6731 | xmlGenericError(xmlGenericErrorContext, ": no state\n"); | 
|  | 6732 | else if (oldstate->seq == NULL) | 
|  | 6733 | xmlGenericError(xmlGenericErrorContext, ": done\n"); | 
|  | 6734 | else if (oldstate->seq->type == XML_ELEMENT_NODE) | 
|  | 6735 | xmlGenericError(xmlGenericErrorContext, ": next elem %s\n", | 
|  | 6736 | oldstate->seq->name); | 
|  | 6737 | else | 
|  | 6738 | xmlGenericError(xmlGenericErrorContext, ": next %s %d\n", | 
|  | 6739 | oldstate->seq->name, oldstate->seq->type); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6740 | #endif | 
|  | 6741 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6742 | case XML_RELAXNG_OPTIONAL: | 
|  | 6743 | oldflags = ctxt->flags; | 
|  | 6744 | ctxt->flags |= FLAGS_IGNORABLE; | 
|  | 6745 | oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); | 
|  | 6746 | ret = xmlRelaxNGValidateDefinition(ctxt, define->content); | 
|  | 6747 | if (ret != 0) { | 
|  | 6748 | xmlRelaxNGFreeValidState(ctxt->state); | 
|  | 6749 | ctxt->state = oldstate; | 
|  | 6750 | ret = 0; | 
|  | 6751 | break; | 
|  | 6752 | } | 
|  | 6753 | xmlRelaxNGFreeValidState(oldstate); | 
|  | 6754 | ctxt->flags = oldflags; | 
|  | 6755 | ret = 0; | 
|  | 6756 | break; | 
|  | 6757 | case XML_RELAXNG_ONEORMORE: | 
|  | 6758 | ret = xmlRelaxNGValidateDefinition(ctxt, define->content); | 
|  | 6759 | if (ret != 0) { | 
|  | 6760 | break; | 
|  | 6761 | } | 
|  | 6762 | /* no break on purpose */ | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 6763 | case XML_RELAXNG_ZEROORMORE: { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6764 | oldflags = ctxt->flags; | 
|  | 6765 | ctxt->flags |= FLAGS_IGNORABLE; | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 6766 | while (ctxt->state->nbAttrLeft != 0) { | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6767 | oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); | 
|  | 6768 | ret = xmlRelaxNGValidateDefinition(ctxt, define->content); | 
|  | 6769 | if (ret != 0) { | 
|  | 6770 | xmlRelaxNGFreeValidState(ctxt->state); | 
|  | 6771 | ctxt->state = oldstate; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6772 | break; | 
|  | 6773 | } | 
|  | 6774 | xmlRelaxNGFreeValidState(oldstate); | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 6775 | } | 
|  | 6776 | if (ret == 0) { | 
|  | 6777 | /* | 
|  | 6778 | * There is no attribute left to be consumed, | 
|  | 6779 | * we can check the closure by looking at ctxt->state->seq | 
|  | 6780 | */ | 
|  | 6781 | xmlNodePtr cur, temp; | 
|  | 6782 |  | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 6783 | cur = ctxt->state->seq; | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 6784 | temp = NULL; | 
|  | 6785 | while ((cur != NULL) && (temp != cur)) { | 
|  | 6786 | temp = cur; | 
|  | 6787 | oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); | 
|  | 6788 | ret = xmlRelaxNGValidateDefinition(ctxt, define->content); | 
|  | 6789 | if (ret != 0) { | 
|  | 6790 | xmlRelaxNGFreeValidState(ctxt->state); | 
|  | 6791 | ctxt->state = oldstate; | 
|  | 6792 | break; | 
|  | 6793 | } | 
|  | 6794 | xmlRelaxNGFreeValidState(oldstate); | 
|  | 6795 | cur = ctxt->state->seq; | 
|  | 6796 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6797 | } | 
|  | 6798 | ctxt->flags = oldflags; | 
| Daniel Veillard | 1ed7f36 | 2003-02-03 10:57:45 +0000 | [diff] [blame] | 6799 | ret = 0; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6800 | break; | 
| Daniel Veillard | 276be4a | 2003-01-24 01:03:34 +0000 | [diff] [blame] | 6801 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6802 | case XML_RELAXNG_CHOICE: { | 
|  | 6803 | xmlRelaxNGDefinePtr list = define->content; | 
| Daniel Veillard | ce14fa5 | 2003-02-19 17:32:48 +0000 | [diff] [blame] | 6804 | int success = 0; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6805 |  | 
|  | 6806 | oldflags = ctxt->flags; | 
|  | 6807 | ctxt->flags |= FLAGS_IGNORABLE; | 
|  | 6808 |  | 
|  | 6809 | while (list != NULL) { | 
|  | 6810 | oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state); | 
|  | 6811 | ret = xmlRelaxNGValidateDefinition(ctxt, list); | 
|  | 6812 | if (ret == 0) { | 
| Daniel Veillard | ce14fa5 | 2003-02-19 17:32:48 +0000 | [diff] [blame] | 6813 | if (xmlRelaxNGEqualValidState(ctxt, ctxt->state, oldstate)){ | 
|  | 6814 | /* | 
|  | 6815 | * if that pattern was nullable flag it but try | 
|  | 6816 | * to make more progresses | 
|  | 6817 | */ | 
|  | 6818 | success = 1; | 
|  | 6819 | } else { | 
|  | 6820 | xmlRelaxNGFreeValidState(oldstate); | 
|  | 6821 | break; | 
|  | 6822 | } | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6823 | } | 
|  | 6824 | xmlRelaxNGFreeValidState(ctxt->state); | 
|  | 6825 | ctxt->state = oldstate; | 
|  | 6826 | list = list->next; | 
|  | 6827 | } | 
|  | 6828 | ctxt->flags = oldflags; | 
| Daniel Veillard | ce14fa5 | 2003-02-19 17:32:48 +0000 | [diff] [blame] | 6829 | if (success == 1) | 
|  | 6830 | ret = 0; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6831 | break; | 
|  | 6832 | } | 
| Daniel Veillard | e2a5a08 | 2003-02-02 14:35:17 +0000 | [diff] [blame] | 6833 | case XML_RELAXNG_DEF: | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6834 | case XML_RELAXNG_GROUP: { | 
|  | 6835 | xmlRelaxNGDefinePtr list = define->content; | 
|  | 6836 |  | 
|  | 6837 | while (list != NULL) { | 
|  | 6838 | ret = xmlRelaxNGValidateDefinition(ctxt, list); | 
|  | 6839 | if (ret != 0) | 
|  | 6840 | break; | 
|  | 6841 | list = list->next; | 
|  | 6842 | } | 
|  | 6843 | break; | 
|  | 6844 | } | 
|  | 6845 | case XML_RELAXNG_INTERLEAVE: | 
| Daniel Veillard | 76fc5ed | 2003-01-28 20:58:15 +0000 | [diff] [blame] | 6846 | ret = xmlRelaxNGValidateInterleave(ctxt, define); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6847 | break; | 
|  | 6848 | case XML_RELAXNG_ATTRIBUTE: | 
|  | 6849 | ret = xmlRelaxNGValidateAttribute(ctxt, define); | 
|  | 6850 | break; | 
| Daniel Veillard | 77648bb | 2003-02-20 15:03:22 +0000 | [diff] [blame] | 6851 | case XML_RELAXNG_NOOP: | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6852 | case XML_RELAXNG_REF: | 
| Daniel Veillard | 419a768 | 2003-02-03 23:22:49 +0000 | [diff] [blame] | 6853 | case XML_RELAXNG_PARENTREF: | 
|  | 6854 | case XML_RELAXNG_EXTERNALREF: | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 6855 | ret = xmlRelaxNGValidateDefinition(ctxt, define->content); | 
|  | 6856 | break; | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 6857 | case XML_RELAXNG_DATATYPE: { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6858 | xmlNodePtr child; | 
|  | 6859 | xmlChar *content = NULL; | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 6860 |  | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6861 | child = node; | 
|  | 6862 | while (child != NULL) { | 
|  | 6863 | if (child->type == XML_ELEMENT_NODE) { | 
|  | 6864 | VALID_CTXT(); | 
|  | 6865 | VALID_ERROR2("Element %s has child elements\n", | 
|  | 6866 | node->parent->name); | 
|  | 6867 | ret = -1; | 
|  | 6868 | break; | 
|  | 6869 | } else if ((child->type == XML_TEXT_NODE) || | 
|  | 6870 | (child->type == XML_CDATA_SECTION_NODE)) { | 
|  | 6871 | content = xmlStrcat(content, child->content); | 
|  | 6872 | } | 
|  | 6873 | /* TODO: handle entities ... */ | 
|  | 6874 | child = child->next; | 
|  | 6875 | } | 
|  | 6876 | if (ret == -1) { | 
|  | 6877 | if (content != NULL) | 
|  | 6878 | xmlFree(content); | 
|  | 6879 | break; | 
|  | 6880 | } | 
|  | 6881 | if (content == NULL) { | 
|  | 6882 | content = xmlStrdup(BAD_CAST ""); | 
|  | 6883 | if (content == NULL) { | 
|  | 6884 | VALID_CTXT(); | 
|  | 6885 | VALID_ERROR("Allocation failure\n"); | 
|  | 6886 | ret = -1; | 
|  | 6887 | break; | 
|  | 6888 | } | 
|  | 6889 | } | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 6890 | ret = xmlRelaxNGValidateDatatype(ctxt, content, define); | 
|  | 6891 | if (ret == -1) { | 
|  | 6892 | VALID_CTXT(); | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 6893 | VALID_ERROR2("internal error validating %s\n", define->name); | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 6894 | } else if (ret == 0) { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6895 | ctxt->state->seq = NULL; | 
| Daniel Veillard | dd1655c | 2003-01-25 18:01:32 +0000 | [diff] [blame] | 6896 | } | 
|  | 6897 | if (content != NULL) | 
|  | 6898 | xmlFree(content); | 
|  | 6899 | break; | 
|  | 6900 | } | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 6901 | case XML_RELAXNG_VALUE: { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6902 | xmlChar *content = NULL; | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 6903 | xmlChar *oldvalue; | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6904 | xmlNodePtr child; | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 6905 |  | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6906 | child = node; | 
|  | 6907 | while (child != NULL) { | 
|  | 6908 | if (child->type == XML_ELEMENT_NODE) { | 
|  | 6909 | VALID_CTXT(); | 
|  | 6910 | VALID_ERROR2("Element %s has child elements\n", | 
|  | 6911 | node->parent->name); | 
|  | 6912 | ret = -1; | 
|  | 6913 | break; | 
|  | 6914 | } else if ((child->type == XML_TEXT_NODE) || | 
|  | 6915 | (child->type == XML_CDATA_SECTION_NODE)) { | 
|  | 6916 | content = xmlStrcat(content, child->content); | 
|  | 6917 | } | 
|  | 6918 | /* TODO: handle entities ... */ | 
|  | 6919 | child = child->next; | 
|  | 6920 | } | 
|  | 6921 | if (ret == -1) { | 
|  | 6922 | if (content != NULL) | 
|  | 6923 | xmlFree(content); | 
|  | 6924 | break; | 
|  | 6925 | } | 
|  | 6926 | if (content == NULL) { | 
|  | 6927 | content = xmlStrdup(BAD_CAST ""); | 
|  | 6928 | if (content == NULL) { | 
|  | 6929 | VALID_CTXT(); | 
|  | 6930 | VALID_ERROR("Allocation failure\n"); | 
|  | 6931 | ret = -1; | 
|  | 6932 | break; | 
|  | 6933 | } | 
|  | 6934 | } | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 6935 | oldvalue = ctxt->state->value; | 
|  | 6936 | ctxt->state->value = content; | 
|  | 6937 | ret = xmlRelaxNGValidateValue(ctxt, define); | 
|  | 6938 | ctxt->state->value = oldvalue; | 
|  | 6939 | if (ret == -1) { | 
|  | 6940 | VALID_CTXT(); | 
| Daniel Veillard | d229879 | 2003-02-14 16:54:11 +0000 | [diff] [blame] | 6941 | if (define->name != NULL) { | 
|  | 6942 | VALID_ERROR2("error validating value %s\n", define->name); | 
|  | 6943 | } else { | 
|  | 6944 | VALID_ERROR("error validating value\n"); | 
|  | 6945 | } | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 6946 | } else if (ret == 0) { | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6947 | ctxt->state->seq = NULL; | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 6948 | } | 
|  | 6949 | if (content != NULL) | 
|  | 6950 | xmlFree(content); | 
|  | 6951 | break; | 
|  | 6952 | } | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 6953 | case XML_RELAXNG_LIST: { | 
|  | 6954 | xmlChar *content; | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6955 | xmlNodePtr child; | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 6956 | xmlChar *oldvalue, *oldendvalue; | 
|  | 6957 | int len; | 
| Daniel Veillard | ea3f398 | 2003-01-26 19:45:18 +0000 | [diff] [blame] | 6958 |  | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 6959 | /* | 
|  | 6960 | * Make sure it's only text nodes | 
|  | 6961 | */ | 
|  | 6962 |  | 
|  | 6963 | content = NULL; | 
|  | 6964 | child = node; | 
|  | 6965 | while (child != NULL) { | 
|  | 6966 | if (child->type == XML_ELEMENT_NODE) { | 
|  | 6967 | VALID_CTXT(); | 
|  | 6968 | VALID_ERROR2("Element %s has child elements\n", | 
|  | 6969 | node->parent->name); | 
|  | 6970 | ret = -1; | 
|  | 6971 | break; | 
|  | 6972 | } else if ((child->type == XML_TEXT_NODE) || | 
|  | 6973 | (child->type == XML_CDATA_SECTION_NODE)) { | 
|  | 6974 | content = xmlStrcat(content, child->content); | 
|  | 6975 | } | 
|  | 6976 | /* TODO: handle entities ... */ | 
|  | 6977 | child = child->next; | 
|  | 6978 | } | 
|  | 6979 | if (ret == -1) { | 
|  | 6980 | if (content != NULL) | 
|  | 6981 | xmlFree(content); | 
|  | 6982 | break; | 
|  | 6983 | } | 
|  | 6984 | if (content == NULL) { | 
|  | 6985 | content = xmlStrdup(BAD_CAST ""); | 
|  | 6986 | if (content == NULL) { | 
|  | 6987 | VALID_CTXT(); | 
|  | 6988 | VALID_ERROR("Allocation failure\n"); | 
|  | 6989 | ret = -1; | 
|  | 6990 | break; | 
|  | 6991 | } | 
|  | 6992 | } | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 6993 | len = xmlStrlen(content); | 
|  | 6994 | oldvalue = ctxt->state->value; | 
|  | 6995 | oldendvalue = ctxt->state->endvalue; | 
|  | 6996 | ctxt->state->value = content; | 
|  | 6997 | ctxt->state->endvalue = content + len; | 
|  | 6998 | ret = xmlRelaxNGValidateValue(ctxt, define); | 
|  | 6999 | ctxt->state->value = oldvalue; | 
|  | 7000 | ctxt->state->endvalue = oldendvalue; | 
|  | 7001 | if (ret == -1) { | 
|  | 7002 | VALID_CTXT(); | 
| Daniel Veillard | 2e9b165 | 2003-02-19 13:29:45 +0000 | [diff] [blame] | 7003 | VALID_ERROR("error validating list\n"); | 
| Daniel Veillard | d431074 | 2003-02-18 21:12:46 +0000 | [diff] [blame] | 7004 | } else if ((ret == 0) && (node != NULL)) { | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 7005 | ctxt->state->seq = node->next; | 
|  | 7006 | } | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 7007 | if (content != NULL) | 
|  | 7008 | xmlFree(content); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 7009 | break; | 
| Daniel Veillard | c6e997c | 2003-01-27 12:35:42 +0000 | [diff] [blame] | 7010 | } | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 7011 | case XML_RELAXNG_START: | 
| Daniel Veillard | 144fae1 | 2003-02-03 13:17:57 +0000 | [diff] [blame] | 7012 | case XML_RELAXNG_EXCEPT: | 
| Daniel Veillard | 8fe9871 | 2003-02-19 00:19:14 +0000 | [diff] [blame] | 7013 | case XML_RELAXNG_PARAM: | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 7014 | TODO | 
| Daniel Veillard | 416589a | 2003-02-17 17:25:42 +0000 | [diff] [blame] | 7015 | ret = -1; | 
| Daniel Veillard | d41f4f4 | 2003-01-29 21:07:52 +0000 | [diff] [blame] | 7016 | break; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 7017 | } | 
| Daniel Veillard | 231d791 | 2003-02-09 14:22:17 +0000 | [diff] [blame] | 7018 | ctxt->depth--; | 
|  | 7019 | #ifdef DEBUG | 
|  | 7020 | for (i = 0;i < ctxt->depth;i++) | 
|  | 7021 | xmlGenericError(xmlGenericErrorContext, " "); | 
|  | 7022 | xmlGenericError(xmlGenericErrorContext, | 
|  | 7023 | "Validating %s ", xmlRelaxNGDefName(define)); | 
|  | 7024 | if (define->name != NULL) | 
|  | 7025 | xmlGenericError(xmlGenericErrorContext, "%s ", define->name); | 
|  | 7026 | if (ret == 0) | 
|  | 7027 | xmlGenericError(xmlGenericErrorContext, "suceeded\n"); | 
|  | 7028 | else | 
|  | 7029 | xmlGenericError(xmlGenericErrorContext, "failed\n"); | 
|  | 7030 | #endif | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 7031 | return(ret); | 
|  | 7032 | } | 
|  | 7033 |  | 
|  | 7034 | /** | 
|  | 7035 | * xmlRelaxNGValidateDocument: | 
|  | 7036 | * @ctxt:  a Relax-NG validation context | 
|  | 7037 | * @doc:  the document | 
|  | 7038 | * | 
|  | 7039 | * Validate the given document | 
|  | 7040 | * | 
|  | 7041 | * Returns 0 if the validation succeeded or an error code. | 
|  | 7042 | */ | 
|  | 7043 | static int | 
|  | 7044 | xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) { | 
|  | 7045 | int ret; | 
|  | 7046 | xmlRelaxNGPtr schema; | 
|  | 7047 | xmlRelaxNGGrammarPtr grammar; | 
|  | 7048 | xmlRelaxNGValidStatePtr state; | 
|  | 7049 |  | 
|  | 7050 | if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL)) | 
|  | 7051 | return(-1); | 
|  | 7052 |  | 
|  | 7053 | schema = ctxt->schema; | 
|  | 7054 | grammar = schema->topgrammar; | 
|  | 7055 | if (grammar == NULL) { | 
|  | 7056 | VALID_CTXT(); | 
|  | 7057 | VALID_ERROR("No top grammar defined\n"); | 
|  | 7058 | return(-1); | 
|  | 7059 | } | 
|  | 7060 | state = xmlRelaxNGNewValidState(ctxt, NULL); | 
|  | 7061 | ctxt->state = state; | 
|  | 7062 | ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start); | 
|  | 7063 | state = ctxt->state; | 
|  | 7064 | if ((state != NULL) && (state->seq != NULL)) { | 
|  | 7065 | xmlNodePtr node; | 
|  | 7066 |  | 
|  | 7067 | node = state->seq; | 
|  | 7068 | node = xmlRelaxNGSkipIgnored(ctxt, node); | 
|  | 7069 | if (node != NULL) { | 
|  | 7070 | VALID_CTXT(); | 
|  | 7071 | VALID_ERROR("extra data on the document\n"); | 
|  | 7072 | ret = -1; | 
|  | 7073 | } | 
|  | 7074 | } | 
|  | 7075 | xmlRelaxNGFreeValidState(state); | 
|  | 7076 |  | 
|  | 7077 | return(ret); | 
|  | 7078 | } | 
|  | 7079 |  | 
|  | 7080 | /************************************************************************ | 
|  | 7081 | * 									* | 
|  | 7082 | * 			Validation interfaces				* | 
|  | 7083 | * 									* | 
|  | 7084 | ************************************************************************/ | 
|  | 7085 | /** | 
|  | 7086 | * xmlRelaxNGNewValidCtxt: | 
|  | 7087 | * @schema:  a precompiled XML RelaxNGs | 
|  | 7088 | * | 
|  | 7089 | * Create an XML RelaxNGs validation context based on the given schema | 
|  | 7090 | * | 
|  | 7091 | * Returns the validation context or NULL in case of error | 
|  | 7092 | */ | 
|  | 7093 | xmlRelaxNGValidCtxtPtr | 
|  | 7094 | xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) { | 
|  | 7095 | xmlRelaxNGValidCtxtPtr ret; | 
|  | 7096 |  | 
|  | 7097 | ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt)); | 
|  | 7098 | if (ret == NULL) { | 
|  | 7099 | xmlGenericError(xmlGenericErrorContext, | 
|  | 7100 | "Failed to allocate new schama validation context\n"); | 
|  | 7101 | return (NULL); | 
|  | 7102 | } | 
|  | 7103 | memset(ret, 0, sizeof(xmlRelaxNGValidCtxt)); | 
|  | 7104 | ret->schema = schema; | 
| Daniel Veillard | 1703c5f | 2003-02-10 14:28:44 +0000 | [diff] [blame] | 7105 | ret->error = xmlGenericError; | 
|  | 7106 | ret->userData = xmlGenericErrorContext; | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 7107 | return (ret); | 
|  | 7108 | } | 
|  | 7109 |  | 
|  | 7110 | /** | 
|  | 7111 | * xmlRelaxNGFreeValidCtxt: | 
|  | 7112 | * @ctxt:  the schema validation context | 
|  | 7113 | * | 
|  | 7114 | * Free the resources associated to the schema validation context | 
|  | 7115 | */ | 
|  | 7116 | void | 
|  | 7117 | xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) { | 
|  | 7118 | if (ctxt == NULL) | 
|  | 7119 | return; | 
|  | 7120 | xmlFree(ctxt); | 
|  | 7121 | } | 
|  | 7122 |  | 
|  | 7123 | /** | 
|  | 7124 | * xmlRelaxNGSetValidErrors: | 
|  | 7125 | * @ctxt:  a Relax-NG validation context | 
|  | 7126 | * @err:  the error function | 
|  | 7127 | * @warn: the warning function | 
|  | 7128 | * @ctx: the functions context | 
|  | 7129 | * | 
|  | 7130 | * Set the error and warning callback informations | 
|  | 7131 | */ | 
|  | 7132 | void | 
|  | 7133 | xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt, | 
|  | 7134 | xmlRelaxNGValidityErrorFunc err, | 
|  | 7135 | xmlRelaxNGValidityWarningFunc warn, void *ctx) { | 
|  | 7136 | if (ctxt == NULL) | 
|  | 7137 | return; | 
|  | 7138 | ctxt->error = err; | 
|  | 7139 | ctxt->warning = warn; | 
|  | 7140 | ctxt->userData = ctx; | 
|  | 7141 | } | 
|  | 7142 |  | 
|  | 7143 | /** | 
|  | 7144 | * xmlRelaxNGValidateDoc: | 
|  | 7145 | * @ctxt:  a Relax-NG validation context | 
|  | 7146 | * @doc:  a parsed document tree | 
|  | 7147 | * | 
|  | 7148 | * Validate a document tree in memory. | 
|  | 7149 | * | 
|  | 7150 | * Returns 0 if the document is valid, a positive error code | 
|  | 7151 | *     number otherwise and -1 in case of internal or API error. | 
|  | 7152 | */ | 
|  | 7153 | int | 
|  | 7154 | xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) { | 
|  | 7155 | int ret; | 
|  | 7156 |  | 
|  | 7157 | if ((ctxt == NULL) || (doc == NULL)) | 
|  | 7158 | return(-1); | 
|  | 7159 |  | 
|  | 7160 | ctxt->doc = doc; | 
|  | 7161 |  | 
|  | 7162 | ret = xmlRelaxNGValidateDocument(ctxt, doc); | 
| Daniel Veillard | 71531f3 | 2003-02-05 13:19:53 +0000 | [diff] [blame] | 7163 | /* | 
|  | 7164 | * TODO: build error codes | 
|  | 7165 | */ | 
|  | 7166 | if (ret == -1) | 
|  | 7167 | return(1); | 
| Daniel Veillard | 6eadf63 | 2003-01-23 18:29:16 +0000 | [diff] [blame] | 7168 | return(ret); | 
|  | 7169 | } | 
|  | 7170 |  | 
|  | 7171 | #endif /* LIBXML_SCHEMAS_ENABLED */ | 
|  | 7172 |  |