missing project/build files
[client-tools.git] / src / external / 3rd / library / libxml / valid.c
blob4c72bf408113cb33b214263b865200ed9898de17
1 /*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
5 * See Copyright for the status of this software.
7 * daniel@veillard.com
8 */
10 #define IN_LIBXML
11 #include "libxml.h"
13 #include <string.h>
15 #ifdef HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
19 #include <libxml/xmlmemory.h>
20 #include <libxml/hash.h>
21 #include <libxml/valid.h>
22 #include <libxml/parser.h>
23 #include <libxml/parserInternals.h>
24 #include <libxml/xmlerror.h>
25 #include <libxml/list.h>
26 #include <libxml/globals.h>
28 /* #define DEBUG_VALID_ALGO */
29 /* #define DEBUG_REGEXP_ALGO */
31 #define TODO \
32 xmlGenericError(xmlGenericErrorContext, \
33 "Unimplemented block at %s:%d\n", \
34 __FILE__, __LINE__);
36 * Generic function for accessing stacks in the Validity Context
39 #define PUSH_AND_POP(scope, type, name) \
40 scope int name##VPush(xmlValidCtxtPtr ctxt, type value) { \
41 if (ctxt->name##Max <= 0) { \
42 ctxt->name##Max = 4; \
43 ctxt->name##Tab = (type *) xmlMalloc( \
44 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
45 if (ctxt->name##Tab == NULL) { \
46 xmlGenericError(xmlGenericErrorContext, \
47 "malloc failed !\n"); \
48 ctxt->name##Max = 0; \
49 return(0); \
50 } \
51 } \
52 if (ctxt->name##Nr >= ctxt->name##Max) { \
53 ctxt->name##Max *= 2; \
54 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
55 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
56 if (ctxt->name##Tab == NULL) { \
57 xmlGenericError(xmlGenericErrorContext, \
58 "realloc failed !\n"); \
59 return(0); \
60 } \
61 } \
62 ctxt->name##Tab[ctxt->name##Nr] = value; \
63 ctxt->name = value; \
64 return(ctxt->name##Nr++); \
65 } \
66 scope type name##VPop(xmlValidCtxtPtr ctxt) { \
67 type ret; \
68 if (ctxt->name##Nr <= 0) return(0); \
69 ctxt->name##Nr--; \
70 if (ctxt->name##Nr > 0) \
71 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
72 else \
73 ctxt->name = NULL; \
74 ret = ctxt->name##Tab[ctxt->name##Nr]; \
75 ctxt->name##Tab[ctxt->name##Nr] = 0; \
76 return(ret); \
77 } \
80 * I use a home made algorithm less complex and easier to
81 * debug/maintain than a generic NFA -> DFA state based algo. The
82 * only restriction is on the deepness of the tree limited by the
83 * size of the occurs bitfield
85 * this is the content of a saved state for rollbacks
88 #define ROLLBACK_OR 0
89 #define ROLLBACK_PARENT 1
91 typedef struct _xmlValidState {
92 xmlElementContentPtr cont; /* pointer to the content model subtree */
93 xmlNodePtr node; /* pointer to the current node in the list */
94 long occurs;/* bitfield for multiple occurrences */
95 unsigned char depth; /* current depth in the overall tree */
96 unsigned char state; /* ROLLBACK_XXX */
97 } _xmlValidState;
99 #define MAX_RECURSE 25000
100 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
101 #define CONT ctxt->vstate->cont
102 #define NODE ctxt->vstate->node
103 #define DEPTH ctxt->vstate->depth
104 #define OCCURS ctxt->vstate->occurs
105 #define STATE ctxt->vstate->state
107 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
108 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
110 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
111 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
113 #ifndef LIBXML_REGEXP_ENABLED
114 static int
115 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
116 xmlNodePtr node, unsigned char depth, long occurs,
117 unsigned char state) {
118 int i = ctxt->vstateNr - 1;
120 if (ctxt->vstateNr > MAX_RECURSE) {
121 return(-1);
123 if (ctxt->vstateNr >= ctxt->vstateMax) {
124 ctxt->vstateMax *= 2;
125 ctxt->vstateTab = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
126 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
127 if (ctxt->vstateTab == NULL) {
128 xmlGenericError(xmlGenericErrorContext,
129 "realloc failed !n");
130 return(-1);
132 ctxt->vstate = &ctxt->vstateTab[0];
135 * Don't push on the stack a state already here
137 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
138 (ctxt->vstateTab[i].node == node) &&
139 (ctxt->vstateTab[i].depth == depth) &&
140 (ctxt->vstateTab[i].occurs == occurs) &&
141 (ctxt->vstateTab[i].state == state))
142 return(ctxt->vstateNr);
143 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
144 ctxt->vstateTab[ctxt->vstateNr].node = node;
145 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
146 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
147 ctxt->vstateTab[ctxt->vstateNr].state = state;
148 return(ctxt->vstateNr++);
151 static int
152 vstateVPop(xmlValidCtxtPtr ctxt) {
153 if (ctxt->vstateNr <= 1) return(-1);
154 ctxt->vstateNr--;
155 ctxt->vstate = &ctxt->vstateTab[0];
156 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
157 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
158 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
159 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
160 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
161 return(ctxt->vstateNr);
164 #endif /* LIBXML_REGEXP_ENABLED */
166 PUSH_AND_POP(static, xmlNodePtr, node)
168 #ifdef DEBUG_VALID_ALGO
169 static void
170 xmlValidPrintNode(xmlNodePtr cur) {
171 if (cur == NULL) {
172 xmlGenericError(xmlGenericErrorContext, "null");
173 return;
175 switch (cur->type) {
176 case XML_ELEMENT_NODE:
177 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
178 break;
179 case XML_TEXT_NODE:
180 xmlGenericError(xmlGenericErrorContext, "text ");
181 break;
182 case XML_CDATA_SECTION_NODE:
183 xmlGenericError(xmlGenericErrorContext, "cdata ");
184 break;
185 case XML_ENTITY_REF_NODE:
186 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
187 break;
188 case XML_PI_NODE:
189 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
190 break;
191 case XML_COMMENT_NODE:
192 xmlGenericError(xmlGenericErrorContext, "comment ");
193 break;
194 case XML_ATTRIBUTE_NODE:
195 xmlGenericError(xmlGenericErrorContext, "?attr? ");
196 break;
197 case XML_ENTITY_NODE:
198 xmlGenericError(xmlGenericErrorContext, "?ent? ");
199 break;
200 case XML_DOCUMENT_NODE:
201 xmlGenericError(xmlGenericErrorContext, "?doc? ");
202 break;
203 case XML_DOCUMENT_TYPE_NODE:
204 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
205 break;
206 case XML_DOCUMENT_FRAG_NODE:
207 xmlGenericError(xmlGenericErrorContext, "?frag? ");
208 break;
209 case XML_NOTATION_NODE:
210 xmlGenericError(xmlGenericErrorContext, "?nota? ");
211 break;
212 case XML_HTML_DOCUMENT_NODE:
213 xmlGenericError(xmlGenericErrorContext, "?html? ");
214 break;
215 #ifdef LIBXML_DOCB_ENABLED
216 case XML_DOCB_DOCUMENT_NODE:
217 xmlGenericError(xmlGenericErrorContext, "?docb? ");
218 break;
219 #endif
220 case XML_DTD_NODE:
221 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
222 break;
223 case XML_ELEMENT_DECL:
224 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
225 break;
226 case XML_ATTRIBUTE_DECL:
227 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
228 break;
229 case XML_ENTITY_DECL:
230 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
231 break;
232 case XML_NAMESPACE_DECL:
233 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
234 break;
235 case XML_XINCLUDE_START:
236 xmlGenericError(xmlGenericErrorContext, "incstart ");
237 break;
238 case XML_XINCLUDE_END:
239 xmlGenericError(xmlGenericErrorContext, "incend ");
240 break;
244 static void
245 xmlValidPrintNodeList(xmlNodePtr cur) {
246 if (cur == NULL)
247 xmlGenericError(xmlGenericErrorContext, "null ");
248 while (cur != NULL) {
249 xmlValidPrintNode(cur);
250 cur = cur->next;
254 static void
255 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
256 char expr[1000];
258 expr[0] = 0;
259 xmlGenericError(xmlGenericErrorContext, "valid: ");
260 xmlValidPrintNodeList(cur);
261 xmlGenericError(xmlGenericErrorContext, "against ");
262 xmlSnprintfElementContent(expr, 5000, cont, 1);
263 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
266 static void
267 xmlValidDebugState(xmlValidStatePtr state) {
268 xmlGenericError(xmlGenericErrorContext, "(");
269 if (state->cont == NULL)
270 xmlGenericError(xmlGenericErrorContext, "null,");
271 else
272 switch (state->cont->type) {
273 case XML_ELEMENT_CONTENT_PCDATA:
274 xmlGenericError(xmlGenericErrorContext, "pcdata,");
275 break;
276 case XML_ELEMENT_CONTENT_ELEMENT:
277 xmlGenericError(xmlGenericErrorContext, "%s,",
278 state->cont->name);
279 break;
280 case XML_ELEMENT_CONTENT_SEQ:
281 xmlGenericError(xmlGenericErrorContext, "seq,");
282 break;
283 case XML_ELEMENT_CONTENT_OR:
284 xmlGenericError(xmlGenericErrorContext, "or,");
285 break;
287 xmlValidPrintNode(state->node);
288 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
289 state->depth, state->occurs, state->state);
292 static void
293 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
294 int i, j;
296 xmlGenericError(xmlGenericErrorContext, "state: ");
297 xmlValidDebugState(ctxt->vstate);
298 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
299 ctxt->vstateNr - 1);
300 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
301 xmlValidDebugState(&ctxt->vstateTab[j]);
302 xmlGenericError(xmlGenericErrorContext, "\n");
305 /*****
306 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
307 *****/
309 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
310 #define DEBUG_VALID_MSG(m) \
311 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
313 #else
314 #define DEBUG_VALID_STATE(n,c)
315 #define DEBUG_VALID_MSG(m)
316 #endif
318 /* TODO: use hash table for accesses to elem and attribute definitions */
320 #define VECTXT(ctxt, node) \
321 if ((ctxt != NULL) && (ctxt->error != NULL) && \
322 (node != NULL)) { \
323 xmlChar *base = xmlNodeGetBase(NULL,node); \
324 if (base != NULL) { \
325 ctxt->error(ctxt->userData, "%s:%d: ", base, \
326 (int) (long) node->content); \
327 xmlFree(base); \
328 } else \
329 ctxt->error(ctxt->userData, ":%d: ", \
330 (int) (long) node->content); \
333 #define VWCTXT(ctxt, node) \
334 if ((ctxt != NULL) && (ctxt->warning != NULL) && \
335 (node != NULL)) { \
336 xmlChar *base = xmlNodeGetBase(NULL,node); \
337 if (base != NULL) { \
338 ctxt->warning(ctxt->userData, "%s:%d: ", base, \
339 (int) (long) node->content); \
340 xmlFree(base); \
341 } else \
342 ctxt->warning(ctxt->userData, ":%d: ", \
343 (int) (long) node->content); \
346 #define VERROR \
347 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
349 #define VWARNING \
350 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
352 #define CHECK_DTD \
353 if (doc == NULL) return(0); \
354 else if ((doc->intSubset == NULL) && \
355 (doc->extSubset == NULL)) return(0)
357 static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
358 int create);
359 xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
361 #ifdef LIBXML_REGEXP_ENABLED
363 /************************************************************************
365 * Content model validation based on the regexps *
367 ************************************************************************/
370 * xmlValidBuildAContentModel:
371 * @content: the content model
372 * @ctxt: the schema parser context
373 * @name: the element name whose content is being built
375 * Generate the automata sequence needed for that type
377 * Returns 1 if successful or 0 in case of error.
379 static int
380 xmlValidBuildAContentModel(xmlElementContentPtr content,
381 xmlValidCtxtPtr ctxt,
382 const xmlChar *name) {
383 if (content == NULL) {
384 VERROR(ctxt->userData,
385 "Found unexpected type = NULL in %s content model\n", name);
386 return(0);
388 switch (content->type) {
389 case XML_ELEMENT_CONTENT_PCDATA:
390 VERROR(ctxt->userData, "ContentModel found PCDATA for element %s\n",
391 name);
392 return(0);
393 break;
394 case XML_ELEMENT_CONTENT_ELEMENT: {
395 xmlAutomataStatePtr oldstate = ctxt->state;
396 xmlChar *QName = NULL;
397 const xmlChar *fname = content->name;
399 if (content->prefix != NULL) {
400 int len;
402 len = xmlStrlen(content->name) +
403 xmlStrlen(content->prefix) + 2;
404 QName = xmlMalloc(len);
405 if (QName == NULL) {
406 VERROR(ctxt->userData,
407 "ContentModel %s : alloc failed\n", name);
408 return(0);
410 snprintf((char *) QName, len, "%s:%s",
411 (char *)content->prefix,
412 (char *)content->name);
413 fname = QName;
416 switch (content->ocur) {
417 case XML_ELEMENT_CONTENT_ONCE:
418 ctxt->state = xmlAutomataNewTransition(ctxt->am,
419 ctxt->state, NULL, fname, NULL);
420 break;
421 case XML_ELEMENT_CONTENT_OPT:
422 ctxt->state = xmlAutomataNewTransition(ctxt->am,
423 ctxt->state, NULL, fname, NULL);
424 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
425 break;
426 case XML_ELEMENT_CONTENT_PLUS:
427 ctxt->state = xmlAutomataNewTransition(ctxt->am,
428 ctxt->state, NULL, fname, NULL);
429 xmlAutomataNewTransition(ctxt->am, ctxt->state,
430 ctxt->state, fname, NULL);
431 break;
432 case XML_ELEMENT_CONTENT_MULT:
433 xmlAutomataNewTransition(ctxt->am, ctxt->state,
434 ctxt->state, fname, NULL);
435 break;
437 if (QName != NULL)
438 xmlFree(QName);
439 break;
441 case XML_ELEMENT_CONTENT_SEQ: {
442 xmlAutomataStatePtr oldstate, oldend;
443 xmlElementContentOccur ocur;
446 * Simply iterate over the content
448 oldstate = ctxt->state;
449 ocur = content->ocur;
450 do {
451 xmlValidBuildAContentModel(content->c1, ctxt, name);
452 content = content->c2;
453 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
454 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
455 xmlValidBuildAContentModel(content, ctxt, name);
456 oldend = ctxt->state;
457 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
458 switch (ocur) {
459 case XML_ELEMENT_CONTENT_ONCE:
460 break;
461 case XML_ELEMENT_CONTENT_OPT:
462 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
463 break;
464 case XML_ELEMENT_CONTENT_MULT:
465 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
466 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
467 break;
468 case XML_ELEMENT_CONTENT_PLUS:
469 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
470 break;
472 break;
474 case XML_ELEMENT_CONTENT_OR: {
475 xmlAutomataStatePtr oldstate, oldend;
476 xmlElementContentOccur ocur;
478 ocur = content->ocur;
479 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
480 (ocur == XML_ELEMENT_CONTENT_MULT)) {
481 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
482 ctxt->state, NULL);
484 oldstate = ctxt->state;
485 oldend = xmlAutomataNewState(ctxt->am);
488 * iterate over the subtypes and remerge the end with an
489 * epsilon transition
491 do {
492 ctxt->state = oldstate;
493 xmlValidBuildAContentModel(content->c1, ctxt, name);
494 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
495 content = content->c2;
496 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
497 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
498 ctxt->state = oldstate;
499 xmlValidBuildAContentModel(content, ctxt, name);
500 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
501 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
502 switch (ocur) {
503 case XML_ELEMENT_CONTENT_ONCE:
504 break;
505 case XML_ELEMENT_CONTENT_OPT:
506 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
507 break;
508 case XML_ELEMENT_CONTENT_MULT:
509 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
510 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
511 break;
512 case XML_ELEMENT_CONTENT_PLUS:
513 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
514 break;
516 break;
518 default:
519 VERROR(ctxt->userData, "ContentModel broken for element %s\n",
520 name);
521 return(0);
523 return(1);
526 * xmlValidBuildContentModel:
527 * @ctxt: a validation context
528 * @elem: an element declaration node
530 * (Re)Build the automata associated to the content model of this
531 * element
533 * Returns 1 in case of success, 0 in case of error
536 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
537 xmlAutomataStatePtr start;
539 if ((ctxt == NULL) || (elem == NULL))
540 return(0);
541 if (elem->type != XML_ELEMENT_DECL)
542 return(0);
543 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
544 return(1);
545 /* TODO: should we rebuild in this case ? */
546 if (elem->contModel != NULL)
547 return(1);
549 ctxt->am = xmlNewAutomata();
550 if (ctxt->am == NULL) {
551 VERROR(ctxt->userData, "Cannot create automata for element %s\n",
552 elem->name);
553 return(0);
555 start = ctxt->state = xmlAutomataGetInitState(ctxt->am);
556 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
557 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
558 elem->contModel = xmlAutomataCompile(ctxt->am);
559 if (!xmlRegexpIsDeterminist(elem->contModel)) {
560 char expr[5000];
561 expr[0] = 0;
562 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
563 VERROR(ctxt->userData, "Content model of %s is not determinist: %s\n",
564 elem->name, expr);
565 #ifdef DEBUG_REGEXP_ALGO
566 xmlRegexpPrint(stderr, elem->contModel);
567 #endif
568 ctxt->valid = 0;
570 ctxt->state = NULL;
571 xmlFreeAutomata(ctxt->am);
572 ctxt->am = NULL;
573 return(1);
576 #endif /* LIBXML_REGEXP_ENABLED */
578 /************************************************************************
580 * QName handling helper *
582 ************************************************************************/
585 * xmlSplitQName2:
586 * @name: an XML parser context
587 * @prefix: a xmlChar **
589 * parse an XML qualified name string
591 * [NS 5] QName ::= (Prefix ':')? LocalPart
593 * [NS 6] Prefix ::= NCName
595 * [NS 7] LocalPart ::= NCName
597 * Returns NULL if not a QName, otherwise the local part, and prefix
598 * is updated to get the Prefix if any.
601 xmlChar *
602 xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
603 int len = 0;
604 xmlChar *ret = NULL;
606 *prefix = NULL;
608 #ifndef XML_XML_NAMESPACE
609 /* xml: prefix is not really a namespace */
610 if ((name[0] == 'x') && (name[1] == 'm') &&
611 (name[2] == 'l') && (name[3] == ':'))
612 return(NULL);
613 #endif
615 /* nasty but valid */
616 if (name[0] == ':')
617 return(NULL);
620 * we are not trying to validate but just to cut, and yes it will
621 * work even if this is as set of UTF-8 encoded chars
623 while ((name[len] != 0) && (name[len] != ':'))
624 len++;
626 if (name[len] == 0)
627 return(NULL);
629 *prefix = xmlStrndup(name, len);
630 ret = xmlStrdup(&name[len + 1]);
632 return(ret);
635 /****************************************************************
637 * Util functions for data allocation/deallocation *
639 ****************************************************************/
642 * xmlNewElementContent:
643 * @name: the subelement name or NULL
644 * @type: the type of element content decl
646 * Allocate an element content structure.
648 * Returns NULL if not, otherwise the new element content structure
650 xmlElementContentPtr
651 xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
652 xmlElementContentPtr ret;
654 switch(type) {
655 case XML_ELEMENT_CONTENT_ELEMENT:
656 if (name == NULL) {
657 xmlGenericError(xmlGenericErrorContext,
658 "xmlNewElementContent : name == NULL !\n");
660 break;
661 case XML_ELEMENT_CONTENT_PCDATA:
662 case XML_ELEMENT_CONTENT_SEQ:
663 case XML_ELEMENT_CONTENT_OR:
664 if (name != NULL) {
665 xmlGenericError(xmlGenericErrorContext,
666 "xmlNewElementContent : name != NULL !\n");
668 break;
669 default:
670 xmlGenericError(xmlGenericErrorContext,
671 "xmlNewElementContent: unknown type %d\n", type);
672 return(NULL);
674 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
675 if (ret == NULL) {
676 xmlGenericError(xmlGenericErrorContext,
677 "xmlNewElementContent : out of memory!\n");
678 return(NULL);
680 memset(ret, 0, sizeof(xmlElementContent));
681 ret->type = type;
682 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
683 if (name != NULL) {
684 xmlChar *prefix = NULL;
685 ret->name = xmlSplitQName2(name, &prefix);
686 if (ret->name == NULL)
687 ret->name = xmlStrdup(name);
688 ret->prefix = prefix;
689 } else {
690 ret->name = NULL;
691 ret->prefix = NULL;
693 ret->c1 = ret->c2 = ret->parent = NULL;
694 return(ret);
698 * xmlCopyElementContent:
699 * @content: An element content pointer.
701 * Build a copy of an element content description.
703 * Returns the new xmlElementContentPtr or NULL in case of error.
705 xmlElementContentPtr
706 xmlCopyElementContent(xmlElementContentPtr cur) {
707 xmlElementContentPtr ret;
709 if (cur == NULL) return(NULL);
710 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
711 if (ret == NULL) {
712 xmlGenericError(xmlGenericErrorContext,
713 "xmlCopyElementContent : out of memory\n");
714 return(NULL);
716 if (cur->prefix != NULL)
717 ret->prefix = xmlStrdup(cur->prefix);
718 ret->ocur = cur->ocur;
719 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
720 if (ret->c1 != NULL)
721 ret->c1->parent = ret;
722 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
723 if (ret->c2 != NULL)
724 ret->c2->parent = ret;
725 return(ret);
729 * xmlFreeElementContent:
730 * @cur: the element content tree to free
732 * Free an element content structure. This is a recursive call !
734 void
735 xmlFreeElementContent(xmlElementContentPtr cur) {
736 if (cur == NULL) return;
737 switch (cur->type) {
738 case XML_ELEMENT_CONTENT_PCDATA:
739 case XML_ELEMENT_CONTENT_ELEMENT:
740 case XML_ELEMENT_CONTENT_SEQ:
741 case XML_ELEMENT_CONTENT_OR:
742 break;
743 default:
744 xmlGenericError(xmlGenericErrorContext,
745 "xmlFreeElementContent : type %d\n", cur->type);
746 return;
748 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
749 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
750 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
751 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
752 xmlFree(cur);
756 * xmlDumpElementContent:
757 * @buf: An XML buffer
758 * @content: An element table
759 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
761 * This will dump the content of the element table as an XML DTD definition
763 static void
764 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
765 if (content == NULL) return;
767 if (glob) xmlBufferWriteChar(buf, "(");
768 switch (content->type) {
769 case XML_ELEMENT_CONTENT_PCDATA:
770 xmlBufferWriteChar(buf, "#PCDATA");
771 break;
772 case XML_ELEMENT_CONTENT_ELEMENT:
773 if (content->prefix != NULL) {
774 xmlBufferWriteCHAR(buf, content->prefix);
775 xmlBufferWriteChar(buf, ":");
777 xmlBufferWriteCHAR(buf, content->name);
778 break;
779 case XML_ELEMENT_CONTENT_SEQ:
780 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
781 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
782 xmlDumpElementContent(buf, content->c1, 1);
783 else
784 xmlDumpElementContent(buf, content->c1, 0);
785 xmlBufferWriteChar(buf, " , ");
786 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
787 xmlDumpElementContent(buf, content->c2, 1);
788 else
789 xmlDumpElementContent(buf, content->c2, 0);
790 break;
791 case XML_ELEMENT_CONTENT_OR:
792 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
793 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
794 xmlDumpElementContent(buf, content->c1, 1);
795 else
796 xmlDumpElementContent(buf, content->c1, 0);
797 xmlBufferWriteChar(buf, " | ");
798 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
799 xmlDumpElementContent(buf, content->c2, 1);
800 else
801 xmlDumpElementContent(buf, content->c2, 0);
802 break;
803 default:
804 xmlGenericError(xmlGenericErrorContext,
805 "xmlDumpElementContent: unknown type %d\n",
806 content->type);
808 if (glob)
809 xmlBufferWriteChar(buf, ")");
810 switch (content->ocur) {
811 case XML_ELEMENT_CONTENT_ONCE:
812 break;
813 case XML_ELEMENT_CONTENT_OPT:
814 xmlBufferWriteChar(buf, "?");
815 break;
816 case XML_ELEMENT_CONTENT_MULT:
817 xmlBufferWriteChar(buf, "*");
818 break;
819 case XML_ELEMENT_CONTENT_PLUS:
820 xmlBufferWriteChar(buf, "+");
821 break;
826 * xmlSprintfElementContent:
827 * @buf: an output buffer
828 * @content: An element table
829 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
831 * Deprecated, unsafe, use xmlSnprintfElementContent
833 void
834 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
835 xmlElementContentPtr content ATTRIBUTE_UNUSED,
836 int glob ATTRIBUTE_UNUSED) {
840 * xmlSnprintfElementContent:
841 * @buf: an output buffer
842 * @size: the buffer size
843 * @content: An element table
844 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
846 * This will dump the content of the element content definition
847 * Intended just for the debug routine
849 void
850 xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
851 int len;
853 if (content == NULL) return;
854 len = strlen(buf);
855 if (size - len < 50) {
856 if ((size - len > 4) && (buf[len - 1] != '.'))
857 strcat(buf, " ...");
858 return;
860 if (glob) strcat(buf, "(");
861 switch (content->type) {
862 case XML_ELEMENT_CONTENT_PCDATA:
863 strcat(buf, "#PCDATA");
864 break;
865 case XML_ELEMENT_CONTENT_ELEMENT:
866 if (content->prefix != NULL) {
867 if (size - len < xmlStrlen(content->prefix) + 10) {
868 strcat(buf, " ...");
869 return;
871 strcat(buf, (char *) content->prefix);
872 strcat(buf, ":");
874 if (size - len < xmlStrlen(content->name) + 10) {
875 strcat(buf, " ...");
876 return;
878 strcat(buf, (char *) content->name);
879 break;
880 case XML_ELEMENT_CONTENT_SEQ:
881 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
882 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
883 xmlSnprintfElementContent(buf, size, content->c1, 1);
884 else
885 xmlSnprintfElementContent(buf, size, content->c1, 0);
886 len = strlen(buf);
887 if (size - len < 50) {
888 if ((size - len > 4) && (buf[len - 1] != '.'))
889 strcat(buf, " ...");
890 return;
892 strcat(buf, " , ");
893 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
894 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
895 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
896 xmlSnprintfElementContent(buf, size, content->c2, 1);
897 else
898 xmlSnprintfElementContent(buf, size, content->c2, 0);
899 break;
900 case XML_ELEMENT_CONTENT_OR:
901 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
902 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
903 xmlSnprintfElementContent(buf, size, content->c1, 1);
904 else
905 xmlSnprintfElementContent(buf, size, content->c1, 0);
906 len = strlen(buf);
907 if (size - len < 50) {
908 if ((size - len > 4) && (buf[len - 1] != '.'))
909 strcat(buf, " ...");
910 return;
912 strcat(buf, " | ");
913 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
914 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
915 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
916 xmlSnprintfElementContent(buf, size, content->c2, 1);
917 else
918 xmlSnprintfElementContent(buf, size, content->c2, 0);
919 break;
921 if (glob)
922 strcat(buf, ")");
923 switch (content->ocur) {
924 case XML_ELEMENT_CONTENT_ONCE:
925 break;
926 case XML_ELEMENT_CONTENT_OPT:
927 strcat(buf, "?");
928 break;
929 case XML_ELEMENT_CONTENT_MULT:
930 strcat(buf, "*");
931 break;
932 case XML_ELEMENT_CONTENT_PLUS:
933 strcat(buf, "+");
934 break;
938 /****************************************************************
940 * Registration of DTD declarations *
942 ****************************************************************/
945 * xmlCreateElementTable:
947 * create and initialize an empty element hash table.
949 * Returns the xmlElementTablePtr just created or NULL in case of error.
951 static xmlElementTablePtr
952 xmlCreateElementTable(void) {
953 return(xmlHashCreate(0));
957 * xmlFreeElement:
958 * @elem: An element
960 * Deallocate the memory used by an element definition
962 static void
963 xmlFreeElement(xmlElementPtr elem) {
964 if (elem == NULL) return;
965 xmlUnlinkNode((xmlNodePtr) elem);
966 xmlFreeElementContent(elem->content);
967 if (elem->name != NULL)
968 xmlFree((xmlChar *) elem->name);
969 if (elem->prefix != NULL)
970 xmlFree((xmlChar *) elem->prefix);
971 #ifdef LIBXML_REGEXP_ENABLED
972 if (elem->contModel != NULL)
973 xmlRegFreeRegexp(elem->contModel);
974 #endif
975 xmlFree(elem);
980 * xmlAddElementDecl:
981 * @ctxt: the validation context
982 * @dtd: pointer to the DTD
983 * @name: the entity name
984 * @type: the element type
985 * @content: the element content tree or NULL
987 * Register a new element declaration
989 * Returns NULL if not, otherwise the entity
991 xmlElementPtr
992 xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
993 xmlElementTypeVal type,
994 xmlElementContentPtr content) {
995 xmlElementPtr ret;
996 xmlElementTablePtr table;
997 xmlAttributePtr oldAttributes = NULL;
998 xmlChar *ns, *uqname;
1000 if (dtd == NULL) {
1001 xmlGenericError(xmlGenericErrorContext,
1002 "xmlAddElementDecl: dtd == NULL\n");
1003 return(NULL);
1005 if (name == NULL) {
1006 xmlGenericError(xmlGenericErrorContext,
1007 "xmlAddElementDecl: name == NULL\n");
1008 return(NULL);
1010 switch (type) {
1011 case XML_ELEMENT_TYPE_EMPTY:
1012 if (content != NULL) {
1013 xmlGenericError(xmlGenericErrorContext,
1014 "xmlAddElementDecl: content != NULL for EMPTY\n");
1015 return(NULL);
1017 break;
1018 case XML_ELEMENT_TYPE_ANY:
1019 if (content != NULL) {
1020 xmlGenericError(xmlGenericErrorContext,
1021 "xmlAddElementDecl: content != NULL for ANY\n");
1022 return(NULL);
1024 break;
1025 case XML_ELEMENT_TYPE_MIXED:
1026 if (content == NULL) {
1027 xmlGenericError(xmlGenericErrorContext,
1028 "xmlAddElementDecl: content == NULL for MIXED\n");
1029 return(NULL);
1031 break;
1032 case XML_ELEMENT_TYPE_ELEMENT:
1033 if (content == NULL) {
1034 xmlGenericError(xmlGenericErrorContext,
1035 "xmlAddElementDecl: content == NULL for ELEMENT\n");
1036 return(NULL);
1038 break;
1039 default:
1040 xmlGenericError(xmlGenericErrorContext,
1041 "xmlAddElementDecl: unknown type %d\n", type);
1042 return(NULL);
1046 * check if name is a QName
1048 uqname = xmlSplitQName2(name, &ns);
1049 if (uqname != NULL)
1050 name = uqname;
1053 * Create the Element table if needed.
1055 table = (xmlElementTablePtr) dtd->elements;
1056 if (table == NULL) {
1057 table = xmlCreateElementTable();
1058 dtd->elements = (void *) table;
1060 if (table == NULL) {
1061 xmlGenericError(xmlGenericErrorContext,
1062 "xmlAddElementDecl: Table creation failed!\n");
1063 return(NULL);
1067 * lookup old attributes inserted on an undefined element in the
1068 * internal subset.
1070 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1071 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1072 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1073 oldAttributes = ret->attributes;
1074 ret->attributes = NULL;
1075 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1076 xmlFreeElement(ret);
1081 * The element may already be present if one of its attribute
1082 * was registered first
1084 ret = xmlHashLookup2(table, name, ns);
1085 if (ret != NULL) {
1086 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1088 * The element is already defined in this DTD.
1090 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1091 if (uqname != NULL)
1092 xmlFree(uqname);
1093 return(NULL);
1095 } else {
1096 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1097 if (ret == NULL) {
1098 xmlGenericError(xmlGenericErrorContext,
1099 "xmlAddElementDecl: out of memory\n");
1100 return(NULL);
1102 memset(ret, 0, sizeof(xmlElement));
1103 ret->type = XML_ELEMENT_DECL;
1106 * fill the structure.
1108 ret->name = xmlStrdup(name);
1109 ret->prefix = ns;
1112 * Validity Check:
1113 * Insertion must not fail
1115 if (xmlHashAddEntry2(table, name, ns, ret)) {
1117 * The element is already defined in this DTD.
1119 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1120 xmlFreeElement(ret);
1121 if (uqname != NULL)
1122 xmlFree(uqname);
1123 return(NULL);
1128 * Finish to fill the structure.
1130 ret->etype = type;
1131 ret->content = xmlCopyElementContent(content);
1132 ret->attributes = oldAttributes;
1135 * Link it to the DTD
1137 ret->parent = dtd;
1138 ret->doc = dtd->doc;
1139 if (dtd->last == NULL) {
1140 dtd->children = dtd->last = (xmlNodePtr) ret;
1141 } else {
1142 dtd->last->next = (xmlNodePtr) ret;
1143 ret->prev = dtd->last;
1144 dtd->last = (xmlNodePtr) ret;
1146 if (uqname != NULL)
1147 xmlFree(uqname);
1148 return(ret);
1152 * xmlFreeElementTable:
1153 * @table: An element table
1155 * Deallocate the memory used by an element hash table.
1157 void
1158 xmlFreeElementTable(xmlElementTablePtr table) {
1159 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1163 * xmlCopyElement:
1164 * @elem: An element
1166 * Build a copy of an element.
1168 * Returns the new xmlElementPtr or NULL in case of error.
1170 static xmlElementPtr
1171 xmlCopyElement(xmlElementPtr elem) {
1172 xmlElementPtr cur;
1174 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1175 if (cur == NULL) {
1176 xmlGenericError(xmlGenericErrorContext,
1177 "xmlCopyElement: out of memory !\n");
1178 return(NULL);
1180 memset(cur, 0, sizeof(xmlElement));
1181 cur->type = XML_ELEMENT_DECL;
1182 cur->etype = elem->etype;
1183 if (elem->name != NULL)
1184 cur->name = xmlStrdup(elem->name);
1185 else
1186 cur->name = NULL;
1187 if (elem->prefix != NULL)
1188 cur->prefix = xmlStrdup(elem->prefix);
1189 else
1190 cur->prefix = NULL;
1191 cur->content = xmlCopyElementContent(elem->content);
1192 /* TODO : rebuild the attribute list on the copy */
1193 cur->attributes = NULL;
1194 return(cur);
1198 * xmlCopyElementTable:
1199 * @table: An element table
1201 * Build a copy of an element table.
1203 * Returns the new xmlElementTablePtr or NULL in case of error.
1205 xmlElementTablePtr
1206 xmlCopyElementTable(xmlElementTablePtr table) {
1207 return((xmlElementTablePtr) xmlHashCopy(table,
1208 (xmlHashCopier) xmlCopyElement));
1212 * xmlDumpElementDecl:
1213 * @buf: the XML buffer output
1214 * @elem: An element table
1216 * This will dump the content of the element declaration as an XML
1217 * DTD definition
1219 void
1220 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1221 switch (elem->etype) {
1222 case XML_ELEMENT_TYPE_EMPTY:
1223 xmlBufferWriteChar(buf, "<!ELEMENT ");
1224 if (elem->prefix != NULL) {
1225 xmlBufferWriteCHAR(buf, elem->prefix);
1226 xmlBufferWriteChar(buf, ":");
1228 xmlBufferWriteCHAR(buf, elem->name);
1229 xmlBufferWriteChar(buf, " EMPTY>\n");
1230 break;
1231 case XML_ELEMENT_TYPE_ANY:
1232 xmlBufferWriteChar(buf, "<!ELEMENT ");
1233 if (elem->prefix != NULL) {
1234 xmlBufferWriteCHAR(buf, elem->prefix);
1235 xmlBufferWriteChar(buf, ":");
1237 xmlBufferWriteCHAR(buf, elem->name);
1238 xmlBufferWriteChar(buf, " ANY>\n");
1239 break;
1240 case XML_ELEMENT_TYPE_MIXED:
1241 xmlBufferWriteChar(buf, "<!ELEMENT ");
1242 if (elem->prefix != NULL) {
1243 xmlBufferWriteCHAR(buf, elem->prefix);
1244 xmlBufferWriteChar(buf, ":");
1246 xmlBufferWriteCHAR(buf, elem->name);
1247 xmlBufferWriteChar(buf, " ");
1248 xmlDumpElementContent(buf, elem->content, 1);
1249 xmlBufferWriteChar(buf, ">\n");
1250 break;
1251 case XML_ELEMENT_TYPE_ELEMENT:
1252 xmlBufferWriteChar(buf, "<!ELEMENT ");
1253 if (elem->prefix != NULL) {
1254 xmlBufferWriteCHAR(buf, elem->prefix);
1255 xmlBufferWriteChar(buf, ":");
1257 xmlBufferWriteCHAR(buf, elem->name);
1258 xmlBufferWriteChar(buf, " ");
1259 xmlDumpElementContent(buf, elem->content, 1);
1260 xmlBufferWriteChar(buf, ">\n");
1261 break;
1262 default:
1263 xmlGenericError(xmlGenericErrorContext,
1264 "xmlDumpElementDecl: internal: unknown type %d\n",
1265 elem->etype);
1270 * xmlDumpElementTable:
1271 * @buf: the XML buffer output
1272 * @table: An element table
1274 * This will dump the content of the element table as an XML DTD definition
1276 void
1277 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1278 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDecl, buf);
1282 * xmlCreateEnumeration:
1283 * @name: the enumeration name or NULL
1285 * create and initialize an enumeration attribute node.
1287 * Returns the xmlEnumerationPtr just created or NULL in case
1288 * of error.
1290 xmlEnumerationPtr
1291 xmlCreateEnumeration(xmlChar *name) {
1292 xmlEnumerationPtr ret;
1294 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1295 if (ret == NULL) {
1296 xmlGenericError(xmlGenericErrorContext,
1297 "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
1298 (long)sizeof(xmlEnumeration));
1299 return(NULL);
1301 memset(ret, 0, sizeof(xmlEnumeration));
1303 if (name != NULL)
1304 ret->name = xmlStrdup(name);
1305 return(ret);
1309 * xmlFreeEnumeration:
1310 * @cur: the tree to free.
1312 * free an enumeration attribute node (recursive).
1314 void
1315 xmlFreeEnumeration(xmlEnumerationPtr cur) {
1316 if (cur == NULL) return;
1318 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1320 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1321 xmlFree(cur);
1325 * xmlCopyEnumeration:
1326 * @cur: the tree to copy.
1328 * Copy an enumeration attribute node (recursive).
1330 * Returns the xmlEnumerationPtr just created or NULL in case
1331 * of error.
1333 xmlEnumerationPtr
1334 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1335 xmlEnumerationPtr ret;
1337 if (cur == NULL) return(NULL);
1338 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1340 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1341 else ret->next = NULL;
1343 return(ret);
1347 * xmlDumpEnumeration:
1348 * @buf: the XML buffer output
1349 * @enum: An enumeration
1351 * This will dump the content of the enumeration
1353 static void
1354 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1355 if (cur == NULL) return;
1357 xmlBufferWriteCHAR(buf, cur->name);
1358 if (cur->next == NULL)
1359 xmlBufferWriteChar(buf, ")");
1360 else {
1361 xmlBufferWriteChar(buf, " | ");
1362 xmlDumpEnumeration(buf, cur->next);
1367 * xmlCreateAttributeTable:
1369 * create and initialize an empty attribute hash table.
1371 * Returns the xmlAttributeTablePtr just created or NULL in case
1372 * of error.
1374 static xmlAttributeTablePtr
1375 xmlCreateAttributeTable(void) {
1376 return(xmlHashCreate(0));
1380 * xmlScanAttributeDeclCallback:
1381 * @attr: the attribute decl
1382 * @list: the list to update
1384 * Callback called by xmlScanAttributeDecl when a new attribute
1385 * has to be entered in the list.
1387 static void
1388 xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
1389 const xmlChar* name ATTRIBUTE_UNUSED) {
1390 attr->nexth = *list;
1391 *list = attr;
1395 * xmlScanAttributeDecl:
1396 * @dtd: pointer to the DTD
1397 * @elem: the element name
1399 * When inserting a new element scan the DtD for existing attributes
1400 * for that element and initialize the Attribute chain
1402 * Returns the pointer to the first attribute decl in the chain,
1403 * possibly NULL.
1405 xmlAttributePtr
1406 xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1407 xmlAttributePtr ret = NULL;
1408 xmlAttributeTablePtr table;
1410 if (dtd == NULL) {
1411 xmlGenericError(xmlGenericErrorContext,
1412 "xmlScanAttributeDecl: dtd == NULL\n");
1413 return(NULL);
1415 if (elem == NULL) {
1416 xmlGenericError(xmlGenericErrorContext,
1417 "xmlScanAttributeDecl: elem == NULL\n");
1418 return(NULL);
1420 table = (xmlAttributeTablePtr) dtd->attributes;
1421 if (table == NULL)
1422 return(NULL);
1424 /* WRONG !!! */
1425 xmlHashScan3(table, NULL, NULL, elem,
1426 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1427 return(ret);
1431 * xmlScanIDAttributeDecl:
1432 * @ctxt: the validation context
1433 * @elem: the element name
1435 * Verify that the element don't have too many ID attributes
1436 * declared.
1438 * Returns the number of ID attributes found.
1440 static int
1441 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1442 xmlAttributePtr cur;
1443 int ret = 0;
1445 if (elem == NULL) return(0);
1446 cur = elem->attributes;
1447 while (cur != NULL) {
1448 if (cur->atype == XML_ATTRIBUTE_ID) {
1449 ret ++;
1450 if (ret > 1)
1451 VERROR(ctxt->userData,
1452 "Element %s has too many ID attributes defined : %s\n",
1453 elem->name, cur->name);
1455 cur = cur->nexth;
1457 return(ret);
1461 * xmlFreeAttribute:
1462 * @elem: An attribute
1464 * Deallocate the memory used by an attribute definition
1466 static void
1467 xmlFreeAttribute(xmlAttributePtr attr) {
1468 if (attr == NULL) return;
1469 xmlUnlinkNode((xmlNodePtr) attr);
1470 if (attr->tree != NULL)
1471 xmlFreeEnumeration(attr->tree);
1472 if (attr->elem != NULL)
1473 xmlFree((xmlChar *) attr->elem);
1474 if (attr->name != NULL)
1475 xmlFree((xmlChar *) attr->name);
1476 if (attr->defaultValue != NULL)
1477 xmlFree((xmlChar *) attr->defaultValue);
1478 if (attr->prefix != NULL)
1479 xmlFree((xmlChar *) attr->prefix);
1480 xmlFree(attr);
1485 * xmlAddAttributeDecl:
1486 * @ctxt: the validation context
1487 * @dtd: pointer to the DTD
1488 * @elem: the element name
1489 * @name: the attribute name
1490 * @ns: the attribute namespace prefix
1491 * @type: the attribute type
1492 * @def: the attribute default type
1493 * @defaultValue: the attribute default value
1494 * @tree: if it's an enumeration, the associated list
1496 * Register a new attribute declaration
1497 * Note that @tree becomes the ownership of the DTD
1499 * Returns NULL if not new, otherwise the attribute decl
1501 xmlAttributePtr
1502 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
1503 const xmlChar *name, const xmlChar *ns,
1504 xmlAttributeType type, xmlAttributeDefault def,
1505 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1506 xmlAttributePtr ret;
1507 xmlAttributeTablePtr table;
1508 xmlElementPtr elemDef;
1510 if (dtd == NULL) {
1511 xmlGenericError(xmlGenericErrorContext,
1512 "xmlAddAttributeDecl: dtd == NULL\n");
1513 xmlFreeEnumeration(tree);
1514 return(NULL);
1516 if (name == NULL) {
1517 xmlGenericError(xmlGenericErrorContext,
1518 "xmlAddAttributeDecl: name == NULL\n");
1519 xmlFreeEnumeration(tree);
1520 return(NULL);
1522 if (elem == NULL) {
1523 xmlGenericError(xmlGenericErrorContext,
1524 "xmlAddAttributeDecl: elem == NULL\n");
1525 xmlFreeEnumeration(tree);
1526 return(NULL);
1530 * Check the type and possibly the default value.
1532 switch (type) {
1533 case XML_ATTRIBUTE_CDATA:
1534 break;
1535 case XML_ATTRIBUTE_ID:
1536 break;
1537 case XML_ATTRIBUTE_IDREF:
1538 break;
1539 case XML_ATTRIBUTE_IDREFS:
1540 break;
1541 case XML_ATTRIBUTE_ENTITY:
1542 break;
1543 case XML_ATTRIBUTE_ENTITIES:
1544 break;
1545 case XML_ATTRIBUTE_NMTOKEN:
1546 break;
1547 case XML_ATTRIBUTE_NMTOKENS:
1548 break;
1549 case XML_ATTRIBUTE_ENUMERATION:
1550 break;
1551 case XML_ATTRIBUTE_NOTATION:
1552 break;
1553 default:
1554 xmlGenericError(xmlGenericErrorContext,
1555 "xmlAddAttributeDecl: unknown type %d\n", type);
1556 xmlFreeEnumeration(tree);
1557 return(NULL);
1559 if ((defaultValue != NULL) &&
1560 (!xmlValidateAttributeValue(type, defaultValue))) {
1561 VERROR(ctxt->userData, "Attribute %s of %s: invalid default value\n",
1562 elem, name, defaultValue);
1563 defaultValue = NULL;
1564 ctxt->valid = 0;
1568 * Check first that an attribute defined in the external subset wasn't
1569 * already defined in the internal subset
1571 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1572 (dtd->doc->intSubset != NULL) &&
1573 (dtd->doc->intSubset->attributes != NULL)) {
1574 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1575 if (ret != NULL)
1576 return(NULL);
1580 * Create the Attribute table if needed.
1582 table = (xmlAttributeTablePtr) dtd->attributes;
1583 if (table == NULL) {
1584 table = xmlCreateAttributeTable();
1585 dtd->attributes = (void *) table;
1587 if (table == NULL) {
1588 xmlGenericError(xmlGenericErrorContext,
1589 "xmlAddAttributeDecl: Table creation failed!\n");
1590 return(NULL);
1594 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1595 if (ret == NULL) {
1596 xmlGenericError(xmlGenericErrorContext,
1597 "xmlAddAttributeDecl: out of memory\n");
1598 return(NULL);
1600 memset(ret, 0, sizeof(xmlAttribute));
1601 ret->type = XML_ATTRIBUTE_DECL;
1604 * fill the structure.
1606 ret->atype = type;
1607 ret->name = xmlStrdup(name);
1608 ret->prefix = xmlStrdup(ns);
1609 ret->elem = xmlStrdup(elem);
1610 ret->def = def;
1611 ret->tree = tree;
1612 if (defaultValue != NULL)
1613 ret->defaultValue = xmlStrdup(defaultValue);
1616 * Validity Check:
1617 * Search the DTD for previous declarations of the ATTLIST
1619 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
1621 * The attribute is already defined in this DTD.
1623 VWARNING(ctxt->userData,
1624 "Attribute %s of element %s: already defined\n",
1625 name, elem);
1626 xmlFreeAttribute(ret);
1627 return(NULL);
1631 * Validity Check:
1632 * Multiple ID per element
1634 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
1635 if (elemDef != NULL) {
1637 if ((type == XML_ATTRIBUTE_ID) &&
1638 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
1639 VERROR(ctxt->userData,
1640 "Element %s has too may ID attributes defined : %s\n",
1641 elem, name);
1642 ctxt->valid = 0;
1646 * Insert namespace default def first they need to be
1647 * processed first.
1649 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1650 ((ret->prefix != NULL &&
1651 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1652 ret->nexth = elemDef->attributes;
1653 elemDef->attributes = ret;
1654 } else {
1655 xmlAttributePtr tmp = elemDef->attributes;
1657 while ((tmp != NULL) &&
1658 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1659 ((ret->prefix != NULL &&
1660 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1661 if (tmp->nexth == NULL)
1662 break;
1663 tmp = tmp->nexth;
1665 if (tmp != NULL) {
1666 ret->nexth = tmp->nexth;
1667 tmp->nexth = ret;
1668 } else {
1669 ret->nexth = elemDef->attributes;
1670 elemDef->attributes = ret;
1676 * Link it to the DTD
1678 ret->parent = dtd;
1679 ret->doc = dtd->doc;
1680 if (dtd->last == NULL) {
1681 dtd->children = dtd->last = (xmlNodePtr) ret;
1682 } else {
1683 dtd->last->next = (xmlNodePtr) ret;
1684 ret->prev = dtd->last;
1685 dtd->last = (xmlNodePtr) ret;
1687 return(ret);
1691 * xmlFreeAttributeTable:
1692 * @table: An attribute table
1694 * Deallocate the memory used by an entities hash table.
1696 void
1697 xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1698 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1702 * xmlCopyAttribute:
1703 * @attr: An attribute
1705 * Build a copy of an attribute.
1707 * Returns the new xmlAttributePtr or NULL in case of error.
1709 static xmlAttributePtr
1710 xmlCopyAttribute(xmlAttributePtr attr) {
1711 xmlAttributePtr cur;
1713 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1714 if (cur == NULL) {
1715 xmlGenericError(xmlGenericErrorContext,
1716 "xmlCopyAttribute: out of memory !\n");
1717 return(NULL);
1719 memset(cur, 0, sizeof(xmlAttribute));
1720 cur->type = XML_ATTRIBUTE_DECL;
1721 cur->atype = attr->atype;
1722 cur->def = attr->def;
1723 cur->tree = xmlCopyEnumeration(attr->tree);
1724 if (attr->elem != NULL)
1725 cur->elem = xmlStrdup(attr->elem);
1726 if (attr->name != NULL)
1727 cur->name = xmlStrdup(attr->name);
1728 if (attr->prefix != NULL)
1729 cur->prefix = xmlStrdup(attr->prefix);
1730 if (attr->defaultValue != NULL)
1731 cur->defaultValue = xmlStrdup(attr->defaultValue);
1732 return(cur);
1736 * xmlCopyAttributeTable:
1737 * @table: An attribute table
1739 * Build a copy of an attribute table.
1741 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1743 xmlAttributeTablePtr
1744 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1745 return((xmlAttributeTablePtr) xmlHashCopy(table,
1746 (xmlHashCopier) xmlCopyAttribute));
1750 * xmlDumpAttributeDecl:
1751 * @buf: the XML buffer output
1752 * @attr: An attribute declaration
1754 * This will dump the content of the attribute declaration as an XML
1755 * DTD definition
1757 void
1758 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1759 xmlBufferWriteChar(buf, "<!ATTLIST ");
1760 xmlBufferWriteCHAR(buf, attr->elem);
1761 xmlBufferWriteChar(buf, " ");
1762 if (attr->prefix != NULL) {
1763 xmlBufferWriteCHAR(buf, attr->prefix);
1764 xmlBufferWriteChar(buf, ":");
1766 xmlBufferWriteCHAR(buf, attr->name);
1767 switch (attr->atype) {
1768 case XML_ATTRIBUTE_CDATA:
1769 xmlBufferWriteChar(buf, " CDATA");
1770 break;
1771 case XML_ATTRIBUTE_ID:
1772 xmlBufferWriteChar(buf, " ID");
1773 break;
1774 case XML_ATTRIBUTE_IDREF:
1775 xmlBufferWriteChar(buf, " IDREF");
1776 break;
1777 case XML_ATTRIBUTE_IDREFS:
1778 xmlBufferWriteChar(buf, " IDREFS");
1779 break;
1780 case XML_ATTRIBUTE_ENTITY:
1781 xmlBufferWriteChar(buf, " ENTITY");
1782 break;
1783 case XML_ATTRIBUTE_ENTITIES:
1784 xmlBufferWriteChar(buf, " ENTITIES");
1785 break;
1786 case XML_ATTRIBUTE_NMTOKEN:
1787 xmlBufferWriteChar(buf, " NMTOKEN");
1788 break;
1789 case XML_ATTRIBUTE_NMTOKENS:
1790 xmlBufferWriteChar(buf, " NMTOKENS");
1791 break;
1792 case XML_ATTRIBUTE_ENUMERATION:
1793 xmlBufferWriteChar(buf, " (");
1794 xmlDumpEnumeration(buf, attr->tree);
1795 break;
1796 case XML_ATTRIBUTE_NOTATION:
1797 xmlBufferWriteChar(buf, " NOTATION (");
1798 xmlDumpEnumeration(buf, attr->tree);
1799 break;
1800 default:
1801 xmlGenericError(xmlGenericErrorContext,
1802 "xmlDumpAttributeDecl: internal: unknown type %d\n",
1803 attr->atype);
1805 switch (attr->def) {
1806 case XML_ATTRIBUTE_NONE:
1807 break;
1808 case XML_ATTRIBUTE_REQUIRED:
1809 xmlBufferWriteChar(buf, " #REQUIRED");
1810 break;
1811 case XML_ATTRIBUTE_IMPLIED:
1812 xmlBufferWriteChar(buf, " #IMPLIED");
1813 break;
1814 case XML_ATTRIBUTE_FIXED:
1815 xmlBufferWriteChar(buf, " #FIXED");
1816 break;
1817 default:
1818 xmlGenericError(xmlGenericErrorContext,
1819 "xmlDumpAttributeDecl: internal: unknown default %d\n",
1820 attr->def);
1822 if (attr->defaultValue != NULL) {
1823 xmlBufferWriteChar(buf, " ");
1824 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1826 xmlBufferWriteChar(buf, ">\n");
1830 * xmlDumpAttributeTable:
1831 * @buf: the XML buffer output
1832 * @table: An attribute table
1834 * This will dump the content of the attribute table as an XML DTD definition
1836 void
1837 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1838 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDecl, buf);
1841 /************************************************************************
1843 * NOTATIONs *
1845 ************************************************************************/
1847 * xmlCreateNotationTable:
1849 * create and initialize an empty notation hash table.
1851 * Returns the xmlNotationTablePtr just created or NULL in case
1852 * of error.
1854 static xmlNotationTablePtr
1855 xmlCreateNotationTable(void) {
1856 return(xmlHashCreate(0));
1860 * xmlFreeNotation:
1861 * @not: A notation
1863 * Deallocate the memory used by an notation definition
1865 static void
1866 xmlFreeNotation(xmlNotationPtr nota) {
1867 if (nota == NULL) return;
1868 if (nota->name != NULL)
1869 xmlFree((xmlChar *) nota->name);
1870 if (nota->PublicID != NULL)
1871 xmlFree((xmlChar *) nota->PublicID);
1872 if (nota->SystemID != NULL)
1873 xmlFree((xmlChar *) nota->SystemID);
1874 xmlFree(nota);
1879 * xmlAddNotationDecl:
1880 * @dtd: pointer to the DTD
1881 * @ctxt: the validation context
1882 * @name: the entity name
1883 * @PublicID: the public identifier or NULL
1884 * @SystemID: the system identifier or NULL
1886 * Register a new notation declaration
1888 * Returns NULL if not, otherwise the entity
1890 xmlNotationPtr
1891 xmlAddNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDtdPtr dtd,
1892 const xmlChar *name,
1893 const xmlChar *PublicID, const xmlChar *SystemID) {
1894 xmlNotationPtr ret;
1895 xmlNotationTablePtr table;
1897 if (dtd == NULL) {
1898 xmlGenericError(xmlGenericErrorContext,
1899 "xmlAddNotationDecl: dtd == NULL\n");
1900 return(NULL);
1902 if (name == NULL) {
1903 xmlGenericError(xmlGenericErrorContext,
1904 "xmlAddNotationDecl: name == NULL\n");
1905 return(NULL);
1907 if ((PublicID == NULL) && (SystemID == NULL)) {
1908 xmlGenericError(xmlGenericErrorContext,
1909 "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1910 return(NULL);
1914 * Create the Notation table if needed.
1916 table = (xmlNotationTablePtr) dtd->notations;
1917 if (table == NULL)
1918 dtd->notations = table = xmlCreateNotationTable();
1919 if (table == NULL) {
1920 xmlGenericError(xmlGenericErrorContext,
1921 "xmlAddNotationDecl: Table creation failed!\n");
1922 return(NULL);
1925 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1926 if (ret == NULL) {
1927 xmlGenericError(xmlGenericErrorContext,
1928 "xmlAddNotationDecl: out of memory\n");
1929 return(NULL);
1931 memset(ret, 0, sizeof(xmlNotation));
1934 * fill the structure.
1936 ret->name = xmlStrdup(name);
1937 if (SystemID != NULL)
1938 ret->SystemID = xmlStrdup(SystemID);
1939 if (PublicID != NULL)
1940 ret->PublicID = xmlStrdup(PublicID);
1943 * Validity Check:
1944 * Check the DTD for previous declarations of the ATTLIST
1946 if (xmlHashAddEntry(table, name, ret)) {
1947 xmlGenericError(xmlGenericErrorContext,
1948 "xmlAddNotationDecl: %s already defined\n", name);
1949 xmlFreeNotation(ret);
1950 return(NULL);
1952 return(ret);
1956 * xmlFreeNotationTable:
1957 * @table: An notation table
1959 * Deallocate the memory used by an entities hash table.
1961 void
1962 xmlFreeNotationTable(xmlNotationTablePtr table) {
1963 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
1967 * xmlCopyNotation:
1968 * @nota: A notation
1970 * Build a copy of a notation.
1972 * Returns the new xmlNotationPtr or NULL in case of error.
1974 static xmlNotationPtr
1975 xmlCopyNotation(xmlNotationPtr nota) {
1976 xmlNotationPtr cur;
1978 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1979 if (cur == NULL) {
1980 xmlGenericError(xmlGenericErrorContext,
1981 "xmlCopyNotation: out of memory !\n");
1982 return(NULL);
1984 if (nota->name != NULL)
1985 cur->name = xmlStrdup(nota->name);
1986 else
1987 cur->name = NULL;
1988 if (nota->PublicID != NULL)
1989 cur->PublicID = xmlStrdup(nota->PublicID);
1990 else
1991 cur->PublicID = NULL;
1992 if (nota->SystemID != NULL)
1993 cur->SystemID = xmlStrdup(nota->SystemID);
1994 else
1995 cur->SystemID = NULL;
1996 return(cur);
2000 * xmlCopyNotationTable:
2001 * @table: A notation table
2003 * Build a copy of a notation table.
2005 * Returns the new xmlNotationTablePtr or NULL in case of error.
2007 xmlNotationTablePtr
2008 xmlCopyNotationTable(xmlNotationTablePtr table) {
2009 return((xmlNotationTablePtr) xmlHashCopy(table,
2010 (xmlHashCopier) xmlCopyNotation));
2014 * xmlDumpNotationDecl:
2015 * @buf: the XML buffer output
2016 * @nota: A notation declaration
2018 * This will dump the content the notation declaration as an XML DTD definition
2020 void
2021 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2022 xmlBufferWriteChar(buf, "<!NOTATION ");
2023 xmlBufferWriteCHAR(buf, nota->name);
2024 if (nota->PublicID != NULL) {
2025 xmlBufferWriteChar(buf, " PUBLIC ");
2026 xmlBufferWriteQuotedString(buf, nota->PublicID);
2027 if (nota->SystemID != NULL) {
2028 xmlBufferWriteChar(buf, " ");
2029 xmlBufferWriteCHAR(buf, nota->SystemID);
2031 } else {
2032 xmlBufferWriteChar(buf, " SYSTEM ");
2033 xmlBufferWriteCHAR(buf, nota->SystemID);
2035 xmlBufferWriteChar(buf, " >\n");
2039 * xmlDumpNotationTable:
2040 * @buf: the XML buffer output
2041 * @table: A notation table
2043 * This will dump the content of the notation table as an XML DTD definition
2045 void
2046 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2047 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDecl, buf);
2050 /************************************************************************
2052 * IDs *
2054 ************************************************************************/
2056 * xmlCreateIDTable:
2058 * create and initialize an empty id hash table.
2060 * Returns the xmlIDTablePtr just created or NULL in case
2061 * of error.
2063 static xmlIDTablePtr
2064 xmlCreateIDTable(void) {
2065 return(xmlHashCreate(0));
2069 * xmlFreeID:
2070 * @not: A id
2072 * Deallocate the memory used by an id definition
2074 static void
2075 xmlFreeID(xmlIDPtr id) {
2076 if (id == NULL) return;
2077 if (id->value != NULL)
2078 xmlFree((xmlChar *) id->value);
2079 xmlFree(id);
2083 * xmlAddID:
2084 * @ctxt: the validation context
2085 * @doc: pointer to the document
2086 * @value: the value name
2087 * @attr: the attribute holding the ID
2089 * Register a new id declaration
2091 * Returns NULL if not, otherwise the new xmlIDPtr
2093 xmlIDPtr
2094 xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2095 xmlAttrPtr attr) {
2096 xmlIDPtr ret;
2097 xmlIDTablePtr table;
2099 if (doc == NULL) {
2100 xmlGenericError(xmlGenericErrorContext,
2101 "xmlAddID: doc == NULL\n");
2102 return(NULL);
2104 if (value == NULL) {
2105 xmlGenericError(xmlGenericErrorContext,
2106 "xmlAddID: value == NULL\n");
2107 return(NULL);
2109 if (attr == NULL) {
2110 xmlGenericError(xmlGenericErrorContext,
2111 "xmlAddID: attr == NULL\n");
2112 return(NULL);
2116 * Create the ID table if needed.
2118 table = (xmlIDTablePtr) doc->ids;
2119 if (table == NULL)
2120 doc->ids = table = xmlCreateIDTable();
2121 if (table == NULL) {
2122 xmlGenericError(xmlGenericErrorContext,
2123 "xmlAddID: Table creation failed!\n");
2124 return(NULL);
2127 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2128 if (ret == NULL) {
2129 xmlGenericError(xmlGenericErrorContext,
2130 "xmlAddID: out of memory\n");
2131 return(NULL);
2135 * fill the structure.
2137 ret->value = xmlStrdup(value);
2138 ret->attr = attr;
2140 if (xmlHashAddEntry(table, value, ret) < 0) {
2142 * The id is already defined in this DTD.
2144 if (ctxt != NULL) {
2145 VECTXT(ctxt, attr->parent);
2146 VERROR(ctxt->userData, "ID %s already defined\n", value);
2148 xmlFreeID(ret);
2149 return(NULL);
2151 return(ret);
2155 * xmlFreeIDTable:
2156 * @table: An id table
2158 * Deallocate the memory used by an ID hash table.
2160 void
2161 xmlFreeIDTable(xmlIDTablePtr table) {
2162 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2166 * xmlIsID:
2167 * @doc: the document
2168 * @elem: the element carrying the attribute
2169 * @attr: the attribute
2171 * Determine whether an attribute is of type ID. In case we have DTD(s)
2172 * then this is done if DTD loading has been requested. In the case
2173 * of HTML documents parsed with the HTML parser, then ID detection is
2174 * done systematically.
2176 * Returns 0 or 1 depending on the lookup result
2179 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2180 if (doc == NULL) return(0);
2181 if (attr == NULL) return(0);
2182 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2183 return(0);
2184 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2185 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2186 (xmlStrEqual(BAD_CAST "name", attr->name)))
2187 return(1);
2188 return(0);
2189 } else {
2190 xmlAttributePtr attrDecl;
2192 if (elem == NULL) return(0);
2193 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2195 * TODO: this sucks ... recomputing this every time is stupid
2197 int len = xmlStrlen(elem->name) + xmlStrlen(elem->ns->prefix) + 2;
2198 xmlChar *fullname;
2200 fullname = xmlMalloc(len);
2201 if (fullname == NULL)
2202 return(0);
2203 snprintf((char *) fullname, len, "%s:%s", (char *) elem->ns->prefix,
2204 (char *) elem->name);
2205 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2206 attr->name);
2207 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2208 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2209 attr->name);
2210 xmlFree(fullname);
2211 } else {
2212 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2213 attr->name);
2214 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2215 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2216 attr->name);
2219 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2220 return(1);
2222 return(0);
2226 * xmlRemoveID
2227 * @doc: the document
2228 * @attr: the attribute
2230 * Remove the given attribute from the ID table maintained internally.
2232 * Returns -1 if the lookup failed and 0 otherwise
2235 xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2236 xmlAttrPtr cur;
2237 xmlIDTablePtr table;
2238 xmlChar *ID;
2240 if (doc == NULL) return(-1);
2241 if (attr == NULL) return(-1);
2242 table = (xmlIDTablePtr) doc->ids;
2243 if (table == NULL)
2244 return(-1);
2246 if (attr == NULL)
2247 return(-1);
2248 ID = xmlNodeListGetString(doc, attr->children, 1);
2249 if (ID == NULL)
2250 return(-1);
2251 cur = xmlHashLookup(table, ID);
2252 if (cur != attr) {
2253 xmlFree(ID);
2254 return(-1);
2256 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2257 xmlFree(ID);
2258 return(0);
2262 * xmlGetID:
2263 * @doc: pointer to the document
2264 * @ID: the ID value
2266 * Search the attribute declaring the given ID
2268 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2270 xmlAttrPtr
2271 xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2272 xmlIDTablePtr table;
2273 xmlIDPtr id;
2275 if (doc == NULL) {
2276 xmlGenericError(xmlGenericErrorContext, "xmlGetID: doc == NULL\n");
2277 return(NULL);
2280 if (ID == NULL) {
2281 xmlGenericError(xmlGenericErrorContext, "xmlGetID: ID == NULL\n");
2282 return(NULL);
2285 table = (xmlIDTablePtr) doc->ids;
2286 if (table == NULL)
2287 return(NULL);
2289 id = xmlHashLookup(table, ID);
2290 if (id == NULL)
2291 return(NULL);
2292 return(id->attr);
2295 /************************************************************************
2297 * Refs *
2299 ************************************************************************/
2300 typedef struct xmlRemoveMemo_t
2302 xmlListPtr l;
2303 xmlAttrPtr ap;
2304 } xmlRemoveMemo;
2306 typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2308 typedef struct xmlValidateMemo_t
2310 xmlValidCtxtPtr ctxt;
2311 const xmlChar *name;
2312 } xmlValidateMemo;
2314 typedef xmlValidateMemo *xmlValidateMemoPtr;
2317 * xmlCreateRefTable:
2319 * create and initialize an empty ref hash table.
2321 * Returns the xmlRefTablePtr just created or NULL in case
2322 * of error.
2324 static xmlRefTablePtr
2325 xmlCreateRefTable(void) {
2326 return(xmlHashCreate(0));
2330 * xmlFreeRef:
2331 * @lk: A list link
2333 * Deallocate the memory used by a ref definition
2335 static void
2336 xmlFreeRef(xmlLinkPtr lk) {
2337 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2338 if (ref == NULL) return;
2339 if (ref->value != NULL)
2340 xmlFree((xmlChar *)ref->value);
2341 xmlFree(ref);
2345 * xmlFreeRefList:
2346 * @list_ref: A list of references.
2348 * Deallocate the memory used by a list of references
2350 static void
2351 xmlFreeRefList(xmlListPtr list_ref) {
2352 if (list_ref == NULL) return;
2353 xmlListDelete(list_ref);
2357 * xmlWalkRemoveRef:
2358 * @data: Contents of current link
2359 * @user: Value supplied by the user
2361 * Returns 0 to abort the walk or 1 to continue
2363 static int
2364 xmlWalkRemoveRef(const void *data, const void *user)
2366 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2367 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2368 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2370 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2371 xmlListRemoveFirst(ref_list, (void *)data);
2372 return 0;
2374 return 1;
2378 * xmlAddRef:
2379 * @ctxt: the validation context
2380 * @doc: pointer to the document
2381 * @value: the value name
2382 * @attr: the attribute holding the Ref
2384 * Register a new ref declaration
2386 * Returns NULL if not, otherwise the new xmlRefPtr
2388 xmlRefPtr
2389 xmlAddRef(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc, const xmlChar *value,
2390 xmlAttrPtr attr) {
2391 xmlRefPtr ret;
2392 xmlRefTablePtr table;
2393 xmlListPtr ref_list;
2395 if (doc == NULL) {
2396 xmlGenericError(xmlGenericErrorContext,
2397 "xmlAddRef: doc == NULL\n");
2398 return(NULL);
2400 if (value == NULL) {
2401 xmlGenericError(xmlGenericErrorContext,
2402 "xmlAddRef: value == NULL\n");
2403 return(NULL);
2405 if (attr == NULL) {
2406 xmlGenericError(xmlGenericErrorContext,
2407 "xmlAddRef: attr == NULL\n");
2408 return(NULL);
2412 * Create the Ref table if needed.
2414 table = (xmlRefTablePtr) doc->refs;
2415 if (table == NULL)
2416 doc->refs = table = xmlCreateRefTable();
2417 if (table == NULL) {
2418 xmlGenericError(xmlGenericErrorContext,
2419 "xmlAddRef: Table creation failed!\n");
2420 return(NULL);
2423 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2424 if (ret == NULL) {
2425 xmlGenericError(xmlGenericErrorContext,
2426 "xmlAddRef: out of memory\n");
2427 return(NULL);
2431 * fill the structure.
2433 ret->value = xmlStrdup(value);
2434 ret->attr = attr;
2436 /* To add a reference :-
2437 * References are maintained as a list of references,
2438 * Lookup the entry, if no entry create new nodelist
2439 * Add the owning node to the NodeList
2440 * Return the ref
2443 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2444 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
2445 xmlGenericError(xmlGenericErrorContext,
2446 "xmlAddRef: Reference list creation failed!\n");
2447 return(NULL);
2449 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2450 xmlListDelete(ref_list);
2451 xmlGenericError(xmlGenericErrorContext,
2452 "xmlAddRef: Reference list insertion failed!\n");
2453 return(NULL);
2456 xmlListInsert(ref_list, ret);
2457 return(ret);
2461 * xmlFreeRefTable:
2462 * @table: An ref table
2464 * Deallocate the memory used by an Ref hash table.
2466 void
2467 xmlFreeRefTable(xmlRefTablePtr table) {
2468 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
2472 * xmlIsRef:
2473 * @doc: the document
2474 * @elem: the element carrying the attribute
2475 * @attr: the attribute
2477 * Determine whether an attribute is of type Ref. In case we have DTD(s)
2478 * then this is simple, otherwise we use an heuristic: name Ref (upper
2479 * or lowercase).
2481 * Returns 0 or 1 depending on the lookup result
2484 xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2485 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2486 return(0);
2487 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2488 /* TODO @@@ */
2489 return(0);
2490 } else {
2491 xmlAttributePtr attrDecl;
2493 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2494 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2495 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2496 elem->name, attr->name);
2498 if ((attrDecl != NULL) &&
2499 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2500 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2501 return(1);
2503 return(0);
2507 * xmlRemoveRef
2508 * @doc: the document
2509 * @attr: the attribute
2511 * Remove the given attribute from the Ref table maintained internally.
2513 * Returns -1 if the lookup failed and 0 otherwise
2516 xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2517 xmlListPtr ref_list;
2518 xmlRefTablePtr table;
2519 xmlChar *ID;
2520 xmlRemoveMemo target;
2522 if (doc == NULL) return(-1);
2523 if (attr == NULL) return(-1);
2524 table = (xmlRefTablePtr) doc->refs;
2525 if (table == NULL)
2526 return(-1);
2528 if (attr == NULL)
2529 return(-1);
2530 ID = xmlNodeListGetString(doc, attr->children, 1);
2531 if (ID == NULL)
2532 return(-1);
2533 ref_list = xmlHashLookup(table, ID);
2535 if(ref_list == NULL) {
2536 xmlFree(ID);
2537 return (-1);
2539 /* At this point, ref_list refers to a list of references which
2540 * have the same key as the supplied attr. Our list of references
2541 * is ordered by reference address and we don't have that information
2542 * here to use when removing. We'll have to walk the list and
2543 * check for a matching attribute, when we find one stop the walk
2544 * and remove the entry.
2545 * The list is ordered by reference, so that means we don't have the
2546 * key. Passing the list and the reference to the walker means we
2547 * will have enough data to be able to remove the entry.
2549 target.l = ref_list;
2550 target.ap = attr;
2552 /* Remove the supplied attr from our list */
2553 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
2555 /*If the list is empty then remove the list entry in the hash */
2556 if (xmlListEmpty(ref_list))
2557 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2558 xmlFreeRefList);
2559 xmlFree(ID);
2560 return(0);
2564 * xmlGetRefs:
2565 * @doc: pointer to the document
2566 * @ID: the ID value
2568 * Find the set of references for the supplied ID.
2570 * Returns NULL if not found, otherwise node set for the ID.
2572 xmlListPtr
2573 xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
2574 xmlRefTablePtr table;
2576 if (doc == NULL) {
2577 xmlGenericError(xmlGenericErrorContext, "xmlGetRefs: doc == NULL\n");
2578 return(NULL);
2581 if (ID == NULL) {
2582 xmlGenericError(xmlGenericErrorContext, "xmlGetRefs: ID == NULL\n");
2583 return(NULL);
2586 table = (xmlRefTablePtr) doc->refs;
2587 if (table == NULL)
2588 return(NULL);
2590 return (xmlHashLookup(table, ID));
2593 /************************************************************************
2595 * Routines for validity checking *
2597 ************************************************************************/
2600 * xmlGetDtdElementDesc:
2601 * @dtd: a pointer to the DtD to search
2602 * @name: the element name
2604 * Search the DTD for the description of this element
2606 * returns the xmlElementPtr if found or NULL
2609 xmlElementPtr
2610 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2611 xmlElementTablePtr table;
2612 xmlElementPtr cur;
2613 xmlChar *uqname = NULL, *prefix = NULL;
2615 if (dtd == NULL) return(NULL);
2616 if (dtd->elements == NULL)
2617 return(NULL);
2618 table = (xmlElementTablePtr) dtd->elements;
2620 uqname = xmlSplitQName2(name, &prefix);
2621 if (uqname != NULL)
2622 name = uqname;
2623 cur = xmlHashLookup2(table, name, prefix);
2624 if (prefix != NULL) xmlFree(prefix);
2625 if (uqname != NULL) xmlFree(uqname);
2626 return(cur);
2629 * xmlGetDtdElementDesc2:
2630 * @dtd: a pointer to the DtD to search
2631 * @name: the element name
2632 * @create: create an empty description if not found
2634 * Search the DTD for the description of this element
2636 * returns the xmlElementPtr if found or NULL
2639 static xmlElementPtr
2640 xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2641 xmlElementTablePtr table;
2642 xmlElementPtr cur;
2643 xmlChar *uqname = NULL, *prefix = NULL;
2645 if (dtd == NULL) return(NULL);
2646 if (dtd->elements == NULL) {
2647 if (!create)
2648 return(NULL);
2650 * Create the Element table if needed.
2652 table = (xmlElementTablePtr) dtd->elements;
2653 if (table == NULL) {
2654 table = xmlCreateElementTable();
2655 dtd->elements = (void *) table;
2657 if (table == NULL) {
2658 xmlGenericError(xmlGenericErrorContext,
2659 "xmlGetDtdElementDesc2: Table creation failed!\n");
2660 return(NULL);
2663 table = (xmlElementTablePtr) dtd->elements;
2665 uqname = xmlSplitQName2(name, &prefix);
2666 if (uqname != NULL)
2667 name = uqname;
2668 cur = xmlHashLookup2(table, name, prefix);
2669 if ((cur == NULL) && (create)) {
2670 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
2671 if (cur == NULL) {
2672 xmlGenericError(xmlGenericErrorContext,
2673 "xmlGetDtdElementDesc2: out of memory\n");
2674 return(NULL);
2676 memset(cur, 0, sizeof(xmlElement));
2677 cur->type = XML_ELEMENT_DECL;
2680 * fill the structure.
2682 cur->name = xmlStrdup(name);
2683 cur->prefix = xmlStrdup(prefix);
2684 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
2686 xmlHashAddEntry2(table, name, prefix, cur);
2688 if (prefix != NULL) xmlFree(prefix);
2689 if (uqname != NULL) xmlFree(uqname);
2690 return(cur);
2694 * xmlGetDtdQElementDesc:
2695 * @dtd: a pointer to the DtD to search
2696 * @name: the element name
2697 * @prefix: the element namespace prefix
2699 * Search the DTD for the description of this element
2701 * returns the xmlElementPtr if found or NULL
2704 xmlElementPtr
2705 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2706 const xmlChar *prefix) {
2707 xmlElementTablePtr table;
2709 if (dtd == NULL) return(NULL);
2710 if (dtd->elements == NULL) return(NULL);
2711 table = (xmlElementTablePtr) dtd->elements;
2713 return(xmlHashLookup2(table, name, prefix));
2717 * xmlGetDtdAttrDesc:
2718 * @dtd: a pointer to the DtD to search
2719 * @elem: the element name
2720 * @name: the attribute name
2722 * Search the DTD for the description of this attribute on
2723 * this element.
2725 * returns the xmlAttributePtr if found or NULL
2728 xmlAttributePtr
2729 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
2730 xmlAttributeTablePtr table;
2731 xmlAttributePtr cur;
2732 xmlChar *uqname = NULL, *prefix = NULL;
2734 if (dtd == NULL) return(NULL);
2735 if (dtd->attributes == NULL) return(NULL);
2737 table = (xmlAttributeTablePtr) dtd->attributes;
2738 if (table == NULL)
2739 return(NULL);
2741 uqname = xmlSplitQName2(name, &prefix);
2743 if (uqname != NULL) {
2744 cur = xmlHashLookup3(table, uqname, prefix, elem);
2745 if (prefix != NULL) xmlFree(prefix);
2746 if (uqname != NULL) xmlFree(uqname);
2747 } else
2748 cur = xmlHashLookup3(table, name, NULL, elem);
2749 return(cur);
2753 * xmlGetDtdQAttrDesc:
2754 * @dtd: a pointer to the DtD to search
2755 * @elem: the element name
2756 * @name: the attribute name
2757 * @prefix: the attribute namespace prefix
2759 * Search the DTD for the description of this qualified attribute on
2760 * this element.
2762 * returns the xmlAttributePtr if found or NULL
2765 xmlAttributePtr
2766 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2767 const xmlChar *prefix) {
2768 xmlAttributeTablePtr table;
2770 if (dtd == NULL) return(NULL);
2771 if (dtd->attributes == NULL) return(NULL);
2772 table = (xmlAttributeTablePtr) dtd->attributes;
2774 return(xmlHashLookup3(table, name, prefix, elem));
2778 * xmlGetDtdNotationDesc:
2779 * @dtd: a pointer to the DtD to search
2780 * @name: the notation name
2782 * Search the DTD for the description of this notation
2784 * returns the xmlNotationPtr if found or NULL
2787 xmlNotationPtr
2788 xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
2789 xmlNotationTablePtr table;
2791 if (dtd == NULL) return(NULL);
2792 if (dtd->notations == NULL) return(NULL);
2793 table = (xmlNotationTablePtr) dtd->notations;
2795 return(xmlHashLookup(table, name));
2799 * xmlValidateNotationUse:
2800 * @ctxt: the validation context
2801 * @doc: the document
2802 * @notationName: the notation name to check
2804 * Validate that the given name match a notation declaration.
2805 * - [ VC: Notation Declared ]
2807 * returns 1 if valid or 0 otherwise
2811 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2812 const xmlChar *notationName) {
2813 xmlNotationPtr notaDecl;
2814 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2816 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2817 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2818 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2820 if (notaDecl == NULL) {
2821 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2822 notationName);
2823 return(0);
2825 return(1);
2829 * xmlIsMixedElement
2830 * @doc: the document
2831 * @name: the element name
2833 * Search in the DtDs whether an element accept Mixed content (or ANY)
2834 * basically if it is supposed to accept text childs
2836 * returns 0 if no, 1 if yes, and -1 if no element description is available
2840 xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
2841 xmlElementPtr elemDecl;
2843 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2845 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2846 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2847 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2848 if (elemDecl == NULL) return(-1);
2849 switch (elemDecl->etype) {
2850 case XML_ELEMENT_TYPE_UNDEFINED:
2851 return(-1);
2852 case XML_ELEMENT_TYPE_ELEMENT:
2853 return(0);
2854 case XML_ELEMENT_TYPE_EMPTY:
2856 * return 1 for EMPTY since we want VC error to pop up
2857 * on <empty> </empty> for example
2859 case XML_ELEMENT_TYPE_ANY:
2860 case XML_ELEMENT_TYPE_MIXED:
2861 return(1);
2863 return(1);
2867 * xmlValidateNameValue:
2868 * @value: an Name value
2870 * Validate that the given value match Name production
2872 * returns 1 if valid or 0 otherwise
2876 xmlValidateNameValue(const xmlChar *value) {
2877 const xmlChar *cur;
2878 int val, len;
2880 if (value == NULL) return(0);
2881 cur = value;
2882 val = xmlStringCurrentChar(NULL, cur, &len);
2883 cur += len;
2884 if (!IS_LETTER(val) && (val != '_') &&
2885 (val != ':')) {
2886 return(0);
2889 val = xmlStringCurrentChar(NULL, cur, &len);
2890 cur += len;
2891 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
2892 (val == '.') || (val == '-') ||
2893 (val == '_') || (val == ':') ||
2894 (IS_COMBINING(val)) ||
2895 (IS_EXTENDER(val))) {
2896 val = xmlStringCurrentChar(NULL, cur, &len);
2897 cur += len;
2900 if (val != 0) return(0);
2902 return(1);
2906 * xmlValidateNamesValue:
2907 * @value: an Names value
2909 * Validate that the given value match Names production
2911 * returns 1 if valid or 0 otherwise
2915 xmlValidateNamesValue(const xmlChar *value) {
2916 const xmlChar *cur;
2917 int val, len;
2919 if (value == NULL) return(0);
2920 cur = value;
2921 val = xmlStringCurrentChar(NULL, cur, &len);
2922 cur += len;
2924 if (!IS_LETTER(val) && (val != '_') &&
2925 (val != ':')) {
2926 return(0);
2929 val = xmlStringCurrentChar(NULL, cur, &len);
2930 cur += len;
2931 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
2932 (val == '.') || (val == '-') ||
2933 (val == '_') || (val == ':') ||
2934 (IS_COMBINING(val)) ||
2935 (IS_EXTENDER(val))) {
2936 val = xmlStringCurrentChar(NULL, cur, &len);
2937 cur += len;
2940 while (IS_BLANK(val)) {
2941 while (IS_BLANK(val)) {
2942 val = xmlStringCurrentChar(NULL, cur, &len);
2943 cur += len;
2946 if (!IS_LETTER(val) && (val != '_') &&
2947 (val != ':')) {
2948 return(0);
2950 val = xmlStringCurrentChar(NULL, cur, &len);
2951 cur += len;
2953 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
2954 (val == '.') || (val == '-') ||
2955 (val == '_') || (val == ':') ||
2956 (IS_COMBINING(val)) ||
2957 (IS_EXTENDER(val))) {
2958 val = xmlStringCurrentChar(NULL, cur, &len);
2959 cur += len;
2963 if (val != 0) return(0);
2965 return(1);
2969 * xmlValidateNmtokenValue:
2970 * @value: an Nmtoken value
2972 * Validate that the given value match Nmtoken production
2974 * [ VC: Name Token ]
2976 * returns 1 if valid or 0 otherwise
2980 xmlValidateNmtokenValue(const xmlChar *value) {
2981 const xmlChar *cur;
2982 int val, len;
2984 if (value == NULL) return(0);
2985 cur = value;
2986 val = xmlStringCurrentChar(NULL, cur, &len);
2987 cur += len;
2989 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
2990 (val != '.') && (val != '-') &&
2991 (val != '_') && (val != ':') &&
2992 (!IS_COMBINING(val)) &&
2993 (!IS_EXTENDER(val)))
2994 return(0);
2996 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
2997 (val == '.') || (val == '-') ||
2998 (val == '_') || (val == ':') ||
2999 (IS_COMBINING(val)) ||
3000 (IS_EXTENDER(val))) {
3001 val = xmlStringCurrentChar(NULL, cur, &len);
3002 cur += len;
3005 if (val != 0) return(0);
3007 return(1);
3011 * xmlValidateNmtokensValue:
3012 * @value: an Nmtokens value
3014 * Validate that the given value match Nmtokens production
3016 * [ VC: Name Token ]
3018 * returns 1 if valid or 0 otherwise
3022 xmlValidateNmtokensValue(const xmlChar *value) {
3023 const xmlChar *cur;
3024 int val, len;
3026 if (value == NULL) return(0);
3027 cur = value;
3028 val = xmlStringCurrentChar(NULL, cur, &len);
3029 cur += len;
3031 while (IS_BLANK(val)) {
3032 val = xmlStringCurrentChar(NULL, cur, &len);
3033 cur += len;
3036 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3037 (val != '.') && (val != '-') &&
3038 (val != '_') && (val != ':') &&
3039 (!IS_COMBINING(val)) &&
3040 (!IS_EXTENDER(val)))
3041 return(0);
3043 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3044 (val == '.') || (val == '-') ||
3045 (val == '_') || (val == ':') ||
3046 (IS_COMBINING(val)) ||
3047 (IS_EXTENDER(val))) {
3048 val = xmlStringCurrentChar(NULL, cur, &len);
3049 cur += len;
3052 while (IS_BLANK(val)) {
3053 while (IS_BLANK(val)) {
3054 val = xmlStringCurrentChar(NULL, cur, &len);
3055 cur += len;
3057 if (val == 0) return(1);
3059 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3060 (val != '.') && (val != '-') &&
3061 (val != '_') && (val != ':') &&
3062 (!IS_COMBINING(val)) &&
3063 (!IS_EXTENDER(val)))
3064 return(0);
3066 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3067 (val == '.') || (val == '-') ||
3068 (val == '_') || (val == ':') ||
3069 (IS_COMBINING(val)) ||
3070 (IS_EXTENDER(val))) {
3071 val = xmlStringCurrentChar(NULL, cur, &len);
3072 cur += len;
3076 if (val != 0) return(0);
3078 return(1);
3082 * xmlValidateNotationDecl:
3083 * @ctxt: the validation context
3084 * @doc: a document instance
3085 * @nota: a notation definition
3087 * Try to validate a single notation definition
3088 * basically it does the following checks as described by the
3089 * XML-1.0 recommendation:
3090 * - it seems that no validity constraint exists on notation declarations
3091 * But this function get called anyway ...
3093 * returns 1 if valid or 0 otherwise
3097 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3098 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3099 int ret = 1;
3101 return(ret);
3105 * xmlValidateAttributeValue:
3106 * @type: an attribute type
3107 * @value: an attribute value
3109 * Validate that the given attribute value match the proper production
3111 * [ VC: ID ]
3112 * Values of type ID must match the Name production....
3114 * [ VC: IDREF ]
3115 * Values of type IDREF must match the Name production, and values
3116 * of type IDREFS must match Names ...
3118 * [ VC: Entity Name ]
3119 * Values of type ENTITY must match the Name production, values
3120 * of type ENTITIES must match Names ...
3122 * [ VC: Name Token ]
3123 * Values of type NMTOKEN must match the Nmtoken production; values
3124 * of type NMTOKENS must match Nmtokens.
3126 * returns 1 if valid or 0 otherwise
3130 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3131 switch (type) {
3132 case XML_ATTRIBUTE_ENTITIES:
3133 case XML_ATTRIBUTE_IDREFS:
3134 return(xmlValidateNamesValue(value));
3135 case XML_ATTRIBUTE_ENTITY:
3136 case XML_ATTRIBUTE_IDREF:
3137 case XML_ATTRIBUTE_ID:
3138 case XML_ATTRIBUTE_NOTATION:
3139 return(xmlValidateNameValue(value));
3140 case XML_ATTRIBUTE_NMTOKENS:
3141 case XML_ATTRIBUTE_ENUMERATION:
3142 return(xmlValidateNmtokensValue(value));
3143 case XML_ATTRIBUTE_NMTOKEN:
3144 return(xmlValidateNmtokenValue(value));
3145 case XML_ATTRIBUTE_CDATA:
3146 break;
3148 return(1);
3152 * xmlValidateAttributeValue2:
3153 * @ctxt: the validation context
3154 * @doc: the document
3155 * @name: the attribute name (used for error reporting only)
3156 * @type: the attribute type
3157 * @value: the attribute value
3159 * Validate that the given attribute value match a given type.
3160 * This typically cannot be done before having finished parsing
3161 * the subsets.
3163 * [ VC: IDREF ]
3164 * Values of type IDREF must match one of the declared IDs
3165 * Values of type IDREFS must match a sequence of the declared IDs
3166 * each Name must match the value of an ID attribute on some element
3167 * in the XML document; i.e. IDREF values must match the value of
3168 * some ID attribute
3170 * [ VC: Entity Name ]
3171 * Values of type ENTITY must match one declared entity
3172 * Values of type ENTITIES must match a sequence of declared entities
3174 * [ VC: Notation Attributes ]
3175 * all notation names in the declaration must be declared.
3177 * returns 1 if valid or 0 otherwise
3180 static int
3181 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3182 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3183 int ret = 1;
3184 switch (type) {
3185 case XML_ATTRIBUTE_IDREFS:
3186 case XML_ATTRIBUTE_IDREF:
3187 case XML_ATTRIBUTE_ID:
3188 case XML_ATTRIBUTE_NMTOKENS:
3189 case XML_ATTRIBUTE_ENUMERATION:
3190 case XML_ATTRIBUTE_NMTOKEN:
3191 case XML_ATTRIBUTE_CDATA:
3192 break;
3193 case XML_ATTRIBUTE_ENTITY: {
3194 xmlEntityPtr ent;
3196 ent = xmlGetDocEntity(doc, value);
3197 if ((ent == NULL) && (doc->standalone == 1)) {
3198 doc->standalone = 0;
3199 ent = xmlGetDocEntity(doc, value);
3200 if (ent != NULL) {
3201 VERROR(ctxt->userData,
3202 "standalone problem: attribute %s reference entity \"%s\" in external subset\n",
3203 name, value);
3204 /* WAIT to get answer from the Core WG on this
3205 ret = 0;
3209 if (ent == NULL) {
3210 VERROR(ctxt->userData,
3211 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3212 name, value);
3213 ret = 0;
3214 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3215 VERROR(ctxt->userData,
3216 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3217 name, value);
3218 ret = 0;
3220 break;
3222 case XML_ATTRIBUTE_ENTITIES: {
3223 xmlChar *dup, *nam = NULL, *cur, save;
3224 xmlEntityPtr ent;
3226 dup = xmlStrdup(value);
3227 if (dup == NULL)
3228 return(0);
3229 cur = dup;
3230 while (*cur != 0) {
3231 nam = cur;
3232 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3233 save = *cur;
3234 *cur = 0;
3235 ent = xmlGetDocEntity(doc, nam);
3236 if (ent == NULL) {
3237 VERROR(ctxt->userData,
3238 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3239 name, nam);
3240 ret = 0;
3241 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3242 VERROR(ctxt->userData,
3243 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3244 name, nam);
3245 ret = 0;
3247 if (save == 0)
3248 break;
3249 *cur = save;
3250 while (IS_BLANK(*cur)) cur++;
3252 xmlFree(dup);
3253 break;
3255 case XML_ATTRIBUTE_NOTATION: {
3256 xmlNotationPtr nota;
3258 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3259 if ((nota == NULL) && (doc->extSubset != NULL))
3260 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3262 if (nota == NULL) {
3263 VERROR(ctxt->userData,
3264 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3265 name, value);
3266 ret = 0;
3268 break;
3271 return(ret);
3275 * xmlValidCtxtNormalizeAttributeValue:
3276 * @ctxt: the validation context
3277 * @doc: the document
3278 * @elem: the parent
3279 * @name: the attribute name
3280 * @value: the attribute value
3281 * @ctxt: the validation context or NULL
3283 * Does the validation related extra step of the normalization of attribute
3284 * values:
3286 * If the declared value is not CDATA, then the XML processor must further
3287 * process the normalized attribute value by discarding any leading and
3288 * trailing space (#x20) characters, and by replacing sequences of space
3289 * (#x20) characters by single space (#x20) character.
3291 * Also check VC: Standalone Document Declaration in P32, and update
3292 * ctxt->valid accordingly
3294 * returns a new normalized string if normalization is needed, NULL otherwise
3295 * the caller must free the returned value.
3298 xmlChar *
3299 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3300 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3301 xmlChar *ret, *dst;
3302 const xmlChar *src;
3303 xmlAttributePtr attrDecl = NULL;
3304 int extsubset = 0;
3306 if (doc == NULL) return(NULL);
3307 if (elem == NULL) return(NULL);
3308 if (name == NULL) return(NULL);
3309 if (value == NULL) return(NULL);
3311 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3312 xmlChar qname[500];
3313 snprintf((char *) qname, sizeof(qname), "%s:%s",
3314 elem->ns->prefix, elem->name);
3315 qname[sizeof(qname) - 1] = 0;
3316 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
3317 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3318 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
3319 if (attrDecl != NULL)
3320 extsubset = 1;
3323 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3324 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3325 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3326 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3327 if (attrDecl != NULL)
3328 extsubset = 1;
3331 if (attrDecl == NULL)
3332 return(NULL);
3333 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3334 return(NULL);
3336 ret = xmlStrdup(value);
3337 if (ret == NULL)
3338 return(NULL);
3339 src = value;
3340 dst = ret;
3341 while (*src == 0x20) src++;
3342 while (*src != 0) {
3343 if (*src == 0x20) {
3344 while (*src == 0x20) src++;
3345 if (*src != 0)
3346 *dst++ = 0x20;
3347 } else {
3348 *dst++ = *src++;
3351 *dst = 0;
3352 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
3353 VERROR(ctxt->userData,
3354 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
3355 name, elem->name);
3356 ctxt->valid = 0;
3358 return(ret);
3362 * xmlValidNormalizeAttributeValue:
3363 * @doc: the document
3364 * @elem: the parent
3365 * @name: the attribute name
3366 * @value: the attribute value
3367 * @ctxt: the validation context or NULL
3369 * Does the validation related extra step of the normalization of attribute
3370 * values:
3372 * If the declared value is not CDATA, then the XML processor must further
3373 * process the normalized attribute value by discarding any leading and
3374 * trailing space (#x20) characters, and by replacing sequences of space
3375 * (#x20) characters by single space (#x20) character.
3377 * returns a new normalized string if normalization is needed, NULL otherwise
3378 * the caller must free the returned value.
3381 xmlChar *
3382 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3383 const xmlChar *name, const xmlChar *value) {
3384 xmlChar *ret, *dst;
3385 const xmlChar *src;
3386 xmlAttributePtr attrDecl = NULL;
3388 if (doc == NULL) return(NULL);
3389 if (elem == NULL) return(NULL);
3390 if (name == NULL) return(NULL);
3391 if (value == NULL) return(NULL);
3393 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3394 xmlChar qname[500];
3395 snprintf((char *) qname, sizeof(qname), "%s:%s",
3396 elem->ns->prefix, elem->name);
3397 qname[sizeof(qname) - 1] = 0;
3398 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
3399 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3400 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
3402 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3403 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3404 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3406 if (attrDecl == NULL)
3407 return(NULL);
3408 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3409 return(NULL);
3411 ret = xmlStrdup(value);
3412 if (ret == NULL)
3413 return(NULL);
3414 src = value;
3415 dst = ret;
3416 while (*src == 0x20) src++;
3417 while (*src != 0) {
3418 if (*src == 0x20) {
3419 while (*src == 0x20) src++;
3420 if (*src != 0)
3421 *dst++ = 0x20;
3422 } else {
3423 *dst++ = *src++;
3426 *dst = 0;
3427 return(ret);
3430 static void
3431 xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
3432 const xmlChar* name ATTRIBUTE_UNUSED) {
3433 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3437 * xmlValidateAttributeDecl:
3438 * @ctxt: the validation context
3439 * @doc: a document instance
3440 * @attr: an attribute definition
3442 * Try to validate a single attribute definition
3443 * basically it does the following checks as described by the
3444 * XML-1.0 recommendation:
3445 * - [ VC: Attribute Default Legal ]
3446 * - [ VC: Enumeration ]
3447 * - [ VC: ID Attribute Default ]
3449 * The ID/IDREF uniqueness and matching are done separately
3451 * returns 1 if valid or 0 otherwise
3455 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3456 xmlAttributePtr attr) {
3457 int ret = 1;
3458 int val;
3459 CHECK_DTD;
3460 if(attr == NULL) return(1);
3462 /* Attribute Default Legal */
3463 /* Enumeration */
3464 if (attr->defaultValue != NULL) {
3465 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3466 if (val == 0) {
3467 VERROR(ctxt->userData,
3468 "Syntax of default value for attribute %s of %s is not valid\n",
3469 attr->name, attr->elem);
3471 ret &= val;
3474 /* ID Attribute Default */
3475 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3476 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3477 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
3478 VERROR(ctxt->userData,
3479 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
3480 attr->name, attr->elem);
3481 ret = 0;
3484 /* One ID per Element Type */
3485 if (attr->atype == XML_ATTRIBUTE_ID) {
3486 int nbId;
3488 /* the trick is that we parse DtD as their own internal subset */
3489 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3490 attr->elem);
3491 if (elem != NULL) {
3492 nbId = xmlScanIDAttributeDecl(NULL, elem);
3493 } else {
3494 xmlAttributeTablePtr table;
3497 * The attribute may be declared in the internal subset and the
3498 * element in the external subset.
3500 nbId = 0;
3501 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3502 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3503 xmlValidateAttributeIdCallback, &nbId);
3505 if (nbId > 1) {
3506 VERROR(ctxt->userData,
3507 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3508 attr->elem, nbId, attr->name);
3509 } else if (doc->extSubset != NULL) {
3510 int extId = 0;
3511 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3512 if (elem != NULL) {
3513 extId = xmlScanIDAttributeDecl(NULL, elem);
3515 if (extId > 1) {
3516 VERROR(ctxt->userData,
3517 "Element %s has %d ID attribute defined in the external subset : %s\n",
3518 attr->elem, extId, attr->name);
3519 } else if (extId + nbId > 1) {
3520 VERROR(ctxt->userData,
3521 "Element %s has ID attributes defined in the internal and external subset : %s\n",
3522 attr->elem, attr->name);
3527 /* Validity Constraint: Enumeration */
3528 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3529 xmlEnumerationPtr tree = attr->tree;
3530 while (tree != NULL) {
3531 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3532 tree = tree->next;
3534 if (tree == NULL) {
3535 VERROR(ctxt->userData,
3536 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
3537 attr->defaultValue, attr->name, attr->elem);
3538 ret = 0;
3542 return(ret);
3546 * xmlValidateElementDecl:
3547 * @ctxt: the validation context
3548 * @doc: a document instance
3549 * @elem: an element definition
3551 * Try to validate a single element definition
3552 * basically it does the following checks as described by the
3553 * XML-1.0 recommendation:
3554 * - [ VC: One ID per Element Type ]
3555 * - [ VC: No Duplicate Types ]
3556 * - [ VC: Unique Element Type Declaration ]
3558 * returns 1 if valid or 0 otherwise
3562 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3563 xmlElementPtr elem) {
3564 int ret = 1;
3565 xmlElementPtr tst;
3567 CHECK_DTD;
3569 if (elem == NULL) return(1);
3571 #if 0
3572 #ifdef LIBXML_REGEXP_ENABLED
3573 /* Build the regexp associated to the content model */
3574 ret = xmlValidBuildContentModel(ctxt, elem);
3575 #endif
3576 #endif
3578 /* No Duplicate Types */
3579 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3580 xmlElementContentPtr cur, next;
3581 const xmlChar *name;
3583 cur = elem->content;
3584 while (cur != NULL) {
3585 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3586 if (cur->c1 == NULL) break;
3587 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3588 name = cur->c1->name;
3589 next = cur->c2;
3590 while (next != NULL) {
3591 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
3592 if (xmlStrEqual(next->name, name)) {
3593 VERROR(ctxt->userData,
3594 "Definition of %s has duplicate references of %s\n",
3595 elem->name, name);
3596 ret = 0;
3598 break;
3600 if (next->c1 == NULL) break;
3601 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
3602 if (xmlStrEqual(next->c1->name, name)) {
3603 VERROR(ctxt->userData,
3604 "Definition of %s has duplicate references of %s\n",
3605 elem->name, name);
3606 ret = 0;
3608 next = next->c2;
3611 cur = cur->c2;
3615 /* VC: Unique Element Type Declaration */
3616 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3617 if ((tst != NULL ) && (tst != elem) &&
3618 ((tst->prefix == elem->prefix) ||
3619 (xmlStrEqual(tst->prefix, elem->prefix))) &&
3620 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
3621 VERROR(ctxt->userData, "Redefinition of element %s\n",
3622 elem->name);
3623 ret = 0;
3625 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3626 if ((tst != NULL ) && (tst != elem) &&
3627 ((tst->prefix == elem->prefix) ||
3628 (xmlStrEqual(tst->prefix, elem->prefix))) &&
3629 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
3630 VERROR(ctxt->userData, "Redefinition of element %s\n",
3631 elem->name);
3632 ret = 0;
3634 /* One ID per Element Type
3635 * already done when registering the attribute
3636 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3637 ret = 0;
3638 } */
3639 return(ret);
3643 * xmlValidateOneAttribute:
3644 * @ctxt: the validation context
3645 * @doc: a document instance
3646 * @elem: an element instance
3647 * @attr: an attribute instance
3648 * @value: the attribute value (without entities processing)
3650 * Try to validate a single attribute for an element
3651 * basically it does the following checks as described by the
3652 * XML-1.0 recommendation:
3653 * - [ VC: Attribute Value Type ]
3654 * - [ VC: Fixed Attribute Default ]
3655 * - [ VC: Entity Name ]
3656 * - [ VC: Name Token ]
3657 * - [ VC: ID ]
3658 * - [ VC: IDREF ]
3659 * - [ VC: Entity Name ]
3660 * - [ VC: Notation Attributes ]
3662 * The ID/IDREF uniqueness and matching are done separately
3664 * returns 1 if valid or 0 otherwise
3668 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3669 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
3670 /* xmlElementPtr elemDecl; */
3671 xmlAttributePtr attrDecl = NULL;
3672 int val;
3673 int ret = 1;
3675 CHECK_DTD;
3676 if ((elem == NULL) || (elem->name == NULL)) return(0);
3677 if ((attr == NULL) || (attr->name == NULL)) return(0);
3679 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3680 xmlChar qname[500];
3681 snprintf((char *) qname, sizeof(qname), "%s:%s",
3682 elem->ns->prefix, elem->name);
3683 qname[sizeof(qname) - 1] = 0;
3684 if (attr->ns != NULL) {
3685 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3686 attr->name, attr->ns->prefix);
3687 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3688 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3689 attr->name, attr->ns->prefix);
3690 } else {
3691 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3692 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3693 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3694 qname, attr->name);
3697 if (attrDecl == NULL) {
3698 if (attr->ns != NULL) {
3699 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3700 attr->name, attr->ns->prefix);
3701 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3702 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3703 attr->name, attr->ns->prefix);
3704 } else {
3705 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3706 elem->name, attr->name);
3707 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3708 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3709 elem->name, attr->name);
3714 /* Validity Constraint: Attribute Value Type */
3715 if (attrDecl == NULL) {
3716 VECTXT(ctxt, elem);
3717 VERROR(ctxt->userData,
3718 "No declaration for attribute %s of element %s\n",
3719 attr->name, elem->name);
3720 return(0);
3722 attr->atype = attrDecl->atype;
3724 val = xmlValidateAttributeValue(attrDecl->atype, value);
3725 if (val == 0) {
3726 VECTXT(ctxt, elem);
3727 VERROR(ctxt->userData,
3728 "Syntax of value for attribute %s of %s is not valid\n",
3729 attr->name, elem->name);
3730 ret = 0;
3733 /* Validity constraint: Fixed Attribute Default */
3734 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3735 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
3736 VECTXT(ctxt, elem);
3737 VERROR(ctxt->userData,
3738 "Value for attribute %s of %s is different from default \"%s\"\n",
3739 attr->name, elem->name, attrDecl->defaultValue);
3740 ret = 0;
3744 /* Validity Constraint: ID uniqueness */
3745 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
3746 if (xmlAddID(ctxt, doc, value, attr) == NULL)
3747 ret = 0;
3750 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3751 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
3752 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
3753 ret = 0;
3756 /* Validity Constraint: Notation Attributes */
3757 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
3758 xmlEnumerationPtr tree = attrDecl->tree;
3759 xmlNotationPtr nota;
3761 /* First check that the given NOTATION was declared */
3762 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3763 if (nota == NULL)
3764 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3766 if (nota == NULL) {
3767 VECTXT(ctxt, elem);
3768 VERROR(ctxt->userData,
3769 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
3770 value, attr->name, elem->name);
3771 ret = 0;
3774 /* Second, verify that it's among the list */
3775 while (tree != NULL) {
3776 if (xmlStrEqual(tree->name, value)) break;
3777 tree = tree->next;
3779 if (tree == NULL) {
3780 VECTXT(ctxt, elem);
3781 VERROR(ctxt->userData,
3782 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
3783 value, attr->name, elem->name);
3784 ret = 0;
3788 /* Validity Constraint: Enumeration */
3789 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
3790 xmlEnumerationPtr tree = attrDecl->tree;
3791 while (tree != NULL) {
3792 if (xmlStrEqual(tree->name, value)) break;
3793 tree = tree->next;
3795 if (tree == NULL) {
3796 VECTXT(ctxt, elem);
3797 VERROR(ctxt->userData,
3798 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
3799 value, attr->name, elem->name);
3800 ret = 0;
3804 /* Fixed Attribute Default */
3805 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3806 (!xmlStrEqual(attrDecl->defaultValue, value))) {
3807 VECTXT(ctxt, elem);
3808 VERROR(ctxt->userData,
3809 "Value for attribute %s of %s must be \"%s\"\n",
3810 attr->name, elem->name, attrDecl->defaultValue);
3811 ret = 0;
3814 /* Extra check for the attribute value */
3815 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3816 attrDecl->atype, value);
3818 return(ret);
3822 * xmlValidateOneNamespace:
3823 * @ctxt: the validation context
3824 * @doc: a document instance
3825 * @elem: an element instance
3826 * @ns: an namespace declaration instance
3827 * @value: the attribute value (without entities processing)
3829 * Try to validate a single namespace declaration for an element
3830 * basically it does the following checks as described by the
3831 * XML-1.0 recommendation:
3832 * - [ VC: Attribute Value Type ]
3833 * - [ VC: Fixed Attribute Default ]
3834 * - [ VC: Entity Name ]
3835 * - [ VC: Name Token ]
3836 * - [ VC: ID ]
3837 * - [ VC: IDREF ]
3838 * - [ VC: Entity Name ]
3839 * - [ VC: Notation Attributes ]
3841 * The ID/IDREF uniqueness and matching are done separately
3843 * returns 1 if valid or 0 otherwise
3847 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3848 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
3849 /* xmlElementPtr elemDecl; */
3850 xmlAttributePtr attrDecl = NULL;
3851 int val;
3852 int ret = 1;
3854 CHECK_DTD;
3855 if ((elem == NULL) || (elem->name == NULL)) return(0);
3856 if ((ns == NULL) || (ns->href == NULL)) return(0);
3858 if (prefix != NULL) {
3859 xmlChar qname[500];
3860 snprintf((char *) qname, sizeof(qname), "%s:%s",
3861 prefix, elem->name);
3862 qname[sizeof(qname) - 1] = 0;
3863 if (ns->prefix != NULL) {
3864 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3865 ns->prefix, BAD_CAST "xmlns");
3866 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3867 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3868 ns->prefix, BAD_CAST "xmlns");
3869 } else {
3870 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname,
3871 BAD_CAST "xmlns");
3872 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3873 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname,
3874 BAD_CAST "xmlns");
3877 if (attrDecl == NULL) {
3878 if (ns->prefix != NULL) {
3879 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3880 ns->prefix, BAD_CAST "xmlns");
3881 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3882 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3883 ns->prefix, BAD_CAST "xmlns");
3884 } else {
3885 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3886 elem->name, BAD_CAST "xmlns");
3887 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3888 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3889 elem->name, BAD_CAST "xmlns");
3894 /* Validity Constraint: Attribute Value Type */
3895 if (attrDecl == NULL) {
3896 VECTXT(ctxt, elem);
3897 if (ns->prefix != NULL) {
3898 VERROR(ctxt->userData,
3899 "No declaration for attribute xmlns:%s of element %s\n",
3900 ns->prefix, elem->name);
3901 } else {
3902 VERROR(ctxt->userData,
3903 "No declaration for attribute xmlns of element %s\n",
3904 elem->name);
3906 return(0);
3909 val = xmlValidateAttributeValue(attrDecl->atype, value);
3910 if (val == 0) {
3911 VECTXT(ctxt, elem);
3912 if (ns->prefix != NULL) {
3913 VERROR(ctxt->userData,
3914 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
3915 ns->prefix, elem->name);
3916 } else {
3917 VERROR(ctxt->userData,
3918 "Syntax of value for attribute xmlns of %s is not valid\n",
3919 elem->name);
3921 ret = 0;
3924 /* Validity constraint: Fixed Attribute Default */
3925 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3926 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
3927 VECTXT(ctxt, elem);
3928 if (ns->prefix != NULL) {
3929 VERROR(ctxt->userData,
3930 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
3931 ns->prefix, elem->name, attrDecl->defaultValue);
3932 } else {
3933 VERROR(ctxt->userData,
3934 "Value for attribute xmlns of %s is different from default \"%s\"\n",
3935 elem->name, attrDecl->defaultValue);
3937 ret = 0;
3941 /* Validity Constraint: ID uniqueness */
3942 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
3943 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
3944 ret = 0;
3947 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3948 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
3949 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
3950 ret = 0;
3953 /* Validity Constraint: Notation Attributes */
3954 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
3955 xmlEnumerationPtr tree = attrDecl->tree;
3956 xmlNotationPtr nota;
3958 /* First check that the given NOTATION was declared */
3959 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3960 if (nota == NULL)
3961 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3963 if (nota == NULL) {
3964 VECTXT(ctxt, elem);
3965 if (ns->prefix != NULL) {
3966 VERROR(ctxt->userData,
3967 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
3968 value, ns->prefix, elem->name);
3969 } else {
3970 VERROR(ctxt->userData,
3971 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
3972 value, elem->name);
3974 ret = 0;
3977 /* Second, verify that it's among the list */
3978 while (tree != NULL) {
3979 if (xmlStrEqual(tree->name, value)) break;
3980 tree = tree->next;
3982 if (tree == NULL) {
3983 VECTXT(ctxt, elem);
3984 if (ns->prefix != NULL) {
3985 VERROR(ctxt->userData,
3986 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
3987 value, ns->prefix, elem->name);
3988 } else {
3989 VERROR(ctxt->userData,
3990 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
3991 value, elem->name);
3993 ret = 0;
3997 /* Validity Constraint: Enumeration */
3998 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
3999 xmlEnumerationPtr tree = attrDecl->tree;
4000 while (tree != NULL) {
4001 if (xmlStrEqual(tree->name, value)) break;
4002 tree = tree->next;
4004 if (tree == NULL) {
4005 VECTXT(ctxt, elem);
4006 if (ns->prefix != NULL) {
4007 VERROR(ctxt->userData,
4008 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4009 value, ns->prefix, elem->name);
4010 } else {
4011 VERROR(ctxt->userData,
4012 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4013 value, elem->name);
4015 ret = 0;
4019 /* Fixed Attribute Default */
4020 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4021 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4022 VECTXT(ctxt, elem);
4023 if (ns->prefix != NULL) {
4024 VERROR(ctxt->userData,
4025 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4026 ns->prefix, elem->name, attrDecl->defaultValue);
4027 } else {
4028 VERROR(ctxt->userData,
4029 "Value for attribute xmlns of %s must be \"%s\"\n",
4030 elem->name, attrDecl->defaultValue);
4032 ret = 0;
4035 /* Extra check for the attribute value */
4036 if (ns->prefix != NULL) {
4037 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4038 attrDecl->atype, value);
4039 } else {
4040 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4041 attrDecl->atype, value);
4044 return(ret);
4047 #ifndef LIBXML_REGEXP_ENABLED
4049 * xmlValidateSkipIgnorable:
4050 * @ctxt: the validation context
4051 * @child: the child list
4053 * Skip ignorable elements w.r.t. the validation process
4055 * returns the first element to consider for validation of the content model
4058 static xmlNodePtr
4059 xmlValidateSkipIgnorable(xmlNodePtr child) {
4060 while (child != NULL) {
4061 switch (child->type) {
4062 /* These things are ignored (skipped) during validation. */
4063 case XML_PI_NODE:
4064 case XML_COMMENT_NODE:
4065 case XML_XINCLUDE_START:
4066 case XML_XINCLUDE_END:
4067 child = child->next;
4068 break;
4069 case XML_TEXT_NODE:
4070 if (xmlIsBlankNode(child))
4071 child = child->next;
4072 else
4073 return(child);
4074 break;
4075 /* keep current node */
4076 default:
4077 return(child);
4080 return(child);
4084 * xmlValidateElementType:
4085 * @ctxt: the validation context
4087 * Try to validate the content model of an element internal function
4089 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4090 * reference is found and -3 if the validation succeeded but
4091 * the content model is not determinist.
4094 static int
4095 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4096 int ret = -1;
4097 int determinist = 1;
4099 NODE = xmlValidateSkipIgnorable(NODE);
4100 if ((NODE == NULL) && (CONT == NULL))
4101 return(1);
4102 if ((NODE == NULL) &&
4103 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4104 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4105 return(1);
4107 if (CONT == NULL) return(-1);
4108 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4109 return(-2);
4112 * We arrive here when more states need to be examined
4114 cont:
4117 * We just recovered from a rollback generated by a possible
4118 * epsilon transition, go directly to the analysis phase
4120 if (STATE == ROLLBACK_PARENT) {
4121 DEBUG_VALID_MSG("restored parent branch");
4122 DEBUG_VALID_STATE(NODE, CONT)
4123 ret = 1;
4124 goto analyze;
4127 DEBUG_VALID_STATE(NODE, CONT)
4129 * we may have to save a backup state here. This is the equivalent
4130 * of handling epsilon transition in NFAs.
4132 if ((CONT != NULL) &&
4133 ((CONT->parent == NULL) ||
4134 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4135 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4136 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4137 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4138 DEBUG_VALID_MSG("saving parent branch");
4139 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4140 return(0);
4145 * Check first if the content matches
4147 switch (CONT->type) {
4148 case XML_ELEMENT_CONTENT_PCDATA:
4149 if (NODE == NULL) {
4150 DEBUG_VALID_MSG("pcdata failed no node");
4151 ret = 0;
4152 break;
4154 if (NODE->type == XML_TEXT_NODE) {
4155 DEBUG_VALID_MSG("pcdata found, skip to next");
4157 * go to next element in the content model
4158 * skipping ignorable elems
4160 do {
4161 NODE = NODE->next;
4162 NODE = xmlValidateSkipIgnorable(NODE);
4163 if ((NODE != NULL) &&
4164 (NODE->type == XML_ENTITY_REF_NODE))
4165 return(-2);
4166 } while ((NODE != NULL) &&
4167 ((NODE->type != XML_ELEMENT_NODE) &&
4168 (NODE->type != XML_TEXT_NODE) &&
4169 (NODE->type != XML_CDATA_SECTION_NODE)));
4170 ret = 1;
4171 break;
4172 } else {
4173 DEBUG_VALID_MSG("pcdata failed");
4174 ret = 0;
4175 break;
4177 break;
4178 case XML_ELEMENT_CONTENT_ELEMENT:
4179 if (NODE == NULL) {
4180 DEBUG_VALID_MSG("element failed no node");
4181 ret = 0;
4182 break;
4184 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4185 (xmlStrEqual(NODE->name, CONT->name)));
4186 if (ret == 1) {
4187 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4188 ret = (CONT->prefix == NULL);
4189 } else if (CONT->prefix == NULL) {
4190 ret = 0;
4191 } else {
4192 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4195 if (ret == 1) {
4196 DEBUG_VALID_MSG("element found, skip to next");
4198 * go to next element in the content model
4199 * skipping ignorable elems
4201 do {
4202 NODE = NODE->next;
4203 NODE = xmlValidateSkipIgnorable(NODE);
4204 if ((NODE != NULL) &&
4205 (NODE->type == XML_ENTITY_REF_NODE))
4206 return(-2);
4207 } while ((NODE != NULL) &&
4208 ((NODE->type != XML_ELEMENT_NODE) &&
4209 (NODE->type != XML_TEXT_NODE) &&
4210 (NODE->type != XML_CDATA_SECTION_NODE)));
4211 } else {
4212 DEBUG_VALID_MSG("element failed");
4213 ret = 0;
4214 break;
4216 break;
4217 case XML_ELEMENT_CONTENT_OR:
4219 * Small optimization.
4221 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4222 if ((NODE == NULL) ||
4223 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4224 DEPTH++;
4225 CONT = CONT->c2;
4226 goto cont;
4228 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4229 ret = (CONT->c1->prefix == NULL);
4230 } else if (CONT->c1->prefix == NULL) {
4231 ret = 0;
4232 } else {
4233 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4235 if (ret == 0) {
4236 DEPTH++;
4237 CONT = CONT->c2;
4238 goto cont;
4243 * save the second branch 'or' branch
4245 DEBUG_VALID_MSG("saving 'or' branch");
4246 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4247 OCCURS, ROLLBACK_OR) < 0)
4248 return(-1);
4249 DEPTH++;
4250 CONT = CONT->c1;
4251 goto cont;
4252 case XML_ELEMENT_CONTENT_SEQ:
4254 * Small optimization.
4256 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4257 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4258 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4259 if ((NODE == NULL) ||
4260 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4261 DEPTH++;
4262 CONT = CONT->c2;
4263 goto cont;
4265 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4266 ret = (CONT->c1->prefix == NULL);
4267 } else if (CONT->c1->prefix == NULL) {
4268 ret = 0;
4269 } else {
4270 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4272 if (ret == 0) {
4273 DEPTH++;
4274 CONT = CONT->c2;
4275 goto cont;
4278 DEPTH++;
4279 CONT = CONT->c1;
4280 goto cont;
4284 * At this point handle going up in the tree
4286 if (ret == -1) {
4287 DEBUG_VALID_MSG("error found returning");
4288 return(ret);
4290 analyze:
4291 while (CONT != NULL) {
4293 * First do the analysis depending on the occurrence model at
4294 * this level.
4296 if (ret == 0) {
4297 switch (CONT->ocur) {
4298 xmlNodePtr cur;
4300 case XML_ELEMENT_CONTENT_ONCE:
4301 cur = ctxt->vstate->node;
4302 DEBUG_VALID_MSG("Once branch failed, rollback");
4303 if (vstateVPop(ctxt) < 0 ) {
4304 DEBUG_VALID_MSG("exhaustion, failed");
4305 return(0);
4307 if (cur != ctxt->vstate->node)
4308 determinist = -3;
4309 goto cont;
4310 case XML_ELEMENT_CONTENT_PLUS:
4311 if (OCCURRENCE == 0) {
4312 cur = ctxt->vstate->node;
4313 DEBUG_VALID_MSG("Plus branch failed, rollback");
4314 if (vstateVPop(ctxt) < 0 ) {
4315 DEBUG_VALID_MSG("exhaustion, failed");
4316 return(0);
4318 if (cur != ctxt->vstate->node)
4319 determinist = -3;
4320 goto cont;
4322 DEBUG_VALID_MSG("Plus branch found");
4323 ret = 1;
4324 break;
4325 case XML_ELEMENT_CONTENT_MULT:
4326 #ifdef DEBUG_VALID_ALGO
4327 if (OCCURRENCE == 0) {
4328 DEBUG_VALID_MSG("Mult branch failed");
4329 } else {
4330 DEBUG_VALID_MSG("Mult branch found");
4332 #endif
4333 ret = 1;
4334 break;
4335 case XML_ELEMENT_CONTENT_OPT:
4336 DEBUG_VALID_MSG("Option branch failed");
4337 ret = 1;
4338 break;
4340 } else {
4341 switch (CONT->ocur) {
4342 case XML_ELEMENT_CONTENT_OPT:
4343 DEBUG_VALID_MSG("Option branch succeeded");
4344 ret = 1;
4345 break;
4346 case XML_ELEMENT_CONTENT_ONCE:
4347 DEBUG_VALID_MSG("Once branch succeeded");
4348 ret = 1;
4349 break;
4350 case XML_ELEMENT_CONTENT_PLUS:
4351 if (STATE == ROLLBACK_PARENT) {
4352 DEBUG_VALID_MSG("Plus branch rollback");
4353 ret = 1;
4354 break;
4356 if (NODE == NULL) {
4357 DEBUG_VALID_MSG("Plus branch exhausted");
4358 ret = 1;
4359 break;
4361 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
4362 SET_OCCURRENCE;
4363 goto cont;
4364 case XML_ELEMENT_CONTENT_MULT:
4365 if (STATE == ROLLBACK_PARENT) {
4366 DEBUG_VALID_MSG("Mult branch rollback");
4367 ret = 1;
4368 break;
4370 if (NODE == NULL) {
4371 DEBUG_VALID_MSG("Mult branch exhausted");
4372 ret = 1;
4373 break;
4375 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
4376 /* SET_OCCURRENCE; */
4377 goto cont;
4380 STATE = 0;
4383 * Then act accordingly at the parent level
4385 RESET_OCCURRENCE;
4386 if (CONT->parent == NULL)
4387 break;
4389 switch (CONT->parent->type) {
4390 case XML_ELEMENT_CONTENT_PCDATA:
4391 DEBUG_VALID_MSG("Error: parent pcdata");
4392 return(-1);
4393 case XML_ELEMENT_CONTENT_ELEMENT:
4394 DEBUG_VALID_MSG("Error: parent element");
4395 return(-1);
4396 case XML_ELEMENT_CONTENT_OR:
4397 if (ret == 1) {
4398 DEBUG_VALID_MSG("Or succeeded");
4399 CONT = CONT->parent;
4400 DEPTH--;
4401 } else {
4402 DEBUG_VALID_MSG("Or failed");
4403 CONT = CONT->parent;
4404 DEPTH--;
4406 break;
4407 case XML_ELEMENT_CONTENT_SEQ:
4408 if (ret == 0) {
4409 DEBUG_VALID_MSG("Sequence failed");
4410 CONT = CONT->parent;
4411 DEPTH--;
4412 } else if (CONT == CONT->parent->c1) {
4413 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4414 CONT = CONT->parent->c2;
4415 goto cont;
4416 } else {
4417 DEBUG_VALID_MSG("Sequence succeeded");
4418 CONT = CONT->parent;
4419 DEPTH--;
4423 if (NODE != NULL) {
4424 xmlNodePtr cur;
4426 cur = ctxt->vstate->node;
4427 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4428 if (vstateVPop(ctxt) < 0 ) {
4429 DEBUG_VALID_MSG("exhaustion, failed");
4430 return(0);
4432 if (cur != ctxt->vstate->node)
4433 determinist = -3;
4434 goto cont;
4436 if (ret == 0) {
4437 xmlNodePtr cur;
4439 cur = ctxt->vstate->node;
4440 DEBUG_VALID_MSG("Failure, rollback");
4441 if (vstateVPop(ctxt) < 0 ) {
4442 DEBUG_VALID_MSG("exhaustion, failed");
4443 return(0);
4445 if (cur != ctxt->vstate->node)
4446 determinist = -3;
4447 goto cont;
4449 return(determinist);
4451 #endif
4454 * xmlSnprintfElements:
4455 * @buf: an output buffer
4456 * @size: the size of the buffer
4457 * @content: An element
4458 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4460 * This will dump the list of elements to the buffer
4461 * Intended just for the debug routine
4463 static void
4464 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
4465 xmlNodePtr cur;
4466 int len;
4468 if (node == NULL) return;
4469 if (glob) strcat(buf, "(");
4470 cur = node;
4471 while (cur != NULL) {
4472 len = strlen(buf);
4473 if (size - len < 50) {
4474 if ((size - len > 4) && (buf[len - 1] != '.'))
4475 strcat(buf, " ...");
4476 return;
4478 switch (cur->type) {
4479 case XML_ELEMENT_NODE:
4480 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4481 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
4482 if ((size - len > 4) && (buf[len - 1] != '.'))
4483 strcat(buf, " ...");
4484 return;
4486 strcat(buf, (char *) cur->ns->prefix);
4487 strcat(buf, ":");
4489 if (size - len < xmlStrlen(cur->name) + 10) {
4490 if ((size - len > 4) && (buf[len - 1] != '.'))
4491 strcat(buf, " ...");
4492 return;
4494 strcat(buf, (char *) cur->name);
4495 if (cur->next != NULL)
4496 strcat(buf, " ");
4497 break;
4498 case XML_TEXT_NODE:
4499 if (xmlIsBlankNode(cur))
4500 break;
4501 case XML_CDATA_SECTION_NODE:
4502 case XML_ENTITY_REF_NODE:
4503 strcat(buf, "CDATA");
4504 if (cur->next != NULL)
4505 strcat(buf, " ");
4506 break;
4507 case XML_ATTRIBUTE_NODE:
4508 case XML_DOCUMENT_NODE:
4509 #ifdef LIBXML_DOCB_ENABLED
4510 case XML_DOCB_DOCUMENT_NODE:
4511 #endif
4512 case XML_HTML_DOCUMENT_NODE:
4513 case XML_DOCUMENT_TYPE_NODE:
4514 case XML_DOCUMENT_FRAG_NODE:
4515 case XML_NOTATION_NODE:
4516 case XML_NAMESPACE_DECL:
4517 strcat(buf, "???");
4518 if (cur->next != NULL)
4519 strcat(buf, " ");
4520 break;
4521 case XML_ENTITY_NODE:
4522 case XML_PI_NODE:
4523 case XML_DTD_NODE:
4524 case XML_COMMENT_NODE:
4525 case XML_ELEMENT_DECL:
4526 case XML_ATTRIBUTE_DECL:
4527 case XML_ENTITY_DECL:
4528 case XML_XINCLUDE_START:
4529 case XML_XINCLUDE_END:
4530 break;
4532 cur = cur->next;
4534 if (glob) strcat(buf, ")");
4538 * xmlValidateElementContent:
4539 * @ctxt: the validation context
4540 * @child: the child list
4541 * @elemDecl: pointer to the element declaration
4542 * @warn: emit the error message
4543 * @parent: the parent element (for error reporting)
4545 * Try to validate the content model of an element
4547 * returns 1 if valid or 0 if not and -1 in case of error
4550 static int
4551 xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
4552 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
4553 int ret = 1;
4554 #ifndef LIBXML_REGEXP_ENABLED
4555 xmlNodePtr repl = NULL, last = NULL, tmp;
4556 #endif
4557 xmlNodePtr cur;
4558 xmlElementContentPtr cont;
4559 const xmlChar *name;
4561 if (elemDecl == NULL)
4562 return(-1);
4563 cont = elemDecl->content;
4564 name = elemDecl->name;
4566 #ifdef LIBXML_REGEXP_ENABLED
4567 /* Build the regexp associated to the content model */
4568 if (elemDecl->contModel == NULL)
4569 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4570 if (elemDecl->contModel == NULL) {
4571 ret = -1;
4572 } else {
4573 xmlRegExecCtxtPtr exec;
4575 ctxt->nodeMax = 0;
4576 ctxt->nodeNr = 0;
4577 ctxt->nodeTab = NULL;
4578 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4579 if (exec != NULL) {
4580 cur = child;
4581 while (cur != NULL) {
4582 switch (cur->type) {
4583 case XML_ENTITY_REF_NODE:
4585 * Push the current node to be able to roll back
4586 * and process within the entity
4588 if ((cur->children != NULL) &&
4589 (cur->children->children != NULL)) {
4590 nodeVPush(ctxt, cur);
4591 cur = cur->children->children;
4592 continue;
4594 break;
4595 case XML_TEXT_NODE:
4596 if (xmlIsBlankNode(cur))
4597 break;
4598 ret = 0;
4599 goto fail;
4600 case XML_CDATA_SECTION_NODE:
4601 TODO
4602 ret = 0;
4603 goto fail;
4604 case XML_ELEMENT_NODE:
4605 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4606 xmlChar *QName;
4607 int len;
4609 len = xmlStrlen(cur->name) +
4610 xmlStrlen(cur->ns->prefix) + 2;
4611 QName = xmlMalloc(len);
4612 if (QName == NULL) {
4613 ret = -1;
4614 goto fail;
4616 snprintf((char *) QName, len, "%s:%s",
4617 (char *)cur->ns->prefix,
4618 (char *)cur->name);
4619 ret = xmlRegExecPushString(exec, QName, NULL);
4620 xmlFree(QName);
4621 } else {
4622 ret = xmlRegExecPushString(exec, cur->name, NULL);
4624 break;
4625 default:
4626 break;
4629 * Switch to next element
4631 cur = cur->next;
4632 while (cur == NULL) {
4633 cur = nodeVPop(ctxt);
4634 if (cur == NULL)
4635 break;
4636 cur = cur->next;
4639 ret = xmlRegExecPushString(exec, NULL, NULL);
4640 fail:
4641 xmlRegFreeExecCtxt(exec);
4644 #else /* LIBXML_REGEXP_ENABLED */
4646 * Allocate the stack
4648 ctxt->vstateMax = 8;
4649 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
4650 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
4651 if (ctxt->vstateTab == NULL) {
4652 xmlGenericError(xmlGenericErrorContext,
4653 "malloc failed !n");
4654 return(-1);
4657 * The first entry in the stack is reserved to the current state
4659 ctxt->nodeMax = 0;
4660 ctxt->nodeNr = 0;
4661 ctxt->nodeTab = NULL;
4662 ctxt->vstate = &ctxt->vstateTab[0];
4663 ctxt->vstateNr = 1;
4664 CONT = cont;
4665 NODE = child;
4666 DEPTH = 0;
4667 OCCURS = 0;
4668 STATE = 0;
4669 ret = xmlValidateElementType(ctxt);
4670 if ((ret == -3) && (warn)) {
4671 VWARNING(ctxt->userData,
4672 "Content model for Element %s is ambiguous\n", name);
4673 } else if (ret == -2) {
4675 * An entities reference appeared at this level.
4676 * Buid a minimal representation of this node content
4677 * sufficient to run the validation process on it
4679 DEBUG_VALID_MSG("Found an entity reference, linearizing");
4680 cur = child;
4681 while (cur != NULL) {
4682 switch (cur->type) {
4683 case XML_ENTITY_REF_NODE:
4685 * Push the current node to be able to roll back
4686 * and process within the entity
4688 if ((cur->children != NULL) &&
4689 (cur->children->children != NULL)) {
4690 nodeVPush(ctxt, cur);
4691 cur = cur->children->children;
4692 continue;
4694 break;
4695 case XML_TEXT_NODE:
4696 if (xmlIsBlankNode(cur))
4697 break;
4698 /* no break on purpose */
4699 case XML_CDATA_SECTION_NODE:
4700 /* no break on purpose */
4701 case XML_ELEMENT_NODE:
4703 * Allocate a new node and minimally fills in
4704 * what's required
4706 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4707 if (tmp == NULL) {
4708 xmlGenericError(xmlGenericErrorContext,
4709 "xmlValidateElementContent : malloc failed\n");
4710 xmlFreeNodeList(repl);
4711 ret = -1;
4712 goto done;
4714 tmp->type = cur->type;
4715 tmp->name = cur->name;
4716 tmp->ns = cur->ns;
4717 tmp->next = NULL;
4718 tmp->content = NULL;
4719 if (repl == NULL)
4720 repl = last = tmp;
4721 else {
4722 last->next = tmp;
4723 last = tmp;
4725 if (cur->type == XML_CDATA_SECTION_NODE) {
4727 * E59 spaces in CDATA does not match the
4728 * nonterminal S
4730 tmp->content = xmlStrdup(BAD_CAST "CDATA");
4732 break;
4733 default:
4734 break;
4737 * Switch to next element
4739 cur = cur->next;
4740 while (cur == NULL) {
4741 cur = nodeVPop(ctxt);
4742 if (cur == NULL)
4743 break;
4744 cur = cur->next;
4749 * Relaunch the validation
4751 ctxt->vstate = &ctxt->vstateTab[0];
4752 ctxt->vstateNr = 1;
4753 CONT = cont;
4754 NODE = repl;
4755 DEPTH = 0;
4756 OCCURS = 0;
4757 STATE = 0;
4758 ret = xmlValidateElementType(ctxt);
4760 #endif /* LIBXML_REGEXP_ENABLED */
4761 if ((warn) && ((ret != 1) && (ret != -3))) {
4762 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
4763 char expr[5000];
4764 char list[5000];
4766 expr[0] = 0;
4767 xmlSnprintfElementContent(expr, 5000, cont, 1);
4768 list[0] = 0;
4769 #ifndef LIBXML_REGEXP_ENABLED
4770 if (repl != NULL)
4771 xmlSnprintfElements(list, 5000, repl, 1);
4772 else
4773 #endif /* LIBXML_REGEXP_ENABLED */
4774 xmlSnprintfElements(list, 5000, child, 1);
4776 if (name != NULL) {
4777 if (parent != NULL) VECTXT(ctxt, parent);
4778 VERROR(ctxt->userData,
4779 "Element %s content does not follow the DTD\nExpecting %s, got %s\n",
4780 name, expr, list);
4781 } else {
4782 if (parent != NULL) VECTXT(ctxt, parent);
4783 VERROR(ctxt->userData,
4784 "Element content does not follow the DTD\nExpecting %s, got %s\n",
4785 expr, list);
4787 } else {
4788 if (name != NULL) {
4789 if (parent != NULL) VECTXT(ctxt, parent);
4790 VERROR(ctxt->userData,
4791 "Element %s content does not follow the DTD\n",
4792 name);
4793 } else {
4794 if (parent != NULL) VECTXT(ctxt, parent);
4795 VERROR(ctxt->userData,
4796 "Element content does not follow the DTD\n");
4799 ret = 0;
4801 if (ret == -3)
4802 ret = 1;
4804 #ifndef LIBXML_REGEXP_ENABLED
4805 done:
4807 * Deallocate the copy if done, and free up the validation stack
4809 while (repl != NULL) {
4810 tmp = repl->next;
4811 xmlFree(repl);
4812 repl = tmp;
4814 ctxt->vstateMax = 0;
4815 if (ctxt->vstateTab != NULL) {
4816 xmlFree(ctxt->vstateTab);
4817 ctxt->vstateTab = NULL;
4819 #endif
4820 ctxt->nodeMax = 0;
4821 ctxt->nodeNr = 0;
4822 if (ctxt->nodeTab != NULL) {
4823 xmlFree(ctxt->nodeTab);
4824 ctxt->nodeTab = NULL;
4826 return(ret);
4831 * xmlValidateCdataElement:
4832 * @ctxt: the validation context
4833 * @doc: a document instance
4834 * @elem: an element instance
4836 * Check that an element follows #CDATA
4838 * returns 1 if valid or 0 otherwise
4840 static int
4841 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4842 xmlNodePtr elem) {
4843 int ret = 1;
4844 xmlNodePtr cur, child;
4846 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
4847 return(0);
4849 child = elem->children;
4851 cur = child;
4852 while (cur != NULL) {
4853 switch (cur->type) {
4854 case XML_ENTITY_REF_NODE:
4856 * Push the current node to be able to roll back
4857 * and process within the entity
4859 if ((cur->children != NULL) &&
4860 (cur->children->children != NULL)) {
4861 nodeVPush(ctxt, cur);
4862 cur = cur->children->children;
4863 continue;
4865 break;
4866 case XML_COMMENT_NODE:
4867 case XML_PI_NODE:
4868 case XML_TEXT_NODE:
4869 case XML_CDATA_SECTION_NODE:
4870 break;
4871 default:
4872 ret = 0;
4873 goto done;
4876 * Switch to next element
4878 cur = cur->next;
4879 while (cur == NULL) {
4880 cur = nodeVPop(ctxt);
4881 if (cur == NULL)
4882 break;
4883 cur = cur->next;
4886 done:
4887 ctxt->nodeMax = 0;
4888 ctxt->nodeNr = 0;
4889 if (ctxt->nodeTab != NULL) {
4890 xmlFree(ctxt->nodeTab);
4891 ctxt->nodeTab = NULL;
4893 return(ret);
4897 * xmlValidateOneElement:
4898 * @ctxt: the validation context
4899 * @doc: a document instance
4900 * @elem: an element instance
4902 * Try to validate a single element and it's attributes,
4903 * basically it does the following checks as described by the
4904 * XML-1.0 recommendation:
4905 * - [ VC: Element Valid ]
4906 * - [ VC: Required Attribute ]
4907 * Then call xmlValidateOneAttribute() for each attribute present.
4909 * The ID/IDREF checkings are done separately
4911 * returns 1 if valid or 0 otherwise
4915 xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4916 xmlNodePtr elem) {
4917 xmlElementPtr elemDecl = NULL;
4918 xmlElementContentPtr cont;
4919 xmlAttributePtr attr;
4920 xmlNodePtr child;
4921 int ret = 1, tmp;
4922 const xmlChar *name;
4923 const xmlChar *prefix = NULL;
4924 int extsubset = 0;
4926 CHECK_DTD;
4928 if (elem == NULL) return(0);
4929 switch (elem->type) {
4930 case XML_ATTRIBUTE_NODE:
4931 VECTXT(ctxt, elem);
4932 VERROR(ctxt->userData,
4933 "Attribute element not expected here\n");
4934 return(0);
4935 case XML_TEXT_NODE:
4936 if (elem->children != NULL) {
4937 VECTXT(ctxt, elem);
4938 VERROR(ctxt->userData, "Text element has childs !\n");
4939 return(0);
4941 if (elem->properties != NULL) {
4942 VECTXT(ctxt, elem);
4943 VERROR(ctxt->userData, "Text element has attributes !\n");
4944 return(0);
4946 if (elem->ns != NULL) {
4947 VECTXT(ctxt, elem);
4948 VERROR(ctxt->userData, "Text element has namespace !\n");
4949 return(0);
4951 if (elem->nsDef != NULL) {
4952 VECTXT(ctxt, elem);
4953 VERROR(ctxt->userData,
4954 "Text element carries namespace definitions !\n");
4955 return(0);
4957 if (elem->content == NULL) {
4958 VECTXT(ctxt, elem);
4959 VERROR(ctxt->userData,
4960 "Text element has no content !\n");
4961 return(0);
4963 return(1);
4964 case XML_XINCLUDE_START:
4965 case XML_XINCLUDE_END:
4966 return(1);
4967 case XML_CDATA_SECTION_NODE:
4968 case XML_ENTITY_REF_NODE:
4969 case XML_PI_NODE:
4970 case XML_COMMENT_NODE:
4971 return(1);
4972 case XML_ENTITY_NODE:
4973 VECTXT(ctxt, elem);
4974 VERROR(ctxt->userData,
4975 "Entity element not expected here\n");
4976 return(0);
4977 case XML_NOTATION_NODE:
4978 VECTXT(ctxt, elem);
4979 VERROR(ctxt->userData,
4980 "Notation element not expected here\n");
4981 return(0);
4982 case XML_DOCUMENT_NODE:
4983 case XML_DOCUMENT_TYPE_NODE:
4984 case XML_DOCUMENT_FRAG_NODE:
4985 VECTXT(ctxt, elem);
4986 VERROR(ctxt->userData,
4987 "Document element not expected here\n");
4988 return(0);
4989 case XML_HTML_DOCUMENT_NODE:
4990 VECTXT(ctxt, elem);
4991 VERROR(ctxt->userData,
4992 "\n");
4993 return(0);
4994 case XML_ELEMENT_NODE:
4995 break;
4996 default:
4997 VECTXT(ctxt, elem);
4998 VERROR(ctxt->userData,
4999 "unknown element type %d\n", elem->type);
5000 return(0);
5002 if (elem->name == NULL) return(0);
5005 * Fetch the declaration for the qualified name
5007 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5008 prefix = elem->ns->prefix;
5010 if (prefix != NULL) {
5011 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5012 elem->name, prefix);
5013 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5014 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5015 elem->name, prefix);
5016 if (elemDecl != NULL)
5017 extsubset = 1;
5022 * Fetch the declaration for the non qualified name
5023 * This is "non-strict" validation should be done on the
5024 * full QName but in that case being flexible makes sense.
5026 if (elemDecl == NULL) {
5027 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5028 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5029 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5030 if (elemDecl != NULL)
5031 extsubset = 1;
5034 if (elemDecl == NULL) {
5035 VECTXT(ctxt, elem);
5036 VERROR(ctxt->userData, "No declaration for element %s\n",
5037 elem->name);
5038 return(0);
5041 /* Check that the element content matches the definition */
5042 switch (elemDecl->etype) {
5043 case XML_ELEMENT_TYPE_UNDEFINED:
5044 VECTXT(ctxt, elem);
5045 VERROR(ctxt->userData, "No declaration for element %s\n",
5046 elem->name);
5047 return(0);
5048 case XML_ELEMENT_TYPE_EMPTY:
5049 if (elem->children != NULL) {
5050 VECTXT(ctxt, elem);
5051 VERROR(ctxt->userData,
5052 "Element %s was declared EMPTY this one has content\n",
5053 elem->name);
5054 ret = 0;
5056 break;
5057 case XML_ELEMENT_TYPE_ANY:
5058 /* I don't think anything is required then */
5059 break;
5060 case XML_ELEMENT_TYPE_MIXED:
5062 /* simple case of declared as #PCDATA */
5063 if ((elemDecl->content != NULL) &&
5064 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5065 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5066 if (!ret) {
5067 VECTXT(ctxt, elem);
5068 VERROR(ctxt->userData,
5069 "Element %s was declared #PCDATA but contains non text nodes\n",
5070 elem->name);
5072 break;
5074 child = elem->children;
5075 /* Hum, this start to get messy */
5076 while (child != NULL) {
5077 if (child->type == XML_ELEMENT_NODE) {
5078 name = child->name;
5079 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
5080 xmlChar qname[500];
5081 snprintf((char *) qname, sizeof(qname), "%s:%s",
5082 child->ns->prefix, child->name);
5083 qname[sizeof(qname) - 1] = 0;
5084 cont = elemDecl->content;
5085 while (cont != NULL) {
5086 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5087 if (xmlStrEqual(cont->name, qname)) break;
5088 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5089 (cont->c1 != NULL) &&
5090 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5091 if (xmlStrEqual(cont->c1->name, qname)) break;
5092 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5093 (cont->c1 == NULL) ||
5094 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5095 /* Internal error !!! */
5096 xmlGenericError(xmlGenericErrorContext,
5097 "Internal: MIXED struct bad\n");
5098 break;
5100 cont = cont->c2;
5102 if (cont != NULL)
5103 goto child_ok;
5105 cont = elemDecl->content;
5106 while (cont != NULL) {
5107 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5108 if (xmlStrEqual(cont->name, name)) break;
5109 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5110 (cont->c1 != NULL) &&
5111 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5112 if (xmlStrEqual(cont->c1->name, name)) break;
5113 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5114 (cont->c1 == NULL) ||
5115 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
5116 /* Internal error !!! */
5117 xmlGenericError(xmlGenericErrorContext,
5118 "Internal: MIXED struct bad\n");
5119 break;
5121 cont = cont->c2;
5123 if (cont == NULL) {
5124 VECTXT(ctxt, elem);
5125 VERROR(ctxt->userData,
5126 "Element %s is not declared in %s list of possible children\n",
5127 name, elem->name);
5128 ret = 0;
5131 child_ok:
5132 child = child->next;
5134 break;
5135 case XML_ELEMENT_TYPE_ELEMENT:
5136 if ((doc->standalone == 1) && (extsubset == 1)) {
5138 * VC: Standalone Document Declaration
5139 * - element types with element content, if white space
5140 * occurs directly within any instance of those types.
5142 child = elem->children;
5143 while (child != NULL) {
5144 if (child->type == XML_TEXT_NODE) {
5145 const xmlChar *content = child->content;
5147 while (IS_BLANK(*content))
5148 content++;
5149 if (*content == 0) {
5150 VECTXT(ctxt, elem);
5151 VERROR(ctxt->userData,
5152 "standalone: %s declared in the external subset contains white spaces nodes\n",
5153 elem->name);
5154 ret = 0;
5155 break;
5158 child =child->next;
5161 child = elem->children;
5162 cont = elemDecl->content;
5163 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
5164 if (tmp <= 0)
5165 ret = tmp;
5166 break;
5169 /* [ VC: Required Attribute ] */
5170 attr = elemDecl->attributes;
5171 while (attr != NULL) {
5172 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
5173 int qualified = -1;
5175 if ((attr->prefix == NULL) &&
5176 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5177 xmlNsPtr ns;
5179 ns = elem->nsDef;
5180 while (ns != NULL) {
5181 if (ns->prefix == NULL)
5182 goto found;
5183 ns = ns->next;
5185 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5186 xmlNsPtr ns;
5188 ns = elem->nsDef;
5189 while (ns != NULL) {
5190 if (xmlStrEqual(attr->name, ns->prefix))
5191 goto found;
5192 ns = ns->next;
5194 } else {
5195 xmlAttrPtr attrib;
5197 attrib = elem->properties;
5198 while (attrib != NULL) {
5199 if (xmlStrEqual(attrib->name, attr->name)) {
5200 if (attr->prefix != NULL) {
5201 xmlNsPtr nameSpace = attrib->ns;
5203 if (nameSpace == NULL)
5204 nameSpace = elem->ns;
5206 * qualified names handling is problematic, having a
5207 * different prefix should be possible but DTDs don't
5208 * allow to define the URI instead of the prefix :-(
5210 if (nameSpace == NULL) {
5211 if (qualified < 0)
5212 qualified = 0;
5213 } else if (!xmlStrEqual(nameSpace->prefix,
5214 attr->prefix)) {
5215 if (qualified < 1)
5216 qualified = 1;
5217 } else
5218 goto found;
5219 } else {
5221 * We should allow applications to define namespaces
5222 * for their application even if the DTD doesn't
5223 * carry one, otherwise, basically we would always
5224 * break.
5226 goto found;
5229 attrib = attrib->next;
5232 if (qualified == -1) {
5233 if (attr->prefix == NULL) {
5234 VECTXT(ctxt, elem);
5235 VERROR(ctxt->userData,
5236 "Element %s does not carry attribute %s\n",
5237 elem->name, attr->name);
5238 ret = 0;
5239 } else {
5240 VECTXT(ctxt, elem);
5241 VERROR(ctxt->userData,
5242 "Element %s does not carry attribute %s:%s\n",
5243 elem->name, attr->prefix,attr->name);
5244 ret = 0;
5246 } else if (qualified == 0) {
5247 VWARNING(ctxt->userData,
5248 "Element %s required attribute %s:%s has no prefix\n",
5249 elem->name, attr->prefix,attr->name);
5250 } else if (qualified == 1) {
5251 VWARNING(ctxt->userData,
5252 "Element %s required attribute %s:%s has different prefix\n",
5253 elem->name, attr->prefix,attr->name);
5255 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5257 * Special tests checking #FIXED namespace declarations
5258 * have the right value since this is not done as an
5259 * attribute checking
5261 if ((attr->prefix == NULL) &&
5262 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5263 xmlNsPtr ns;
5265 ns = elem->nsDef;
5266 while (ns != NULL) {
5267 if (ns->prefix == NULL) {
5268 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
5269 VECTXT(ctxt, elem);
5270 VERROR(ctxt->userData,
5271 "Element %s namespace name for default namespace does not match the DTD\n",
5272 elem->name);
5273 ret = 0;
5275 goto found;
5277 ns = ns->next;
5279 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5280 xmlNsPtr ns;
5282 ns = elem->nsDef;
5283 while (ns != NULL) {
5284 if (xmlStrEqual(attr->name, ns->prefix)) {
5285 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
5286 VECTXT(ctxt, elem);
5287 VERROR(ctxt->userData,
5288 "Element %s namespace name for %s does not match the DTD\n",
5289 elem->name, ns->prefix);
5290 ret = 0;
5292 goto found;
5294 ns = ns->next;
5298 found:
5299 attr = attr->nexth;
5301 return(ret);
5305 * xmlValidateRoot:
5306 * @ctxt: the validation context
5307 * @doc: a document instance
5309 * Try to validate a the root element
5310 * basically it does the following check as described by the
5311 * XML-1.0 recommendation:
5312 * - [ VC: Root Element Type ]
5313 * it doesn't try to recurse or apply other check to the element
5315 * returns 1 if valid or 0 otherwise
5319 xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5320 xmlNodePtr root;
5321 if (doc == NULL) return(0);
5323 root = xmlDocGetRootElement(doc);
5324 if ((root == NULL) || (root->name == NULL)) {
5325 VERROR(ctxt->userData, "Not valid: no root element\n");
5326 return(0);
5330 * When doing post validation against a separate DTD, those may
5331 * no internal subset has been generated
5333 if ((doc->intSubset != NULL) &&
5334 (doc->intSubset->name != NULL)) {
5336 * Check first the document root against the NQName
5338 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
5339 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
5340 xmlChar qname[500];
5341 snprintf((char *) qname, sizeof(qname), "%s:%s",
5342 root->ns->prefix, root->name);
5343 qname[sizeof(qname) - 1] = 0;
5344 if (xmlStrEqual(doc->intSubset->name, qname))
5345 goto name_ok;
5347 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
5348 (xmlStrEqual(root->name, BAD_CAST "html")))
5349 goto name_ok;
5350 VECTXT(ctxt, root);
5351 VERROR(ctxt->userData,
5352 "Not valid: root and DTD name do not match '%s' and '%s'\n",
5353 root->name, doc->intSubset->name);
5354 return(0);
5358 name_ok:
5359 return(1);
5364 * xmlValidateElement:
5365 * @ctxt: the validation context
5366 * @doc: a document instance
5367 * @elem: an element instance
5369 * Try to validate the subtree under an element
5371 * returns 1 if valid or 0 otherwise
5375 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
5376 xmlNodePtr child;
5377 xmlAttrPtr attr;
5378 xmlChar *value;
5379 int ret = 1;
5381 if (elem == NULL) return(0);
5384 * XInclude elements were added after parsing in the infoset,
5385 * they don't really mean anything validation wise.
5387 if ((elem->type == XML_XINCLUDE_START) ||
5388 (elem->type == XML_XINCLUDE_END))
5389 return(1);
5391 CHECK_DTD;
5394 * Entities references have to be handled separately
5396 if (elem->type == XML_ENTITY_REF_NODE) {
5397 return(1);
5400 ret &= xmlValidateOneElement(ctxt, doc, elem);
5401 attr = elem->properties;
5402 while(attr != NULL) {
5403 value = xmlNodeListGetString(doc, attr->children, 0);
5404 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
5405 if (value != NULL)
5406 xmlFree(value);
5407 attr= attr->next;
5409 child = elem->children;
5410 while (child != NULL) {
5411 ret &= xmlValidateElement(ctxt, doc, child);
5412 child = child->next;
5415 return(ret);
5419 * xmlValidateRef:
5420 * @ref: A reference to be validated
5421 * @ctxt: Validation context
5422 * @name: Name of ID we are searching for
5425 static void
5426 xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
5427 const xmlChar *name) {
5428 xmlAttrPtr id;
5429 xmlAttrPtr attr;
5431 if (ref == NULL)
5432 return;
5433 attr = ref->attr;
5434 if (attr == NULL)
5435 return;
5436 if (attr->atype == XML_ATTRIBUTE_IDREF) {
5437 id = xmlGetID(ctxt->doc, name);
5438 if (id == NULL) {
5439 VECTXT(ctxt, attr->parent);
5440 VERROR(ctxt->userData,
5441 "IDREF attribute %s references an unknown ID \"%s\"\n",
5442 attr->name, name);
5443 ctxt->valid = 0;
5445 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
5446 xmlChar *dup, *str = NULL, *cur, save;
5448 dup = xmlStrdup(name);
5449 if (dup == NULL) {
5450 ctxt->valid = 0;
5451 return;
5453 cur = dup;
5454 while (*cur != 0) {
5455 str = cur;
5456 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5457 save = *cur;
5458 *cur = 0;
5459 id = xmlGetID(ctxt->doc, str);
5460 if (id == NULL) {
5461 VECTXT(ctxt, attr->parent);
5462 VERROR(ctxt->userData,
5463 "IDREFS attribute %s references an unknown ID \"%s\"\n",
5464 attr->name, str);
5465 ctxt->valid = 0;
5467 if (save == 0)
5468 break;
5469 *cur = save;
5470 while (IS_BLANK(*cur)) cur++;
5472 xmlFree(dup);
5477 * xmlWalkValidateList:
5478 * @data: Contents of current link
5479 * @user: Value supplied by the user
5481 * Returns 0 to abort the walk or 1 to continue
5483 static int
5484 xmlWalkValidateList(const void *data, const void *user)
5486 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
5487 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
5488 return 1;
5492 * xmlValidateCheckRefCallback:
5493 * @ref_list: List of references
5494 * @ctxt: Validation context
5495 * @name: Name of ID we are searching for
5498 static void
5499 xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
5500 const xmlChar *name) {
5501 xmlValidateMemo memo;
5503 if (ref_list == NULL)
5504 return;
5505 memo.ctxt = ctxt;
5506 memo.name = name;
5508 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
5513 * xmlValidateDocumentFinal:
5514 * @ctxt: the validation context
5515 * @doc: a document instance
5517 * Does the final step for the document validation once all the
5518 * incremental validation steps have been completed
5520 * basically it does the following checks described by the XML Rec
5523 * returns 1 if valid or 0 otherwise
5527 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5528 xmlRefTablePtr table;
5530 if (doc == NULL) {
5531 xmlGenericError(xmlGenericErrorContext,
5532 "xmlValidateDocumentFinal: doc == NULL\n");
5533 return(0);
5537 * Check all the NOTATION/NOTATIONS attributes
5540 * Check all the ENTITY/ENTITIES attributes definition for validity
5543 * Check all the IDREF/IDREFS attributes definition for validity
5545 table = (xmlRefTablePtr) doc->refs;
5546 ctxt->doc = doc;
5547 ctxt->valid = 1;
5548 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
5549 return(ctxt->valid);
5553 * xmlValidateDtd:
5554 * @ctxt: the validation context
5555 * @doc: a document instance
5556 * @dtd: a dtd instance
5558 * Try to validate the document against the dtd instance
5560 * basically it does check all the definitions in the DtD.
5562 * returns 1 if valid or 0 otherwise
5566 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
5567 int ret;
5568 xmlDtdPtr oldExt;
5569 xmlNodePtr root;
5571 if (dtd == NULL) return(0);
5572 if (doc == NULL) return(0);
5573 oldExt = doc->extSubset;
5574 doc->extSubset = dtd;
5575 ret = xmlValidateRoot(ctxt, doc);
5576 if (ret == 0) {
5577 doc->extSubset = oldExt;
5578 return(ret);
5580 if (doc->ids != NULL) {
5581 xmlFreeIDTable(doc->ids);
5582 doc->ids = NULL;
5584 if (doc->refs != NULL) {
5585 xmlFreeRefTable(doc->refs);
5586 doc->refs = NULL;
5588 root = xmlDocGetRootElement(doc);
5589 ret = xmlValidateElement(ctxt, doc, root);
5590 ret &= xmlValidateDocumentFinal(ctxt, doc);
5591 doc->extSubset = oldExt;
5592 return(ret);
5595 static void
5596 xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
5597 const xmlChar *name ATTRIBUTE_UNUSED) {
5598 if (cur == NULL)
5599 return;
5600 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
5601 xmlChar *notation = cur->content;
5603 if (notation != NULL) {
5604 int ret;
5606 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
5607 if (ret != 1) {
5608 ctxt->valid = 0;
5614 static void
5615 xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
5616 const xmlChar *name ATTRIBUTE_UNUSED) {
5617 int ret;
5618 xmlDocPtr doc;
5619 xmlElementPtr elem;
5621 if (cur == NULL)
5622 return;
5623 switch (cur->atype) {
5624 case XML_ATTRIBUTE_CDATA:
5625 case XML_ATTRIBUTE_ID:
5626 case XML_ATTRIBUTE_IDREF :
5627 case XML_ATTRIBUTE_IDREFS:
5628 case XML_ATTRIBUTE_NMTOKEN:
5629 case XML_ATTRIBUTE_NMTOKENS:
5630 case XML_ATTRIBUTE_ENUMERATION:
5631 break;
5632 case XML_ATTRIBUTE_ENTITY:
5633 case XML_ATTRIBUTE_ENTITIES:
5634 case XML_ATTRIBUTE_NOTATION:
5635 if (cur->defaultValue != NULL) {
5637 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
5638 cur->atype, cur->defaultValue);
5639 if ((ret == 0) && (ctxt->valid == 1))
5640 ctxt->valid = 0;
5642 if (cur->tree != NULL) {
5643 xmlEnumerationPtr tree = cur->tree;
5644 while (tree != NULL) {
5645 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
5646 cur->name, cur->atype, tree->name);
5647 if ((ret == 0) && (ctxt->valid == 1))
5648 ctxt->valid = 0;
5649 tree = tree->next;
5653 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
5654 doc = cur->doc;
5655 if ((doc == NULL) || (cur->elem == NULL)) {
5656 VERROR(ctxt->userData,
5657 "xmlValidateAttributeCallback(%s): internal error\n",
5658 cur->name);
5659 return;
5661 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
5662 if (elem == NULL)
5663 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
5664 if (elem == NULL) {
5665 VERROR(ctxt->userData,
5666 "attribute %s: could not find decl for element %s\n",
5667 cur->name, cur->elem);
5668 return;
5670 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
5671 VERROR(ctxt->userData,
5672 "NOTATION attribute %s declared for EMPTY element %s\n",
5673 cur->name, cur->elem);
5674 ctxt->valid = 0;
5680 * xmlValidateDtdFinal:
5681 * @ctxt: the validation context
5682 * @doc: a document instance
5684 * Does the final step for the dtds validation once all the
5685 * subsets have been parsed
5687 * basically it does the following checks described by the XML Rec
5688 * - check that ENTITY and ENTITIES type attributes default or
5689 * possible values matches one of the defined entities.
5690 * - check that NOTATION type attributes default or
5691 * possible values matches one of the defined notations.
5693 * returns 1 if valid or 0 if invalid and -1 if not well-formed
5697 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5698 xmlDtdPtr dtd;
5699 xmlAttributeTablePtr table;
5700 xmlEntitiesTablePtr entities;
5702 if (doc == NULL) return(0);
5703 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
5704 return(0);
5705 ctxt->doc = doc;
5706 ctxt->valid = 1;
5707 dtd = doc->intSubset;
5708 if ((dtd != NULL) && (dtd->attributes != NULL)) {
5709 table = (xmlAttributeTablePtr) dtd->attributes;
5710 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
5712 if ((dtd != NULL) && (dtd->entities != NULL)) {
5713 entities = (xmlEntitiesTablePtr) dtd->entities;
5714 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
5715 ctxt);
5717 dtd = doc->extSubset;
5718 if ((dtd != NULL) && (dtd->attributes != NULL)) {
5719 table = (xmlAttributeTablePtr) dtd->attributes;
5720 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
5722 if ((dtd != NULL) && (dtd->entities != NULL)) {
5723 entities = (xmlEntitiesTablePtr) dtd->entities;
5724 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
5725 ctxt);
5727 return(ctxt->valid);
5731 * xmlValidateDocument:
5732 * @ctxt: the validation context
5733 * @doc: a document instance
5735 * Try to validate the document instance
5737 * basically it does the all the checks described by the XML Rec
5738 * i.e. validates the internal and external subset (if present)
5739 * and validate the document tree.
5741 * returns 1 if valid or 0 otherwise
5745 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5746 int ret;
5747 xmlNodePtr root;
5749 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
5750 VERROR(ctxt->userData, "no DTD found!\n" );
5751 return(0);
5753 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
5754 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
5755 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
5756 doc->intSubset->SystemID);
5757 if (doc->extSubset == NULL) {
5758 if (doc->intSubset->SystemID != NULL) {
5759 VERROR(ctxt->userData,
5760 "Could not load the external subset \"%s\"\n",
5761 doc->intSubset->SystemID);
5762 } else {
5763 VERROR(ctxt->userData,
5764 "Could not load the external subset \"%s\"\n",
5765 doc->intSubset->ExternalID);
5767 return(0);
5771 if (doc->ids != NULL) {
5772 xmlFreeIDTable(doc->ids);
5773 doc->ids = NULL;
5775 if (doc->refs != NULL) {
5776 xmlFreeRefTable(doc->refs);
5777 doc->refs = NULL;
5779 ret = xmlValidateDtdFinal(ctxt, doc);
5780 if (!xmlValidateRoot(ctxt, doc)) return(0);
5782 root = xmlDocGetRootElement(doc);
5783 ret &= xmlValidateElement(ctxt, doc, root);
5784 ret &= xmlValidateDocumentFinal(ctxt, doc);
5785 return(ret);
5789 /************************************************************************
5791 * Routines for dynamic validation editing *
5793 ************************************************************************/
5796 * xmlValidGetPotentialChildren:
5797 * @ctree: an element content tree
5798 * @list: an array to store the list of child names
5799 * @len: a pointer to the number of element in the list
5800 * @max: the size of the array
5802 * Build/extend a list of potential children allowed by the content tree
5804 * returns the number of element in the list, or -1 in case of error.
5808 xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
5809 int *len, int max) {
5810 int i;
5812 if ((ctree == NULL) || (list == NULL) || (len == NULL))
5813 return(-1);
5814 if (*len >= max) return(*len);
5816 switch (ctree->type) {
5817 case XML_ELEMENT_CONTENT_PCDATA:
5818 for (i = 0; i < *len;i++)
5819 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
5820 list[(*len)++] = BAD_CAST "#PCDATA";
5821 break;
5822 case XML_ELEMENT_CONTENT_ELEMENT:
5823 for (i = 0; i < *len;i++)
5824 if (xmlStrEqual(ctree->name, list[i])) return(*len);
5825 list[(*len)++] = ctree->name;
5826 break;
5827 case XML_ELEMENT_CONTENT_SEQ:
5828 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
5829 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
5830 break;
5831 case XML_ELEMENT_CONTENT_OR:
5832 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
5833 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
5834 break;
5837 return(*len);
5841 * xmlValidGetValidElements:
5842 * @prev: an element to insert after
5843 * @next: an element to insert next
5844 * @list: an array to store the list of child names
5845 * @max: the size of the array
5847 * This function returns the list of authorized children to insert
5848 * within an existing tree while respecting the validity constraints
5849 * forced by the Dtd. The insertion point is defined using @prev and
5850 * @next in the following ways:
5851 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
5852 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
5853 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
5854 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
5855 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
5857 * pointers to the element names are inserted at the beginning of the array
5858 * and do not need to be freed.
5860 * returns the number of element in the list, or -1 in case of error. If
5861 * the function returns the value @max the caller is invited to grow the
5862 * receiving array and retry.
5866 xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
5867 int max) {
5868 xmlValidCtxt vctxt;
5869 int nb_valid_elements = 0;
5870 const xmlChar *elements[256];
5871 int nb_elements = 0, i;
5872 const xmlChar *name;
5874 xmlNode *ref_node;
5875 xmlNode *parent;
5876 xmlNode *test_node;
5878 xmlNode *prev_next;
5879 xmlNode *next_prev;
5880 xmlNode *parent_childs;
5881 xmlNode *parent_last;
5883 xmlElement *element_desc;
5885 memset(&vctxt, 0, sizeof (xmlValidCtxt));
5887 if (prev == NULL && next == NULL)
5888 return(-1);
5890 if (list == NULL) return(-1);
5891 if (max <= 0) return(-1);
5893 nb_valid_elements = 0;
5894 ref_node = prev ? prev : next;
5895 parent = ref_node->parent;
5898 * Retrieves the parent element declaration
5900 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
5901 parent->name);
5902 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
5903 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
5904 parent->name);
5905 if (element_desc == NULL) return(-1);
5908 * Do a backup of the current tree structure
5910 prev_next = prev ? prev->next : NULL;
5911 next_prev = next ? next->prev : NULL;
5912 parent_childs = parent->children;
5913 parent_last = parent->last;
5916 * Creates a dummy node and insert it into the tree
5918 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
5919 test_node->doc = ref_node->doc;
5920 test_node->parent = parent;
5921 test_node->prev = prev;
5922 test_node->next = next;
5923 name = test_node->name;
5925 if (prev) prev->next = test_node;
5926 else parent->children = test_node;
5928 if (next) next->prev = test_node;
5929 else parent->last = test_node;
5932 * Insert each potential child node and check if the parent is
5933 * still valid
5935 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
5936 elements, &nb_elements, 256);
5938 for (i = 0;i < nb_elements;i++) {
5939 test_node->name = elements[i];
5940 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
5941 int j;
5943 for (j = 0; j < nb_valid_elements;j++)
5944 if (xmlStrEqual(elements[i], list[j])) break;
5945 list[nb_valid_elements++] = elements[i];
5946 if (nb_valid_elements >= max) break;
5951 * Restore the tree structure
5953 if (prev) prev->next = prev_next;
5954 if (next) next->prev = next_prev;
5955 parent->children = parent_childs;
5956 parent->last = parent_last;
5959 * Free up the dummy node
5961 test_node->name = name;
5962 xmlFreeNode(test_node);
5964 return(nb_valid_elements);