blob: bdb70741be6b369bf58a4819eb34b66ff500a32c [file] [log] [blame]
Daniel Veillard39a1f9a1999-01-17 19:11:59 +00001/*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel.Veillard@w3.org
8 */
9
Daniel Veillard7f7d1111999-09-22 09:46:25 +000010#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000011#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000012#else
13#include "config.h"
14#endif
15
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000016#include <stdio.h>
Daniel Veillard39a1f9a1999-01-17 19:11:59 +000017#include <string.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018
19#ifdef HAVE_STDLIB_H
20#include <stdlib.h>
21#endif
22
Daniel Veillard361d8452000-04-03 19:48:13 +000023#include <libxml/xmlmemory.h>
Daniel Veillard126f2792000-10-24 17:10:12 +000024#include <libxml/hash.h>
Daniel Veillard361d8452000-04-03 19:48:13 +000025#include <libxml/valid.h>
26#include <libxml/parser.h>
27#include <libxml/parserInternals.h>
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000028#include <libxml/xmlerror.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000029
Daniel Veillardcf461992000-03-14 18:30:20 +000030/*
31 * Generic function for accessing stacks in the Validity Context
32 */
33
34#define PUSH_AND_POP(scope, type, name) \
35scope int name##VPush(xmlValidCtxtPtr ctxt, type value) { \
36 if (ctxt->name##Nr >= ctxt->name##Max) { \
37 ctxt->name##Max *= 2; \
Daniel Veillard32bc74e2000-07-14 14:49:25 +000038 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillardcf461992000-03-14 18:30:20 +000039 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
40 if (ctxt->name##Tab == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000041 xmlGenericError(xmlGenericErrorContext, \
42 "realloc failed !\n"); \
Daniel Veillardcf461992000-03-14 18:30:20 +000043 return(0); \
44 } \
45 } \
46 ctxt->name##Tab[ctxt->name##Nr] = value; \
47 ctxt->name = value; \
48 return(ctxt->name##Nr++); \
49} \
50scope type name##VPop(xmlValidCtxtPtr ctxt) { \
51 type ret; \
52 if (ctxt->name##Nr <= 0) return(0); \
53 ctxt->name##Nr--; \
54 if (ctxt->name##Nr > 0) \
55 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
56 else \
57 ctxt->name = NULL; \
58 ret = ctxt->name##Tab[ctxt->name##Nr]; \
59 ctxt->name##Tab[ctxt->name##Nr] = 0; \
60 return(ret); \
61} \
62
63PUSH_AND_POP(static, xmlNodePtr, node)
64
65/* #define DEBUG_VALID_ALGO */
66
67#ifdef DEBUG_VALID_ALGO
68void xmlValidPrintNodeList(xmlNodePtr cur) {
69 if (cur == NULL)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000070 xmlGenericError(xmlGenericErrorContext, "null ");
Daniel Veillardcf461992000-03-14 18:30:20 +000071 while (cur != NULL) {
72 switch (cur->type) {
73 case XML_ELEMENT_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000074 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +000075 break;
76 case XML_TEXT_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000077 xmlGenericError(xmlGenericErrorContext, "text ");
Daniel Veillardcf461992000-03-14 18:30:20 +000078 break;
79 case XML_CDATA_SECTION_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000080 xmlGenericError(xmlGenericErrorContext, "cdata ");
Daniel Veillardcf461992000-03-14 18:30:20 +000081 break;
82 case XML_ENTITY_REF_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000083 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +000084 break;
85 case XML_PI_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000086 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
Daniel Veillardcf461992000-03-14 18:30:20 +000087 break;
88 case XML_COMMENT_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000089 xmlGenericError(xmlGenericErrorContext, "comment ");
Daniel Veillardcf461992000-03-14 18:30:20 +000090 break;
91 case XML_ATTRIBUTE_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000092 xmlGenericError(xmlGenericErrorContext, "?attr? ");
Daniel Veillardcf461992000-03-14 18:30:20 +000093 break;
94 case XML_ENTITY_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000095 xmlGenericError(xmlGenericErrorContext, "?ent? ");
Daniel Veillardcf461992000-03-14 18:30:20 +000096 break;
97 case XML_DOCUMENT_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000098 xmlGenericError(xmlGenericErrorContext, "?doc? ");
Daniel Veillardcf461992000-03-14 18:30:20 +000099 break;
100 case XML_DOCUMENT_TYPE_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000101 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000102 break;
103 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000104 xmlGenericError(xmlGenericErrorContext, "?frag? ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000105 break;
106 case XML_NOTATION_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000107 xmlGenericError(xmlGenericErrorContext, "?nota? ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000108 break;
109 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000110 xmlGenericError(xmlGenericErrorContext, "?html? ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000111 break;
112 case XML_DTD_NODE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000113 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000114 break;
115 case XML_ELEMENT_DECL:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000116 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000117 break;
118 case XML_ATTRIBUTE_DECL:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000119 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000120 break;
121 case XML_ENTITY_DECL:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000122 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000123 break;
124 }
125 cur = cur->next;
126 }
127}
128
129void xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
130 char expr[1000];
131
132 expr[0] = 0;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000133 xmlGenericError(xmlGenericErrorContext, "valid: ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000134 xmlValidPrintNodeList(cur);
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000135 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardcf461992000-03-14 18:30:20 +0000136 xmlSprintfElementContent(expr, cont, 0);
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000137 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
Daniel Veillardcf461992000-03-14 18:30:20 +0000138}
139
140#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
141#else
142#define DEBUG_VALID_STATE(n,c)
143#endif
144
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000145/* TODO: use hash table for accesses to elem and attribute dedinitions */
146
Daniel Veillardb05deb71999-08-10 19:04:08 +0000147#define VERROR \
148 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
149
150#define VWARNING \
151 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
152
153#define CHECK_DTD \
154 if (doc == NULL) return(0); \
Daniel Veillardcd429612000-10-11 15:57:05 +0000155 else if ((doc->intSubset == NULL) && \
156 (doc->extSubset == NULL)) return(0)
Daniel Veillardb05deb71999-08-10 19:04:08 +0000157
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000158xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
159xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000160
Daniel Veillardbe803962000-06-28 23:40:59 +0000161/************************************************************************
162 * *
163 * QName handling helper *
164 * *
165 ************************************************************************/
166
167/**
168 * xmlSplitQName2:
169 * @name: an XML parser context
170 * @prefix: a xmlChar **
171 *
172 * parse an XML qualified name string
173 *
174 * [NS 5] QName ::= (Prefix ':')? LocalPart
175 *
176 * [NS 6] Prefix ::= NCName
177 *
178 * [NS 7] LocalPart ::= NCName
179 *
180 * Returns NULL if not a QName, otherwise the local part, and prefix
181 * is updated to get the Prefix if any.
182 */
183
184xmlChar *
185xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
186 int len = 0;
187 xmlChar *ret = NULL;
188
189 *prefix = NULL;
190
191 /* xml: prefix is not really a namespace */
192 if ((name[0] == 'x') && (name[1] == 'm') &&
193 (name[2] == 'l') && (name[3] == ':'))
194 return(NULL);
195
196 /* nasty but valid */
197 if (name[0] == ':')
198 return(NULL);
199
200 /*
201 * we are not trying to validate but just to cut, and yes it will
202 * work even if this is as set of UTF-8 encoded chars
203 */
204 while ((name[len] != 0) && (name[len] != ':'))
205 len++;
206
207 if (name[len] == 0)
208 return(NULL);
209
210 *prefix = xmlStrndup(name, len);
211 ret = xmlStrdup(&name[len + 1]);
212
213 return(ret);
214}
215
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000216/****************************************************************
217 * *
218 * Util functions for data allocation/deallocation *
219 * *
220 ****************************************************************/
221
222/**
223 * xmlNewElementContent:
224 * @name: the subelement name or NULL
225 * @type: the type of element content decl
226 *
227 * Allocate an element content structure.
228 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000229 * Returns NULL if not, othervise the new element content structure
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000230 */
231xmlElementContentPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000232xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000233 xmlElementContentPtr ret;
234
235 switch(type) {
236 case XML_ELEMENT_CONTENT_ELEMENT:
237 if (name == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000238 xmlGenericError(xmlGenericErrorContext,
239 "xmlNewElementContent : name == NULL !\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000240 }
241 break;
242 case XML_ELEMENT_CONTENT_PCDATA:
243 case XML_ELEMENT_CONTENT_SEQ:
244 case XML_ELEMENT_CONTENT_OR:
245 if (name != NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000246 xmlGenericError(xmlGenericErrorContext,
247 "xmlNewElementContent : name != NULL !\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000248 }
249 break;
250 default:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000251 xmlGenericError(xmlGenericErrorContext,
252 "xmlNewElementContent: unknown type %d\n", type);
Daniel Veillard0142b842000-01-14 14:45:24 +0000253 return(NULL);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000254 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000255 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000256 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000257 xmlGenericError(xmlGenericErrorContext,
258 "xmlNewElementContent : out of memory!\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000259 return(NULL);
260 }
261 ret->type = type;
262 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000263 if (name != NULL)
264 ret->name = xmlStrdup(name);
265 else
266 ret->name = NULL;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000267 ret->c1 = ret->c2 = NULL;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000268 return(ret);
269}
270
271/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000272 * xmlCopyElementContent:
273 * @content: An element content pointer.
274 *
275 * Build a copy of an element content description.
276 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000277 * Returns the new xmlElementContentPtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000278 */
279xmlElementContentPtr
Daniel Veillard1e346af1999-02-22 10:33:01 +0000280xmlCopyElementContent(xmlElementContentPtr cur) {
281 xmlElementContentPtr ret;
282
283 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000284 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
Daniel Veillard14fff061999-06-22 21:49:07 +0000285 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000286 xmlGenericError(xmlGenericErrorContext,
287 "xmlCopyElementContent : out of memory\n");
Daniel Veillard14fff061999-06-22 21:49:07 +0000288 return(NULL);
289 }
290 ret->ocur = cur->ocur;
291 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
292 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000293 return(ret);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000294}
295
296/**
Daniel Veillard1899e851999-02-01 12:18:54 +0000297 * xmlFreeElementContent:
298 * @cur: the element content tree to free
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000299 *
300 * Free an element content structure. This is a recursive call !
301 */
302void
303xmlFreeElementContent(xmlElementContentPtr cur) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000304 if (cur == NULL) return;
Daniel Veillard87b95392000-08-12 21:12:04 +0000305 switch (cur->type) {
306 case XML_ELEMENT_CONTENT_PCDATA:
307 case XML_ELEMENT_CONTENT_ELEMENT:
308 case XML_ELEMENT_CONTENT_SEQ:
309 case XML_ELEMENT_CONTENT_OR:
310 break;
311 default:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000312 xmlGenericError(xmlGenericErrorContext,
313 "xmlFreeElementContent : type %d\n", cur->type);
Daniel Veillard87b95392000-08-12 21:12:04 +0000314 return;
315 }
Daniel Veillard1e346af1999-02-22 10:33:01 +0000316 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
317 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000318 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000319 memset(cur, -1, sizeof(xmlElementContent));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000320 xmlFree(cur);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000321}
322
Daniel Veillard1899e851999-02-01 12:18:54 +0000323/**
324 * xmlDumpElementContent:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000325 * @buf: An XML buffer
Daniel Veillard1899e851999-02-01 12:18:54 +0000326 * @content: An element table
327 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
328 *
329 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard1899e851999-02-01 12:18:54 +0000330 */
331void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000332xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
Daniel Veillard1899e851999-02-01 12:18:54 +0000333 if (content == NULL) return;
334
Daniel Veillard5099ae81999-04-21 20:12:07 +0000335 if (glob) xmlBufferWriteChar(buf, "(");
Daniel Veillard1899e851999-02-01 12:18:54 +0000336 switch (content->type) {
337 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000338 xmlBufferWriteChar(buf, "#PCDATA");
Daniel Veillard1899e851999-02-01 12:18:54 +0000339 break;
340 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000341 xmlBufferWriteCHAR(buf, content->name);
Daniel Veillard1899e851999-02-01 12:18:54 +0000342 break;
343 case XML_ELEMENT_CONTENT_SEQ:
344 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
345 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000346 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000347 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000348 xmlDumpElementContent(buf, content->c1, 0);
349 xmlBufferWriteChar(buf, " , ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000350 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000351 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000352 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000353 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000354 break;
355 case XML_ELEMENT_CONTENT_OR:
356 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
357 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillard5099ae81999-04-21 20:12:07 +0000358 xmlDumpElementContent(buf, content->c1, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000359 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000360 xmlDumpElementContent(buf, content->c1, 0);
361 xmlBufferWriteChar(buf, " | ");
Daniel Veillard1899e851999-02-01 12:18:54 +0000362 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000363 xmlDumpElementContent(buf, content->c2, 1);
Daniel Veillard1899e851999-02-01 12:18:54 +0000364 else
Daniel Veillard5099ae81999-04-21 20:12:07 +0000365 xmlDumpElementContent(buf, content->c2, 0);
Daniel Veillard1899e851999-02-01 12:18:54 +0000366 break;
367 default:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000368 xmlGenericError(xmlGenericErrorContext,
369 "xmlDumpElementContent: unknown type %d\n",
Daniel Veillard1899e851999-02-01 12:18:54 +0000370 content->type);
371 }
372 if (glob)
Daniel Veillard5099ae81999-04-21 20:12:07 +0000373 xmlBufferWriteChar(buf, ")");
Daniel Veillard1899e851999-02-01 12:18:54 +0000374 switch (content->ocur) {
375 case XML_ELEMENT_CONTENT_ONCE:
376 break;
377 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000378 xmlBufferWriteChar(buf, "?");
Daniel Veillard1899e851999-02-01 12:18:54 +0000379 break;
380 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000381 xmlBufferWriteChar(buf, "*");
Daniel Veillard1899e851999-02-01 12:18:54 +0000382 break;
383 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5099ae81999-04-21 20:12:07 +0000384 xmlBufferWriteChar(buf, "+");
Daniel Veillard1899e851999-02-01 12:18:54 +0000385 break;
386 }
387}
388
Daniel Veillardb05deb71999-08-10 19:04:08 +0000389/**
390 * xmlSprintfElementContent:
391 * @buf: an output buffer
392 * @content: An element table
393 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
394 *
395 * This will dump the content of the element content definition
396 * Intended just for the debug routine
397 */
398void
399xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
400 if (content == NULL) return;
401 if (glob) strcat(buf, "(");
402 switch (content->type) {
403 case XML_ELEMENT_CONTENT_PCDATA:
404 strcat(buf, "#PCDATA");
405 break;
406 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardb96e6431999-08-29 21:02:19 +0000407 strcat(buf, (char *) content->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000408 break;
409 case XML_ELEMENT_CONTENT_SEQ:
410 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
411 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
412 xmlSprintfElementContent(buf, content->c1, 1);
413 else
414 xmlSprintfElementContent(buf, content->c1, 0);
415 strcat(buf, " , ");
416 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
417 xmlSprintfElementContent(buf, content->c2, 1);
418 else
419 xmlSprintfElementContent(buf, content->c2, 0);
420 break;
421 case XML_ELEMENT_CONTENT_OR:
422 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
423 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
424 xmlSprintfElementContent(buf, content->c1, 1);
425 else
426 xmlSprintfElementContent(buf, content->c1, 0);
427 strcat(buf, " | ");
428 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
429 xmlSprintfElementContent(buf, content->c2, 1);
430 else
431 xmlSprintfElementContent(buf, content->c2, 0);
432 break;
433 }
434 if (glob)
435 strcat(buf, ")");
436 switch (content->ocur) {
437 case XML_ELEMENT_CONTENT_ONCE:
438 break;
439 case XML_ELEMENT_CONTENT_OPT:
440 strcat(buf, "?");
441 break;
442 case XML_ELEMENT_CONTENT_MULT:
443 strcat(buf, "*");
444 break;
445 case XML_ELEMENT_CONTENT_PLUS:
446 strcat(buf, "+");
447 break;
448 }
449}
450
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000451/****************************************************************
452 * *
453 * Registration of DTD declarations *
454 * *
455 ****************************************************************/
456
Daniel Veillard3b9def11999-01-31 22:15:06 +0000457/**
458 * xmlCreateElementTable:
459 *
460 * create and initialize an empty element hash table.
461 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000462 * Returns the xmlElementTablePtr just created or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000463 */
464xmlElementTablePtr
465xmlCreateElementTable(void) {
Daniel Veillard126f2792000-10-24 17:10:12 +0000466 return(xmlHashCreate(0));
467}
Daniel Veillard3b9def11999-01-31 22:15:06 +0000468
Daniel Veillard126f2792000-10-24 17:10:12 +0000469/**
470 * xmlFreeElement:
471 * @elem: An element
472 *
473 * Deallocate the memory used by an element definition
474 */
475void
476xmlFreeElement(xmlElementPtr elem) {
477 if (elem == NULL) return;
478 xmlUnlinkNode((xmlNodePtr) elem);
479 xmlFreeElementContent(elem->content);
480 if (elem->name != NULL)
481 xmlFree((xmlChar *) elem->name);
482 if (elem->prefix != NULL)
483 xmlFree((xmlChar *) elem->prefix);
484 memset(elem, -1, sizeof(xmlElement));
485 xmlFree(elem);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000486}
487
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000488
489/**
490 * xmlAddElementDecl:
Daniel Veillard00fdf371999-10-08 09:40:39 +0000491 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000492 * @dtd: pointer to the DTD
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000493 * @name: the entity name
Daniel Veillard1e346af1999-02-22 10:33:01 +0000494 * @type: the element type
495 * @content: the element content tree or NULL
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000496 *
497 * Register a new element declaration
498 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000499 * Returns NULL if not, othervise the entity
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000500 */
501xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000502xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
Daniel Veillardcf461992000-03-14 18:30:20 +0000503 xmlElementTypeVal type,
504 xmlElementContentPtr content) {
Daniel Veillard126f2792000-10-24 17:10:12 +0000505 xmlElementPtr ret;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000506 xmlElementTablePtr table;
Daniel Veillardbe803962000-06-28 23:40:59 +0000507 xmlChar *ns, *uqname;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000508
509 if (dtd == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000510 xmlGenericError(xmlGenericErrorContext,
511 "xmlAddElementDecl: dtd == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000512 return(NULL);
513 }
514 if (name == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000515 xmlGenericError(xmlGenericErrorContext,
516 "xmlAddElementDecl: name == NULL\n");
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000517 return(NULL);
518 }
519 switch (type) {
520 case XML_ELEMENT_TYPE_EMPTY:
521 if (content != NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000522 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000523 "xmlAddElementDecl: content != NULL for EMPTY\n");
524 return(NULL);
525 }
526 break;
527 case XML_ELEMENT_TYPE_ANY:
528 if (content != NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000529 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000530 "xmlAddElementDecl: content != NULL for ANY\n");
531 return(NULL);
532 }
533 break;
534 case XML_ELEMENT_TYPE_MIXED:
535 if (content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000536 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000537 "xmlAddElementDecl: content == NULL for MIXED\n");
538 return(NULL);
539 }
540 break;
541 case XML_ELEMENT_TYPE_ELEMENT:
542 if (content == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000543 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000544 "xmlAddElementDecl: content == NULL for ELEMENT\n");
545 return(NULL);
546 }
547 break;
548 default:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000549 xmlGenericError(xmlGenericErrorContext,
550 "xmlAddElementDecl: unknown type %d\n", type);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000551 return(NULL);
552 }
553
554 /*
Daniel Veillardbe803962000-06-28 23:40:59 +0000555 * check if name is a QName
556 */
557 uqname = xmlSplitQName2(name, &ns);
558 if (uqname != NULL)
559 name = uqname;
560
561 /*
Daniel Veillard3b9def11999-01-31 22:15:06 +0000562 * Create the Element table if needed.
563 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000564 table = (xmlElementTablePtr) dtd->elements;
565 if (table == NULL) {
566 table = xmlCreateElementTable();
567 dtd->elements = (void *) table;
568 }
Daniel Veillard3b9def11999-01-31 22:15:06 +0000569 if (table == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000570 xmlGenericError(xmlGenericErrorContext,
571 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillard3b9def11999-01-31 22:15:06 +0000572 return(NULL);
573 }
574
Daniel Veillard6454aec1999-09-02 22:04:43 +0000575 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
Daniel Veillardb05deb71999-08-10 19:04:08 +0000576 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000577 xmlGenericError(xmlGenericErrorContext,
578 "xmlAddElementDecl: out of memory\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +0000579 return(NULL);
580 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000581 memset(ret, 0, sizeof(xmlElement));
582 ret->type = XML_ELEMENT_DECL;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000583
584 /*
585 * fill the structure.
586 */
Daniel Veillardcf461992000-03-14 18:30:20 +0000587 ret->etype = type;
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000588 ret->name = xmlStrdup(name);
Daniel Veillardbe803962000-06-28 23:40:59 +0000589 ret->prefix = ns;
Daniel Veillard14fff061999-06-22 21:49:07 +0000590 ret->content = xmlCopyElementContent(content);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000591 ret->attributes = xmlScanAttributeDecl(dtd, name);
Daniel Veillard126f2792000-10-24 17:10:12 +0000592
593 /*
594 * Validity Check:
595 * Insertion must not fail
596 */
597 if (xmlHashAddEntry2(table, name, ns, ret)) {
598 /*
599 * The element is already defined in this Dtd.
600 */
601 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
602 xmlFreeElement(ret);
603 if (uqname != NULL)
604 xmlFree(uqname);
605 return(NULL);
606 }
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000607
Daniel Veillardcf461992000-03-14 18:30:20 +0000608 /*
609 * Link it to the Dtd
610 */
611 ret->parent = dtd;
612 ret->doc = dtd->doc;
613 if (dtd->last == NULL) {
614 dtd->children = dtd->last = (xmlNodePtr) ret;
615 } else {
616 dtd->last->next = (xmlNodePtr) ret;
617 ret->prev = dtd->last;
618 dtd->last = (xmlNodePtr) ret;
619 }
Daniel Veillardbe803962000-06-28 23:40:59 +0000620 if (uqname != NULL)
621 xmlFree(uqname);
Daniel Veillard39a1f9a1999-01-17 19:11:59 +0000622 return(ret);
623}
624
Daniel Veillard3b9def11999-01-31 22:15:06 +0000625/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000626 * xmlFreeElementTable:
627 * @table: An element table
628 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000629 * Deallocate the memory used by an element hash table.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000630 */
631void
632xmlFreeElementTable(xmlElementTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +0000633 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
634}
Daniel Veillard3b9def11999-01-31 22:15:06 +0000635
Daniel Veillard126f2792000-10-24 17:10:12 +0000636/**
637 * xmlCopyElement:
638 * @elem: An element
639 *
640 * Build a copy of an element.
641 *
642 * Returns the new xmlElementPtr or NULL in case of error.
643 */
644xmlElementPtr
645xmlCopyElement(xmlElementPtr elem) {
646 xmlElementPtr cur;
Daniel Veillard3b9def11999-01-31 22:15:06 +0000647
Daniel Veillard126f2792000-10-24 17:10:12 +0000648 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
649 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000650 xmlGenericError(xmlGenericErrorContext,
651 "xmlCopyElement: out of memory !\n");
Daniel Veillard126f2792000-10-24 17:10:12 +0000652 return(NULL);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000653 }
Daniel Veillard126f2792000-10-24 17:10:12 +0000654 memset(cur, 0, sizeof(xmlElement));
655 cur->type = XML_ELEMENT_DECL;
656 cur->etype = elem->etype;
657 if (elem->name != NULL)
658 cur->name = xmlStrdup(elem->name);
659 else
660 cur->name = NULL;
661 if (elem->prefix != NULL)
662 cur->prefix = xmlStrdup(elem->prefix);
663 else
664 cur->prefix = NULL;
665 cur->content = xmlCopyElementContent(elem->content);
666 /* TODO : rebuild the attribute list on the copy */
667 cur->attributes = NULL;
668 return(cur);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000669}
670
671/**
672 * xmlCopyElementTable:
673 * @table: An element table
674 *
675 * Build a copy of an element table.
676 *
Daniel Veillard1e346af1999-02-22 10:33:01 +0000677 * Returns the new xmlElementTablePtr or NULL in case of error.
Daniel Veillard3b9def11999-01-31 22:15:06 +0000678 */
679xmlElementTablePtr
680xmlCopyElementTable(xmlElementTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +0000681 return((xmlElementTablePtr) xmlHashCopy(table,
682 (xmlHashCopier) xmlCopyElement));
Daniel Veillard3b9def11999-01-31 22:15:06 +0000683}
684
685/**
Daniel Veillardcf461992000-03-14 18:30:20 +0000686 * xmlDumpElementDecl:
687 * @buf: the XML buffer output
688 * @elem: An element table
689 *
690 * This will dump the content of the element declaration as an XML
691 * DTD definition
692 */
693void
694xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
695 switch (elem->etype) {
696 case XML_ELEMENT_TYPE_EMPTY:
697 xmlBufferWriteChar(buf, "<!ELEMENT ");
698 xmlBufferWriteCHAR(buf, elem->name);
699 xmlBufferWriteChar(buf, " EMPTY>\n");
700 break;
701 case XML_ELEMENT_TYPE_ANY:
702 xmlBufferWriteChar(buf, "<!ELEMENT ");
703 xmlBufferWriteCHAR(buf, elem->name);
704 xmlBufferWriteChar(buf, " ANY>\n");
705 break;
706 case XML_ELEMENT_TYPE_MIXED:
707 xmlBufferWriteChar(buf, "<!ELEMENT ");
708 xmlBufferWriteCHAR(buf, elem->name);
709 xmlBufferWriteChar(buf, " ");
710 xmlDumpElementContent(buf, elem->content, 1);
711 xmlBufferWriteChar(buf, ">\n");
712 break;
713 case XML_ELEMENT_TYPE_ELEMENT:
714 xmlBufferWriteChar(buf, "<!ELEMENT ");
715 xmlBufferWriteCHAR(buf, elem->name);
716 xmlBufferWriteChar(buf, " ");
717 xmlDumpElementContent(buf, elem->content, 1);
718 xmlBufferWriteChar(buf, ">\n");
719 break;
720 default:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000721 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcf461992000-03-14 18:30:20 +0000722 "xmlDumpElementDecl: internal: unknown type %d\n",
723 elem->etype);
724 }
725}
726
727/**
Daniel Veillard3b9def11999-01-31 22:15:06 +0000728 * xmlDumpElementTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +0000729 * @buf: the XML buffer output
Daniel Veillard3b9def11999-01-31 22:15:06 +0000730 * @table: An element table
731 *
732 * This will dump the content of the element table as an XML DTD definition
Daniel Veillard3b9def11999-01-31 22:15:06 +0000733 */
734void
Daniel Veillard5099ae81999-04-21 20:12:07 +0000735xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +0000736 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDecl, buf);
Daniel Veillard3b9def11999-01-31 22:15:06 +0000737}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000738
739/**
740 * xmlCreateEnumeration:
741 * @name: the enumeration name or NULL
742 *
743 * create and initialize an enumeration attribute node.
744 *
745 * Returns the xmlEnumerationPtr just created or NULL in case
746 * of error.
747 */
748xmlEnumerationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000749xmlCreateEnumeration(xmlChar *name) {
Daniel Veillard1e346af1999-02-22 10:33:01 +0000750 xmlEnumerationPtr ret;
751
Daniel Veillard6454aec1999-09-02 22:04:43 +0000752 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000753 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000754 xmlGenericError(xmlGenericErrorContext,
755 "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
Daniel Veillardbe70ff71999-07-05 16:50:46 +0000756 (long)sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000757 return(NULL);
758 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000759 memset(ret, 0, sizeof(xmlEnumeration));
Daniel Veillard1e346af1999-02-22 10:33:01 +0000760
761 if (name != NULL)
762 ret->name = xmlStrdup(name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000763 return(ret);
764}
765
766/**
767 * xmlFreeEnumeration:
768 * @cur: the tree to free.
769 *
770 * free an enumeration attribute node (recursive).
771 */
772void
773xmlFreeEnumeration(xmlEnumerationPtr cur) {
774 if (cur == NULL) return;
775
776 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
777
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000778 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000779 memset(cur, -1, sizeof(xmlEnumeration));
Daniel Veillard6454aec1999-09-02 22:04:43 +0000780 xmlFree(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000781}
782
783/**
784 * xmlCopyEnumeration:
785 * @cur: the tree to copy.
786 *
787 * Copy an enumeration attribute node (recursive).
788 *
789 * Returns the xmlEnumerationPtr just created or NULL in case
790 * of error.
791 */
792xmlEnumerationPtr
793xmlCopyEnumeration(xmlEnumerationPtr cur) {
794 xmlEnumerationPtr ret;
795
796 if (cur == NULL) return(NULL);
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000797 ret = xmlCreateEnumeration((xmlChar *) cur->name);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000798
799 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
800 else ret->next = NULL;
801
802 return(ret);
803}
804
805/**
Daniel Veillardb05deb71999-08-10 19:04:08 +0000806 * xmlDumpEnumeration:
807 * @buf: the XML buffer output
808 * @enum: An enumeration
809 *
810 * This will dump the content of the enumeration
811 */
812void
813xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
814 if (cur == NULL) return;
815
816 xmlBufferWriteCHAR(buf, cur->name);
817 if (cur->next == NULL)
818 xmlBufferWriteChar(buf, ")");
819 else {
820 xmlBufferWriteChar(buf, " | ");
821 xmlDumpEnumeration(buf, cur->next);
822 }
823}
824
825/**
Daniel Veillard1e346af1999-02-22 10:33:01 +0000826 * xmlCreateAttributeTable:
827 *
828 * create and initialize an empty attribute hash table.
829 *
830 * Returns the xmlAttributeTablePtr just created or NULL in case
831 * of error.
832 */
833xmlAttributeTablePtr
834xmlCreateAttributeTable(void) {
Daniel Veillard126f2792000-10-24 17:10:12 +0000835 return(xmlHashCreate(0));
836}
Daniel Veillard1e346af1999-02-22 10:33:01 +0000837
Daniel Veillard126f2792000-10-24 17:10:12 +0000838/**
839 * xmlScanAttributeDeclCallback:
840 * @attr: the attribute decl
841 * @list: the list to update
842 *
843 * Callback called by xmlScanAttributeDecl when a new attribute
844 * has to be entered in the list.
845 */
846void
847xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
848 const xmlChar* name) {
849 attr->nexth = *list;
850 *list = attr;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000851}
852
Daniel Veillardb05deb71999-08-10 19:04:08 +0000853/**
854 * xmlScanAttributeDecl:
855 * @dtd: pointer to the DTD
856 * @elem: the element name
857 *
858 * When inserting a new element scan the DtD for existing attributes
859 * for taht element and initialize the Attribute chain
860 *
861 * Returns the pointer to the first attribute decl in the chain,
862 * possibly NULL.
863 */
864xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000865xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000866 xmlAttributePtr ret = NULL;
867 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000868
869 if (dtd == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000870 xmlGenericError(xmlGenericErrorContext,
871 "xmlScanAttributeDecl: dtd == NULL\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +0000872 return(NULL);
873 }
874 if (elem == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000875 xmlGenericError(xmlGenericErrorContext,
876 "xmlScanAttributeDecl: elem == NULL\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +0000877 return(NULL);
878 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000879 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000880 if (table == NULL)
881 return(NULL);
882
Daniel Veillard126f2792000-10-24 17:10:12 +0000883 /* WRONG !!! */
884 xmlHashScan3(table, NULL, NULL, elem,
885 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +0000886 return(ret);
887}
888
889/**
890 * xmlScanIDAttributeDecl:
891 * @ctxt: the validation context
892 * @elem: the element name
893 *
Daniel Veillard71b656e2000-01-05 14:46:17 +0000894 * Verify that the element don't have too many ID attributes
Daniel Veillardb05deb71999-08-10 19:04:08 +0000895 * declared.
896 *
897 * Returns the number of ID attributes found.
898 */
899int
900xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
901 xmlAttributePtr cur;
902 int ret = 0;
903
904 if (elem == NULL) return(0);
905 cur = elem->attributes;
906 while (cur != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +0000907 if (cur->atype == XML_ATTRIBUTE_ID) {
Daniel Veillardb05deb71999-08-10 19:04:08 +0000908 ret ++;
909 if (ret > 1)
910 VERROR(ctxt->userData,
911 "Element %s has too may ID attributes defined : %s\n",
912 elem->name, cur->name);
913 }
Daniel Veillardcf461992000-03-14 18:30:20 +0000914 cur = cur->nexth;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000915 }
916 return(ret);
917}
918
Daniel Veillard126f2792000-10-24 17:10:12 +0000919/**
920 * xmlFreeAttribute:
921 * @elem: An attribute
922 *
923 * Deallocate the memory used by an attribute definition
924 */
925void
926xmlFreeAttribute(xmlAttributePtr attr) {
927 if (attr == NULL) return;
928 xmlUnlinkNode((xmlNodePtr) attr);
929 if (attr->tree != NULL)
930 xmlFreeEnumeration(attr->tree);
931 if (attr->elem != NULL)
932 xmlFree((xmlChar *) attr->elem);
933 if (attr->name != NULL)
934 xmlFree((xmlChar *) attr->name);
935 if (attr->defaultValue != NULL)
936 xmlFree((xmlChar *) attr->defaultValue);
937 if (attr->prefix != NULL)
938 xmlFree((xmlChar *) attr->prefix);
939 memset(attr, -1, sizeof(xmlAttribute));
940 xmlFree(attr);
941}
942
Daniel Veillard1e346af1999-02-22 10:33:01 +0000943
944/**
945 * xmlAddAttributeDecl:
Daniel Veillardb05deb71999-08-10 19:04:08 +0000946 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +0000947 * @dtd: pointer to the DTD
948 * @elem: the element name
949 * @name: the attribute name
Daniel Veillardcf461992000-03-14 18:30:20 +0000950 * @ns: the attribute namespace prefix
Daniel Veillard1e346af1999-02-22 10:33:01 +0000951 * @type: the attribute type
952 * @def: the attribute default type
953 * @defaultValue: the attribute default value
954 * @tree: if it's an enumeration, the associated list
955 *
956 * Register a new attribute declaration
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000957 * Note that @tree becomes the ownership of the DTD
Daniel Veillard1e346af1999-02-22 10:33:01 +0000958 *
Daniel Veillardbe803962000-06-28 23:40:59 +0000959 * Returns NULL if not new, othervise the attribute decl
Daniel Veillard1e346af1999-02-22 10:33:01 +0000960 */
961xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000962xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
Daniel Veillardcf461992000-03-14 18:30:20 +0000963 const xmlChar *name, const xmlChar *ns,
964 xmlAttributeType type, xmlAttributeDefault def,
965 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
Daniel Veillard126f2792000-10-24 17:10:12 +0000966 xmlAttributePtr ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000967 xmlAttributeTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +0000968 xmlElementPtr elemDef;
Daniel Veillard1e346af1999-02-22 10:33:01 +0000969
970 if (dtd == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000971 xmlGenericError(xmlGenericErrorContext,
972 "xmlAddAttributeDecl: dtd == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000973 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000974 return(NULL);
975 }
976 if (name == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000977 xmlGenericError(xmlGenericErrorContext,
978 "xmlAddAttributeDecl: name == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000979 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000980 return(NULL);
981 }
982 if (elem == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000983 xmlGenericError(xmlGenericErrorContext,
984 "xmlAddAttributeDecl: elem == NULL\n");
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +0000985 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +0000986 return(NULL);
987 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000988 /*
989 * Check the type and possibly the default value.
990 */
Daniel Veillard1e346af1999-02-22 10:33:01 +0000991 switch (type) {
992 case XML_ATTRIBUTE_CDATA:
993 break;
994 case XML_ATTRIBUTE_ID:
995 break;
996 case XML_ATTRIBUTE_IDREF:
997 break;
998 case XML_ATTRIBUTE_IDREFS:
999 break;
1000 case XML_ATTRIBUTE_ENTITY:
1001 break;
1002 case XML_ATTRIBUTE_ENTITIES:
1003 break;
1004 case XML_ATTRIBUTE_NMTOKEN:
1005 break;
1006 case XML_ATTRIBUTE_NMTOKENS:
1007 break;
1008 case XML_ATTRIBUTE_ENUMERATION:
1009 break;
1010 case XML_ATTRIBUTE_NOTATION:
1011 break;
1012 default:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001013 xmlGenericError(xmlGenericErrorContext,
1014 "xmlAddAttributeDecl: unknown type %d\n", type);
Daniel Veillardf0cc7cc2000-08-26 21:40:43 +00001015 xmlFreeEnumeration(tree);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001016 return(NULL);
1017 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00001018 if ((defaultValue != NULL) &&
1019 (!xmlValidateAttributeValue(type, defaultValue))) {
1020 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
1021 elem, name, defaultValue);
1022 defaultValue = NULL;
1023 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001024
1025 /*
1026 * Create the Attribute table if needed.
1027 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001028 table = (xmlAttributeTablePtr) dtd->attributes;
1029 if (table == NULL) {
1030 table = xmlCreateAttributeTable();
1031 dtd->attributes = (void *) table;
1032 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001033 if (table == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001034 xmlGenericError(xmlGenericErrorContext,
1035 "xmlAddAttributeDecl: Table creation failed!\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001036 return(NULL);
1037 }
1038
Daniel Veillard1e346af1999-02-22 10:33:01 +00001039
Daniel Veillard6454aec1999-09-02 22:04:43 +00001040 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001041 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001042 xmlGenericError(xmlGenericErrorContext,
1043 "xmlAddAttributeDecl: out of memory\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00001044 return(NULL);
1045 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001046 memset(ret, 0, sizeof(xmlAttribute));
1047 ret->type = XML_ATTRIBUTE_DECL;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001048
1049 /*
1050 * fill the structure.
1051 */
Daniel Veillardcf461992000-03-14 18:30:20 +00001052 ret->atype = type;
1053 ret->name = xmlStrdup(name);
1054 ret->prefix = xmlStrdup(ns);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001055 ret->elem = xmlStrdup(elem);
1056 ret->def = def;
1057 ret->tree = tree;
1058 if (defaultValue != NULL)
1059 ret->defaultValue = xmlStrdup(defaultValue);
Daniel Veillard126f2792000-10-24 17:10:12 +00001060
1061 /*
1062 * Validity Check:
1063 * Search the DTD for previous declarations of the ATTLIST
1064 */
1065 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
1066 /*
1067 * The attribute is already defined in this Dtd.
1068 */
1069 VWARNING(ctxt->userData,
1070 "Attribute %s on %s: already defined\n",
1071 name, elem);
1072 xmlFreeAttribute(ret);
1073 return(NULL);
1074 }
1075
1076 /*
1077 * Validity Check:
1078 * Multiple ID per element
1079 */
1080 elemDef = xmlGetDtdElementDesc(dtd, elem);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001081 if (elemDef != NULL) {
1082 if ((type == XML_ATTRIBUTE_ID) &&
1083 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
1084 VERROR(ctxt->userData,
1085 "Element %s has too may ID attributes defined : %s\n",
1086 elem, name);
Daniel Veillardcf461992000-03-14 18:30:20 +00001087 ret->nexth = elemDef->attributes;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001088 elemDef->attributes = ret;
1089 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001090
Daniel Veillardcf461992000-03-14 18:30:20 +00001091 /*
1092 * Link it to the Dtd
1093 */
1094 ret->parent = dtd;
1095 ret->doc = dtd->doc;
1096 if (dtd->last == NULL) {
1097 dtd->children = dtd->last = (xmlNodePtr) ret;
1098 } else {
1099 dtd->last->next = (xmlNodePtr) ret;
1100 ret->prev = dtd->last;
1101 dtd->last = (xmlNodePtr) ret;
1102 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001103 return(ret);
1104}
1105
1106/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001107 * xmlFreeAttributeTable:
1108 * @table: An attribute table
1109 *
1110 * Deallocate the memory used by an entities hash table.
1111 */
1112void
1113xmlFreeAttributeTable(xmlAttributeTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001114 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1115}
Daniel Veillard1e346af1999-02-22 10:33:01 +00001116
Daniel Veillard126f2792000-10-24 17:10:12 +00001117/**
1118 * xmlCopyAttribute:
1119 * @attr: An attribute
1120 *
1121 * Build a copy of an attribute.
1122 *
1123 * Returns the new xmlAttributePtr or NULL in case of error.
1124 */
1125xmlAttributePtr
1126xmlCopyAttribute(xmlAttributePtr attr) {
1127 xmlAttributePtr cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001128
Daniel Veillard126f2792000-10-24 17:10:12 +00001129 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1130 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001131 xmlGenericError(xmlGenericErrorContext,
1132 "xmlCopyAttribute: out of memory !\n");
Daniel Veillard126f2792000-10-24 17:10:12 +00001133 return(NULL);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001134 }
Daniel Veillard126f2792000-10-24 17:10:12 +00001135 memset(cur, 0, sizeof(xmlAttribute));
1136 cur->atype = attr->atype;
1137 cur->def = attr->def;
1138 cur->tree = xmlCopyEnumeration(attr->tree);
1139 if (attr->elem != NULL)
1140 cur->elem = xmlStrdup(attr->elem);
1141 if (attr->name != NULL)
1142 cur->name = xmlStrdup(attr->name);
1143 if (attr->defaultValue != NULL)
1144 cur->defaultValue = xmlStrdup(attr->defaultValue);
1145 return(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001146}
1147
1148/**
1149 * xmlCopyAttributeTable:
1150 * @table: An attribute table
1151 *
1152 * Build a copy of an attribute table.
1153 *
1154 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1155 */
1156xmlAttributeTablePtr
1157xmlCopyAttributeTable(xmlAttributeTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001158 return((xmlAttributeTablePtr) xmlHashCopy(table,
1159 (xmlHashCopier) xmlCopyAttribute));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001160}
1161
1162/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001163 * xmlDumpAttributeDecl:
1164 * @buf: the XML buffer output
1165 * @attr: An attribute declaration
1166 *
1167 * This will dump the content of the attribute declaration as an XML
1168 * DTD definition
1169 */
1170void
1171xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1172 xmlBufferWriteChar(buf, "<!ATTLIST ");
1173 xmlBufferWriteCHAR(buf, attr->elem);
1174 xmlBufferWriteChar(buf, " ");
Daniel Veillardbe803962000-06-28 23:40:59 +00001175 if (attr->prefix != NULL) {
1176 xmlBufferWriteCHAR(buf, attr->prefix);
1177 xmlBufferWriteChar(buf, ":");
1178 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001179 xmlBufferWriteCHAR(buf, attr->name);
1180 switch (attr->atype) {
1181 case XML_ATTRIBUTE_CDATA:
1182 xmlBufferWriteChar(buf, " CDATA");
1183 break;
1184 case XML_ATTRIBUTE_ID:
1185 xmlBufferWriteChar(buf, " ID");
1186 break;
1187 case XML_ATTRIBUTE_IDREF:
1188 xmlBufferWriteChar(buf, " IDREF");
1189 break;
1190 case XML_ATTRIBUTE_IDREFS:
1191 xmlBufferWriteChar(buf, " IDREFS");
1192 break;
1193 case XML_ATTRIBUTE_ENTITY:
1194 xmlBufferWriteChar(buf, " ENTITY");
1195 break;
1196 case XML_ATTRIBUTE_ENTITIES:
1197 xmlBufferWriteChar(buf, " ENTITIES");
1198 break;
1199 case XML_ATTRIBUTE_NMTOKEN:
1200 xmlBufferWriteChar(buf, " NMTOKEN");
1201 break;
1202 case XML_ATTRIBUTE_NMTOKENS:
1203 xmlBufferWriteChar(buf, " NMTOKENS");
1204 break;
1205 case XML_ATTRIBUTE_ENUMERATION:
1206 xmlBufferWriteChar(buf, " (");
1207 xmlDumpEnumeration(buf, attr->tree);
1208 break;
1209 case XML_ATTRIBUTE_NOTATION:
1210 xmlBufferWriteChar(buf, " NOTATION (");
1211 xmlDumpEnumeration(buf, attr->tree);
1212 break;
1213 default:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001214 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcf461992000-03-14 18:30:20 +00001215 "xmlDumpAttributeTable: internal: unknown type %d\n",
1216 attr->atype);
1217 }
1218 switch (attr->def) {
1219 case XML_ATTRIBUTE_NONE:
1220 break;
1221 case XML_ATTRIBUTE_REQUIRED:
1222 xmlBufferWriteChar(buf, " #REQUIRED");
1223 break;
1224 case XML_ATTRIBUTE_IMPLIED:
1225 xmlBufferWriteChar(buf, " #IMPLIED");
1226 break;
1227 case XML_ATTRIBUTE_FIXED:
1228 xmlBufferWriteChar(buf, " #FIXED");
1229 break;
1230 default:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001231 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcf461992000-03-14 18:30:20 +00001232 "xmlDumpAttributeTable: internal: unknown default %d\n",
1233 attr->def);
1234 }
1235 if (attr->defaultValue != NULL) {
1236 xmlBufferWriteChar(buf, " ");
1237 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1238 }
1239 xmlBufferWriteChar(buf, ">\n");
1240}
1241
1242/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001243 * xmlDumpAttributeTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001244 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001245 * @table: An attribute table
1246 *
1247 * This will dump the content of the attribute table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001248 */
1249void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001250xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001251 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDecl, buf);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001252}
1253
1254/************************************************************************
1255 * *
1256 * NOTATIONs *
1257 * *
1258 ************************************************************************/
1259/**
1260 * xmlCreateNotationTable:
1261 *
1262 * create and initialize an empty notation hash table.
1263 *
1264 * Returns the xmlNotationTablePtr just created or NULL in case
1265 * of error.
1266 */
1267xmlNotationTablePtr
1268xmlCreateNotationTable(void) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001269 return(xmlHashCreate(0));
1270}
Daniel Veillard1e346af1999-02-22 10:33:01 +00001271
Daniel Veillard126f2792000-10-24 17:10:12 +00001272/**
1273 * xmlFreeNotation:
1274 * @not: A notation
1275 *
1276 * Deallocate the memory used by an notation definition
1277 */
1278void
1279xmlFreeNotation(xmlNotationPtr nota) {
1280 if (nota == NULL) return;
1281 if (nota->name != NULL)
1282 xmlFree((xmlChar *) nota->name);
1283 if (nota->PublicID != NULL)
1284 xmlFree((xmlChar *) nota->PublicID);
1285 if (nota->SystemID != NULL)
1286 xmlFree((xmlChar *) nota->SystemID);
1287 memset(nota, -1, sizeof(xmlNotation));
1288 xmlFree(nota);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001289}
1290
1291
1292/**
1293 * xmlAddNotationDecl:
1294 * @dtd: pointer to the DTD
Daniel Veillardb05deb71999-08-10 19:04:08 +00001295 * @ctxt: the validation context
Daniel Veillard1e346af1999-02-22 10:33:01 +00001296 * @name: the entity name
1297 * @PublicID: the public identifier or NULL
1298 * @SystemID: the system identifier or NULL
1299 *
1300 * Register a new notation declaration
1301 *
1302 * Returns NULL if not, othervise the entity
1303 */
1304xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001305xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1306 const xmlChar *PublicID, const xmlChar *SystemID) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001307 xmlNotationPtr ret;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001308 xmlNotationTablePtr table;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001309
1310 if (dtd == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlAddNotationDecl: dtd == NULL\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001313 return(NULL);
1314 }
1315 if (name == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001316 xmlGenericError(xmlGenericErrorContext,
1317 "xmlAddNotationDecl: name == NULL\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001318 return(NULL);
1319 }
1320 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001321 xmlGenericError(xmlGenericErrorContext,
1322 "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001323 }
1324
1325 /*
1326 * Create the Notation table if needed.
1327 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001328 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001329 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001330 dtd->notations = table = xmlCreateNotationTable();
Daniel Veillard1e346af1999-02-22 10:33:01 +00001331 if (table == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001332 xmlGenericError(xmlGenericErrorContext,
1333 "xmlAddNotationDecl: Table creation failed!\n");
Daniel Veillard1e346af1999-02-22 10:33:01 +00001334 return(NULL);
1335 }
1336
Daniel Veillard6454aec1999-09-02 22:04:43 +00001337 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001338 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001339 xmlGenericError(xmlGenericErrorContext,
1340 "xmlAddNotationDecl: out of memory\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00001341 return(NULL);
1342 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001343 memset(ret, 0, sizeof(xmlNotation));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001344
1345 /*
1346 * fill the structure.
1347 */
1348 ret->name = xmlStrdup(name);
1349 if (SystemID != NULL)
1350 ret->SystemID = xmlStrdup(SystemID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001351 if (PublicID != NULL)
1352 ret->PublicID = xmlStrdup(PublicID);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001353
Daniel Veillard126f2792000-10-24 17:10:12 +00001354 /*
1355 * Validity Check:
1356 * Check the DTD for previous declarations of the ATTLIST
1357 */
1358 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001359 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard126f2792000-10-24 17:10:12 +00001360 "xmlAddNotationDecl: %s already defined\n", name);
1361 xmlFreeNotation(ret);
1362 return(NULL);
1363 }
Daniel Veillard1e346af1999-02-22 10:33:01 +00001364 return(ret);
1365}
1366
1367/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001368 * xmlFreeNotationTable:
1369 * @table: An notation table
1370 *
1371 * Deallocate the memory used by an entities hash table.
1372 */
1373void
1374xmlFreeNotationTable(xmlNotationTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001375 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
1376}
Daniel Veillard1e346af1999-02-22 10:33:01 +00001377
Daniel Veillard126f2792000-10-24 17:10:12 +00001378/**
1379 * xmlCopyNotation:
1380 * @nota: A notation
1381 *
1382 * Build a copy of a notation.
1383 *
1384 * Returns the new xmlNotationPtr or NULL in case of error.
1385 */
1386xmlNotationPtr
1387xmlCopyNotation(xmlNotationPtr nota) {
1388 xmlNotationPtr cur;
Daniel Veillard1e346af1999-02-22 10:33:01 +00001389
Daniel Veillard126f2792000-10-24 17:10:12 +00001390 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1391 if (cur == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001392 xmlGenericError(xmlGenericErrorContext,
1393 "xmlCopyNotation: out of memory !\n");
Daniel Veillard126f2792000-10-24 17:10:12 +00001394 return(NULL);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001395 }
Daniel Veillard126f2792000-10-24 17:10:12 +00001396 if (nota->name != NULL)
1397 cur->name = xmlStrdup(nota->name);
1398 else
1399 cur->name = NULL;
1400 if (nota->PublicID != NULL)
1401 cur->PublicID = xmlStrdup(nota->PublicID);
1402 else
1403 cur->PublicID = NULL;
1404 if (nota->SystemID != NULL)
1405 cur->SystemID = xmlStrdup(nota->SystemID);
1406 else
1407 cur->SystemID = NULL;
1408 return(cur);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001409}
1410
1411/**
1412 * xmlCopyNotationTable:
1413 * @table: A notation table
1414 *
1415 * Build a copy of a notation table.
1416 *
1417 * Returns the new xmlNotationTablePtr or NULL in case of error.
1418 */
1419xmlNotationTablePtr
1420xmlCopyNotationTable(xmlNotationTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001421 return((xmlNotationTablePtr) xmlHashCopy(table,
1422 (xmlHashCopier) xmlCopyNotation));
Daniel Veillard1e346af1999-02-22 10:33:01 +00001423}
1424
1425/**
Daniel Veillardcf461992000-03-14 18:30:20 +00001426 * xmlDumpNotationDecl:
1427 * @buf: the XML buffer output
1428 * @nota: A notation declaration
1429 *
1430 * This will dump the content the notation declaration as an XML DTD definition
1431 */
1432void
1433xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
1434 xmlBufferWriteChar(buf, "<!NOTATION ");
1435 xmlBufferWriteCHAR(buf, nota->name);
1436 if (nota->PublicID != NULL) {
1437 xmlBufferWriteChar(buf, " PUBLIC ");
1438 xmlBufferWriteQuotedString(buf, nota->PublicID);
1439 if (nota->SystemID != NULL) {
1440 xmlBufferWriteChar(buf, " ");
1441 xmlBufferWriteCHAR(buf, nota->SystemID);
1442 }
1443 } else {
1444 xmlBufferWriteChar(buf, " SYSTEM ");
1445 xmlBufferWriteCHAR(buf, nota->SystemID);
1446 }
1447 xmlBufferWriteChar(buf, " >\n");
1448}
1449
1450/**
Daniel Veillard1e346af1999-02-22 10:33:01 +00001451 * xmlDumpNotationTable:
Daniel Veillard011b63c1999-06-02 17:44:04 +00001452 * @buf: the XML buffer output
Daniel Veillard1e346af1999-02-22 10:33:01 +00001453 * @table: A notation table
1454 *
1455 * This will dump the content of the notation table as an XML DTD definition
Daniel Veillard1e346af1999-02-22 10:33:01 +00001456 */
1457void
Daniel Veillard5099ae81999-04-21 20:12:07 +00001458xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001459 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDecl, buf);
Daniel Veillard1e346af1999-02-22 10:33:01 +00001460}
Daniel Veillardb05deb71999-08-10 19:04:08 +00001461
1462/************************************************************************
1463 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001464 * IDs *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001465 * *
1466 ************************************************************************/
1467/**
1468 * xmlCreateIDTable:
1469 *
1470 * create and initialize an empty id hash table.
1471 *
1472 * Returns the xmlIDTablePtr just created or NULL in case
1473 * of error.
1474 */
1475xmlIDTablePtr
1476xmlCreateIDTable(void) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001477 return(xmlHashCreate(0));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001478}
1479
Daniel Veillard126f2792000-10-24 17:10:12 +00001480/**
1481 * xmlFreeID:
1482 * @not: A id
1483 *
1484 * Deallocate the memory used by an id definition
1485 */
1486void
1487xmlFreeID(xmlIDPtr id) {
1488 if (id == NULL) return;
1489 if (id->value != NULL)
1490 xmlFree((xmlChar *) id->value);
1491 memset(id, -1, sizeof(xmlID));
1492 xmlFree(id);
1493}
Daniel Veillard991e63d1999-08-15 23:32:28 +00001494
1495/**
1496 * xmlAddID:
1497 * @ctxt: the validation context
1498 * @doc: pointer to the document
1499 * @value: the value name
1500 * @attr: the attribute holding the ID
1501 *
1502 * Register a new id declaration
1503 *
1504 * Returns NULL if not, othervise the new xmlIDPtr
1505 */
1506xmlIDPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001507xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillard991e63d1999-08-15 23:32:28 +00001508 xmlAttrPtr attr) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001509 xmlIDPtr ret;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001510 xmlIDTablePtr table;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001511
1512 if (doc == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001513 xmlGenericError(xmlGenericErrorContext,
1514 "xmlAddIDDecl: doc == NULL\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001515 return(NULL);
1516 }
1517 if (value == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001518 xmlGenericError(xmlGenericErrorContext,
1519 "xmlAddIDDecl: value == NULL\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001520 return(NULL);
1521 }
1522 if (attr == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001523 xmlGenericError(xmlGenericErrorContext,
1524 "xmlAddIDDecl: attr == NULL\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001525 return(NULL);
1526 }
1527
1528 /*
1529 * Create the ID table if needed.
1530 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001531 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001532 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001533 doc->ids = table = xmlCreateIDTable();
Daniel Veillard991e63d1999-08-15 23:32:28 +00001534 if (table == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001535 xmlGenericError(xmlGenericErrorContext,
1536 "xmlAddID: Table creation failed!\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001537 return(NULL);
1538 }
1539
Daniel Veillard6454aec1999-09-02 22:04:43 +00001540 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001541 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001542 xmlGenericError(xmlGenericErrorContext,
1543 "xmlAddID: out of memory\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001544 return(NULL);
1545 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001546
1547 /*
1548 * fill the structure.
1549 */
1550 ret->value = xmlStrdup(value);
1551 ret->attr = attr;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001552
Daniel Veillard126f2792000-10-24 17:10:12 +00001553 if (xmlHashAddEntry(table, value, ret) < 0) {
1554 /*
1555 * The id is already defined in this Dtd.
1556 */
1557 VERROR(ctxt->userData, "ID %s already defined\n", value);
1558 xmlFreeID(ret);
1559 return(NULL);
1560 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001561 return(ret);
1562}
1563
1564/**
Daniel Veillard991e63d1999-08-15 23:32:28 +00001565 * xmlFreeIDTable:
1566 * @table: An id table
1567 *
1568 * Deallocate the memory used by an ID hash table.
1569 */
1570void
1571xmlFreeIDTable(xmlIDTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001572 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001573}
1574
1575/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001576 * xmlIsID:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001577 * @doc: the document
1578 * @elem: the element carrying the attribute
1579 * @attr: the attribute
1580 *
1581 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1582 * then this is simple, otherwise we use an heuristic: name ID (upper
1583 * or lowercase).
1584 *
1585 * Returns 0 or 1 depending on the lookup result
1586 */
1587int
1588xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard71b656e2000-01-05 14:46:17 +00001589 if (doc == NULL) return(0);
1590 if (attr == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001591 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillarde8282ed2000-10-10 23:01:31 +00001592 return(0);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001593 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001594 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
1595 (xmlStrEqual(BAD_CAST "name", attr->name)))
Daniel Veillard71b656e2000-01-05 14:46:17 +00001596 return(1);
1597 return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001598 } else {
1599 xmlAttributePtr attrDecl;
1600
Daniel Veillard71b656e2000-01-05 14:46:17 +00001601 if (elem == NULL) return(0);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001602 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1603 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1604 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1605 attr->name);
1606
Daniel Veillardcf461992000-03-14 18:30:20 +00001607 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001608 return(1);
1609 }
1610 return(0);
1611}
1612
Daniel Veillardb96e6431999-08-29 21:02:19 +00001613/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001614 * xmlRemoveID
1615 * @doc: the document
1616 * @attr: the attribute
1617 *
1618 * Remove the given attribute from the ID table maintained internally.
1619 *
1620 * Returns -1 if the lookup failed and 0 otherwise
1621 */
1622int
1623xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001624 xmlAttrPtr cur;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001625 xmlIDTablePtr table;
Daniel Veillard126f2792000-10-24 17:10:12 +00001626 xmlChar *ID;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001627
1628 if (doc == NULL) return(-1);
1629 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001630 table = (xmlIDTablePtr) doc->ids;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001631 if (table == NULL)
1632 return(-1);
1633
Daniel Veillard126f2792000-10-24 17:10:12 +00001634 if (attr == NULL)
1635 return(-1);
1636 ID = xmlNodeListGetString(doc, attr->children, 1);
1637 if (ID == NULL)
1638 return(-1);
1639 cur = xmlHashLookup(table, ID);
1640 if (cur != attr) {
1641 xmlFree(ID);
1642 return(-1);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001643 }
Daniel Veillard126f2792000-10-24 17:10:12 +00001644 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
1645 xmlFree(ID);
1646 return(0);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001647}
1648
1649/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001650 * xmlGetID:
1651 * @doc: pointer to the document
1652 * @ID: the ID value
1653 *
1654 * Search the attribute declaring the given ID
1655 *
1656 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1657 */
1658xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001659xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001660 xmlIDTablePtr table;
Daniel Veillard126f2792000-10-24 17:10:12 +00001661 xmlIDPtr id;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001662
1663 if (doc == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001664 xmlGenericError(xmlGenericErrorContext, "xmlGetID: doc == NULL\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001665 return(NULL);
1666 }
1667
1668 if (ID == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001669 xmlGenericError(xmlGenericErrorContext, "xmlGetID: ID == NULL\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001670 return(NULL);
1671 }
1672
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001673 table = (xmlIDTablePtr) doc->ids;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001674 if (table == NULL)
1675 return(NULL);
1676
Daniel Veillard126f2792000-10-24 17:10:12 +00001677 id = xmlHashLookup(table, ID);
1678 if (id == NULL)
1679 return(NULL);
1680 return(id->attr);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001681}
1682
Daniel Veillard991e63d1999-08-15 23:32:28 +00001683/************************************************************************
1684 * *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001685 * Refs *
1686 * *
1687 ************************************************************************/
1688/**
1689 * xmlCreateRefTable:
1690 *
1691 * create and initialize an empty ref hash table.
1692 *
1693 * Returns the xmlRefTablePtr just created or NULL in case
1694 * of error.
1695 */
1696xmlRefTablePtr
1697xmlCreateRefTable(void) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001698 return(xmlHashCreate(0));
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001699}
1700
Daniel Veillard126f2792000-10-24 17:10:12 +00001701/**
1702 * xmlFreeRef:
1703 * @ref: A ref
1704 *
1705 * Deallocate the memory used by an ref definition
1706 */
1707void
1708xmlFreeRef(xmlRefPtr ref) {
1709 if (ref == NULL) return;
1710 if (ref->value != NULL)
1711 xmlFree((xmlChar *) ref->value);
1712 memset(ref, -1, sizeof(xmlRef));
1713 xmlFree(ref);
1714}
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001715
1716/**
1717 * xmlAddRef:
1718 * @ctxt: the validation context
1719 * @doc: pointer to the document
1720 * @value: the value name
1721 * @attr: the attribute holding the Ref
1722 *
1723 * Register a new ref declaration
1724 *
1725 * Returns NULL if not, othervise the new xmlRefPtr
1726 */
1727xmlRefPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001728xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001729 xmlAttrPtr attr) {
1730 xmlRefPtr ret;
1731 xmlRefTablePtr table;
1732
1733 if (doc == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001734 xmlGenericError(xmlGenericErrorContext,
1735 "xmlAddRefDecl: doc == NULL\n");
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001736 return(NULL);
1737 }
1738 if (value == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001739 xmlGenericError(xmlGenericErrorContext,
1740 "xmlAddRefDecl: value == NULL\n");
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001741 return(NULL);
1742 }
1743 if (attr == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001744 xmlGenericError(xmlGenericErrorContext,
1745 "xmlAddRefDecl: attr == NULL\n");
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001746 return(NULL);
1747 }
1748
1749 /*
1750 * Create the Ref table if needed.
1751 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001752 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001753 if (table == NULL)
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001754 doc->refs = table = xmlCreateRefTable();
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001755 if (table == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001756 xmlGenericError(xmlGenericErrorContext,
1757 "xmlAddRef: Table creation failed!\n");
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001758 return(NULL);
1759 }
1760
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001761 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1762 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001763 xmlGenericError(xmlGenericErrorContext,
1764 "xmlAddRef: out of memory\n");
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001765 return(NULL);
1766 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001767
1768 /*
1769 * fill the structure.
1770 */
1771 ret->value = xmlStrdup(value);
1772 ret->attr = attr;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001773
Daniel Veillard126f2792000-10-24 17:10:12 +00001774 /*
1775 * !!! Should we keep track of all refs ? and use xmlHashAddEntry2 ?
1776 */
1777 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard1f83d392001-02-08 09:37:42 +00001778 /*
1779 * Since there is no discrimination on error returns
1780 * from xmlHashAddEntry, I'm presuming <0 means the
1781 * key already exists.
1782 */
1783 xmlHashUpdateEntry(table, value, ret, (xmlHashDeallocator) xmlFreeRef);
Daniel Veillard126f2792000-10-24 17:10:12 +00001784 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001785 return(ret);
1786}
1787
1788/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001789 * xmlFreeRefTable:
1790 * @table: An ref table
1791 *
1792 * Deallocate the memory used by an Ref hash table.
1793 */
1794void
1795xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001796 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRef);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001797}
1798
1799/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001800 * xmlIsRef:
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001801 * @doc: the document
1802 * @elem: the element carrying the attribute
1803 * @attr: the attribute
1804 *
1805 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1806 * then this is simple, otherwise we use an heuristic: name Ref (upper
1807 * or lowercase).
1808 *
1809 * Returns 0 or 1 depending on the lookup result
1810 */
1811int
1812xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1813 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1814 return(0);
Daniel Veillardd83eb822000-06-30 18:39:56 +00001815 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1816 /* TODO @@@ */
1817 return(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001818 } else {
1819 xmlAttributePtr attrDecl;
1820
1821 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1822 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1823 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1824 attr->name);
1825
Daniel Veillardcf461992000-03-14 18:30:20 +00001826 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001827 return(1);
1828 }
1829 return(0);
1830}
1831
1832/**
Daniel Veillard71b656e2000-01-05 14:46:17 +00001833 * xmlRemoveRef
1834 * @doc: the document
1835 * @attr: the attribute
1836 *
1837 * Remove the given attribute from the Ref table maintained internally.
1838 *
1839 * Returns -1 if the lookup failed and 0 otherwise
1840 */
1841int
1842xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard126f2792000-10-24 17:10:12 +00001843 xmlAttrPtr cur;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001844 xmlRefTablePtr table;
Daniel Veillard126f2792000-10-24 17:10:12 +00001845 xmlChar *ID;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001846
1847 if (doc == NULL) return(-1);
1848 if (attr == NULL) return(-1);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001849 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard71b656e2000-01-05 14:46:17 +00001850 if (table == NULL)
1851 return(-1);
1852
Daniel Veillard126f2792000-10-24 17:10:12 +00001853 if (attr == NULL)
1854 return(-1);
1855 ID = xmlNodeListGetString(doc, attr->children, 1);
1856 if (ID == NULL)
1857 return(-1);
1858 cur = xmlHashLookup(table, ID);
1859 if (cur != attr) {
1860 xmlFree(ID);
1861 return(-1);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001862 }
Daniel Veillard126f2792000-10-24 17:10:12 +00001863 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeRef);
1864 xmlFree(ID);
1865 return(0);
Daniel Veillard71b656e2000-01-05 14:46:17 +00001866}
1867
1868/**
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001869 * xmlGetRef:
1870 * @doc: pointer to the document
1871 * @Ref: the Ref value
1872 *
Daniel Veillard71b656e2000-01-05 14:46:17 +00001873 * Search the next attribute declaring the given Ref
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001874 *
1875 * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1876 */
1877xmlAttrPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001878xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001879 xmlRefTablePtr table;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001880
1881 if (doc == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001882 xmlGenericError(xmlGenericErrorContext, "xmlGetRef: doc == NULL\n");
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001883 return(NULL);
1884 }
1885
1886 if (Ref == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001887 xmlGenericError(xmlGenericErrorContext, "xmlGetRef: Ref == NULL\n");
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001888 return(NULL);
1889 }
1890
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001891 table = (xmlRefTablePtr) doc->refs;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001892 if (table == NULL)
1893 return(NULL);
1894
Daniel Veillard126f2792000-10-24 17:10:12 +00001895 return(xmlHashLookup(table, Ref));
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001896}
1897
1898/************************************************************************
1899 * *
Daniel Veillardb05deb71999-08-10 19:04:08 +00001900 * Routines for validity checking *
1901 * *
1902 ************************************************************************/
1903
1904/**
1905 * xmlGetDtdElementDesc:
1906 * @dtd: a pointer to the DtD to search
1907 * @name: the element name
1908 *
1909 * Search the Dtd for the description of this element
1910 *
1911 * returns the xmlElementPtr if found or NULL
1912 */
1913
1914xmlElementPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001915xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001916 xmlElementTablePtr table;
1917 xmlElementPtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00001918 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001919
1920 if (dtd == NULL) return(NULL);
1921 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001922 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001923
Daniel Veillardbe803962000-06-28 23:40:59 +00001924 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillard126f2792000-10-24 17:10:12 +00001925 if (uqname != NULL) {
1926 cur = xmlHashLookup2(table, uqname, prefix);
1927 if (prefix != NULL) xmlFree(prefix);
1928 if (uqname != NULL) xmlFree(uqname);
1929 } else
1930 cur = xmlHashLookup2(table, name, NULL);
1931 return(cur);
Daniel Veillardbe803962000-06-28 23:40:59 +00001932}
1933
1934/**
1935 * xmlGetDtdQElementDesc:
1936 * @dtd: a pointer to the DtD to search
1937 * @name: the element name
1938 * @prefix: the element namespace prefix
1939 *
1940 * Search the Dtd for the description of this element
1941 *
1942 * returns the xmlElementPtr if found or NULL
1943 */
1944
1945xmlElementPtr
1946xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
1947 const xmlChar *prefix) {
1948 xmlElementTablePtr table;
Daniel Veillardbe803962000-06-28 23:40:59 +00001949
1950 if (dtd == NULL) return(NULL);
1951 if (dtd->elements == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00001952 table = (xmlElementTablePtr) dtd->elements;
Daniel Veillardbe803962000-06-28 23:40:59 +00001953
Daniel Veillard126f2792000-10-24 17:10:12 +00001954 return(xmlHashLookup2(table, name, prefix));
Daniel Veillardb05deb71999-08-10 19:04:08 +00001955}
1956
1957/**
1958 * xmlGetDtdAttrDesc:
1959 * @dtd: a pointer to the DtD to search
1960 * @elem: the element name
1961 * @name: the attribute name
1962 *
1963 * Search the Dtd for the description of this attribute on
1964 * this element.
1965 *
1966 * returns the xmlAttributePtr if found or NULL
1967 */
1968
1969xmlAttributePtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001970xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001971 xmlAttributeTablePtr table;
1972 xmlAttributePtr cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00001973 xmlChar *uqname = NULL, *prefix = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00001974
1975 if (dtd == NULL) return(NULL);
1976 if (dtd->attributes == NULL) return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001977
Daniel Veillardb1059e22000-09-16 14:02:43 +00001978 table = (xmlAttributeTablePtr) dtd->attributes;
1979 if (table == NULL)
1980 return(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00001981
Daniel Veillardbe803962000-06-28 23:40:59 +00001982 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillardbe803962000-06-28 23:40:59 +00001983
Daniel Veillard126f2792000-10-24 17:10:12 +00001984 if (uqname != NULL) {
1985 cur = xmlHashLookup3(table, uqname, prefix, elem);
1986 if (prefix != NULL) xmlFree(prefix);
1987 if (uqname != NULL) xmlFree(uqname);
1988 } else
1989 cur = xmlHashLookup3(table, name, NULL, elem);
1990 return(cur);
Daniel Veillardbe803962000-06-28 23:40:59 +00001991}
1992
1993/**
1994 * xmlGetDtdQAttrDesc:
1995 * @dtd: a pointer to the DtD to search
1996 * @elem: the element name
1997 * @name: the attribute name
1998 * @prefix: the attribute namespace prefix
1999 *
2000 * Search the Dtd for the description of this qualified attribute on
2001 * this element.
2002 *
2003 * returns the xmlAttributePtr if found or NULL
2004 */
2005
2006xmlAttributePtr
2007xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2008 const xmlChar *prefix) {
2009 xmlAttributeTablePtr table;
Daniel Veillardbe803962000-06-28 23:40:59 +00002010
2011 if (dtd == NULL) return(NULL);
2012 if (dtd->attributes == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002013 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillardbe803962000-06-28 23:40:59 +00002014
Daniel Veillard126f2792000-10-24 17:10:12 +00002015 return(xmlHashLookup3(table, name, prefix, elem));
Daniel Veillardb05deb71999-08-10 19:04:08 +00002016}
2017
2018/**
2019 * xmlGetDtdNotationDesc:
2020 * @dtd: a pointer to the DtD to search
2021 * @name: the notation name
2022 *
2023 * Search the Dtd for the description of this notation
2024 *
2025 * returns the xmlNotationPtr if found or NULL
2026 */
2027
2028xmlNotationPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002029xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002030 xmlNotationTablePtr table;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002031
2032 if (dtd == NULL) return(NULL);
2033 if (dtd->notations == NULL) return(NULL);
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002034 table = (xmlNotationTablePtr) dtd->notations;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002035
Daniel Veillard126f2792000-10-24 17:10:12 +00002036 return(xmlHashLookup(table, name));
Daniel Veillardb05deb71999-08-10 19:04:08 +00002037}
2038
2039/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00002040 * xmlValidateNotationUse:
2041 * @ctxt: the validation context
2042 * @doc: the document
2043 * @notationName: the notation name to check
2044 *
2045 * Validate that the given mame match a notation declaration.
2046 * - [ VC: Notation Declared ]
2047 *
2048 * returns 1 if valid or 0 otherwise
2049 */
2050
2051int
2052xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002053 const xmlChar *notationName) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002054 xmlNotationPtr notaDecl;
2055 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2056
2057 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2058 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2059 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2060
2061 if (notaDecl == NULL) {
2062 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2063 notationName);
2064 return(0);
2065 }
2066 return(1);
2067}
2068
2069/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002070 * xmlIsMixedElement
2071 * @doc: the document
2072 * @name: the element name
2073 *
2074 * Search in the DtDs whether an element accept Mixed content (or ANY)
2075 * basically if it is supposed to accept text childs
2076 *
2077 * returns 0 if no, 1 if yes, and -1 if no element description is available
2078 */
2079
2080int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002081xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002082 xmlElementPtr elemDecl;
2083
2084 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2085
2086 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2087 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2088 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2089 if (elemDecl == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002090 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002091 case XML_ELEMENT_TYPE_ELEMENT:
2092 return(0);
2093 case XML_ELEMENT_TYPE_EMPTY:
2094 /*
2095 * return 1 for EMPTY since we want VC error to pop up
2096 * on <empty> </empty> for example
2097 */
2098 case XML_ELEMENT_TYPE_ANY:
2099 case XML_ELEMENT_TYPE_MIXED:
2100 return(1);
2101 }
2102 return(1);
2103}
2104
2105/**
2106 * xmlValidateNameValue:
2107 * @value: an Name value
2108 *
2109 * Validate that the given value match Name production
2110 *
2111 * returns 1 if valid or 0 otherwise
2112 */
2113
2114int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002115xmlValidateNameValue(const xmlChar *value) {
2116 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002117
2118 if (value == NULL) return(0);
2119 cur = value;
2120
2121 if (!IS_LETTER(*cur) && (*cur != '_') &&
2122 (*cur != ':')) {
2123 return(0);
2124 }
2125
2126 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2127 (*cur == '.') || (*cur == '-') ||
2128 (*cur == '_') || (*cur == ':') ||
2129 (IS_COMBINING(*cur)) ||
2130 (IS_EXTENDER(*cur)))
2131 cur++;
2132
2133 if (*cur != 0) return(0);
2134
2135 return(1);
2136}
2137
2138/**
2139 * xmlValidateNamesValue:
2140 * @value: an Names value
2141 *
2142 * Validate that the given value match Names production
2143 *
2144 * returns 1 if valid or 0 otherwise
2145 */
2146
2147int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002148xmlValidateNamesValue(const xmlChar *value) {
2149 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002150
2151 if (value == NULL) return(0);
2152 cur = value;
2153
2154 if (!IS_LETTER(*cur) && (*cur != '_') &&
2155 (*cur != ':')) {
2156 return(0);
2157 }
2158
2159 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2160 (*cur == '.') || (*cur == '-') ||
2161 (*cur == '_') || (*cur == ':') ||
2162 (IS_COMBINING(*cur)) ||
2163 (IS_EXTENDER(*cur)))
2164 cur++;
2165
2166 while (IS_BLANK(*cur)) {
2167 while (IS_BLANK(*cur)) cur++;
2168
2169 if (!IS_LETTER(*cur) && (*cur != '_') &&
2170 (*cur != ':')) {
2171 return(0);
2172 }
2173
2174 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2175 (*cur == '.') || (*cur == '-') ||
2176 (*cur == '_') || (*cur == ':') ||
2177 (IS_COMBINING(*cur)) ||
2178 (IS_EXTENDER(*cur)))
2179 cur++;
2180 }
2181
2182 if (*cur != 0) return(0);
2183
2184 return(1);
2185}
2186
2187/**
2188 * xmlValidateNmtokenValue:
2189 * @value: an Mntoken value
2190 *
2191 * Validate that the given value match Nmtoken production
2192 *
2193 * [ VC: Name Token ]
2194 *
2195 * returns 1 if valid or 0 otherwise
2196 */
2197
2198int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002199xmlValidateNmtokenValue(const xmlChar *value) {
2200 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002201
2202 if (value == NULL) return(0);
2203 cur = value;
2204
2205 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2206 (*cur != '.') && (*cur != '-') &&
2207 (*cur != '_') && (*cur != ':') &&
2208 (!IS_COMBINING(*cur)) &&
2209 (!IS_EXTENDER(*cur)))
2210 return(0);
2211
2212 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2213 (*cur == '.') || (*cur == '-') ||
2214 (*cur == '_') || (*cur == ':') ||
2215 (IS_COMBINING(*cur)) ||
2216 (IS_EXTENDER(*cur)))
2217 cur++;
2218
2219 if (*cur != 0) return(0);
2220
2221 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002222}
2223
2224/**
2225 * xmlValidateNmtokensValue:
2226 * @value: an Mntokens value
2227 *
2228 * Validate that the given value match Nmtokens production
2229 *
2230 * [ VC: Name Token ]
2231 *
2232 * returns 1 if valid or 0 otherwise
2233 */
2234
2235int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002236xmlValidateNmtokensValue(const xmlChar *value) {
2237 const xmlChar *cur;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002238
2239 if (value == NULL) return(0);
2240 cur = value;
2241
Daniel Veillardcf461992000-03-14 18:30:20 +00002242 while (IS_BLANK(*cur)) cur++;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002243 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2244 (*cur != '.') && (*cur != '-') &&
2245 (*cur != '_') && (*cur != ':') &&
2246 (!IS_COMBINING(*cur)) &&
2247 (!IS_EXTENDER(*cur)))
2248 return(0);
2249
2250 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2251 (*cur == '.') || (*cur == '-') ||
2252 (*cur == '_') || (*cur == ':') ||
2253 (IS_COMBINING(*cur)) ||
2254 (IS_EXTENDER(*cur)))
2255 cur++;
2256
2257 while (IS_BLANK(*cur)) {
2258 while (IS_BLANK(*cur)) cur++;
Daniel Veillardcf461992000-03-14 18:30:20 +00002259 if (*cur == 0) return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002260
2261 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2262 (*cur != '.') && (*cur != '-') &&
2263 (*cur != '_') && (*cur != ':') &&
2264 (!IS_COMBINING(*cur)) &&
2265 (!IS_EXTENDER(*cur)))
2266 return(0);
2267
2268 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2269 (*cur == '.') || (*cur == '-') ||
2270 (*cur == '_') || (*cur == ':') ||
2271 (IS_COMBINING(*cur)) ||
2272 (IS_EXTENDER(*cur)))
2273 cur++;
2274 }
2275
2276 if (*cur != 0) return(0);
2277
2278 return(1);
2279}
2280
2281/**
2282 * xmlValidateNotationDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002283 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002284 * @doc: a document instance
2285 * @nota: a notation definition
2286 *
2287 * Try to validate a single notation definition
2288 * basically it does the following checks as described by the
2289 * XML-1.0 recommendation:
2290 * - it seems that no validity constraing exist on notation declarations
2291 * But this function get called anyway ...
2292 *
2293 * returns 1 if valid or 0 otherwise
2294 */
2295
2296int
2297xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2298 xmlNotationPtr nota) {
2299 int ret = 1;
2300
2301 return(ret);
2302}
2303
2304/**
2305 * xmlValidateAttributeValue:
2306 * @type: an attribute type
2307 * @value: an attribute value
2308 *
2309 * Validate that the given attribute value match the proper production
2310 *
2311 * [ VC: ID ]
2312 * Values of type ID must match the Name production....
2313 *
2314 * [ VC: IDREF ]
2315 * Values of type IDREF must match the Name production, and values
2316 * of type IDREFS must match Names ...
2317 *
2318 * [ VC: Entity Name ]
2319 * Values of type ENTITY must match the Name production, values
2320 * of type ENTITIES must match Names ...
2321 *
2322 * [ VC: Name Token ]
2323 * Values of type NMTOKEN must match the Nmtoken production; values
2324 * of type NMTOKENS must match Nmtokens.
2325 *
2326 * returns 1 if valid or 0 otherwise
2327 */
2328
2329int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002330xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002331 switch (type) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002332 case XML_ATTRIBUTE_ENTITIES:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002333 case XML_ATTRIBUTE_IDREFS:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002334 return(xmlValidateNamesValue(value));
Daniel Veillardb96e6431999-08-29 21:02:19 +00002335 case XML_ATTRIBUTE_ENTITY:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002336 case XML_ATTRIBUTE_IDREF:
2337 case XML_ATTRIBUTE_ID:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002338 case XML_ATTRIBUTE_NOTATION:
2339 return(xmlValidateNameValue(value));
2340 case XML_ATTRIBUTE_NMTOKENS:
2341 case XML_ATTRIBUTE_ENUMERATION:
2342 return(xmlValidateNmtokensValue(value));
2343 case XML_ATTRIBUTE_NMTOKEN:
2344 return(xmlValidateNmtokenValue(value));
2345 case XML_ATTRIBUTE_CDATA:
2346 break;
2347 }
2348 return(1);
2349}
2350
2351/**
Daniel Veillardcf461992000-03-14 18:30:20 +00002352 * xmlValidateAttributeValue2:
2353 * @ctxt: the validation context
2354 * @doc: the document
2355 * @name: the attribute name (used for error reporting only)
2356 * @type: the attribute type
2357 * @value: the attribute value
2358 *
2359 * Validate that the given attribute value match a given type.
2360 * This typically cannot be done before having finished parsing
2361 * the subsets.
2362 *
2363 * [ VC: IDREF ]
2364 * Values of type IDREF must match one of the declared IDs
2365 * Values of type IDREFS must match a sequence of the declared IDs
2366 * each Name must match the value of an ID attribute on some element
2367 * in the XML document; i.e. IDREF values must match the value of
2368 * some ID attribute
2369 *
2370 * [ VC: Entity Name ]
2371 * Values of type ENTITY must match one declared entity
2372 * Values of type ENTITIES must match a sequence of declared entities
2373 *
2374 * [ VC: Notation Attributes ]
2375 * all notation names in the declaration must be declared.
2376 *
2377 * returns 1 if valid or 0 otherwise
2378 */
2379
2380int
2381xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2382 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2383 int ret = 1;
2384 switch (type) {
2385 case XML_ATTRIBUTE_IDREFS:
2386 case XML_ATTRIBUTE_IDREF:
2387 case XML_ATTRIBUTE_ID:
2388 case XML_ATTRIBUTE_NMTOKENS:
2389 case XML_ATTRIBUTE_ENUMERATION:
2390 case XML_ATTRIBUTE_NMTOKEN:
2391 case XML_ATTRIBUTE_CDATA:
2392 break;
2393 case XML_ATTRIBUTE_ENTITY: {
2394 xmlEntityPtr ent;
2395
2396 ent = xmlGetDocEntity(doc, value);
2397 if (ent == NULL) {
2398 VERROR(ctxt->userData,
2399 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2400 name, value);
2401 ret = 0;
2402 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2403 VERROR(ctxt->userData,
2404 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2405 name, value);
2406 ret = 0;
2407 }
2408 break;
2409 }
2410 case XML_ATTRIBUTE_ENTITIES: {
2411 xmlChar *dup, *nam = NULL, *cur, save;
2412 xmlEntityPtr ent;
2413
2414 dup = xmlStrdup(value);
2415 if (dup == NULL)
2416 return(0);
2417 cur = dup;
2418 while (*cur != 0) {
2419 nam = cur;
2420 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2421 save = *cur;
2422 *cur = 0;
2423 ent = xmlGetDocEntity(doc, nam);
2424 if (ent == NULL) {
2425 VERROR(ctxt->userData,
2426 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2427 name, nam);
2428 ret = 0;
2429 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2430 VERROR(ctxt->userData,
2431 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2432 name, nam);
2433 ret = 0;
2434 }
2435 if (save == 0)
2436 break;
2437 *cur = save;
2438 while (IS_BLANK(*cur)) cur++;
2439 }
2440 xmlFree(dup);
2441 break;
2442 }
2443 case XML_ATTRIBUTE_NOTATION: {
2444 xmlNotationPtr nota;
2445
2446 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2447 if ((nota == NULL) && (doc->extSubset != NULL))
2448 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2449
2450 if (nota == NULL) {
2451 VERROR(ctxt->userData,
2452 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2453 name, value);
2454 ret = 0;
2455 }
2456 break;
2457 }
2458 }
2459 return(ret);
2460}
2461
2462/**
2463 * xmlValidNormalizeAttributeValue:
2464 * @doc: the document
2465 * @elem: the parent
2466 * @name: the attribute name
2467 * @value: the attribute value
2468 *
2469 * Does the validation related extra step of the normalization of attribute
2470 * values:
2471 *
2472 * If the declared value is not CDATA, then the XML processor must further
2473 * process the normalized attribute value by discarding any leading and
2474 * trailing space (#x20) characters, and by replacing sequences of space
2475 * (#x20) characters by single space (#x20) character.
2476 *
2477 * returns a new normalized string if normalization is needed, NULL otherwise
2478 * the caller must free the returned value.
2479 */
2480
2481xmlChar *
2482xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2483 const xmlChar *name, const xmlChar *value) {
2484 xmlChar *ret, *dst;
2485 const xmlChar *src;
Daniel Veillardbe803962000-06-28 23:40:59 +00002486 xmlAttributePtr attrDecl = NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00002487
2488 if (doc == NULL) return(NULL);
2489 if (elem == NULL) return(NULL);
2490 if (name == NULL) return(NULL);
2491 if (value == NULL) return(NULL);
2492
Daniel Veillardbe803962000-06-28 23:40:59 +00002493 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2494 xmlChar qname[500];
2495#ifdef HAVE_SNPRINTF
2496 snprintf((char *) qname, sizeof(qname), "%s:%s",
2497 elem->ns->prefix, elem->name);
2498#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00002499 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00002500#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00002501 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00002502 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2503 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2504 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2505 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002506 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2507 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2508 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2509
2510 if (attrDecl == NULL)
2511 return(NULL);
2512 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2513 return(NULL);
2514
2515 ret = xmlStrdup(value);
2516 if (ret == NULL)
2517 return(NULL);
2518 src = value;
2519 dst = ret;
2520 while (*src == 0x20) src++;
2521 while (*src != 0) {
2522 if (*src == 0x20) {
2523 while (*src == 0x20) src++;
2524 if (*src != 0)
2525 *dst++ = 0x20;
2526 } else {
2527 *dst++ = *src++;
2528 }
2529 }
2530 *dst = 0;
2531 return(ret);
2532}
2533
Daniel Veillard126f2792000-10-24 17:10:12 +00002534void
2535xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
2536 const xmlChar* name) {
2537 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
2538}
2539
Daniel Veillardcf461992000-03-14 18:30:20 +00002540/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00002541 * xmlValidateAttributeDecl:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002542 * @ctxt: the validation context
Daniel Veillardb05deb71999-08-10 19:04:08 +00002543 * @doc: a document instance
2544 * @attr: an attribute definition
2545 *
2546 * Try to validate a single attribute definition
2547 * basically it does the following checks as described by the
2548 * XML-1.0 recommendation:
2549 * - [ VC: Attribute Default Legal ]
2550 * - [ VC: Enumeration ]
2551 * - [ VC: ID Attribute Default ]
2552 *
2553 * The ID/IDREF uniqueness and matching are done separately
2554 *
2555 * returns 1 if valid or 0 otherwise
2556 */
2557
2558int
2559xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2560 xmlAttributePtr attr) {
2561 int ret = 1;
2562 int val;
2563 CHECK_DTD;
2564 if(attr == NULL) return(1);
2565
2566 /* Attribute Default Legal */
2567 /* Enumeration */
2568 if (attr->defaultValue != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002569 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002570 if (val == 0) {
2571 VERROR(ctxt->userData,
2572 "Syntax of default value for attribute %s on %s is not valid\n",
2573 attr->name, attr->elem);
2574 }
2575 ret &= val;
2576 }
2577
2578 /* ID Attribute Default */
Daniel Veillardcf461992000-03-14 18:30:20 +00002579 if ((attr->atype == XML_ATTRIBUTE_ID)&&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002580 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2581 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2582 VERROR(ctxt->userData,
2583 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2584 attr->name, attr->elem);
2585 ret = 0;
2586 }
2587
Daniel Veillardb96e6431999-08-29 21:02:19 +00002588 /* One ID per Element Type */
Daniel Veillardcf461992000-03-14 18:30:20 +00002589 if (attr->atype == XML_ATTRIBUTE_ID) {
2590 int nbId;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002591
2592 /* the trick is taht we parse DtD as their own internal subset */
Daniel Veillardcf461992000-03-14 18:30:20 +00002593 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
Daniel Veillardb05deb71999-08-10 19:04:08 +00002594 attr->elem);
2595 if (elem != NULL) {
2596 nbId = xmlScanIDAttributeDecl(NULL, elem);
Daniel Veillardcf461992000-03-14 18:30:20 +00002597 } else {
2598 xmlAttributeTablePtr table;
Daniel Veillardcf461992000-03-14 18:30:20 +00002599
2600 /*
2601 * The attribute may be declared in the internal subset and the
2602 * element in the external subset.
2603 */
2604 nbId = 0;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002605 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
Daniel Veillard126f2792000-10-24 17:10:12 +00002606 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
2607 xmlValidateAttributeIdCallback, &nbId);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002608 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002609 if (nbId > 1) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002610 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002611 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2612 attr->elem, nbId, attr->name);
2613 } else if (doc->extSubset != NULL) {
2614 int extId = 0;
2615 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2616 if (elem != NULL) {
2617 extId = xmlScanIDAttributeDecl(NULL, elem);
2618 }
2619 if (extId > 1) {
2620 VERROR(ctxt->userData,
2621 "Element %s has %d ID attribute defined in the external subset : %s\n",
2622 attr->elem, extId, attr->name);
2623 } else if (extId + nbId > 1) {
2624 VERROR(ctxt->userData,
2625"Element %s has ID attributes defined in the internal and external subset : %s\n",
2626 attr->elem, attr->name);
2627 }
2628 }
2629 }
2630
2631 /* Validity Constraint: Enumeration */
2632 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2633 xmlEnumerationPtr tree = attr->tree;
2634 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002635 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
Daniel Veillardcf461992000-03-14 18:30:20 +00002636 tree = tree->next;
2637 }
2638 if (tree == NULL) {
2639 VERROR(ctxt->userData,
2640"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2641 attr->defaultValue, attr->name, attr->elem);
2642 ret = 0;
2643 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002644 }
2645
2646 return(ret);
2647}
2648
2649/**
2650 * xmlValidateElementDecl:
2651 * @ctxt: the validation context
2652 * @doc: a document instance
2653 * @elem: an element definition
2654 *
2655 * Try to validate a single element definition
2656 * basically it does the following checks as described by the
2657 * XML-1.0 recommendation:
2658 * - [ VC: One ID per Element Type ]
2659 * - [ VC: No Duplicate Types ]
2660 * - [ VC: Unique Element Type Declaration ]
2661 *
2662 * returns 1 if valid or 0 otherwise
2663 */
2664
2665int
2666xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2667 xmlElementPtr elem) {
2668 int ret = 1;
2669 xmlElementPtr tst;
2670
2671 CHECK_DTD;
2672
2673 if (elem == NULL) return(1);
2674
2675 /* No Duplicate Types */
Daniel Veillardcf461992000-03-14 18:30:20 +00002676 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002677 xmlElementContentPtr cur, next;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002678 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002679
2680 cur = elem->content;
2681 while (cur != NULL) {
2682 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2683 if (cur->c1 == NULL) break;
2684 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2685 name = cur->c1->name;
2686 next = cur->c2;
2687 while (next != NULL) {
2688 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002689 if (xmlStrEqual(next->name, name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002690 VERROR(ctxt->userData,
2691 "Definition of %s has duplicate references of %s\n",
2692 elem->name, name);
2693 ret = 0;
2694 }
2695 break;
2696 }
2697 if (next->c1 == NULL) break;
2698 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002699 if (xmlStrEqual(next->c1->name, name)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002700 VERROR(ctxt->userData,
2701 "Definition of %s has duplicate references of %s\n",
2702 elem->name, name);
2703 ret = 0;
2704 }
2705 next = next->c2;
2706 }
2707 }
2708 cur = cur->c2;
2709 }
2710 }
2711
2712 /* VC: Unique Element Type Declaration */
2713 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2714 if ((tst != NULL ) && (tst != elem)) {
2715 VERROR(ctxt->userData, "Redefinition of element %s\n",
2716 elem->name);
2717 ret = 0;
2718 }
2719 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2720 if ((tst != NULL ) && (tst != elem)) {
2721 VERROR(ctxt->userData, "Redefinition of element %s\n",
2722 elem->name);
2723 ret = 0;
2724 }
2725
2726 /* One ID per Element Type */
2727 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2728 ret = 0;
2729 }
2730 return(ret);
2731}
2732
2733/**
2734 * xmlValidateOneAttribute:
2735 * @ctxt: the validation context
2736 * @doc: a document instance
2737 * @elem: an element instance
2738 * @attr: an attribute instance
Daniel Veillard00fdf371999-10-08 09:40:39 +00002739 * @value: the attribute value (without entities processing)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002740 *
2741 * Try to validate a single attribute for an element
Daniel Veillardcf461992000-03-14 18:30:20 +00002742 * basically it does the following checks as described by the
Daniel Veillardb05deb71999-08-10 19:04:08 +00002743 * XML-1.0 recommendation:
2744 * - [ VC: Attribute Value Type ]
2745 * - [ VC: Fixed Attribute Default ]
2746 * - [ VC: Entity Name ]
2747 * - [ VC: Name Token ]
2748 * - [ VC: ID ]
2749 * - [ VC: IDREF ]
2750 * - [ VC: Entity Name ]
2751 * - [ VC: Notation Attributes ]
2752 *
2753 * The ID/IDREF uniqueness and matching are done separately
2754 *
2755 * returns 1 if valid or 0 otherwise
2756 */
2757
2758int
2759xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002760 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002761 /* xmlElementPtr elemDecl; */
Daniel Veillardbe803962000-06-28 23:40:59 +00002762 xmlAttributePtr attrDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002763 int val;
2764 int ret = 1;
2765
2766 CHECK_DTD;
2767 if ((elem == NULL) || (elem->name == NULL)) return(0);
2768 if ((attr == NULL) || (attr->name == NULL)) return(0);
2769
Daniel Veillardbe803962000-06-28 23:40:59 +00002770 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2771 xmlChar qname[500];
2772#ifdef HAVE_SNPRINTF
2773 snprintf((char *) qname, sizeof(qname), "%s:%s",
2774 elem->ns->prefix, elem->name);
2775#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00002776 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00002777#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00002778 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00002779 if (attr->ns != NULL) {
2780 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
2781 attr->name, attr->ns->prefix);
2782 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2783 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
2784 attr->name, attr->ns->prefix);
2785 } else {
2786 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
2787 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2788 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2789 qname, attr->name);
2790 }
2791 }
2792 if (attrDecl == NULL) {
2793 if (attr->ns != NULL) {
2794 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
2795 attr->name, attr->ns->prefix);
2796 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2797 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
2798 attr->name, attr->ns->prefix);
2799 } else {
2800 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
2801 elem->name, attr->name);
2802 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2803 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2804 elem->name, attr->name);
2805 }
2806 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002807
2808
2809 /* Validity Constraint: Attribute Value Type */
2810 if (attrDecl == NULL) {
2811 VERROR(ctxt->userData,
2812 "No declaration for attribute %s on element %s\n",
2813 attr->name, elem->name);
2814 return(0);
2815 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002816 attr->atype = attrDecl->atype;
2817
2818 val = xmlValidateAttributeValue(attrDecl->atype, value);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002819 if (val == 0) {
2820 VERROR(ctxt->userData,
2821 "Syntax of value for attribute %s on %s is not valid\n",
2822 attr->name, elem->name);
2823 ret = 0;
2824 }
2825
Daniel Veillardcf461992000-03-14 18:30:20 +00002826 /* Validity constraint: Fixed Attribute Default */
2827 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002828 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002829 VERROR(ctxt->userData,
2830 "Value for attribute %s on %s is differnt from default \"%s\"\n",
2831 attr->name, elem->name, attrDecl->defaultValue);
2832 ret = 0;
2833 }
2834 }
2835
Daniel Veillardb96e6431999-08-29 21:02:19 +00002836 /* Validity Constraint: ID uniqueness */
Daniel Veillardcf461992000-03-14 18:30:20 +00002837 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
Daniel Veillard5eef6222001-02-07 18:24:48 +00002838 if (xmlAddID(ctxt, doc, value, attr) == NULL)
2839 ret = 0;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002840 }
2841
Daniel Veillardcf461992000-03-14 18:30:20 +00002842 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
2843 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
Daniel Veillard5eef6222001-02-07 18:24:48 +00002844 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
2845 ret = 0;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00002846 }
2847
Daniel Veillardb05deb71999-08-10 19:04:08 +00002848 /* Validity Constraint: Notation Attributes */
Daniel Veillardcf461992000-03-14 18:30:20 +00002849 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002850 xmlEnumerationPtr tree = attrDecl->tree;
2851 xmlNotationPtr nota;
2852
2853 /* First check that the given NOTATION was declared */
2854 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2855 if (nota == NULL)
2856 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2857
2858 if (nota == NULL) {
2859 VERROR(ctxt->userData,
2860 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2861 value, attr->name, elem->name);
2862 ret = 0;
2863 }
2864
2865 /* Second, verify that it's among the list */
2866 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002867 if (xmlStrEqual(tree->name, value)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002868 tree = tree->next;
2869 }
2870 if (tree == NULL) {
2871 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00002872"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00002873 value, attr->name, elem->name);
2874 ret = 0;
2875 }
2876 }
2877
2878 /* Validity Constraint: Enumeration */
Daniel Veillardcf461992000-03-14 18:30:20 +00002879 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002880 xmlEnumerationPtr tree = attrDecl->tree;
2881 while (tree != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002882 if (xmlStrEqual(tree->name, value)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00002883 tree = tree->next;
2884 }
2885 if (tree == NULL) {
2886 VERROR(ctxt->userData,
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00002887 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
Daniel Veillardb05deb71999-08-10 19:04:08 +00002888 value, attr->name, elem->name);
2889 ret = 0;
2890 }
2891 }
2892
2893 /* Fixed Attribute Default */
2894 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002895 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002896 VERROR(ctxt->userData,
2897 "Value for attribute %s on %s must be \"%s\"\n",
2898 attr->name, elem->name, attrDecl->defaultValue);
2899 ret = 0;
2900 }
2901
Daniel Veillardcf461992000-03-14 18:30:20 +00002902 /* Extra check for the attribute value */
2903 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
2904 attrDecl->atype, value);
2905
Daniel Veillardb05deb71999-08-10 19:04:08 +00002906 return(ret);
2907}
2908
Daniel Veillardc2f4df22001-01-04 14:06:39 +00002909/* Find the next XML_ELEMENT_NODE, subject to the content constraints.
2910 * Return -1 if we found something unexpected, or 1 otherwise.
2911 */
2912
2913static int
2914xmlValidateFindNextElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2915 xmlElementContentPtr cont)
2916{
2917 while (*child && (*child)->type != XML_ELEMENT_NODE) {
2918 switch ((*child)->type) {
2919 /*
2920 * If there is an entity declared and it's not empty
2921 * Push the current node on the stack and process with the
2922 * entity content.
2923 */
2924 case XML_ENTITY_REF_NODE:
2925 if (((*child)->children != NULL) &&
2926 ((*child)->children->children != NULL)) {
2927 nodeVPush(ctxt, *child);
2928 *child = (*child)->children->children;
2929 continue;
2930 }
2931 break;
2932
2933 /* These things are ignored (skipped) during validation. */
2934 case XML_PI_NODE:
2935 case XML_COMMENT_NODE:
2936 case XML_XINCLUDE_START:
2937 case XML_XINCLUDE_END:
2938 break;
2939
2940 case XML_TEXT_NODE:
2941 if (xmlIsBlankNode(*child)
2942 && (cont->type == XML_ELEMENT_CONTENT_ELEMENT
2943 || cont->type == XML_ELEMENT_CONTENT_SEQ
2944 || cont->type == XML_ELEMENT_CONTENT_OR))
2945 break;
2946 return -1;
2947
2948 default:
2949 return -1;
2950 }
2951 *child = (*child)->next;
2952 }
2953
2954 return 1;
2955}
2956
Daniel Veillardb05deb71999-08-10 19:04:08 +00002957int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2958 xmlElementContentPtr cont);
2959
2960/**
2961 * xmlValidateElementTypeExpr:
2962 * @ctxt: the validation context
2963 * @child: pointer to the child list
2964 * @cont: pointer to the content declaration
2965 *
2966 * Try to validate the content of an element of type element
2967 * but don't handle the occurence factor
2968 *
2969 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2970 * also update child value in-situ.
2971 */
2972
2973int
2974xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2975 xmlElementContentPtr cont) {
2976 xmlNodePtr cur;
2977 int ret = 1;
2978
2979 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002980 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardc2f4df22001-01-04 14:06:39 +00002981 ret = xmlValidateFindNextElement(ctxt, child, cont);
2982 if (ret < 0)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002983 return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00002984 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002985 switch (cont->type) {
2986 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardda07c342000-01-25 18:31:22 +00002987 if (*child == NULL) return(0);
2988 if ((*child)->type == XML_TEXT_NODE) return(1);
2989 return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002990 case XML_ELEMENT_CONTENT_ELEMENT:
2991 if (*child == NULL) return(0);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002992 ret = (xmlStrEqual((*child)->name, cont->name));
Daniel Veillardcf461992000-03-14 18:30:20 +00002993 if (ret == 1) {
2994 while ((*child)->next == NULL) {
2995 if (((*child)->parent != NULL) &&
2996 ((*child)->parent->type == XML_ENTITY_DECL)) {
2997 *child = nodeVPop(ctxt);
2998 } else
2999 break;
3000 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003001 *child = (*child)->next;
Daniel Veillardcf461992000-03-14 18:30:20 +00003002 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003003 return(ret);
3004 case XML_ELEMENT_CONTENT_OR:
3005 cur = *child;
3006 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3007 if (ret == -1) return(-1);
3008 if (ret == 1) {
3009 return(1);
3010 }
3011 /* rollback and retry the other path */
3012 *child = cur;
3013 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3014 if (ret == -1) return(-1);
3015 if (ret == 0) {
3016 *child = cur;
3017 return(0);
3018 }
3019 return(1);
3020 case XML_ELEMENT_CONTENT_SEQ:
3021 cur = *child;
3022 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3023 if (ret == -1) return(-1);
3024 if (ret == 0) {
3025 *child = cur;
3026 return(0);
3027 }
3028 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3029 if (ret == -1) return(-1);
3030 if (ret == 0) {
3031 *child = cur;
3032 return(0);
3033 }
3034 return(1);
3035 }
3036 return(ret);
3037}
3038
3039/**
3040 * xmlValidateElementTypeElement:
3041 * @ctxt: the validation context
3042 * @child: pointer to the child list
3043 * @cont: pointer to the content declaration
3044 *
3045 * Try to validate the content of an element of type element
3046 * yeah, Yet Another Regexp Implementation, and recursive
3047 *
3048 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3049 * also update child and content values in-situ.
3050 */
3051
3052int
3053xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3054 xmlElementContentPtr cont) {
3055 xmlNodePtr cur;
Daniel Veillardc2f4df22001-01-04 14:06:39 +00003056 int ret;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003057
3058 if (cont == NULL) return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003059
3060 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardc2f4df22001-01-04 14:06:39 +00003061 ret = xmlValidateFindNextElement(ctxt, child, cont);
3062 if (ret < 0)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003063 return(-1);
Daniel Veillardcf461992000-03-14 18:30:20 +00003064 DEBUG_VALID_STATE(*child, cont)
Daniel Veillardb05deb71999-08-10 19:04:08 +00003065 cur = *child;
3066 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3067 if (ret == -1) return(-1);
3068 switch (cont->ocur) {
3069 case XML_ELEMENT_CONTENT_ONCE:
3070 if (ret == 1) {
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003071 /* skip ignorable elems */
3072 while ((*child != NULL) &&
Daniel Veillardc2f4df22001-01-04 14:06:39 +00003073 ((*child)->type == XML_PI_NODE
3074 || (*child)->type == XML_COMMENT_NODE
3075 || (*child)->type == XML_XINCLUDE_START
3076 || (*child)->type == XML_XINCLUDE_END)) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003077 while ((*child)->next == NULL) {
3078 if (((*child)->parent != NULL) &&
3079 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3080 *child = (*child)->parent;
3081 } else
3082 break;
3083 }
3084 *child = (*child)->next;
Daniel Veillard3a2ebdd2000-01-25 19:27:27 +00003085 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003086 return(1);
3087 }
3088 *child = cur;
3089 return(0);
3090 case XML_ELEMENT_CONTENT_OPT:
3091 if (ret == 0) {
3092 *child = cur;
3093 return(1);
3094 }
3095 break;
3096 case XML_ELEMENT_CONTENT_MULT:
3097 if (ret == 0) {
3098 *child = cur;
3099 break;
3100 }
3101 /* no break on purpose */
3102 case XML_ELEMENT_CONTENT_PLUS:
3103 if (ret == 0) {
3104 *child = cur;
3105 return(0);
3106 }
Daniel Veillard683cb022000-10-22 12:04:13 +00003107 if (ret == -1) return(-1);
3108 cur = *child;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003109 do {
Daniel Veillard683cb022000-10-22 12:04:13 +00003110 if (*child == NULL)
3111 break; /* while */
Daniel Veillardc2f4df22001-01-04 14:06:39 +00003112 if ((*child)->type == XML_TEXT_NODE
3113 && xmlIsBlankNode(*child)) {
Daniel Veillard683cb022000-10-22 12:04:13 +00003114 *child = (*child)->next;
3115 continue;
3116 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003117 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
Daniel Veillard683cb022000-10-22 12:04:13 +00003118 if (ret == 1)
3119 cur = *child;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003120 } while (ret == 1);
3121 if (ret == -1) return(-1);
3122 *child = cur;
3123 break;
3124 }
Daniel Veillardc2f4df22001-01-04 14:06:39 +00003125
3126 return xmlValidateFindNextElement(ctxt, child, cont);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003127}
3128
3129/**
3130 * xmlSprintfElementChilds:
3131 * @buf: an output buffer
3132 * @content: An element
3133 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3134 *
3135 * This will dump the list of childs to the buffer
3136 * Intended just for the debug routine
3137 */
3138void
3139xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3140 xmlNodePtr cur;
3141
3142 if (node == NULL) return;
3143 if (glob) strcat(buf, "(");
Daniel Veillardcf461992000-03-14 18:30:20 +00003144 cur = node->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003145 while (cur != NULL) {
3146 switch (cur->type) {
3147 case XML_ELEMENT_NODE:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003148 strcat(buf, (char *) cur->name);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003149 if (cur->next != NULL)
3150 strcat(buf, " ");
3151 break;
3152 case XML_TEXT_NODE:
Daniel Veillardcd429612000-10-11 15:57:05 +00003153 if (xmlIsBlankNode(cur))
3154 break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003155 case XML_CDATA_SECTION_NODE:
3156 case XML_ENTITY_REF_NODE:
3157 strcat(buf, "CDATA");
3158 if (cur->next != NULL)
3159 strcat(buf, " ");
3160 break;
3161 case XML_ATTRIBUTE_NODE:
3162 case XML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00003163#ifdef LIBXML_SGML_ENABLED
3164 case XML_SGML_DOCUMENT_NODE:
3165#endif
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003166 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003167 case XML_DOCUMENT_TYPE_NODE:
3168 case XML_DOCUMENT_FRAG_NODE:
3169 case XML_NOTATION_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003170 case XML_NAMESPACE_DECL:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003171 strcat(buf, "???");
3172 if (cur->next != NULL)
3173 strcat(buf, " ");
3174 break;
3175 case XML_ENTITY_NODE:
3176 case XML_PI_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003177 case XML_DTD_NODE:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003178 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003179 case XML_ELEMENT_DECL:
3180 case XML_ATTRIBUTE_DECL:
3181 case XML_ENTITY_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003182 case XML_XINCLUDE_START:
3183 case XML_XINCLUDE_END:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003184 break;
3185 }
3186 cur = cur->next;
3187 }
3188 if (glob) strcat(buf, ")");
3189}
3190
3191
3192/**
3193 * xmlValidateOneElement:
3194 * @ctxt: the validation context
3195 * @doc: a document instance
3196 * @elem: an element instance
3197 *
3198 * Try to validate a single element and it's attributes,
3199 * basically it does the following checks as described by the
3200 * XML-1.0 recommendation:
3201 * - [ VC: Element Valid ]
3202 * - [ VC: Required Attribute ]
3203 * Then call xmlValidateOneAttribute() for each attribute present.
3204 *
3205 * The ID/IDREF checkings are done separately
3206 *
3207 * returns 1 if valid or 0 otherwise
3208 */
3209
3210int
3211xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3212 xmlNodePtr elem) {
Daniel Veillardbe803962000-06-28 23:40:59 +00003213 xmlElementPtr elemDecl = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003214 xmlElementContentPtr cont;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003215 xmlAttributePtr attr;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003216 xmlNodePtr child;
3217 int ret = 1;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003218 const xmlChar *name;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003219
3220 CHECK_DTD;
3221
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003222 if (elem == NULL) return(0);
3223 if (elem->type == XML_TEXT_NODE) {
3224 }
3225 switch (elem->type) {
3226 case XML_ATTRIBUTE_NODE:
3227 VERROR(ctxt->userData,
3228 "Attribute element not expected here\n");
3229 return(0);
3230 case XML_TEXT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00003231 if (elem->children != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003232 VERROR(ctxt->userData, "Text element has childs !\n");
3233 return(0);
3234 }
3235 if (elem->properties != NULL) {
3236 VERROR(ctxt->userData, "Text element has attributes !\n");
3237 return(0);
3238 }
3239 if (elem->ns != NULL) {
3240 VERROR(ctxt->userData, "Text element has namespace !\n");
3241 return(0);
3242 }
Daniel Veillard87b95392000-08-12 21:12:04 +00003243 if (elem->nsDef != NULL) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003244 VERROR(ctxt->userData,
3245 "Text element carries namespace definitions !\n");
3246 return(0);
3247 }
3248 if (elem->content == NULL) {
3249 VERROR(ctxt->userData,
3250 "Text element has no content !\n");
3251 return(0);
3252 }
3253 return(1);
Daniel Veillardc2f4df22001-01-04 14:06:39 +00003254 case XML_XINCLUDE_START:
3255 case XML_XINCLUDE_END:
3256 return(1);
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003257 case XML_CDATA_SECTION_NODE:
3258 case XML_ENTITY_REF_NODE:
3259 case XML_PI_NODE:
3260 case XML_COMMENT_NODE:
3261 return(1);
3262 case XML_ENTITY_NODE:
3263 VERROR(ctxt->userData,
3264 "Entity element not expected here\n");
3265 return(0);
3266 case XML_NOTATION_NODE:
3267 VERROR(ctxt->userData,
3268 "Notation element not expected here\n");
3269 return(0);
3270 case XML_DOCUMENT_NODE:
3271 case XML_DOCUMENT_TYPE_NODE:
3272 case XML_DOCUMENT_FRAG_NODE:
3273 VERROR(ctxt->userData,
3274 "Document element not expected here\n");
3275 return(0);
3276 case XML_HTML_DOCUMENT_NODE:
3277 VERROR(ctxt->userData,
3278 "\n");
3279 return(0);
3280 case XML_ELEMENT_NODE:
3281 break;
3282 default:
3283 VERROR(ctxt->userData,
3284 "unknown element type %d\n", elem->type);
3285 return(0);
3286 }
3287 if (elem->name == NULL) return(0);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003288
Daniel Veillardbe803962000-06-28 23:40:59 +00003289 /*
3290 * Fetch the declaration for the qualified name
3291 */
3292 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3293 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3294 elem->name, elem->ns->prefix);
3295 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3296 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3297 elem->name, elem->ns->prefix);
3298 }
3299
3300 /*
3301 * Fetch the declaration for the non qualified name
3302 */
3303 if (elemDecl == NULL) {
3304 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3305 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3306 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3307 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003308 if (elemDecl == NULL) {
3309 VERROR(ctxt->userData, "No declaration for element %s\n",
3310 elem->name);
3311 return(0);
3312 }
3313
3314 /* Check taht the element content matches the definition */
Daniel Veillardcf461992000-03-14 18:30:20 +00003315 switch (elemDecl->etype) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003316 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardcf461992000-03-14 18:30:20 +00003317 if (elem->children != NULL) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003318 VERROR(ctxt->userData,
3319 "Element %s was declared EMPTY this one has content\n",
3320 elem->name);
3321 ret = 0;
3322 }
3323 break;
3324 case XML_ELEMENT_TYPE_ANY:
3325 /* I don't think anything is required then */
3326 break;
3327 case XML_ELEMENT_TYPE_MIXED:
3328 /* Hum, this start to get messy */
Daniel Veillardcf461992000-03-14 18:30:20 +00003329 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003330 while (child != NULL) {
3331 if (child->type == XML_ELEMENT_NODE) {
3332 name = child->name;
Daniel Veillardbe803962000-06-28 23:40:59 +00003333 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3334 xmlChar qname[500];
3335#ifdef HAVE_SNPRINTF
3336 snprintf((char *) qname, sizeof(qname), "%s:%s",
3337 child->ns->prefix, child->name);
3338#else
Daniel Veillard39c7d712000-09-10 16:14:55 +00003339 sprintf((char *) qname, "%s:%s",
3340 child->ns->prefix, child->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003341#endif
Daniel Veillard39c7d712000-09-10 16:14:55 +00003342 qname[sizeof(qname) - 1] = 0;
Daniel Veillardbe803962000-06-28 23:40:59 +00003343 cont = elemDecl->content;
3344 while (cont != NULL) {
3345 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003346 if (xmlStrEqual(cont->name, qname)) break;
Daniel Veillardbe803962000-06-28 23:40:59 +00003347 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3348 (cont->c1 != NULL) &&
3349 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003350 if (xmlStrEqual(cont->c1->name, qname)) break;
Daniel Veillardbe803962000-06-28 23:40:59 +00003351 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3352 (cont->c1 == NULL) ||
3353 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3354 /* Internal error !!! */
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003355 xmlGenericError(xmlGenericErrorContext,
3356 "Internal: MIXED struct bad\n");
Daniel Veillardbe803962000-06-28 23:40:59 +00003357 break;
3358 }
3359 cont = cont->c2;
3360 }
3361 if (cont != NULL)
3362 goto child_ok;
3363 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003364 cont = elemDecl->content;
3365 while (cont != NULL) {
3366 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003367 if (xmlStrEqual(cont->name, name)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003368 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3369 (cont->c1 != NULL) &&
3370 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003371 if (xmlStrEqual(cont->c1->name, name)) break;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003372 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3373 (cont->c1 == NULL) ||
3374 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3375 /* Internal error !!! */
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003376 xmlGenericError(xmlGenericErrorContext,
3377 "Internal: MIXED struct bad\n");
Daniel Veillardb05deb71999-08-10 19:04:08 +00003378 break;
3379 }
3380 cont = cont->c2;
3381 }
3382 if (cont == NULL) {
3383 VERROR(ctxt->userData,
3384 "Element %s is not declared in %s list of possible childs\n",
3385 name, elem->name);
3386 ret = 0;
3387 }
3388 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003389child_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003390 child = child->next;
3391 }
3392 break;
3393 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillardcf461992000-03-14 18:30:20 +00003394 child = elem->children;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003395 cont = elemDecl->content;
3396 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
Daniel Veillard683cb022000-10-22 12:04:13 +00003397 while ((child != NULL) && (child->type == XML_TEXT_NODE) &&
3398 (xmlIsBlankNode(child))) {
3399 child = child->next;
3400 continue;
3401 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003402 if ((ret == 0) || (child != NULL)) {
3403 char expr[1000];
3404 char list[2000];
3405
3406 expr[0] = 0;
3407 xmlSprintfElementContent(expr, cont, 1);
3408 list[0] = 0;
3409 xmlSprintfElementChilds(list, elem, 1);
3410
3411 VERROR(ctxt->userData,
3412 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3413 elem->name, expr, list);
3414 ret = 0;
3415 }
3416 break;
3417 }
3418
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003419 /* [ VC: Required Attribute ] */
3420 attr = elemDecl->attributes;
3421 while (attr != NULL) {
3422 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3423 xmlAttrPtr attrib;
3424 int qualified = -1;
3425
3426 attrib = elem->properties;
3427 while (attrib != NULL) {
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003428 if (xmlStrEqual(attrib->name, attr->name)) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003429 if (attr->prefix != NULL) {
3430 xmlNsPtr nameSpace = attrib->ns;
3431
3432 if (nameSpace == NULL)
3433 nameSpace = elem->ns;
3434 /*
3435 * qualified names handling is problematic, having a
3436 * different prefix should be possible but DTDs don't
3437 * allow to define the URI instead of the prefix :-(
3438 */
3439 if (nameSpace == NULL) {
3440 if (qualified < 0)
3441 qualified = 0;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003442 } else if (!xmlStrEqual(nameSpace->prefix, attr->prefix)) {
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003443 if (qualified < 1)
3444 qualified = 1;
3445 } else
3446 goto found;
3447 } else {
3448 /*
3449 * We should allow applications to define namespaces
3450 * for their application even if the DTD doesn't
3451 * carry one, otherwise, basically we would always
3452 * break.
3453 */
3454 goto found;
3455 }
3456 }
3457 attrib = attrib->next;
3458 }
3459 if (qualified == -1) {
3460 if (attr->prefix == NULL) {
3461 VERROR(ctxt->userData,
3462 "Element %s doesn't carry attribute %s\n",
3463 elem->name, attr->name);
Daniel Veillardc2def842000-11-07 14:21:01 +00003464 ret = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003465 } else {
3466 VERROR(ctxt->userData,
3467 "Element %s doesn't carry attribute %s:%s\n",
3468 elem->name, attr->prefix,attr->name);
Daniel Veillardc2def842000-11-07 14:21:01 +00003469 ret = 0;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003470 }
3471 } else if (qualified == 0) {
3472 VWARNING(ctxt->userData,
3473 "Element %s required attribute %s:%s has no prefix\n",
3474 elem->name, attr->prefix,attr->name);
3475 } else if (qualified == 1) {
3476 VWARNING(ctxt->userData,
3477 "Element %s required attribute %s:%s has different prefix\n",
3478 elem->name, attr->prefix,attr->name);
3479 }
3480 }
3481found:
Daniel Veillardcf461992000-03-14 18:30:20 +00003482 attr = attr->nexth;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003483 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003484 return(ret);
3485}
3486
3487/**
3488 * xmlValidateRoot:
3489 * @ctxt: the validation context
3490 * @doc: a document instance
3491 *
3492 * Try to validate a the root element
3493 * basically it does the following check as described by the
3494 * XML-1.0 recommendation:
3495 * - [ VC: Root Element Type ]
3496 * it doesn't try to recurse or apply other check to the element
3497 *
3498 * returns 1 if valid or 0 otherwise
3499 */
3500
3501int
3502xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003503 xmlNodePtr root;
Daniel Veillardb05deb71999-08-10 19:04:08 +00003504 if (doc == NULL) return(0);
3505
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003506 root = xmlDocGetRootElement(doc);
3507 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003508 VERROR(ctxt->userData, "Not valid: no root element\n");
3509 return(0);
3510 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003511
3512 /*
Daniel Veillardcd429612000-10-11 15:57:05 +00003513 * When doing post validation against a separate DTD, those may
3514 * no internal subset has been generated
Daniel Veillardbe803962000-06-28 23:40:59 +00003515 */
Daniel Veillardcd429612000-10-11 15:57:05 +00003516 if ((doc->intSubset != NULL) &&
3517 (doc->intSubset->name != NULL)) {
3518 /*
3519 * Check first the document root against the NQName
3520 */
3521 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
3522 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3523 xmlChar qname[500];
Daniel Veillardbe803962000-06-28 23:40:59 +00003524#ifdef HAVE_SNPRINTF
Daniel Veillardcd429612000-10-11 15:57:05 +00003525 snprintf((char *) qname, sizeof(qname), "%s:%s",
3526 root->ns->prefix, root->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003527#else
Daniel Veillardcd429612000-10-11 15:57:05 +00003528 sprintf((char *) qname, "%s:%s", root->ns->prefix, root->name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003529#endif
Daniel Veillardcd429612000-10-11 15:57:05 +00003530 qname[sizeof(qname) - 1] = 0;
3531 if (xmlStrEqual(doc->intSubset->name, qname))
3532 goto name_ok;
3533 }
3534 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
3535 (xmlStrEqual(root->name, BAD_CAST "html")))
Daniel Veillardbe803962000-06-28 23:40:59 +00003536 goto name_ok;
Daniel Veillardcd429612000-10-11 15:57:05 +00003537 VERROR(ctxt->userData,
3538 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3539 root->name, doc->intSubset->name);
3540 return(0);
3541
3542 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003543 }
Daniel Veillardbe803962000-06-28 23:40:59 +00003544name_ok:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003545 return(1);
3546}
3547
3548
3549/**
3550 * xmlValidateElement:
3551 * @ctxt: the validation context
3552 * @doc: a document instance
3553 * @elem: an element instance
3554 *
3555 * Try to validate the subtree under an element
3556 *
3557 * returns 1 if valid or 0 otherwise
3558 */
3559
3560int
3561xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003562 xmlNodePtr child;
3563 xmlAttrPtr attr;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003564 xmlChar *value;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003565 int ret = 1;
3566
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003567 if (elem == NULL) return(0);
Daniel Veillardc2f4df22001-01-04 14:06:39 +00003568
3569 /*
3570 * XInclude elements were added after parsing in the infoset,
3571 * they don't really mean anything validation wise.
3572 */
3573 if ((elem->type == XML_XINCLUDE_START) ||
3574 (elem->type == XML_XINCLUDE_END))
3575 return(1);
3576
Daniel Veillardb05deb71999-08-10 19:04:08 +00003577 CHECK_DTD;
3578
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003579 ret &= xmlValidateOneElement(ctxt, doc, elem);
3580 attr = elem->properties;
3581 while(attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003582 value = xmlNodeListGetString(doc, attr->children, 0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003583 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3584 if (value != NULL)
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003585 xmlFree(value);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003586 attr= attr->next;
3587 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003588 child = elem->children;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003589 while (child != NULL) {
3590 ret &= xmlValidateElement(ctxt, doc, child);
3591 child = child->next;
3592 }
3593
3594 return(ret);
3595}
3596
Daniel Veillard126f2792000-10-24 17:10:12 +00003597
3598void
3599xmlValidateCheckRefCallback(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
3600 const xmlChar *name) {
3601 xmlAttrPtr id;
3602 xmlAttrPtr attr;
3603
3604 if (ref == NULL)
3605 return;
3606 attr = ref->attr;
3607 if (attr == NULL)
3608 return;
3609 if (attr->atype == XML_ATTRIBUTE_IDREF) {
3610 id = xmlGetID(ctxt->doc, name);
3611 if (id == NULL) {
3612 VERROR(ctxt->userData,
3613 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3614 attr->name, name);
3615 ctxt->valid = 0;
3616 }
3617 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
3618 xmlChar *dup, *str = NULL, *cur, save;
3619
3620 dup = xmlStrdup(name);
3621 if (dup == NULL) {
3622 ctxt->valid = 0;
3623 return;
3624 }
3625 cur = dup;
3626 while (*cur != 0) {
3627 str = cur;
3628 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3629 save = *cur;
3630 *cur = 0;
3631 id = xmlGetID(ctxt->doc, str);
3632 if (id == NULL) {
3633 VERROR(ctxt->userData,
3634 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3635 attr->name, str);
3636 ctxt->valid = 0;
3637 }
3638 if (save == 0)
3639 break;
3640 *cur = save;
3641 while (IS_BLANK(*cur)) cur++;
3642 }
3643 xmlFree(dup);
3644 }
3645}
3646
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003647/**
3648 * xmlValidateDocumentFinal:
3649 * @ctxt: the validation context
3650 * @doc: a document instance
3651 *
3652 * Does the final step for the document validation once all the
3653 * incremental validation steps have been completed
3654 *
3655 * basically it does the following checks described by the XML Rec
3656 *
3657 *
3658 * returns 1 if valid or 0 otherwise
3659 */
3660
3661int
3662xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003663 xmlRefTablePtr table;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003664
3665 if (doc == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003666 xmlGenericError(xmlGenericErrorContext,
3667 "xmlValidateDocumentFinal: doc == NULL\n");
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003668 return(0);
3669 }
3670
3671 /*
Daniel Veillardcf461992000-03-14 18:30:20 +00003672 * Check all the NOTATION/NOTATIONS attributes
3673 */
3674 /*
3675 * Check all the ENTITY/ENTITIES attributes definition for validity
3676 */
3677 /*
3678 * Check all the IDREF/IDREFS attributes definition for validity
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003679 */
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003680 table = (xmlRefTablePtr) doc->refs;
Daniel Veillard126f2792000-10-24 17:10:12 +00003681 ctxt->doc = doc;
3682 ctxt->valid = 1;
3683 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
3684 return(ctxt->valid);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003685}
3686
3687/**
3688 * xmlValidateDtd:
3689 * @ctxt: the validation context
3690 * @doc: a document instance
3691 * @dtd: a dtd instance
3692 *
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003693 * Try to validate the document against the dtd instance
Daniel Veillardb05deb71999-08-10 19:04:08 +00003694 *
3695 * basically it does check all the definitions in the DtD.
3696 *
3697 * returns 1 if valid or 0 otherwise
3698 */
3699
3700int
3701xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003702 int ret;
3703 xmlDtdPtr oldExt;
3704 xmlNodePtr root;
3705
3706 if (dtd == NULL) return(0);
3707 if (doc == NULL) return(0);
3708 oldExt = doc->extSubset;
3709 doc->extSubset = dtd;
3710 ret = xmlValidateRoot(ctxt, doc);
3711 if (ret == 0) {
3712 doc->extSubset = oldExt;
3713 return(ret);
3714 }
Daniel Veillard5eef6222001-02-07 18:24:48 +00003715 if (doc->ids != NULL) {
3716 xmlFreeIDTable(doc->ids);
3717 doc->ids = NULL;
3718 }
3719 if (doc->refs != NULL) {
3720 xmlFreeRefTable(doc->refs);
3721 doc->refs = NULL;
3722 }
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003723 root = xmlDocGetRootElement(doc);
3724 ret = xmlValidateElement(ctxt, doc, root);
3725 ret &= xmlValidateDocumentFinal(ctxt, doc);
3726 doc->extSubset = oldExt;
3727 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003728}
3729
Daniel Veillard126f2792000-10-24 17:10:12 +00003730void
3731xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
3732 const xmlChar *name) {
3733 if (cur == NULL)
3734 return;
3735 switch (cur->atype) {
3736 case XML_ATTRIBUTE_CDATA:
3737 case XML_ATTRIBUTE_ID:
3738 case XML_ATTRIBUTE_IDREF :
3739 case XML_ATTRIBUTE_IDREFS:
3740 case XML_ATTRIBUTE_NMTOKEN:
3741 case XML_ATTRIBUTE_NMTOKENS:
3742 case XML_ATTRIBUTE_ENUMERATION:
3743 break;
3744 case XML_ATTRIBUTE_ENTITY:
3745 case XML_ATTRIBUTE_ENTITIES:
3746 case XML_ATTRIBUTE_NOTATION:
3747 if (cur->defaultValue != NULL) {
3748 ctxt->valid &= xmlValidateAttributeValue2(ctxt, ctxt->doc,
3749 cur->name, cur->atype, cur->defaultValue);
3750 }
3751 if (cur->tree != NULL) {
3752 xmlEnumerationPtr tree = cur->tree;
3753 while (tree != NULL) {
3754 ctxt->valid &= xmlValidateAttributeValue2(ctxt, ctxt->doc,
3755 cur->name, cur->atype, tree->name);
3756 tree = tree->next;
3757 }
3758 }
3759 }
3760}
3761
Daniel Veillardb05deb71999-08-10 19:04:08 +00003762/**
Daniel Veillardcf461992000-03-14 18:30:20 +00003763 * xmlValidateDtdFinal:
3764 * @ctxt: the validation context
3765 * @doc: a document instance
3766 *
3767 * Does the final step for the dtds validation once all the
3768 * subsets have been parsed
3769 *
3770 * basically it does the following checks described by the XML Rec
3771 * - check that ENTITY and ENTITIES type attributes default or
3772 * possible values matches one of the defined entities.
3773 * - check that NOTATION type attributes default or
3774 * possible values matches one of the defined notations.
3775 *
3776 * returns 1 if valid or 0 otherwise
3777 */
3778
3779int
3780xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillard126f2792000-10-24 17:10:12 +00003781 int ret = 1;
Daniel Veillardcf461992000-03-14 18:30:20 +00003782 xmlDtdPtr dtd;
3783 xmlAttributeTablePtr table;
Daniel Veillardcf461992000-03-14 18:30:20 +00003784
3785 if (doc == NULL) return(0);
3786 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3787 return(0);
Daniel Veillard126f2792000-10-24 17:10:12 +00003788 ctxt->doc = doc;
3789 ctxt->valid = ret;
Daniel Veillardcf461992000-03-14 18:30:20 +00003790 dtd = doc->intSubset;
3791 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003792 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillard126f2792000-10-24 17:10:12 +00003793 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillardcf461992000-03-14 18:30:20 +00003794 }
3795 dtd = doc->extSubset;
3796 if ((dtd != NULL) && (dtd->attributes != NULL)) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003797 table = (xmlAttributeTablePtr) dtd->attributes;
Daniel Veillard126f2792000-10-24 17:10:12 +00003798 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillardcf461992000-03-14 18:30:20 +00003799 }
Daniel Veillard126f2792000-10-24 17:10:12 +00003800 return(ctxt->valid);
Daniel Veillardcf461992000-03-14 18:30:20 +00003801}
3802
3803/**
Daniel Veillardb05deb71999-08-10 19:04:08 +00003804 * xmlValidateDocument:
3805 * @ctxt: the validation context
3806 * @doc: a document instance
3807 *
3808 * Try to validate the document instance
3809 *
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003810 * basically it does the all the checks described by the XML Rec
Daniel Veillardb05deb71999-08-10 19:04:08 +00003811 * i.e. validates the internal and external subset (if present)
3812 * and validate the document tree.
3813 *
3814 * returns 1 if valid or 0 otherwise
3815 */
3816
3817int
3818xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003819 int ret;
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003820 xmlNodePtr root;
3821
3822 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3823 return(0);
3824 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
3825 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
3826 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
3827 doc->intSubset->SystemID);
3828 if (doc->extSubset == NULL) {
3829 if (doc->intSubset->SystemID != NULL) {
3830 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003831 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003832 doc->intSubset->SystemID);
3833 } else {
3834 VERROR(ctxt->userData,
Daniel Veillardcf461992000-03-14 18:30:20 +00003835 "Could not load the external subset \"%s\"\n",
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003836 doc->intSubset->ExternalID);
3837 }
3838 return(0);
3839 }
3840 }
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003841
Daniel Veillard5eef6222001-02-07 18:24:48 +00003842 if (doc->ids != NULL) {
3843 xmlFreeIDTable(doc->ids);
3844 doc->ids = NULL;
3845 }
3846 if (doc->refs != NULL) {
3847 xmlFreeRefTable(doc->refs);
3848 doc->refs = NULL;
3849 }
Daniel Veillardcf461992000-03-14 18:30:20 +00003850 ret = xmlValidateDtdFinal(ctxt, doc);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003851 if (!xmlValidateRoot(ctxt, doc)) return(0);
3852
Daniel Veillard944b5ff1999-12-15 19:08:24 +00003853 root = xmlDocGetRootElement(doc);
Daniel Veillardcf461992000-03-14 18:30:20 +00003854 ret &= xmlValidateElement(ctxt, doc, root);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00003855 ret &= xmlValidateDocumentFinal(ctxt, doc);
3856 return(ret);
Daniel Veillardb05deb71999-08-10 19:04:08 +00003857}
3858
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003859
3860/************************************************************************
3861 * *
3862 * Routines for dynamic validation editing *
3863 * *
3864 ************************************************************************/
3865
3866/**
3867 * xmlValidGetPotentialChildren:
3868 * @ctree: an element content tree
3869 * @list: an array to store the list of child names
3870 * @len: a pointer to the number of element in the list
3871 * @max: the size of the array
3872 *
3873 * Build/extend a list of potential children allowed by the content tree
3874 *
3875 * returns the number of element in the list, or -1 in case of error.
3876 */
3877
3878int
3879xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
3880 int *len, int max) {
3881 int i;
3882
3883 if ((ctree == NULL) || (list == NULL) || (len == NULL))
3884 return(-1);
3885 if (*len >= max) return(*len);
3886
3887 switch (ctree->type) {
3888 case XML_ELEMENT_CONTENT_PCDATA:
3889 for (i = 0; i < *len;i++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003890 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
Daniel Veillarda819dac1999-11-24 18:04:22 +00003891 list[(*len)++] = BAD_CAST "#PCDATA";
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003892 break;
3893 case XML_ELEMENT_CONTENT_ELEMENT:
3894 for (i = 0; i < *len;i++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003895 if (xmlStrEqual(ctree->name, list[i])) return(*len);
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003896 list[(*len)++] = ctree->name;
3897 break;
3898 case XML_ELEMENT_CONTENT_SEQ:
3899 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3900 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3901 break;
3902 case XML_ELEMENT_CONTENT_OR:
3903 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3904 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3905 break;
3906 }
3907
3908 return(*len);
3909}
3910
3911/**
3912 * xmlValidGetValidElements:
3913 * @prev: an element to insert after
3914 * @next: an element to insert next
3915 * @list: an array to store the list of child names
3916 * @max: the size of the array
3917 *
3918 * This function returns the list of authorized children to insert
3919 * within an existing tree while respecting the validity constraints
3920 * forced by the Dtd. The insertion point is defined using @prev and
3921 * @next in the following ways:
3922 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3923 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3924 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3925 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3926 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
3927 *
3928 * pointers to the element names are inserted at the beginning of the array
3929 * and do not need to be freed.
3930 *
3931 * returns the number of element in the list, or -1 in case of error. If
3932 * the function returns the value @max the caller is invited to grow the
3933 * receiving array and retry.
3934 */
3935
3936int
3937xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3938 int max) {
3939 int nb_valid_elements = 0;
3940 const xmlChar *elements[256];
3941 int nb_elements = 0, i;
3942
3943 xmlNode *ref_node;
3944 xmlNode *parent;
3945 xmlNode *test_node;
3946
3947 xmlNode *prev_next;
3948 xmlNode *next_prev;
3949 xmlNode *parent_childs;
3950 xmlNode *parent_last;
3951
3952 xmlElement *element_desc;
3953
3954 if (prev == NULL && next == NULL)
3955 return(-1);
3956
3957 if (list == NULL) return(-1);
3958 if (max <= 0) return(-1);
3959
3960 nb_valid_elements = 0;
3961 ref_node = prev ? prev : next;
3962 parent = ref_node->parent;
3963
3964 /*
3965 * Retrieves the parent element declaration
3966 */
3967 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3968 parent->name);
3969 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3970 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3971 parent->name);
3972 if (element_desc == NULL) return(-1);
3973
3974 /*
3975 * Do a backup of the current tree structure
3976 */
3977 prev_next = prev ? prev->next : NULL;
3978 next_prev = next ? next->prev : NULL;
Daniel Veillardcf461992000-03-14 18:30:20 +00003979 parent_childs = parent->children;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003980 parent_last = parent->last;
3981
3982 /*
3983 * Creates a dummy node and insert it into the tree
3984 */
Daniel Veillarda819dac1999-11-24 18:04:22 +00003985 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003986 test_node->doc = ref_node->doc;
3987 test_node->parent = parent;
3988 test_node->prev = prev;
3989 test_node->next = next;
3990
3991 if (prev) prev->next = test_node;
Daniel Veillardcf461992000-03-14 18:30:20 +00003992 else parent->children = test_node;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00003993
3994 if (next) next->prev = test_node;
3995 else parent->last = test_node;
3996
3997 /*
3998 * Insert each potential child node and check if the parent is
3999 * still valid
4000 */
4001 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4002 elements, &nb_elements, 256);
4003
4004 for (i = 0;i < nb_elements;i++) {
4005 test_node->name = elements[i];
4006 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4007 int j;
4008
4009 for (j = 0; j < nb_valid_elements;j++)
Daniel Veillard8b5dd832000-10-01 20:28:44 +00004010 if (xmlStrEqual(elements[i], list[j])) break;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004011 list[nb_valid_elements++] = elements[i];
4012 if (nb_valid_elements >= max) break;
4013 }
4014 }
4015
4016 /*
4017 * Restore the tree structure
4018 */
4019 if (prev) prev->next = prev_next;
4020 if (next) next->prev = next_prev;
Daniel Veillardcf461992000-03-14 18:30:20 +00004021 parent->children = parent_childs;
Daniel Veillard7c1206f1999-10-14 09:10:25 +00004022 parent->last = parent_last;
4023
4024 return(nb_valid_elements);
4025}