2 * valid.c : part of the code use to do the DTD handling and the validity
5 * See Copyright for the status of this software.
19 #include <libxml/xmlmemory.h>
20 #include <libxml/hash.h>
21 #include <libxml/uri.h>
22 #include <libxml/valid.h>
23 #include <libxml/parser.h>
24 #include <libxml/parserInternals.h>
25 #include <libxml/xmlerror.h>
26 #include <libxml/list.h>
27 #include <libxml/globals.h>
29 static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
31 /* #define DEBUG_VALID_ALGO */
32 /* #define DEBUG_REGEXP_ALGO */
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
39 /************************************************************************
41 * Error handling routines *
43 ************************************************************************/
47 * @ctxt: an XML validation parser context
48 * @extra: extra informations
50 * Handle an out of memory error
53 xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
55 xmlGenericErrorFunc channel = NULL;
56 xmlParserCtxtPtr pctxt = NULL;
60 channel = ctxt->error;
61 data = ctxt->userData;
62 /* Use the special values to detect if it is part of a parsing
64 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
65 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
66 long delta = (char *) ctxt - (char *) ctxt->userData;
67 if ((delta > 0) && (delta < 250))
68 pctxt = ctxt->userData;
72 __xmlRaiseError(NULL, channel, data,
73 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
74 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
75 "Memory allocation failed : %s\n", extra);
77 __xmlRaiseError(NULL, channel, data,
78 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
79 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
80 "Memory allocation failed\n");
85 * @ctxt: an XML validation parser context
86 * @error: the error number
87 * @extra: extra informations
89 * Handle a validation error
92 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
93 const char *msg, const char *extra)
95 xmlGenericErrorFunc channel = NULL;
96 xmlParserCtxtPtr pctxt = NULL;
100 channel = ctxt->error;
101 data = ctxt->userData;
102 /* Use the special values to detect if it is part of a parsing
104 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
105 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
106 long delta = (char *) ctxt - (char *) ctxt->userData;
107 if ((delta > 0) && (delta < 250))
108 pctxt = ctxt->userData;
112 __xmlRaiseError(NULL, channel, data,
113 pctxt, NULL, XML_FROM_VALID, error,
114 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
117 __xmlRaiseError(NULL, channel, data,
118 pctxt, NULL, XML_FROM_VALID, error,
119 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
123 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
126 * @ctxt: an XML validation parser context
127 * @node: the node raising the error
128 * @error: the error number
129 * @str1: extra informations
130 * @str2: extra informations
131 * @str3: extra informations
133 * Handle a validation error, provide contextual informations
136 xmlErrValidNode(xmlValidCtxtPtr ctxt,
137 xmlNodePtr node, xmlParserErrors error,
138 const char *msg, const xmlChar * str1,
139 const xmlChar * str2, const xmlChar * str3)
141 xmlStructuredErrorFunc schannel = NULL;
142 xmlGenericErrorFunc channel = NULL;
143 xmlParserCtxtPtr pctxt = NULL;
147 channel = ctxt->error;
148 data = ctxt->userData;
149 /* Use the special values to detect if it is part of a parsing
151 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
152 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
153 long delta = (char *) ctxt - (char *) ctxt->userData;
154 if ((delta > 0) && (delta < 250))
155 pctxt = ctxt->userData;
158 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
159 XML_ERR_ERROR, NULL, 0,
162 (const char *) str3, 0, 0, msg, str1, str2, str3);
164 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
166 #ifdef LIBXML_VALID_ENABLED
169 * @ctxt: an XML validation parser context
170 * @node: the node raising the error
171 * @error: the error number
172 * @str1: extra informations
173 * @int2: extra informations
174 * @str3: extra informations
176 * Handle a validation error, provide contextual informations
179 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
180 xmlNodePtr node, xmlParserErrors error,
181 const char *msg, const xmlChar * str1,
182 int int2, const xmlChar * str3)
184 xmlStructuredErrorFunc schannel = NULL;
185 xmlGenericErrorFunc channel = NULL;
186 xmlParserCtxtPtr pctxt = NULL;
190 channel = ctxt->error;
191 data = ctxt->userData;
192 /* Use the special values to detect if it is part of a parsing
194 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
195 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
196 long delta = (char *) ctxt - (char *) ctxt->userData;
197 if ((delta > 0) && (delta < 250))
198 pctxt = ctxt->userData;
201 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
202 XML_ERR_ERROR, NULL, 0,
205 NULL, int2, 0, msg, str1, int2, str3);
209 * xmlErrValidWarning:
210 * @ctxt: an XML validation parser context
211 * @node: the node raising the error
212 * @error: the error number
213 * @str1: extra information
214 * @str2: extra information
215 * @str3: extra information
217 * Handle a validation error, provide contextual information
220 xmlErrValidWarning(xmlValidCtxtPtr ctxt,
221 xmlNodePtr node, xmlParserErrors error,
222 const char *msg, const xmlChar * str1,
223 const xmlChar * str2, const xmlChar * str3)
225 xmlStructuredErrorFunc schannel = NULL;
226 xmlGenericErrorFunc channel = NULL;
227 xmlParserCtxtPtr pctxt = NULL;
231 channel = ctxt->warning;
232 data = ctxt->userData;
233 /* Use the special values to detect if it is part of a parsing
235 if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
236 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
237 long delta = (char *) ctxt - (char *) ctxt->userData;
238 if ((delta > 0) && (delta < 250))
239 pctxt = ctxt->userData;
242 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
243 XML_ERR_WARNING, NULL, 0,
246 (const char *) str3, 0, 0, msg, str1, str2, str3);
251 #ifdef LIBXML_REGEXP_ENABLED
253 * If regexp are enabled we can do continuous validation without the
254 * need of a tree to validate the content model. this is done in each
256 * Each xmlValidState represent the validation state associated to the
257 * set of nodes currently open from the document root to the current element.
261 typedef struct _xmlValidState {
262 xmlElementPtr elemDecl; /* pointer to the content model */
263 xmlNodePtr node; /* pointer to the current node */
264 xmlRegExecCtxtPtr exec; /* regexp runtime */
269 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
270 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
271 ctxt->vstateMax = 10;
272 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
273 sizeof(ctxt->vstateTab[0]));
274 if (ctxt->vstateTab == NULL) {
275 xmlVErrMemory(ctxt, "malloc failed");
280 if (ctxt->vstateNr >= ctxt->vstateMax) {
283 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
284 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
286 xmlVErrMemory(ctxt, "realloc failed");
289 ctxt->vstateMax *= 2;
290 ctxt->vstateTab = tmp;
292 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
293 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
294 ctxt->vstateTab[ctxt->vstateNr].node = node;
295 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
296 if (elemDecl->contModel == NULL)
297 xmlValidBuildContentModel(ctxt, elemDecl);
298 if (elemDecl->contModel != NULL) {
299 ctxt->vstateTab[ctxt->vstateNr].exec =
300 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
302 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
303 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
304 XML_ERR_INTERNAL_ERROR,
305 "Failed to build content model regexp for %s\n",
306 node->name, NULL, NULL);
309 return(ctxt->vstateNr++);
313 vstateVPop(xmlValidCtxtPtr ctxt) {
314 xmlElementPtr elemDecl;
316 if (ctxt->vstateNr < 1) return(-1);
318 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
319 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
320 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
321 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
322 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
324 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
325 if (ctxt->vstateNr >= 1)
326 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
329 return(ctxt->vstateNr);
332 #else /* not LIBXML_REGEXP_ENABLED */
334 * If regexp are not enabled, it uses a home made algorithm less
335 * complex and easier to
336 * debug/maintain than a generic NFA -> DFA state based algo. The
337 * only restriction is on the deepness of the tree limited by the
338 * size of the occurs bitfield
340 * this is the content of a saved state for rollbacks
343 #define ROLLBACK_OR 0
344 #define ROLLBACK_PARENT 1
346 typedef struct _xmlValidState {
347 xmlElementContentPtr cont; /* pointer to the content model subtree */
348 xmlNodePtr node; /* pointer to the current node in the list */
349 long occurs;/* bitfield for multiple occurrences */
350 unsigned char depth; /* current depth in the overall tree */
351 unsigned char state; /* ROLLBACK_XXX */
354 #define MAX_RECURSE 25000
355 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
356 #define CONT ctxt->vstate->cont
357 #define NODE ctxt->vstate->node
358 #define DEPTH ctxt->vstate->depth
359 #define OCCURS ctxt->vstate->occurs
360 #define STATE ctxt->vstate->state
362 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
363 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
365 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
366 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
369 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
370 xmlNodePtr node, unsigned char depth, long occurs,
371 unsigned char state) {
372 int i = ctxt->vstateNr - 1;
374 if (ctxt->vstateNr > MAX_RECURSE) {
377 if (ctxt->vstateTab == NULL) {
379 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
380 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
381 if (ctxt->vstateTab == NULL) {
382 xmlVErrMemory(ctxt, "malloc failed");
386 if (ctxt->vstateNr >= ctxt->vstateMax) {
389 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
390 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
392 xmlVErrMemory(ctxt, "malloc failed");
395 ctxt->vstateMax *= 2;
396 ctxt->vstateTab = tmp;
397 ctxt->vstate = &ctxt->vstateTab[0];
400 * Don't push on the stack a state already here
402 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
403 (ctxt->vstateTab[i].node == node) &&
404 (ctxt->vstateTab[i].depth == depth) &&
405 (ctxt->vstateTab[i].occurs == occurs) &&
406 (ctxt->vstateTab[i].state == state))
407 return(ctxt->vstateNr);
408 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
409 ctxt->vstateTab[ctxt->vstateNr].node = node;
410 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
411 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
412 ctxt->vstateTab[ctxt->vstateNr].state = state;
413 return(ctxt->vstateNr++);
417 vstateVPop(xmlValidCtxtPtr ctxt) {
418 if (ctxt->vstateNr <= 1) return(-1);
420 ctxt->vstate = &ctxt->vstateTab[0];
421 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
422 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
423 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
424 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
425 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
426 return(ctxt->vstateNr);
429 #endif /* LIBXML_REGEXP_ENABLED */
432 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
434 if (ctxt->nodeMax <= 0) {
437 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
438 sizeof(ctxt->nodeTab[0]));
439 if (ctxt->nodeTab == NULL) {
440 xmlVErrMemory(ctxt, "malloc failed");
445 if (ctxt->nodeNr >= ctxt->nodeMax) {
447 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
448 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
450 xmlVErrMemory(ctxt, "realloc failed");
456 ctxt->nodeTab[ctxt->nodeNr] = value;
458 return (ctxt->nodeNr++);
461 nodeVPop(xmlValidCtxtPtr ctxt)
465 if (ctxt->nodeNr <= 0)
468 if (ctxt->nodeNr > 0)
469 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
472 ret = ctxt->nodeTab[ctxt->nodeNr];
473 ctxt->nodeTab[ctxt->nodeNr] = NULL;
477 #ifdef DEBUG_VALID_ALGO
479 xmlValidPrintNode(xmlNodePtr cur) {
481 xmlGenericError(xmlGenericErrorContext, "null");
485 case XML_ELEMENT_NODE:
486 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
489 xmlGenericError(xmlGenericErrorContext, "text ");
491 case XML_CDATA_SECTION_NODE:
492 xmlGenericError(xmlGenericErrorContext, "cdata ");
494 case XML_ENTITY_REF_NODE:
495 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
498 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
500 case XML_COMMENT_NODE:
501 xmlGenericError(xmlGenericErrorContext, "comment ");
503 case XML_ATTRIBUTE_NODE:
504 xmlGenericError(xmlGenericErrorContext, "?attr? ");
506 case XML_ENTITY_NODE:
507 xmlGenericError(xmlGenericErrorContext, "?ent? ");
509 case XML_DOCUMENT_NODE:
510 xmlGenericError(xmlGenericErrorContext, "?doc? ");
512 case XML_DOCUMENT_TYPE_NODE:
513 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
515 case XML_DOCUMENT_FRAG_NODE:
516 xmlGenericError(xmlGenericErrorContext, "?frag? ");
518 case XML_NOTATION_NODE:
519 xmlGenericError(xmlGenericErrorContext, "?nota? ");
521 case XML_HTML_DOCUMENT_NODE:
522 xmlGenericError(xmlGenericErrorContext, "?html? ");
524 #ifdef LIBXML_DOCB_ENABLED
525 case XML_DOCB_DOCUMENT_NODE:
526 xmlGenericError(xmlGenericErrorContext, "?docb? ");
530 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
532 case XML_ELEMENT_DECL:
533 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
535 case XML_ATTRIBUTE_DECL:
536 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
538 case XML_ENTITY_DECL:
539 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
541 case XML_NAMESPACE_DECL:
542 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
544 case XML_XINCLUDE_START:
545 xmlGenericError(xmlGenericErrorContext, "incstart ");
547 case XML_XINCLUDE_END:
548 xmlGenericError(xmlGenericErrorContext, "incend ");
554 xmlValidPrintNodeList(xmlNodePtr cur) {
556 xmlGenericError(xmlGenericErrorContext, "null ");
557 while (cur != NULL) {
558 xmlValidPrintNode(cur);
564 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
568 xmlGenericError(xmlGenericErrorContext, "valid: ");
569 xmlValidPrintNodeList(cur);
570 xmlGenericError(xmlGenericErrorContext, "against ");
571 xmlSnprintfElementContent(expr, 5000, cont, 1);
572 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
576 xmlValidDebugState(xmlValidStatePtr state) {
577 xmlGenericError(xmlGenericErrorContext, "(");
578 if (state->cont == NULL)
579 xmlGenericError(xmlGenericErrorContext, "null,");
581 switch (state->cont->type) {
582 case XML_ELEMENT_CONTENT_PCDATA:
583 xmlGenericError(xmlGenericErrorContext, "pcdata,");
585 case XML_ELEMENT_CONTENT_ELEMENT:
586 xmlGenericError(xmlGenericErrorContext, "%s,",
589 case XML_ELEMENT_CONTENT_SEQ:
590 xmlGenericError(xmlGenericErrorContext, "seq,");
592 case XML_ELEMENT_CONTENT_OR:
593 xmlGenericError(xmlGenericErrorContext, "or,");
596 xmlValidPrintNode(state->node);
597 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
598 state->depth, state->occurs, state->state);
602 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
605 xmlGenericError(xmlGenericErrorContext, "state: ");
606 xmlValidDebugState(ctxt->vstate);
607 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
609 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
610 xmlValidDebugState(&ctxt->vstateTab[j]);
611 xmlGenericError(xmlGenericErrorContext, "\n");
615 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
618 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
619 #define DEBUG_VALID_MSG(m) \
620 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
623 #define DEBUG_VALID_STATE(n,c)
624 #define DEBUG_VALID_MSG(m)
627 /* TODO: use hash table for accesses to elem and attribute definitions */
631 if (doc == NULL) return(0); \
632 else if ((doc->intSubset == NULL) && \
633 (doc->extSubset == NULL)) return(0)
635 xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
637 #ifdef LIBXML_REGEXP_ENABLED
639 /************************************************************************
641 * Content model validation based on the regexps *
643 ************************************************************************/
646 * xmlValidBuildAContentModel:
647 * @content: the content model
648 * @ctxt: the schema parser context
649 * @name: the element name whose content is being built
651 * Generate the automata sequence needed for that type
653 * Returns 1 if successful or 0 in case of error.
656 xmlValidBuildAContentModel(xmlElementContentPtr content,
657 xmlValidCtxtPtr ctxt,
658 const xmlChar *name) {
659 if (content == NULL) {
660 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
661 "Found NULL content in content model of %s\n",
665 switch (content->type) {
666 case XML_ELEMENT_CONTENT_PCDATA:
667 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
668 "Found PCDATA in content model of %s\n",
672 case XML_ELEMENT_CONTENT_ELEMENT: {
673 xmlAutomataStatePtr oldstate = ctxt->state;
677 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
678 if (fullname == NULL) {
679 xmlVErrMemory(ctxt, "Building content model");
683 switch (content->ocur) {
684 case XML_ELEMENT_CONTENT_ONCE:
685 ctxt->state = xmlAutomataNewTransition(ctxt->am,
686 ctxt->state, NULL, fullname, NULL);
688 case XML_ELEMENT_CONTENT_OPT:
689 ctxt->state = xmlAutomataNewTransition(ctxt->am,
690 ctxt->state, NULL, fullname, NULL);
691 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
693 case XML_ELEMENT_CONTENT_PLUS:
694 ctxt->state = xmlAutomataNewTransition(ctxt->am,
695 ctxt->state, NULL, fullname, NULL);
696 xmlAutomataNewTransition(ctxt->am, ctxt->state,
697 ctxt->state, fullname, NULL);
699 case XML_ELEMENT_CONTENT_MULT:
700 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
702 xmlAutomataNewTransition(ctxt->am,
703 ctxt->state, ctxt->state, fullname, NULL);
706 if ((fullname != fn) && (fullname != content->name))
710 case XML_ELEMENT_CONTENT_SEQ: {
711 xmlAutomataStatePtr oldstate, oldend;
712 xmlElementContentOccur ocur;
715 * Simply iterate over the content
717 oldstate = ctxt->state;
718 ocur = content->ocur;
719 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
720 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
721 oldstate = ctxt->state;
724 xmlValidBuildAContentModel(content->c1, ctxt, name);
725 content = content->c2;
726 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
727 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
728 xmlValidBuildAContentModel(content, ctxt, name);
729 oldend = ctxt->state;
730 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
732 case XML_ELEMENT_CONTENT_ONCE:
734 case XML_ELEMENT_CONTENT_OPT:
735 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
737 case XML_ELEMENT_CONTENT_MULT:
738 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
739 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
741 case XML_ELEMENT_CONTENT_PLUS:
742 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
747 case XML_ELEMENT_CONTENT_OR: {
748 xmlAutomataStatePtr oldstate, oldend;
749 xmlElementContentOccur ocur;
751 ocur = content->ocur;
752 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
753 (ocur == XML_ELEMENT_CONTENT_MULT)) {
754 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
757 oldstate = ctxt->state;
758 oldend = xmlAutomataNewState(ctxt->am);
761 * iterate over the subtypes and remerge the end with an
765 ctxt->state = oldstate;
766 xmlValidBuildAContentModel(content->c1, ctxt, name);
767 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
768 content = content->c2;
769 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
770 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
771 ctxt->state = oldstate;
772 xmlValidBuildAContentModel(content, ctxt, name);
773 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
774 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
776 case XML_ELEMENT_CONTENT_ONCE:
778 case XML_ELEMENT_CONTENT_OPT:
779 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
781 case XML_ELEMENT_CONTENT_MULT:
782 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
783 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
785 case XML_ELEMENT_CONTENT_PLUS:
786 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
792 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
793 "ContentModel broken for element %s\n",
794 (const char *) name);
800 * xmlValidBuildContentModel:
801 * @ctxt: a validation context
802 * @elem: an element declaration node
804 * (Re)Build the automata associated to the content model of this
807 * Returns 1 in case of success, 0 in case of error
810 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
812 if ((ctxt == NULL) || (elem == NULL))
814 if (elem->type != XML_ELEMENT_DECL)
816 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
818 /* TODO: should we rebuild in this case ? */
819 if (elem->contModel != NULL) {
820 if (!xmlRegexpIsDeterminist(elem->contModel)) {
827 ctxt->am = xmlNewAutomata();
828 if (ctxt->am == NULL) {
829 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
830 XML_ERR_INTERNAL_ERROR,
831 "Cannot create automata for element %s\n",
832 elem->name, NULL, NULL);
835 ctxt->state = xmlAutomataGetInitState(ctxt->am);
836 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
837 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
838 elem->contModel = xmlAutomataCompile(ctxt->am);
839 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
842 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
843 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
844 XML_DTD_CONTENT_NOT_DETERMINIST,
845 "Content model of %s is not determinist: %s\n",
846 elem->name, BAD_CAST expr, NULL);
847 #ifdef DEBUG_REGEXP_ALGO
848 xmlRegexpPrint(stderr, elem->contModel);
852 xmlFreeAutomata(ctxt->am);
857 xmlFreeAutomata(ctxt->am);
862 #endif /* LIBXML_REGEXP_ENABLED */
864 /****************************************************************
866 * Util functions for data allocation/deallocation *
868 ****************************************************************/
873 * Allocate a validation context structure.
875 * Returns NULL if not, otherwise the new validation context structure
877 xmlValidCtxtPtr xmlNewValidCtxt(void) {
880 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
881 xmlVErrMemory(NULL, "malloc failed");
885 (void) memset(ret, 0, sizeof (xmlValidCtxt));
892 * @cur: the validation context to free
894 * Free a validation context structure.
897 xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
898 if (cur->vstateTab != NULL)
899 xmlFree(cur->vstateTab);
900 if (cur->nodeTab != NULL)
901 xmlFree(cur->nodeTab);
905 #endif /* LIBXML_VALID_ENABLED */
908 * xmlNewDocElementContent:
910 * @name: the subelement name or NULL
911 * @type: the type of element content decl
913 * Allocate an element content structure for the document.
915 * Returns NULL if not, otherwise the new element content structure
918 xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
919 xmlElementContentType type) {
920 xmlElementContentPtr ret;
921 xmlDictPtr dict = NULL;
927 case XML_ELEMENT_CONTENT_ELEMENT:
929 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
930 "xmlNewElementContent : name == NULL !\n",
934 case XML_ELEMENT_CONTENT_PCDATA:
935 case XML_ELEMENT_CONTENT_SEQ:
936 case XML_ELEMENT_CONTENT_OR:
938 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
939 "xmlNewElementContent : name != NULL !\n",
944 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
945 "Internal: ELEMENT content corrupted invalid type\n",
949 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
951 xmlVErrMemory(NULL, "malloc failed");
954 memset(ret, 0, sizeof(xmlElementContent));
956 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
961 tmp = xmlSplitQName3(name, &l);
964 ret->name = xmlStrdup(name);
966 ret->name = xmlDictLookup(dict, name, -1);
969 ret->prefix = xmlStrndup(name, l);
970 ret->name = xmlStrdup(tmp);
972 ret->prefix = xmlDictLookup(dict, name, l);
973 ret->name = xmlDictLookup(dict, tmp, -1);
981 * xmlNewElementContent:
982 * @name: the subelement name or NULL
983 * @type: the type of element content decl
985 * Allocate an element content structure.
986 * Deprecated in favor of xmlNewDocElementContent
988 * Returns NULL if not, otherwise the new element content structure
991 xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
992 return(xmlNewDocElementContent(NULL, name, type));
996 * xmlCopyDocElementContent:
997 * @doc: the document owning the element declaration
998 * @cur: An element content pointer.
1000 * Build a copy of an element content description.
1002 * Returns the new xmlElementContentPtr or NULL in case of error.
1004 xmlElementContentPtr
1005 xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1006 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1007 xmlDictPtr dict = NULL;
1009 if (cur == NULL) return(NULL);
1014 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1016 xmlVErrMemory(NULL, "malloc failed");
1019 memset(ret, 0, sizeof(xmlElementContent));
1020 ret->type = cur->type;
1021 ret->ocur = cur->ocur;
1022 if (cur->name != NULL) {
1024 ret->name = xmlDictLookup(dict, cur->name, -1);
1026 ret->name = xmlStrdup(cur->name);
1029 if (cur->prefix != NULL) {
1031 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1033 ret->prefix = xmlStrdup(cur->prefix);
1035 if (cur->c1 != NULL)
1036 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1037 if (ret->c1 != NULL)
1038 ret->c1->parent = ret;
1039 if (cur->c2 != NULL) {
1042 while (cur != NULL) {
1043 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1045 xmlVErrMemory(NULL, "malloc failed");
1048 memset(tmp, 0, sizeof(xmlElementContent));
1049 tmp->type = cur->type;
1050 tmp->ocur = cur->ocur;
1052 if (cur->name != NULL) {
1054 tmp->name = xmlDictLookup(dict, cur->name, -1);
1056 tmp->name = xmlStrdup(cur->name);
1059 if (cur->prefix != NULL) {
1061 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1063 tmp->prefix = xmlStrdup(cur->prefix);
1065 if (cur->c1 != NULL)
1066 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1067 if (tmp->c1 != NULL)
1068 tmp->c1->parent = ret;
1077 * xmlCopyElementContent:
1078 * @cur: An element content pointer.
1080 * Build a copy of an element content description.
1081 * Deprecated, use xmlCopyDocElementContent instead
1083 * Returns the new xmlElementContentPtr or NULL in case of error.
1085 xmlElementContentPtr
1086 xmlCopyElementContent(xmlElementContentPtr cur) {
1087 return(xmlCopyDocElementContent(NULL, cur));
1091 * xmlFreeDocElementContent:
1092 * @doc: the document owning the element declaration
1093 * @cur: the element content tree to free
1095 * Free an element content structure. The whole subtree is removed.
1098 xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1099 xmlElementContentPtr next;
1100 xmlDictPtr dict = NULL;
1105 while (cur != NULL) {
1107 switch (cur->type) {
1108 case XML_ELEMENT_CONTENT_PCDATA:
1109 case XML_ELEMENT_CONTENT_ELEMENT:
1110 case XML_ELEMENT_CONTENT_SEQ:
1111 case XML_ELEMENT_CONTENT_OR:
1114 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1115 "Internal: ELEMENT content corrupted invalid type\n",
1119 if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1121 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1122 xmlFree((xmlChar *) cur->name);
1123 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1124 xmlFree((xmlChar *) cur->prefix);
1126 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1127 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1135 * xmlFreeElementContent:
1136 * @cur: the element content tree to free
1138 * Free an element content structure. The whole subtree is removed.
1139 * Deprecated, use xmlFreeDocElementContent instead
1142 xmlFreeElementContent(xmlElementContentPtr cur) {
1143 xmlFreeDocElementContent(NULL, cur);
1146 #ifdef LIBXML_OUTPUT_ENABLED
1148 * xmlDumpElementContent:
1149 * @buf: An XML buffer
1150 * @content: An element table
1151 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1153 * This will dump the content of the element table as an XML DTD definition
1156 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1157 if (content == NULL) return;
1159 if (glob) xmlBufferWriteChar(buf, "(");
1160 switch (content->type) {
1161 case XML_ELEMENT_CONTENT_PCDATA:
1162 xmlBufferWriteChar(buf, "#PCDATA");
1164 case XML_ELEMENT_CONTENT_ELEMENT:
1165 if (content->prefix != NULL) {
1166 xmlBufferWriteCHAR(buf, content->prefix);
1167 xmlBufferWriteChar(buf, ":");
1169 xmlBufferWriteCHAR(buf, content->name);
1171 case XML_ELEMENT_CONTENT_SEQ:
1172 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1173 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1174 xmlDumpElementContent(buf, content->c1, 1);
1176 xmlDumpElementContent(buf, content->c1, 0);
1177 xmlBufferWriteChar(buf, " , ");
1178 if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1179 ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1180 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
1181 xmlDumpElementContent(buf, content->c2, 1);
1183 xmlDumpElementContent(buf, content->c2, 0);
1185 case XML_ELEMENT_CONTENT_OR:
1186 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1187 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1188 xmlDumpElementContent(buf, content->c1, 1);
1190 xmlDumpElementContent(buf, content->c1, 0);
1191 xmlBufferWriteChar(buf, " | ");
1192 if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1193 ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1194 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
1195 xmlDumpElementContent(buf, content->c2, 1);
1197 xmlDumpElementContent(buf, content->c2, 0);
1200 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1201 "Internal: ELEMENT content corrupted invalid type\n",
1205 xmlBufferWriteChar(buf, ")");
1206 switch (content->ocur) {
1207 case XML_ELEMENT_CONTENT_ONCE:
1209 case XML_ELEMENT_CONTENT_OPT:
1210 xmlBufferWriteChar(buf, "?");
1212 case XML_ELEMENT_CONTENT_MULT:
1213 xmlBufferWriteChar(buf, "*");
1215 case XML_ELEMENT_CONTENT_PLUS:
1216 xmlBufferWriteChar(buf, "+");
1222 * xmlSprintfElementContent:
1223 * @buf: an output buffer
1224 * @content: An element table
1225 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1227 * Deprecated, unsafe, use xmlSnprintfElementContent
1230 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1231 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1232 int englob ATTRIBUTE_UNUSED) {
1234 #endif /* LIBXML_OUTPUT_ENABLED */
1237 * xmlSnprintfElementContent:
1238 * @buf: an output buffer
1239 * @size: the buffer size
1240 * @content: An element table
1241 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1243 * This will dump the content of the element content definition
1244 * Intended just for the debug routine
1247 xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
1250 if (content == NULL) return;
1252 if (size - len < 50) {
1253 if ((size - len > 4) && (buf[len - 1] != '.'))
1254 strcat(buf, " ...");
1257 if (englob) strcat(buf, "(");
1258 switch (content->type) {
1259 case XML_ELEMENT_CONTENT_PCDATA:
1260 strcat(buf, "#PCDATA");
1262 case XML_ELEMENT_CONTENT_ELEMENT:
1263 if (content->prefix != NULL) {
1264 if (size - len < xmlStrlen(content->prefix) + 10) {
1265 strcat(buf, " ...");
1268 strcat(buf, (char *) content->prefix);
1271 if (size - len < xmlStrlen(content->name) + 10) {
1272 strcat(buf, " ...");
1275 if (content->name != NULL)
1276 strcat(buf, (char *) content->name);
1278 case XML_ELEMENT_CONTENT_SEQ:
1279 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1280 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1281 xmlSnprintfElementContent(buf, size, content->c1, 1);
1283 xmlSnprintfElementContent(buf, size, content->c1, 0);
1285 if (size - len < 50) {
1286 if ((size - len > 4) && (buf[len - 1] != '.'))
1287 strcat(buf, " ...");
1291 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1292 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1293 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1294 xmlSnprintfElementContent(buf, size, content->c2, 1);
1296 xmlSnprintfElementContent(buf, size, content->c2, 0);
1298 case XML_ELEMENT_CONTENT_OR:
1299 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1300 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1301 xmlSnprintfElementContent(buf, size, content->c1, 1);
1303 xmlSnprintfElementContent(buf, size, content->c1, 0);
1305 if (size - len < 50) {
1306 if ((size - len > 4) && (buf[len - 1] != '.'))
1307 strcat(buf, " ...");
1311 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1312 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1313 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1314 xmlSnprintfElementContent(buf, size, content->c2, 1);
1316 xmlSnprintfElementContent(buf, size, content->c2, 0);
1321 switch (content->ocur) {
1322 case XML_ELEMENT_CONTENT_ONCE:
1324 case XML_ELEMENT_CONTENT_OPT:
1327 case XML_ELEMENT_CONTENT_MULT:
1330 case XML_ELEMENT_CONTENT_PLUS:
1336 /****************************************************************
1338 * Registration of DTD declarations *
1340 ****************************************************************/
1346 * Deallocate the memory used by an element definition
1349 xmlFreeElement(xmlElementPtr elem) {
1350 if (elem == NULL) return;
1351 xmlUnlinkNode((xmlNodePtr) elem);
1352 xmlFreeDocElementContent(elem->doc, elem->content);
1353 if (elem->name != NULL)
1354 xmlFree((xmlChar *) elem->name);
1355 if (elem->prefix != NULL)
1356 xmlFree((xmlChar *) elem->prefix);
1357 #ifdef LIBXML_REGEXP_ENABLED
1358 if (elem->contModel != NULL)
1359 xmlRegFreeRegexp(elem->contModel);
1366 * xmlAddElementDecl:
1367 * @ctxt: the validation context
1368 * @dtd: pointer to the DTD
1369 * @name: the entity name
1370 * @type: the element type
1371 * @content: the element content tree or NULL
1373 * Register a new element declaration
1375 * Returns NULL if not, otherwise the entity
1378 xmlAddElementDecl(xmlValidCtxtPtr ctxt,
1379 xmlDtdPtr dtd, const xmlChar *name,
1380 xmlElementTypeVal type,
1381 xmlElementContentPtr content) {
1383 xmlElementTablePtr table;
1384 xmlAttributePtr oldAttributes = NULL;
1385 xmlChar *ns, *uqname;
1395 case XML_ELEMENT_TYPE_EMPTY:
1396 if (content != NULL) {
1397 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1398 "xmlAddElementDecl: content != NULL for EMPTY\n",
1403 case XML_ELEMENT_TYPE_ANY:
1404 if (content != NULL) {
1405 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1406 "xmlAddElementDecl: content != NULL for ANY\n",
1411 case XML_ELEMENT_TYPE_MIXED:
1412 if (content == NULL) {
1413 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1414 "xmlAddElementDecl: content == NULL for MIXED\n",
1419 case XML_ELEMENT_TYPE_ELEMENT:
1420 if (content == NULL) {
1421 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1422 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1428 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1429 "Internal: ELEMENT decl corrupted invalid type\n",
1435 * check if name is a QName
1437 uqname = xmlSplitQName2(name, &ns);
1442 * Create the Element table if needed.
1444 table = (xmlElementTablePtr) dtd->elements;
1445 if (table == NULL) {
1446 xmlDictPtr dict = NULL;
1448 if (dtd->doc != NULL)
1449 dict = dtd->doc->dict;
1450 table = xmlHashCreateDict(0, dict);
1451 dtd->elements = (void *) table;
1453 if (table == NULL) {
1455 "xmlAddElementDecl: Table creation failed!\n");
1464 * lookup old attributes inserted on an undefined element in the
1467 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1468 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1469 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1470 oldAttributes = ret->attributes;
1471 ret->attributes = NULL;
1472 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1473 xmlFreeElement(ret);
1478 * The element may already be present if one of its attribute
1479 * was registered first
1481 ret = xmlHashLookup2(table, name, ns);
1483 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1484 #ifdef LIBXML_VALID_ENABLED
1486 * The element is already defined in this DTD.
1488 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1489 "Redefinition of element %s\n",
1491 #endif /* LIBXML_VALID_ENABLED */
1503 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1505 xmlVErrMemory(ctxt, "malloc failed");
1512 memset(ret, 0, sizeof(xmlElement));
1513 ret->type = XML_ELEMENT_DECL;
1516 * fill the structure.
1518 ret->name = xmlStrdup(name);
1519 if (ret->name == NULL) {
1520 xmlVErrMemory(ctxt, "malloc failed");
1532 * Insertion must not fail
1534 if (xmlHashAddEntry2(table, name, ns, ret)) {
1535 #ifdef LIBXML_VALID_ENABLED
1537 * The element is already defined in this DTD.
1539 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1540 "Redefinition of element %s\n",
1542 #endif /* LIBXML_VALID_ENABLED */
1543 xmlFreeElement(ret);
1549 * For new element, may have attributes from earlier
1550 * definition in internal subset
1552 ret->attributes = oldAttributes;
1556 * Finish to fill the structure.
1560 * Avoid a stupid copy when called by the parser
1561 * and flag it by setting a special parent value
1562 * so the parser doesn't unallocate it.
1564 if ((ctxt != NULL) &&
1565 ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1566 (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
1567 ret->content = content;
1568 if (content != NULL)
1569 content->parent = (xmlElementContentPtr) 1;
1571 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1575 * Link it to the DTD
1578 ret->doc = dtd->doc;
1579 if (dtd->last == NULL) {
1580 dtd->children = dtd->last = (xmlNodePtr) ret;
1582 dtd->last->next = (xmlNodePtr) ret;
1583 ret->prev = dtd->last;
1584 dtd->last = (xmlNodePtr) ret;
1592 * xmlFreeElementTable:
1593 * @table: An element table
1595 * Deallocate the memory used by an element hash table.
1598 xmlFreeElementTable(xmlElementTablePtr table) {
1599 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1602 #ifdef LIBXML_TREE_ENABLED
1607 * Build a copy of an element.
1609 * Returns the new xmlElementPtr or NULL in case of error.
1611 static xmlElementPtr
1612 xmlCopyElement(xmlElementPtr elem) {
1615 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1617 xmlVErrMemory(NULL, "malloc failed");
1620 memset(cur, 0, sizeof(xmlElement));
1621 cur->type = XML_ELEMENT_DECL;
1622 cur->etype = elem->etype;
1623 if (elem->name != NULL)
1624 cur->name = xmlStrdup(elem->name);
1627 if (elem->prefix != NULL)
1628 cur->prefix = xmlStrdup(elem->prefix);
1631 cur->content = xmlCopyElementContent(elem->content);
1632 /* TODO : rebuild the attribute list on the copy */
1633 cur->attributes = NULL;
1638 * xmlCopyElementTable:
1639 * @table: An element table
1641 * Build a copy of an element table.
1643 * Returns the new xmlElementTablePtr or NULL in case of error.
1646 xmlCopyElementTable(xmlElementTablePtr table) {
1647 return((xmlElementTablePtr) xmlHashCopy(table,
1648 (xmlHashCopier) xmlCopyElement));
1650 #endif /* LIBXML_TREE_ENABLED */
1652 #ifdef LIBXML_OUTPUT_ENABLED
1654 * xmlDumpElementDecl:
1655 * @buf: the XML buffer output
1656 * @elem: An element table
1658 * This will dump the content of the element declaration as an XML
1662 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1663 if ((buf == NULL) || (elem == NULL))
1665 switch (elem->etype) {
1666 case XML_ELEMENT_TYPE_EMPTY:
1667 xmlBufferWriteChar(buf, "<!ELEMENT ");
1668 if (elem->prefix != NULL) {
1669 xmlBufferWriteCHAR(buf, elem->prefix);
1670 xmlBufferWriteChar(buf, ":");
1672 xmlBufferWriteCHAR(buf, elem->name);
1673 xmlBufferWriteChar(buf, " EMPTY>\n");
1675 case XML_ELEMENT_TYPE_ANY:
1676 xmlBufferWriteChar(buf, "<!ELEMENT ");
1677 if (elem->prefix != NULL) {
1678 xmlBufferWriteCHAR(buf, elem->prefix);
1679 xmlBufferWriteChar(buf, ":");
1681 xmlBufferWriteCHAR(buf, elem->name);
1682 xmlBufferWriteChar(buf, " ANY>\n");
1684 case XML_ELEMENT_TYPE_MIXED:
1685 xmlBufferWriteChar(buf, "<!ELEMENT ");
1686 if (elem->prefix != NULL) {
1687 xmlBufferWriteCHAR(buf, elem->prefix);
1688 xmlBufferWriteChar(buf, ":");
1690 xmlBufferWriteCHAR(buf, elem->name);
1691 xmlBufferWriteChar(buf, " ");
1692 xmlDumpElementContent(buf, elem->content, 1);
1693 xmlBufferWriteChar(buf, ">\n");
1695 case XML_ELEMENT_TYPE_ELEMENT:
1696 xmlBufferWriteChar(buf, "<!ELEMENT ");
1697 if (elem->prefix != NULL) {
1698 xmlBufferWriteCHAR(buf, elem->prefix);
1699 xmlBufferWriteChar(buf, ":");
1701 xmlBufferWriteCHAR(buf, elem->name);
1702 xmlBufferWriteChar(buf, " ");
1703 xmlDumpElementContent(buf, elem->content, 1);
1704 xmlBufferWriteChar(buf, ">\n");
1707 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1708 "Internal: ELEMENT struct corrupted invalid type\n",
1714 * xmlDumpElementDeclScan:
1715 * @elem: An element table
1716 * @buf: the XML buffer output
1718 * This routine is used by the hash scan function. It just reverses
1722 xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1723 xmlDumpElementDecl(buf, elem);
1727 * xmlDumpElementTable:
1728 * @buf: the XML buffer output
1729 * @table: An element table
1731 * This will dump the content of the element table as an XML DTD definition
1734 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1735 if ((buf == NULL) || (table == NULL))
1737 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
1739 #endif /* LIBXML_OUTPUT_ENABLED */
1742 * xmlCreateEnumeration:
1743 * @name: the enumeration name or NULL
1745 * create and initialize an enumeration attribute node.
1747 * Returns the xmlEnumerationPtr just created or NULL in case
1751 xmlCreateEnumeration(const xmlChar *name) {
1752 xmlEnumerationPtr ret;
1754 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1756 xmlVErrMemory(NULL, "malloc failed");
1759 memset(ret, 0, sizeof(xmlEnumeration));
1762 ret->name = xmlStrdup(name);
1767 * xmlFreeEnumeration:
1768 * @cur: the tree to free.
1770 * free an enumeration attribute node (recursive).
1773 xmlFreeEnumeration(xmlEnumerationPtr cur) {
1774 if (cur == NULL) return;
1776 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1778 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1782 #ifdef LIBXML_TREE_ENABLED
1784 * xmlCopyEnumeration:
1785 * @cur: the tree to copy.
1787 * Copy an enumeration attribute node (recursive).
1789 * Returns the xmlEnumerationPtr just created or NULL in case
1793 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1794 xmlEnumerationPtr ret;
1796 if (cur == NULL) return(NULL);
1797 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1799 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1800 else ret->next = NULL;
1804 #endif /* LIBXML_TREE_ENABLED */
1806 #ifdef LIBXML_OUTPUT_ENABLED
1808 * xmlDumpEnumeration:
1809 * @buf: the XML buffer output
1810 * @enum: An enumeration
1812 * This will dump the content of the enumeration
1815 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1816 if ((buf == NULL) || (cur == NULL))
1819 xmlBufferWriteCHAR(buf, cur->name);
1820 if (cur->next == NULL)
1821 xmlBufferWriteChar(buf, ")");
1823 xmlBufferWriteChar(buf, " | ");
1824 xmlDumpEnumeration(buf, cur->next);
1827 #endif /* LIBXML_OUTPUT_ENABLED */
1829 #ifdef LIBXML_VALID_ENABLED
1831 * xmlScanAttributeDeclCallback:
1832 * @attr: the attribute decl
1833 * @list: the list to update
1835 * Callback called by xmlScanAttributeDecl when a new attribute
1836 * has to be entered in the list.
1839 xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
1840 const xmlChar* name ATTRIBUTE_UNUSED) {
1841 attr->nexth = *list;
1846 * xmlScanAttributeDecl:
1847 * @dtd: pointer to the DTD
1848 * @elem: the element name
1850 * When inserting a new element scan the DtD for existing attributes
1851 * for that element and initialize the Attribute chain
1853 * Returns the pointer to the first attribute decl in the chain,
1857 xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1858 xmlAttributePtr ret = NULL;
1859 xmlAttributeTablePtr table;
1867 table = (xmlAttributeTablePtr) dtd->attributes;
1872 xmlHashScan3(table, NULL, NULL, elem,
1873 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1878 * xmlScanIDAttributeDecl:
1879 * @ctxt: the validation context
1880 * @elem: the element name
1881 * @err: whether to raise errors here
1883 * Verify that the element don't have too many ID attributes
1886 * Returns the number of ID attributes found.
1889 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1890 xmlAttributePtr cur;
1893 if (elem == NULL) return(0);
1894 cur = elem->attributes;
1895 while (cur != NULL) {
1896 if (cur->atype == XML_ATTRIBUTE_ID) {
1898 if ((ret > 1) && (err))
1899 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1900 "Element %s has too many ID attributes defined : %s\n",
1901 elem->name, cur->name, NULL);
1907 #endif /* LIBXML_VALID_ENABLED */
1911 * @elem: An attribute
1913 * Deallocate the memory used by an attribute definition
1916 xmlFreeAttribute(xmlAttributePtr attr) {
1919 if (attr == NULL) return;
1920 if (attr->doc != NULL)
1921 dict = attr->doc->dict;
1924 xmlUnlinkNode((xmlNodePtr) attr);
1925 if (attr->tree != NULL)
1926 xmlFreeEnumeration(attr->tree);
1928 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1929 xmlFree((xmlChar *) attr->elem);
1930 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1931 xmlFree((xmlChar *) attr->name);
1932 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1933 xmlFree((xmlChar *) attr->prefix);
1934 if ((attr->defaultValue != NULL) &&
1935 (!xmlDictOwns(dict, attr->defaultValue)))
1936 xmlFree((xmlChar *) attr->defaultValue);
1938 if (attr->elem != NULL)
1939 xmlFree((xmlChar *) attr->elem);
1940 if (attr->name != NULL)
1941 xmlFree((xmlChar *) attr->name);
1942 if (attr->defaultValue != NULL)
1943 xmlFree((xmlChar *) attr->defaultValue);
1944 if (attr->prefix != NULL)
1945 xmlFree((xmlChar *) attr->prefix);
1952 * xmlAddAttributeDecl:
1953 * @ctxt: the validation context
1954 * @dtd: pointer to the DTD
1955 * @elem: the element name
1956 * @name: the attribute name
1957 * @ns: the attribute namespace prefix
1958 * @type: the attribute type
1959 * @def: the attribute default type
1960 * @defaultValue: the attribute default value
1961 * @tree: if it's an enumeration, the associated list
1963 * Register a new attribute declaration
1964 * Note that @tree becomes the ownership of the DTD
1966 * Returns NULL if not new, otherwise the attribute decl
1969 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
1970 xmlDtdPtr dtd, const xmlChar *elem,
1971 const xmlChar *name, const xmlChar *ns,
1972 xmlAttributeType type, xmlAttributeDefault def,
1973 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1974 xmlAttributePtr ret;
1975 xmlAttributeTablePtr table;
1976 xmlElementPtr elemDef;
1977 xmlDictPtr dict = NULL;
1980 xmlFreeEnumeration(tree);
1984 xmlFreeEnumeration(tree);
1988 xmlFreeEnumeration(tree);
1991 if (dtd->doc != NULL)
1992 dict = dtd->doc->dict;
1994 #ifdef LIBXML_VALID_ENABLED
1996 * Check the type and possibly the default value.
1999 case XML_ATTRIBUTE_CDATA:
2001 case XML_ATTRIBUTE_ID:
2003 case XML_ATTRIBUTE_IDREF:
2005 case XML_ATTRIBUTE_IDREFS:
2007 case XML_ATTRIBUTE_ENTITY:
2009 case XML_ATTRIBUTE_ENTITIES:
2011 case XML_ATTRIBUTE_NMTOKEN:
2013 case XML_ATTRIBUTE_NMTOKENS:
2015 case XML_ATTRIBUTE_ENUMERATION:
2017 case XML_ATTRIBUTE_NOTATION:
2020 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2021 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2023 xmlFreeEnumeration(tree);
2026 if ((defaultValue != NULL) &&
2027 (!xmlValidateAttributeValue(type, defaultValue))) {
2028 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2029 "Attribute %s of %s: invalid default value\n",
2030 elem, name, defaultValue);
2031 defaultValue = NULL;
2035 #endif /* LIBXML_VALID_ENABLED */
2038 * Check first that an attribute defined in the external subset wasn't
2039 * already defined in the internal subset
2041 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2042 (dtd->doc->intSubset != NULL) &&
2043 (dtd->doc->intSubset->attributes != NULL)) {
2044 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2050 * Create the Attribute table if needed.
2052 table = (xmlAttributeTablePtr) dtd->attributes;
2053 if (table == NULL) {
2054 table = xmlHashCreateDict(0, dict);
2055 dtd->attributes = (void *) table;
2057 if (table == NULL) {
2059 "xmlAddAttributeDecl: Table creation failed!\n");
2064 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2066 xmlVErrMemory(ctxt, "malloc failed");
2069 memset(ret, 0, sizeof(xmlAttribute));
2070 ret->type = XML_ATTRIBUTE_DECL;
2073 * fill the structure.
2077 * doc must be set before possible error causes call
2078 * to xmlFreeAttribute (because it's used to check on
2081 ret->doc = dtd->doc;
2083 ret->name = xmlDictLookup(dict, name, -1);
2084 ret->prefix = xmlDictLookup(dict, ns, -1);
2085 ret->elem = xmlDictLookup(dict, elem, -1);
2087 ret->name = xmlStrdup(name);
2088 ret->prefix = xmlStrdup(ns);
2089 ret->elem = xmlStrdup(elem);
2093 if (defaultValue != NULL) {
2095 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2097 ret->defaultValue = xmlStrdup(defaultValue);
2102 * Search the DTD for previous declarations of the ATTLIST
2104 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2105 #ifdef LIBXML_VALID_ENABLED
2107 * The attribute is already defined in this DTD.
2109 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2110 "Attribute %s of element %s: already defined\n",
2112 #endif /* LIBXML_VALID_ENABLED */
2113 xmlFreeAttribute(ret);
2119 * Multiple ID per element
2121 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2122 if (elemDef != NULL) {
2124 #ifdef LIBXML_VALID_ENABLED
2125 if ((type == XML_ATTRIBUTE_ID) &&
2126 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2127 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2128 "Element %s has too may ID attributes defined : %s\n",
2133 #endif /* LIBXML_VALID_ENABLED */
2136 * Insert namespace default def first they need to be
2139 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2140 ((ret->prefix != NULL &&
2141 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2142 ret->nexth = elemDef->attributes;
2143 elemDef->attributes = ret;
2145 xmlAttributePtr tmp = elemDef->attributes;
2147 while ((tmp != NULL) &&
2148 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2149 ((ret->prefix != NULL &&
2150 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2151 if (tmp->nexth == NULL)
2156 ret->nexth = tmp->nexth;
2159 ret->nexth = elemDef->attributes;
2160 elemDef->attributes = ret;
2166 * Link it to the DTD
2169 if (dtd->last == NULL) {
2170 dtd->children = dtd->last = (xmlNodePtr) ret;
2172 dtd->last->next = (xmlNodePtr) ret;
2173 ret->prev = dtd->last;
2174 dtd->last = (xmlNodePtr) ret;
2180 * xmlFreeAttributeTable:
2181 * @table: An attribute table
2183 * Deallocate the memory used by an entities hash table.
2186 xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2187 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2190 #ifdef LIBXML_TREE_ENABLED
2193 * @attr: An attribute
2195 * Build a copy of an attribute.
2197 * Returns the new xmlAttributePtr or NULL in case of error.
2199 static xmlAttributePtr
2200 xmlCopyAttribute(xmlAttributePtr attr) {
2201 xmlAttributePtr cur;
2203 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2205 xmlVErrMemory(NULL, "malloc failed");
2208 memset(cur, 0, sizeof(xmlAttribute));
2209 cur->type = XML_ATTRIBUTE_DECL;
2210 cur->atype = attr->atype;
2211 cur->def = attr->def;
2212 cur->tree = xmlCopyEnumeration(attr->tree);
2213 if (attr->elem != NULL)
2214 cur->elem = xmlStrdup(attr->elem);
2215 if (attr->name != NULL)
2216 cur->name = xmlStrdup(attr->name);
2217 if (attr->prefix != NULL)
2218 cur->prefix = xmlStrdup(attr->prefix);
2219 if (attr->defaultValue != NULL)
2220 cur->defaultValue = xmlStrdup(attr->defaultValue);
2225 * xmlCopyAttributeTable:
2226 * @table: An attribute table
2228 * Build a copy of an attribute table.
2230 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2232 xmlAttributeTablePtr
2233 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2234 return((xmlAttributeTablePtr) xmlHashCopy(table,
2235 (xmlHashCopier) xmlCopyAttribute));
2237 #endif /* LIBXML_TREE_ENABLED */
2239 #ifdef LIBXML_OUTPUT_ENABLED
2241 * xmlDumpAttributeDecl:
2242 * @buf: the XML buffer output
2243 * @attr: An attribute declaration
2245 * This will dump the content of the attribute declaration as an XML
2249 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2250 if ((buf == NULL) || (attr == NULL))
2252 xmlBufferWriteChar(buf, "<!ATTLIST ");
2253 xmlBufferWriteCHAR(buf, attr->elem);
2254 xmlBufferWriteChar(buf, " ");
2255 if (attr->prefix != NULL) {
2256 xmlBufferWriteCHAR(buf, attr->prefix);
2257 xmlBufferWriteChar(buf, ":");
2259 xmlBufferWriteCHAR(buf, attr->name);
2260 switch (attr->atype) {
2261 case XML_ATTRIBUTE_CDATA:
2262 xmlBufferWriteChar(buf, " CDATA");
2264 case XML_ATTRIBUTE_ID:
2265 xmlBufferWriteChar(buf, " ID");
2267 case XML_ATTRIBUTE_IDREF:
2268 xmlBufferWriteChar(buf, " IDREF");
2270 case XML_ATTRIBUTE_IDREFS:
2271 xmlBufferWriteChar(buf, " IDREFS");
2273 case XML_ATTRIBUTE_ENTITY:
2274 xmlBufferWriteChar(buf, " ENTITY");
2276 case XML_ATTRIBUTE_ENTITIES:
2277 xmlBufferWriteChar(buf, " ENTITIES");
2279 case XML_ATTRIBUTE_NMTOKEN:
2280 xmlBufferWriteChar(buf, " NMTOKEN");
2282 case XML_ATTRIBUTE_NMTOKENS:
2283 xmlBufferWriteChar(buf, " NMTOKENS");
2285 case XML_ATTRIBUTE_ENUMERATION:
2286 xmlBufferWriteChar(buf, " (");
2287 xmlDumpEnumeration(buf, attr->tree);
2289 case XML_ATTRIBUTE_NOTATION:
2290 xmlBufferWriteChar(buf, " NOTATION (");
2291 xmlDumpEnumeration(buf, attr->tree);
2294 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2295 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2298 switch (attr->def) {
2299 case XML_ATTRIBUTE_NONE:
2301 case XML_ATTRIBUTE_REQUIRED:
2302 xmlBufferWriteChar(buf, " #REQUIRED");
2304 case XML_ATTRIBUTE_IMPLIED:
2305 xmlBufferWriteChar(buf, " #IMPLIED");
2307 case XML_ATTRIBUTE_FIXED:
2308 xmlBufferWriteChar(buf, " #FIXED");
2311 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2312 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2315 if (attr->defaultValue != NULL) {
2316 xmlBufferWriteChar(buf, " ");
2317 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2319 xmlBufferWriteChar(buf, ">\n");
2323 * xmlDumpAttributeDeclScan:
2324 * @attr: An attribute declaration
2325 * @buf: the XML buffer output
2327 * This is used with the hash scan function - just reverses arguments
2330 xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2331 xmlDumpAttributeDecl(buf, attr);
2335 * xmlDumpAttributeTable:
2336 * @buf: the XML buffer output
2337 * @table: An attribute table
2339 * This will dump the content of the attribute table as an XML DTD definition
2342 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2343 if ((buf == NULL) || (table == NULL))
2345 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
2347 #endif /* LIBXML_OUTPUT_ENABLED */
2349 /************************************************************************
2353 ************************************************************************/
2358 * Deallocate the memory used by an notation definition
2361 xmlFreeNotation(xmlNotationPtr nota) {
2362 if (nota == NULL) return;
2363 if (nota->name != NULL)
2364 xmlFree((xmlChar *) nota->name);
2365 if (nota->PublicID != NULL)
2366 xmlFree((xmlChar *) nota->PublicID);
2367 if (nota->SystemID != NULL)
2368 xmlFree((xmlChar *) nota->SystemID);
2374 * xmlAddNotationDecl:
2375 * @dtd: pointer to the DTD
2376 * @ctxt: the validation context
2377 * @name: the entity name
2378 * @PublicID: the public identifier or NULL
2379 * @SystemID: the system identifier or NULL
2381 * Register a new notation declaration
2383 * Returns NULL if not, otherwise the entity
2386 xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
2387 const xmlChar *name,
2388 const xmlChar *PublicID, const xmlChar *SystemID) {
2390 xmlNotationTablePtr table;
2398 if ((PublicID == NULL) && (SystemID == NULL)) {
2403 * Create the Notation table if needed.
2405 table = (xmlNotationTablePtr) dtd->notations;
2406 if (table == NULL) {
2407 xmlDictPtr dict = NULL;
2408 if (dtd->doc != NULL)
2409 dict = dtd->doc->dict;
2411 dtd->notations = table = xmlHashCreateDict(0, dict);
2413 if (table == NULL) {
2415 "xmlAddNotationDecl: Table creation failed!\n");
2419 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2421 xmlVErrMemory(ctxt, "malloc failed");
2424 memset(ret, 0, sizeof(xmlNotation));
2427 * fill the structure.
2429 ret->name = xmlStrdup(name);
2430 if (SystemID != NULL)
2431 ret->SystemID = xmlStrdup(SystemID);
2432 if (PublicID != NULL)
2433 ret->PublicID = xmlStrdup(PublicID);
2437 * Check the DTD for previous declarations of the ATTLIST
2439 if (xmlHashAddEntry(table, name, ret)) {
2440 #ifdef LIBXML_VALID_ENABLED
2441 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2442 "xmlAddNotationDecl: %s already defined\n",
2443 (const char *) name);
2444 #endif /* LIBXML_VALID_ENABLED */
2445 xmlFreeNotation(ret);
2452 * xmlFreeNotationTable:
2453 * @table: An notation table
2455 * Deallocate the memory used by an entities hash table.
2458 xmlFreeNotationTable(xmlNotationTablePtr table) {
2459 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2462 #ifdef LIBXML_TREE_ENABLED
2467 * Build a copy of a notation.
2469 * Returns the new xmlNotationPtr or NULL in case of error.
2471 static xmlNotationPtr
2472 xmlCopyNotation(xmlNotationPtr nota) {
2475 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2477 xmlVErrMemory(NULL, "malloc failed");
2480 if (nota->name != NULL)
2481 cur->name = xmlStrdup(nota->name);
2484 if (nota->PublicID != NULL)
2485 cur->PublicID = xmlStrdup(nota->PublicID);
2487 cur->PublicID = NULL;
2488 if (nota->SystemID != NULL)
2489 cur->SystemID = xmlStrdup(nota->SystemID);
2491 cur->SystemID = NULL;
2496 * xmlCopyNotationTable:
2497 * @table: A notation table
2499 * Build a copy of a notation table.
2501 * Returns the new xmlNotationTablePtr or NULL in case of error.
2504 xmlCopyNotationTable(xmlNotationTablePtr table) {
2505 return((xmlNotationTablePtr) xmlHashCopy(table,
2506 (xmlHashCopier) xmlCopyNotation));
2508 #endif /* LIBXML_TREE_ENABLED */
2510 #ifdef LIBXML_OUTPUT_ENABLED
2512 * xmlDumpNotationDecl:
2513 * @buf: the XML buffer output
2514 * @nota: A notation declaration
2516 * This will dump the content the notation declaration as an XML DTD definition
2519 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2520 if ((buf == NULL) || (nota == NULL))
2522 xmlBufferWriteChar(buf, "<!NOTATION ");
2523 xmlBufferWriteCHAR(buf, nota->name);
2524 if (nota->PublicID != NULL) {
2525 xmlBufferWriteChar(buf, " PUBLIC ");
2526 xmlBufferWriteQuotedString(buf, nota->PublicID);
2527 if (nota->SystemID != NULL) {
2528 xmlBufferWriteChar(buf, " ");
2529 xmlBufferWriteQuotedString(buf, nota->SystemID);
2532 xmlBufferWriteChar(buf, " SYSTEM ");
2533 xmlBufferWriteQuotedString(buf, nota->SystemID);
2535 xmlBufferWriteChar(buf, " >\n");
2539 * xmlDumpNotationDeclScan:
2540 * @nota: A notation declaration
2541 * @buf: the XML buffer output
2543 * This is called with the hash scan function, and just reverses args
2546 xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2547 xmlDumpNotationDecl(buf, nota);
2551 * xmlDumpNotationTable:
2552 * @buf: the XML buffer output
2553 * @table: A notation table
2555 * This will dump the content of the notation table as an XML DTD definition
2558 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2559 if ((buf == NULL) || (table == NULL))
2561 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
2563 #endif /* LIBXML_OUTPUT_ENABLED */
2565 /************************************************************************
2569 ************************************************************************/
2574 * Free a string if it is not owned by the "dict" dictionnary in the
2577 #define DICT_FREE(str) \
2578 if ((str) && ((!dict) || \
2579 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2580 xmlFree((char *)(str));
2586 * Deallocate the memory used by an id definition
2589 xmlFreeID(xmlIDPtr id) {
2590 xmlDictPtr dict = NULL;
2592 if (id == NULL) return;
2594 if (id->doc != NULL)
2595 dict = id->doc->dict;
2597 if (id->value != NULL)
2598 DICT_FREE(id->value)
2599 if (id->name != NULL)
2607 * @ctxt: the validation context
2608 * @doc: pointer to the document
2609 * @value: the value name
2610 * @attr: the attribute holding the ID
2612 * Register a new id declaration
2614 * Returns NULL if not, otherwise the new xmlIDPtr
2617 xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2620 xmlIDTablePtr table;
2625 if (value == NULL) {
2633 * Create the ID table if needed.
2635 table = (xmlIDTablePtr) doc->ids;
2636 if (table == NULL) {
2637 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2639 if (table == NULL) {
2641 "xmlAddID: Table creation failed!\n");
2645 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2647 xmlVErrMemory(ctxt, "malloc failed");
2652 * fill the structure.
2654 ret->value = xmlStrdup(value);
2656 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2658 * Operating in streaming mode, attr is gonna disapear
2660 if (doc->dict != NULL)
2661 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2663 ret->name = xmlStrdup(attr->name);
2669 ret->lineno = xmlGetLineNo(attr->parent);
2671 if (xmlHashAddEntry(table, value, ret) < 0) {
2672 #ifdef LIBXML_VALID_ENABLED
2674 * The id is already defined in this DTD.
2676 if ((ctxt != NULL) && (ctxt->error != NULL)) {
2677 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2678 "ID %s already defined\n",
2681 #endif /* LIBXML_VALID_ENABLED */
2686 attr->atype = XML_ATTRIBUTE_ID;
2692 * @table: An id table
2694 * Deallocate the memory used by an ID hash table.
2697 xmlFreeIDTable(xmlIDTablePtr table) {
2698 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2703 * @doc: the document
2704 * @elem: the element carrying the attribute
2705 * @attr: the attribute
2707 * Determine whether an attribute is of type ID. In case we have DTD(s)
2708 * then this is done if DTD loading has been requested. In the case
2709 * of HTML documents parsed with the HTML parser, then ID detection is
2710 * done systematically.
2712 * Returns 0 or 1 depending on the lookup result
2715 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2716 if ((attr == NULL) || (attr->name == NULL)) return(0);
2717 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2718 (!strcmp((char *) attr->name, "id")) &&
2719 (!strcmp((char *) attr->ns->prefix, "xml")))
2721 if (doc == NULL) return(0);
2722 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2724 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2725 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2726 ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2727 ((elem == NULL) || (!xmlStrEqual(elem->name, BAD_CAST "input")))))
2730 } else if (elem == NULL) {
2733 xmlAttributePtr attrDecl = NULL;
2735 xmlChar felem[50], fattr[50];
2736 xmlChar *fullelemname, *fullattrname;
2738 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2739 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2740 (xmlChar *)elem->name;
2742 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2743 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2744 (xmlChar *)attr->name;
2746 if (fullelemname != NULL && fullattrname != NULL) {
2747 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2749 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2750 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2754 if ((fullattrname != fattr) && (fullattrname != attr->name))
2755 xmlFree(fullattrname);
2756 if ((fullelemname != felem) && (fullelemname != elem->name))
2757 xmlFree(fullelemname);
2759 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2767 * @doc: the document
2768 * @attr: the attribute
2770 * Remove the given attribute from the ID table maintained internally.
2772 * Returns -1 if the lookup failed and 0 otherwise
2775 xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2776 xmlIDTablePtr table;
2780 if (doc == NULL) return(-1);
2781 if (attr == NULL) return(-1);
2782 table = (xmlIDTablePtr) doc->ids;
2788 ID = xmlNodeListGetString(doc, attr->children, 1);
2791 id = xmlHashLookup(table, ID);
2792 if (id == NULL || id->attr != attr) {
2796 xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
2804 * @doc: pointer to the document
2807 * Search the attribute declaring the given ID
2809 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2812 xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2813 xmlIDTablePtr table;
2824 table = (xmlIDTablePtr) doc->ids;
2828 id = xmlHashLookup(table, ID);
2831 if (id->attr == NULL) {
2833 * We are operating on a stream, return a well known reference
2834 * since the attribute node doesn't exist anymore
2836 return((xmlAttrPtr) doc);
2841 /************************************************************************
2845 ************************************************************************/
2846 typedef struct xmlRemoveMemo_t
2852 typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2854 typedef struct xmlValidateMemo_t
2856 xmlValidCtxtPtr ctxt;
2857 const xmlChar *name;
2860 typedef xmlValidateMemo *xmlValidateMemoPtr;
2866 * Deallocate the memory used by a ref definition
2869 xmlFreeRef(xmlLinkPtr lk) {
2870 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2871 if (ref == NULL) return;
2872 if (ref->value != NULL)
2873 xmlFree((xmlChar *)ref->value);
2874 if (ref->name != NULL)
2875 xmlFree((xmlChar *)ref->name);
2881 * @list_ref: A list of references.
2883 * Deallocate the memory used by a list of references
2886 xmlFreeRefList(xmlListPtr list_ref) {
2887 if (list_ref == NULL) return;
2888 xmlListDelete(list_ref);
2893 * @data: Contents of current link
2894 * @user: Value supplied by the user
2896 * Returns 0 to abort the walk or 1 to continue
2899 xmlWalkRemoveRef(const void *data, const void *user)
2901 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2902 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2903 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2905 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2906 xmlListRemoveFirst(ref_list, (void *)data);
2914 * @data0: Value supplied by the user
2915 * @data1: Value supplied by the user
2917 * Do nothing, return 0. Used to create unordered lists.
2920 xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2921 const void *data1 ATTRIBUTE_UNUSED)
2928 * @ctxt: the validation context
2929 * @doc: pointer to the document
2930 * @value: the value name
2931 * @attr: the attribute holding the Ref
2933 * Register a new ref declaration
2935 * Returns NULL if not, otherwise the new xmlRefPtr
2938 xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2941 xmlRefTablePtr table;
2942 xmlListPtr ref_list;
2947 if (value == NULL) {
2955 * Create the Ref table if needed.
2957 table = (xmlRefTablePtr) doc->refs;
2958 if (table == NULL) {
2959 doc->refs = table = xmlHashCreateDict(0, doc->dict);
2961 if (table == NULL) {
2963 "xmlAddRef: Table creation failed!\n");
2967 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2969 xmlVErrMemory(ctxt, "malloc failed");
2974 * fill the structure.
2976 ret->value = xmlStrdup(value);
2977 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2979 * Operating in streaming mode, attr is gonna disapear
2981 ret->name = xmlStrdup(attr->name);
2987 ret->lineno = xmlGetLineNo(attr->parent);
2989 /* To add a reference :-
2990 * References are maintained as a list of references,
2991 * Lookup the entry, if no entry create new nodelist
2992 * Add the owning node to the NodeList
2996 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2997 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
2998 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2999 "xmlAddRef: Reference list creation failed!\n",
3003 if (xmlHashAddEntry(table, value, ref_list) < 0) {
3004 xmlListDelete(ref_list);
3005 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3006 "xmlAddRef: Reference list insertion failed!\n",
3011 /* xmlListInsert(ref_list, ret); */
3012 xmlListAppend(ref_list, ret);
3018 * @table: An ref table
3020 * Deallocate the memory used by an Ref hash table.
3023 xmlFreeRefTable(xmlRefTablePtr table) {
3024 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
3029 * @doc: the document
3030 * @elem: the element carrying the attribute
3031 * @attr: the attribute
3033 * Determine whether an attribute is of type Ref. In case we have DTD(s)
3034 * then this is simple, otherwise we use an heuristic: name Ref (upper
3037 * Returns 0 or 1 depending on the lookup result
3040 xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
3045 if (doc == NULL) return(0);
3048 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3050 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3054 xmlAttributePtr attrDecl;
3056 if (elem == NULL) return(0);
3057 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3058 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3059 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3060 elem->name, attr->name);
3062 if ((attrDecl != NULL) &&
3063 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3064 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3072 * @doc: the document
3073 * @attr: the attribute
3075 * Remove the given attribute from the Ref table maintained internally.
3077 * Returns -1 if the lookup failed and 0 otherwise
3080 xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
3081 xmlListPtr ref_list;
3082 xmlRefTablePtr table;
3084 xmlRemoveMemo target;
3086 if (doc == NULL) return(-1);
3087 if (attr == NULL) return(-1);
3088 table = (xmlRefTablePtr) doc->refs;
3094 ID = xmlNodeListGetString(doc, attr->children, 1);
3097 ref_list = xmlHashLookup(table, ID);
3099 if(ref_list == NULL) {
3103 /* At this point, ref_list refers to a list of references which
3104 * have the same key as the supplied attr. Our list of references
3105 * is ordered by reference address and we don't have that information
3106 * here to use when removing. We'll have to walk the list and
3107 * check for a matching attribute, when we find one stop the walk
3108 * and remove the entry.
3109 * The list is ordered by reference, so that means we don't have the
3110 * key. Passing the list and the reference to the walker means we
3111 * will have enough data to be able to remove the entry.
3113 target.l = ref_list;
3116 /* Remove the supplied attr from our list */
3117 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3119 /*If the list is empty then remove the list entry in the hash */
3120 if (xmlListEmpty(ref_list))
3121 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3129 * @doc: pointer to the document
3132 * Find the set of references for the supplied ID.
3134 * Returns NULL if not found, otherwise node set for the ID.
3137 xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
3138 xmlRefTablePtr table;
3148 table = (xmlRefTablePtr) doc->refs;
3152 return (xmlHashLookup(table, ID));
3155 /************************************************************************
3157 * Routines for validity checking *
3159 ************************************************************************/
3162 * xmlGetDtdElementDesc:
3163 * @dtd: a pointer to the DtD to search
3164 * @name: the element name
3166 * Search the DTD for the description of this element
3168 * returns the xmlElementPtr if found or NULL
3172 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3173 xmlElementTablePtr table;
3175 xmlChar *uqname = NULL, *prefix = NULL;
3177 if ((dtd == NULL) || (name == NULL)) return(NULL);
3178 if (dtd->elements == NULL)
3180 table = (xmlElementTablePtr) dtd->elements;
3182 uqname = xmlSplitQName2(name, &prefix);
3185 cur = xmlHashLookup2(table, name, prefix);
3186 if (prefix != NULL) xmlFree(prefix);
3187 if (uqname != NULL) xmlFree(uqname);
3191 * xmlGetDtdElementDesc2:
3192 * @dtd: a pointer to the DtD to search
3193 * @name: the element name
3194 * @create: create an empty description if not found
3196 * Search the DTD for the description of this element
3198 * returns the xmlElementPtr if found or NULL
3201 static xmlElementPtr
3202 xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3203 xmlElementTablePtr table;
3205 xmlChar *uqname = NULL, *prefix = NULL;
3207 if (dtd == NULL) return(NULL);
3208 if (dtd->elements == NULL) {
3209 xmlDictPtr dict = NULL;
3211 if (dtd->doc != NULL)
3212 dict = dtd->doc->dict;
3217 * Create the Element table if needed.
3219 table = (xmlElementTablePtr) dtd->elements;
3220 if (table == NULL) {
3221 table = xmlHashCreateDict(0, dict);
3222 dtd->elements = (void *) table;
3224 if (table == NULL) {
3225 xmlVErrMemory(NULL, "element table allocation failed");
3229 table = (xmlElementTablePtr) dtd->elements;
3231 uqname = xmlSplitQName2(name, &prefix);
3234 cur = xmlHashLookup2(table, name, prefix);
3235 if ((cur == NULL) && (create)) {
3236 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3238 xmlVErrMemory(NULL, "malloc failed");
3241 memset(cur, 0, sizeof(xmlElement));
3242 cur->type = XML_ELEMENT_DECL;
3245 * fill the structure.
3247 cur->name = xmlStrdup(name);
3248 cur->prefix = xmlStrdup(prefix);
3249 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3251 xmlHashAddEntry2(table, name, prefix, cur);
3253 if (prefix != NULL) xmlFree(prefix);
3254 if (uqname != NULL) xmlFree(uqname);
3259 * xmlGetDtdQElementDesc:
3260 * @dtd: a pointer to the DtD to search
3261 * @name: the element name
3262 * @prefix: the element namespace prefix
3264 * Search the DTD for the description of this element
3266 * returns the xmlElementPtr if found or NULL
3270 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3271 const xmlChar *prefix) {
3272 xmlElementTablePtr table;
3274 if (dtd == NULL) return(NULL);
3275 if (dtd->elements == NULL) return(NULL);
3276 table = (xmlElementTablePtr) dtd->elements;
3278 return(xmlHashLookup2(table, name, prefix));
3282 * xmlGetDtdAttrDesc:
3283 * @dtd: a pointer to the DtD to search
3284 * @elem: the element name
3285 * @name: the attribute name
3287 * Search the DTD for the description of this attribute on
3290 * returns the xmlAttributePtr if found or NULL
3294 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3295 xmlAttributeTablePtr table;
3296 xmlAttributePtr cur;
3297 xmlChar *uqname = NULL, *prefix = NULL;
3299 if (dtd == NULL) return(NULL);
3300 if (dtd->attributes == NULL) return(NULL);
3302 table = (xmlAttributeTablePtr) dtd->attributes;
3306 uqname = xmlSplitQName2(name, &prefix);
3308 if (uqname != NULL) {
3309 cur = xmlHashLookup3(table, uqname, prefix, elem);
3310 if (prefix != NULL) xmlFree(prefix);
3311 if (uqname != NULL) xmlFree(uqname);
3313 cur = xmlHashLookup3(table, name, NULL, elem);
3318 * xmlGetDtdQAttrDesc:
3319 * @dtd: a pointer to the DtD to search
3320 * @elem: the element name
3321 * @name: the attribute name
3322 * @prefix: the attribute namespace prefix
3324 * Search the DTD for the description of this qualified attribute on
3327 * returns the xmlAttributePtr if found or NULL
3331 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3332 const xmlChar *prefix) {
3333 xmlAttributeTablePtr table;
3335 if (dtd == NULL) return(NULL);
3336 if (dtd->attributes == NULL) return(NULL);
3337 table = (xmlAttributeTablePtr) dtd->attributes;
3339 return(xmlHashLookup3(table, name, prefix, elem));
3343 * xmlGetDtdNotationDesc:
3344 * @dtd: a pointer to the DtD to search
3345 * @name: the notation name
3347 * Search the DTD for the description of this notation
3349 * returns the xmlNotationPtr if found or NULL
3353 xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3354 xmlNotationTablePtr table;
3356 if (dtd == NULL) return(NULL);
3357 if (dtd->notations == NULL) return(NULL);
3358 table = (xmlNotationTablePtr) dtd->notations;
3360 return(xmlHashLookup(table, name));
3363 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3365 * xmlValidateNotationUse:
3366 * @ctxt: the validation context
3367 * @doc: the document
3368 * @notationName: the notation name to check
3370 * Validate that the given name match a notation declaration.
3371 * - [ VC: Notation Declared ]
3373 * returns 1 if valid or 0 otherwise
3377 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3378 const xmlChar *notationName) {
3379 xmlNotationPtr notaDecl;
3380 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3382 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3383 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3384 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3386 if ((notaDecl == NULL) && (ctxt != NULL)) {
3387 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3388 "NOTATION %s is not declared\n",
3389 notationName, NULL, NULL);
3394 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3397 * xmlIsMixedElement:
3398 * @doc: the document
3399 * @name: the element name
3401 * Search in the DtDs whether an element accept Mixed content (or ANY)
3402 * basically if it is supposed to accept text childs
3404 * returns 0 if no, 1 if yes, and -1 if no element description is available
3408 xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3409 xmlElementPtr elemDecl;
3411 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3413 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3414 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3415 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3416 if (elemDecl == NULL) return(-1);
3417 switch (elemDecl->etype) {
3418 case XML_ELEMENT_TYPE_UNDEFINED:
3420 case XML_ELEMENT_TYPE_ELEMENT:
3422 case XML_ELEMENT_TYPE_EMPTY:
3424 * return 1 for EMPTY since we want VC error to pop up
3425 * on <empty> </empty> for example
3427 case XML_ELEMENT_TYPE_ANY:
3428 case XML_ELEMENT_TYPE_MIXED:
3434 #ifdef LIBXML_VALID_ENABLED
3436 * xmlValidateNameValue:
3437 * @value: an Name value
3439 * Validate that the given value match Name production
3441 * returns 1 if valid or 0 otherwise
3445 xmlValidateNameValue(const xmlChar *value) {
3449 if (value == NULL) return(0);
3451 val = xmlStringCurrentChar(NULL, cur, &len);
3453 if (!IS_LETTER(val) && (val != '_') &&
3458 val = xmlStringCurrentChar(NULL, cur, &len);
3460 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3461 (val == '.') || (val == '-') ||
3462 (val == '_') || (val == ':') ||
3463 (IS_COMBINING(val)) ||
3464 (IS_EXTENDER(val))) {
3465 val = xmlStringCurrentChar(NULL, cur, &len);
3469 if (val != 0) return(0);
3475 * xmlValidateNamesValue:
3476 * @value: an Names value
3478 * Validate that the given value match Names production
3480 * returns 1 if valid or 0 otherwise
3484 xmlValidateNamesValue(const xmlChar *value) {
3488 if (value == NULL) return(0);
3490 val = xmlStringCurrentChar(NULL, cur, &len);
3493 if (!IS_LETTER(val) && (val != '_') &&
3498 val = xmlStringCurrentChar(NULL, cur, &len);
3500 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3501 (val == '.') || (val == '-') ||
3502 (val == '_') || (val == ':') ||
3503 (IS_COMBINING(val)) ||
3504 (IS_EXTENDER(val))) {
3505 val = xmlStringCurrentChar(NULL, cur, &len);
3509 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3510 while (val == 0x20) {
3511 while (val == 0x20) {
3512 val = xmlStringCurrentChar(NULL, cur, &len);
3516 if (!IS_LETTER(val) && (val != '_') &&
3520 val = xmlStringCurrentChar(NULL, cur, &len);
3523 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3524 (val == '.') || (val == '-') ||
3525 (val == '_') || (val == ':') ||
3526 (IS_COMBINING(val)) ||
3527 (IS_EXTENDER(val))) {
3528 val = xmlStringCurrentChar(NULL, cur, &len);
3533 if (val != 0) return(0);
3539 * xmlValidateNmtokenValue:
3540 * @value: an Nmtoken value
3542 * Validate that the given value match Nmtoken production
3544 * [ VC: Name Token ]
3546 * returns 1 if valid or 0 otherwise
3550 xmlValidateNmtokenValue(const xmlChar *value) {
3554 if (value == NULL) return(0);
3556 val = xmlStringCurrentChar(NULL, cur, &len);
3559 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3560 (val != '.') && (val != '-') &&
3561 (val != '_') && (val != ':') &&
3562 (!IS_COMBINING(val)) &&
3563 (!IS_EXTENDER(val)))
3566 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3567 (val == '.') || (val == '-') ||
3568 (val == '_') || (val == ':') ||
3569 (IS_COMBINING(val)) ||
3570 (IS_EXTENDER(val))) {
3571 val = xmlStringCurrentChar(NULL, cur, &len);
3575 if (val != 0) return(0);
3581 * xmlValidateNmtokensValue:
3582 * @value: an Nmtokens value
3584 * Validate that the given value match Nmtokens production
3586 * [ VC: Name Token ]
3588 * returns 1 if valid or 0 otherwise
3592 xmlValidateNmtokensValue(const xmlChar *value) {
3596 if (value == NULL) return(0);
3598 val = xmlStringCurrentChar(NULL, cur, &len);
3601 while (IS_BLANK(val)) {
3602 val = xmlStringCurrentChar(NULL, cur, &len);
3606 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3607 (val != '.') && (val != '-') &&
3608 (val != '_') && (val != ':') &&
3609 (!IS_COMBINING(val)) &&
3610 (!IS_EXTENDER(val)))
3613 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3614 (val == '.') || (val == '-') ||
3615 (val == '_') || (val == ':') ||
3616 (IS_COMBINING(val)) ||
3617 (IS_EXTENDER(val))) {
3618 val = xmlStringCurrentChar(NULL, cur, &len);
3622 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3623 while (val == 0x20) {
3624 while (val == 0x20) {
3625 val = xmlStringCurrentChar(NULL, cur, &len);
3628 if (val == 0) return(1);
3630 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3631 (val != '.') && (val != '-') &&
3632 (val != '_') && (val != ':') &&
3633 (!IS_COMBINING(val)) &&
3634 (!IS_EXTENDER(val)))
3637 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3638 (val == '.') || (val == '-') ||
3639 (val == '_') || (val == ':') ||
3640 (IS_COMBINING(val)) ||
3641 (IS_EXTENDER(val))) {
3642 val = xmlStringCurrentChar(NULL, cur, &len);
3647 if (val != 0) return(0);
3653 * xmlValidateNotationDecl:
3654 * @ctxt: the validation context
3655 * @doc: a document instance
3656 * @nota: a notation definition
3658 * Try to validate a single notation definition
3659 * basically it does the following checks as described by the
3660 * XML-1.0 recommendation:
3661 * - it seems that no validity constraint exists on notation declarations
3662 * But this function get called anyway ...
3664 * returns 1 if valid or 0 otherwise
3668 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3669 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3676 * xmlValidateAttributeValue:
3677 * @type: an attribute type
3678 * @value: an attribute value
3680 * Validate that the given attribute value match the proper production
3683 * Values of type ID must match the Name production....
3686 * Values of type IDREF must match the Name production, and values
3687 * of type IDREFS must match Names ...
3689 * [ VC: Entity Name ]
3690 * Values of type ENTITY must match the Name production, values
3691 * of type ENTITIES must match Names ...
3693 * [ VC: Name Token ]
3694 * Values of type NMTOKEN must match the Nmtoken production; values
3695 * of type NMTOKENS must match Nmtokens.
3697 * returns 1 if valid or 0 otherwise
3701 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3703 case XML_ATTRIBUTE_ENTITIES:
3704 case XML_ATTRIBUTE_IDREFS:
3705 return(xmlValidateNamesValue(value));
3706 case XML_ATTRIBUTE_ENTITY:
3707 case XML_ATTRIBUTE_IDREF:
3708 case XML_ATTRIBUTE_ID:
3709 case XML_ATTRIBUTE_NOTATION:
3710 return(xmlValidateNameValue(value));
3711 case XML_ATTRIBUTE_NMTOKENS:
3712 case XML_ATTRIBUTE_ENUMERATION:
3713 return(xmlValidateNmtokensValue(value));
3714 case XML_ATTRIBUTE_NMTOKEN:
3715 return(xmlValidateNmtokenValue(value));
3716 case XML_ATTRIBUTE_CDATA:
3723 * xmlValidateAttributeValue2:
3724 * @ctxt: the validation context
3725 * @doc: the document
3726 * @name: the attribute name (used for error reporting only)
3727 * @type: the attribute type
3728 * @value: the attribute value
3730 * Validate that the given attribute value match a given type.
3731 * This typically cannot be done before having finished parsing
3735 * Values of type IDREF must match one of the declared IDs
3736 * Values of type IDREFS must match a sequence of the declared IDs
3737 * each Name must match the value of an ID attribute on some element
3738 * in the XML document; i.e. IDREF values must match the value of
3741 * [ VC: Entity Name ]
3742 * Values of type ENTITY must match one declared entity
3743 * Values of type ENTITIES must match a sequence of declared entities
3745 * [ VC: Notation Attributes ]
3746 * all notation names in the declaration must be declared.
3748 * returns 1 if valid or 0 otherwise
3752 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3753 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3756 case XML_ATTRIBUTE_IDREFS:
3757 case XML_ATTRIBUTE_IDREF:
3758 case XML_ATTRIBUTE_ID:
3759 case XML_ATTRIBUTE_NMTOKENS:
3760 case XML_ATTRIBUTE_ENUMERATION:
3761 case XML_ATTRIBUTE_NMTOKEN:
3762 case XML_ATTRIBUTE_CDATA:
3764 case XML_ATTRIBUTE_ENTITY: {
3767 ent = xmlGetDocEntity(doc, value);
3768 /* yeah it's a bit messy... */
3769 if ((ent == NULL) && (doc->standalone == 1)) {
3770 doc->standalone = 0;
3771 ent = xmlGetDocEntity(doc, value);
3774 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3775 XML_DTD_UNKNOWN_ENTITY,
3776 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3779 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3780 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3781 XML_DTD_ENTITY_TYPE,
3782 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3788 case XML_ATTRIBUTE_ENTITIES: {
3789 xmlChar *dup, *nam = NULL, *cur, save;
3792 dup = xmlStrdup(value);
3798 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
3801 ent = xmlGetDocEntity(doc, nam);
3803 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3804 XML_DTD_UNKNOWN_ENTITY,
3805 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3808 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3809 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3810 XML_DTD_ENTITY_TYPE,
3811 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3818 while (IS_BLANK_CH(*cur)) cur++;
3823 case XML_ATTRIBUTE_NOTATION: {
3824 xmlNotationPtr nota;
3826 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3827 if ((nota == NULL) && (doc->extSubset != NULL))
3828 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3831 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3832 XML_DTD_UNKNOWN_NOTATION,
3833 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3844 * xmlValidCtxtNormalizeAttributeValue:
3845 * @ctxt: the validation context
3846 * @doc: the document
3848 * @name: the attribute name
3849 * @value: the attribute value
3850 * @ctxt: the validation context or NULL
3852 * Does the validation related extra step of the normalization of attribute
3855 * If the declared value is not CDATA, then the XML processor must further
3856 * process the normalized attribute value by discarding any leading and
3857 * trailing space (#x20) characters, and by replacing sequences of space
3858 * (#x20) characters by single space (#x20) character.
3860 * Also check VC: Standalone Document Declaration in P32, and update
3861 * ctxt->valid accordingly
3863 * returns a new normalized string if normalization is needed, NULL otherwise
3864 * the caller must free the returned value.
3868 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3869 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3872 xmlAttributePtr attrDecl = NULL;
3875 if (doc == NULL) return(NULL);
3876 if (elem == NULL) return(NULL);
3877 if (name == NULL) return(NULL);
3878 if (value == NULL) return(NULL);
3880 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3884 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3885 if (fullname == NULL)
3887 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
3888 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3889 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3890 if (attrDecl != NULL)
3893 if ((fullname != fn) && (fullname != elem->name))
3896 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3897 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3898 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3899 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3900 if (attrDecl != NULL)
3904 if (attrDecl == NULL)
3906 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3909 ret = xmlStrdup(value);
3914 while (*src == 0x20) src++;
3917 while (*src == 0x20) src++;
3925 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
3926 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
3927 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
3928 name, elem->name, NULL);
3935 * xmlValidNormalizeAttributeValue:
3936 * @doc: the document
3938 * @name: the attribute name
3939 * @value: the attribute value
3941 * Does the validation related extra step of the normalization of attribute
3944 * If the declared value is not CDATA, then the XML processor must further
3945 * process the normalized attribute value by discarding any leading and
3946 * trailing space (#x20) characters, and by replacing sequences of space
3947 * (#x20) characters by single space (#x20) character.
3949 * Returns a new normalized string if normalization is needed, NULL otherwise
3950 * the caller must free the returned value.
3954 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3955 const xmlChar *name, const xmlChar *value) {
3958 xmlAttributePtr attrDecl = NULL;
3960 if (doc == NULL) return(NULL);
3961 if (elem == NULL) return(NULL);
3962 if (name == NULL) return(NULL);
3963 if (value == NULL) return(NULL);
3965 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3969 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3970 if (fullname == NULL)
3972 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
3973 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3974 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3975 if ((fullname != fn) && (fullname != elem->name))
3978 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3979 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3980 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3982 if (attrDecl == NULL)
3984 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3987 ret = xmlStrdup(value);
3992 while (*src == 0x20) src++;
3995 while (*src == 0x20) src++;
4007 xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
4008 const xmlChar* name ATTRIBUTE_UNUSED) {
4009 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4013 * xmlValidateAttributeDecl:
4014 * @ctxt: the validation context
4015 * @doc: a document instance
4016 * @attr: an attribute definition
4018 * Try to validate a single attribute definition
4019 * basically it does the following checks as described by the
4020 * XML-1.0 recommendation:
4021 * - [ VC: Attribute Default Legal ]
4022 * - [ VC: Enumeration ]
4023 * - [ VC: ID Attribute Default ]
4025 * The ID/IDREF uniqueness and matching are done separately
4027 * returns 1 if valid or 0 otherwise
4031 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4032 xmlAttributePtr attr) {
4036 if(attr == NULL) return(1);
4038 /* Attribute Default Legal */
4040 if (attr->defaultValue != NULL) {
4041 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
4043 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4044 "Syntax of default value for attribute %s of %s is not valid\n",
4045 attr->name, attr->elem, NULL);
4050 /* ID Attribute Default */
4051 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4052 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4053 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4054 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4055 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4056 attr->name, attr->elem, NULL);
4060 /* One ID per Element Type */
4061 if (attr->atype == XML_ATTRIBUTE_ID) {
4064 /* the trick is that we parse DtD as their own internal subset */
4065 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4068 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4070 xmlAttributeTablePtr table;
4073 * The attribute may be declared in the internal subset and the
4074 * element in the external subset.
4077 if (doc->intSubset != NULL) {
4078 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4079 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4080 xmlValidateAttributeIdCallback, &nbId);
4085 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4086 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4087 attr->elem, nbId, attr->name);
4088 } else if (doc->extSubset != NULL) {
4090 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4092 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4095 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4096 "Element %s has %d ID attribute defined in the external subset : %s\n",
4097 attr->elem, extId, attr->name);
4098 } else if (extId + nbId > 1) {
4099 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4100 "Element %s has ID attributes defined in the internal and external subset : %s\n",
4101 attr->elem, attr->name, NULL);
4106 /* Validity Constraint: Enumeration */
4107 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4108 xmlEnumerationPtr tree = attr->tree;
4109 while (tree != NULL) {
4110 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4114 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4115 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4116 attr->defaultValue, attr->name, attr->elem);
4125 * xmlValidateElementDecl:
4126 * @ctxt: the validation context
4127 * @doc: a document instance
4128 * @elem: an element definition
4130 * Try to validate a single element definition
4131 * basically it does the following checks as described by the
4132 * XML-1.0 recommendation:
4133 * - [ VC: One ID per Element Type ]
4134 * - [ VC: No Duplicate Types ]
4135 * - [ VC: Unique Element Type Declaration ]
4137 * returns 1 if valid or 0 otherwise
4141 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4142 xmlElementPtr elem) {
4148 if (elem == NULL) return(1);
4151 #ifdef LIBXML_REGEXP_ENABLED
4152 /* Build the regexp associated to the content model */
4153 ret = xmlValidBuildContentModel(ctxt, elem);
4157 /* No Duplicate Types */
4158 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4159 xmlElementContentPtr cur, next;
4160 const xmlChar *name;
4162 cur = elem->content;
4163 while (cur != NULL) {
4164 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4165 if (cur->c1 == NULL) break;
4166 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4167 name = cur->c1->name;
4169 while (next != NULL) {
4170 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4171 if ((xmlStrEqual(next->name, name)) &&
4172 (xmlStrEqual(next->prefix, cur->prefix))) {
4173 if (cur->prefix == NULL) {
4174 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4175 "Definition of %s has duplicate references of %s\n",
4176 elem->name, name, NULL);
4178 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4179 "Definition of %s has duplicate references of %s:%s\n",
4180 elem->name, cur->prefix, name);
4186 if (next->c1 == NULL) break;
4187 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4188 if ((xmlStrEqual(next->c1->name, name)) &&
4189 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
4190 if (cur->prefix == NULL) {
4191 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4192 "Definition of %s has duplicate references to %s\n",
4193 elem->name, name, NULL);
4195 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4196 "Definition of %s has duplicate references to %s:%s\n",
4197 elem->name, cur->prefix, name);
4208 /* VC: Unique Element Type Declaration */
4209 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4210 if ((tst != NULL ) && (tst != elem) &&
4211 ((tst->prefix == elem->prefix) ||
4212 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4213 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4214 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4215 "Redefinition of element %s\n",
4216 elem->name, NULL, NULL);
4219 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4220 if ((tst != NULL ) && (tst != elem) &&
4221 ((tst->prefix == elem->prefix) ||
4222 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4223 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4224 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4225 "Redefinition of element %s\n",
4226 elem->name, NULL, NULL);
4229 /* One ID per Element Type
4230 * already done when registering the attribute
4231 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4238 * xmlValidateOneAttribute:
4239 * @ctxt: the validation context
4240 * @doc: a document instance
4241 * @elem: an element instance
4242 * @attr: an attribute instance
4243 * @value: the attribute value (without entities processing)
4245 * Try to validate a single attribute for an element
4246 * basically it does the following checks as described by the
4247 * XML-1.0 recommendation:
4248 * - [ VC: Attribute Value Type ]
4249 * - [ VC: Fixed Attribute Default ]
4250 * - [ VC: Entity Name ]
4251 * - [ VC: Name Token ]
4254 * - [ VC: Entity Name ]
4255 * - [ VC: Notation Attributes ]
4257 * The ID/IDREF uniqueness and matching are done separately
4259 * returns 1 if valid or 0 otherwise
4263 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4264 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4266 xmlAttributePtr attrDecl = NULL;
4271 if ((elem == NULL) || (elem->name == NULL)) return(0);
4272 if ((attr == NULL) || (attr->name == NULL)) return(0);
4274 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4278 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4279 if (fullname == NULL)
4281 if (attr->ns != NULL) {
4282 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4283 attr->name, attr->ns->prefix);
4284 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4285 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4286 attr->name, attr->ns->prefix);
4288 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4289 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4290 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4291 fullname, attr->name);
4293 if ((fullname != fn) && (fullname != elem->name))
4296 if (attrDecl == NULL) {
4297 if (attr->ns != NULL) {
4298 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4299 attr->name, attr->ns->prefix);
4300 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4301 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4302 attr->name, attr->ns->prefix);
4304 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4305 elem->name, attr->name);
4306 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4307 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4308 elem->name, attr->name);
4313 /* Validity Constraint: Attribute Value Type */
4314 if (attrDecl == NULL) {
4315 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4316 "No declaration for attribute %s of element %s\n",
4317 attr->name, elem->name, NULL);
4320 attr->atype = attrDecl->atype;
4322 val = xmlValidateAttributeValue(attrDecl->atype, value);
4324 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4325 "Syntax of value for attribute %s of %s is not valid\n",
4326 attr->name, elem->name, NULL);
4330 /* Validity constraint: Fixed Attribute Default */
4331 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4332 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4333 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4334 "Value for attribute %s of %s is different from default \"%s\"\n",
4335 attr->name, elem->name, attrDecl->defaultValue);
4340 /* Validity Constraint: ID uniqueness */
4341 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4342 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4346 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4347 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4348 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4352 /* Validity Constraint: Notation Attributes */
4353 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4354 xmlEnumerationPtr tree = attrDecl->tree;
4355 xmlNotationPtr nota;
4357 /* First check that the given NOTATION was declared */
4358 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4360 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4363 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4364 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4365 value, attr->name, elem->name);
4369 /* Second, verify that it's among the list */
4370 while (tree != NULL) {
4371 if (xmlStrEqual(tree->name, value)) break;
4375 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4376 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4377 value, attr->name, elem->name);
4382 /* Validity Constraint: Enumeration */
4383 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4384 xmlEnumerationPtr tree = attrDecl->tree;
4385 while (tree != NULL) {
4386 if (xmlStrEqual(tree->name, value)) break;
4390 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4391 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4392 value, attr->name, elem->name);
4397 /* Fixed Attribute Default */
4398 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4399 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4400 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4401 "Value for attribute %s of %s must be \"%s\"\n",
4402 attr->name, elem->name, attrDecl->defaultValue);
4406 /* Extra check for the attribute value */
4407 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4408 attrDecl->atype, value);
4414 * xmlValidateOneNamespace:
4415 * @ctxt: the validation context
4416 * @doc: a document instance
4417 * @elem: an element instance
4418 * @prefix: the namespace prefix
4419 * @ns: an namespace declaration instance
4420 * @value: the attribute value (without entities processing)
4422 * Try to validate a single namespace declaration for an element
4423 * basically it does the following checks as described by the
4424 * XML-1.0 recommendation:
4425 * - [ VC: Attribute Value Type ]
4426 * - [ VC: Fixed Attribute Default ]
4427 * - [ VC: Entity Name ]
4428 * - [ VC: Name Token ]
4431 * - [ VC: Entity Name ]
4432 * - [ VC: Notation Attributes ]
4434 * The ID/IDREF uniqueness and matching are done separately
4436 * returns 1 if valid or 0 otherwise
4440 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4441 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4442 /* xmlElementPtr elemDecl; */
4443 xmlAttributePtr attrDecl = NULL;
4448 if ((elem == NULL) || (elem->name == NULL)) return(0);
4449 if ((ns == NULL) || (ns->href == NULL)) return(0);
4451 if (prefix != NULL) {
4455 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4456 if (fullname == NULL) {
4457 xmlVErrMemory(ctxt, "Validating namespace");
4460 if (ns->prefix != NULL) {
4461 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4462 ns->prefix, BAD_CAST "xmlns");
4463 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4464 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4465 ns->prefix, BAD_CAST "xmlns");
4467 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4469 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4470 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4473 if ((fullname != fn) && (fullname != elem->name))
4476 if (attrDecl == NULL) {
4477 if (ns->prefix != NULL) {
4478 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4479 ns->prefix, BAD_CAST "xmlns");
4480 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4481 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4482 ns->prefix, BAD_CAST "xmlns");
4484 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4485 elem->name, BAD_CAST "xmlns");
4486 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4487 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4488 elem->name, BAD_CAST "xmlns");
4493 /* Validity Constraint: Attribute Value Type */
4494 if (attrDecl == NULL) {
4495 if (ns->prefix != NULL) {
4496 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4497 "No declaration for attribute xmlns:%s of element %s\n",
4498 ns->prefix, elem->name, NULL);
4500 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4501 "No declaration for attribute xmlns of element %s\n",
4502 elem->name, NULL, NULL);
4507 val = xmlValidateAttributeValue(attrDecl->atype, value);
4509 if (ns->prefix != NULL) {
4510 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4511 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4512 ns->prefix, elem->name, NULL);
4514 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4515 "Syntax of value for attribute xmlns of %s is not valid\n",
4516 elem->name, NULL, NULL);
4521 /* Validity constraint: Fixed Attribute Default */
4522 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4523 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4524 if (ns->prefix != NULL) {
4525 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4526 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4527 ns->prefix, elem->name, attrDecl->defaultValue);
4529 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4530 "Value for attribute xmlns of %s is different from default \"%s\"\n",
4531 elem->name, attrDecl->defaultValue, NULL);
4537 /* Validity Constraint: ID uniqueness */
4538 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4539 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4543 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4544 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4545 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4549 /* Validity Constraint: Notation Attributes */
4550 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4551 xmlEnumerationPtr tree = attrDecl->tree;
4552 xmlNotationPtr nota;
4554 /* First check that the given NOTATION was declared */
4555 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4557 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4560 if (ns->prefix != NULL) {
4561 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4562 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4563 value, ns->prefix, elem->name);
4565 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4566 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4567 value, elem->name, NULL);
4572 /* Second, verify that it's among the list */
4573 while (tree != NULL) {
4574 if (xmlStrEqual(tree->name, value)) break;
4578 if (ns->prefix != NULL) {
4579 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4580 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4581 value, ns->prefix, elem->name);
4583 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4584 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4585 value, elem->name, NULL);
4591 /* Validity Constraint: Enumeration */
4592 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4593 xmlEnumerationPtr tree = attrDecl->tree;
4594 while (tree != NULL) {
4595 if (xmlStrEqual(tree->name, value)) break;
4599 if (ns->prefix != NULL) {
4600 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4601 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4602 value, ns->prefix, elem->name);
4604 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4605 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4606 value, elem->name, NULL);
4612 /* Fixed Attribute Default */
4613 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4614 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4615 if (ns->prefix != NULL) {
4616 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4617 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4618 ns->prefix, elem->name, attrDecl->defaultValue);
4620 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4621 "Value for attribute xmlns of %s must be \"%s\"\n",
4622 elem->name, attrDecl->defaultValue, NULL);
4627 /* Extra check for the attribute value */
4628 if (ns->prefix != NULL) {
4629 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4630 attrDecl->atype, value);
4632 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4633 attrDecl->atype, value);
4639 #ifndef LIBXML_REGEXP_ENABLED
4641 * xmlValidateSkipIgnorable:
4642 * @ctxt: the validation context
4643 * @child: the child list
4645 * Skip ignorable elements w.r.t. the validation process
4647 * returns the first element to consider for validation of the content model
4651 xmlValidateSkipIgnorable(xmlNodePtr child) {
4652 while (child != NULL) {
4653 switch (child->type) {
4654 /* These things are ignored (skipped) during validation. */
4656 case XML_COMMENT_NODE:
4657 case XML_XINCLUDE_START:
4658 case XML_XINCLUDE_END:
4659 child = child->next;
4662 if (xmlIsBlankNode(child))
4663 child = child->next;
4667 /* keep current node */
4676 * xmlValidateElementType:
4677 * @ctxt: the validation context
4679 * Try to validate the content model of an element internal function
4681 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4682 * reference is found and -3 if the validation succeeded but
4683 * the content model is not determinist.
4687 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4689 int determinist = 1;
4691 NODE = xmlValidateSkipIgnorable(NODE);
4692 if ((NODE == NULL) && (CONT == NULL))
4694 if ((NODE == NULL) &&
4695 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4696 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4699 if (CONT == NULL) return(-1);
4700 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4704 * We arrive here when more states need to be examined
4709 * We just recovered from a rollback generated by a possible
4710 * epsilon transition, go directly to the analysis phase
4712 if (STATE == ROLLBACK_PARENT) {
4713 DEBUG_VALID_MSG("restored parent branch");
4714 DEBUG_VALID_STATE(NODE, CONT)
4719 DEBUG_VALID_STATE(NODE, CONT)
4721 * we may have to save a backup state here. This is the equivalent
4722 * of handling epsilon transition in NFAs.
4724 if ((CONT != NULL) &&
4725 ((CONT->parent == NULL) ||
4726 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4727 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4728 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4729 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4730 DEBUG_VALID_MSG("saving parent branch");
4731 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4737 * Check first if the content matches
4739 switch (CONT->type) {
4740 case XML_ELEMENT_CONTENT_PCDATA:
4742 DEBUG_VALID_MSG("pcdata failed no node");
4746 if (NODE->type == XML_TEXT_NODE) {
4747 DEBUG_VALID_MSG("pcdata found, skip to next");
4749 * go to next element in the content model
4750 * skipping ignorable elems
4754 NODE = xmlValidateSkipIgnorable(NODE);
4755 if ((NODE != NULL) &&
4756 (NODE->type == XML_ENTITY_REF_NODE))
4758 } while ((NODE != NULL) &&
4759 ((NODE->type != XML_ELEMENT_NODE) &&
4760 (NODE->type != XML_TEXT_NODE) &&
4761 (NODE->type != XML_CDATA_SECTION_NODE)));
4765 DEBUG_VALID_MSG("pcdata failed");
4770 case XML_ELEMENT_CONTENT_ELEMENT:
4772 DEBUG_VALID_MSG("element failed no node");
4776 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4777 (xmlStrEqual(NODE->name, CONT->name)));
4779 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4780 ret = (CONT->prefix == NULL);
4781 } else if (CONT->prefix == NULL) {
4784 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4788 DEBUG_VALID_MSG("element found, skip to next");
4790 * go to next element in the content model
4791 * skipping ignorable elems
4795 NODE = xmlValidateSkipIgnorable(NODE);
4796 if ((NODE != NULL) &&
4797 (NODE->type == XML_ENTITY_REF_NODE))
4799 } while ((NODE != NULL) &&
4800 ((NODE->type != XML_ELEMENT_NODE) &&
4801 (NODE->type != XML_TEXT_NODE) &&
4802 (NODE->type != XML_CDATA_SECTION_NODE)));
4804 DEBUG_VALID_MSG("element failed");
4809 case XML_ELEMENT_CONTENT_OR:
4811 * Small optimization.
4813 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4814 if ((NODE == NULL) ||
4815 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4820 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4821 ret = (CONT->c1->prefix == NULL);
4822 } else if (CONT->c1->prefix == NULL) {
4825 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4835 * save the second branch 'or' branch
4837 DEBUG_VALID_MSG("saving 'or' branch");
4838 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4839 OCCURS, ROLLBACK_OR) < 0)
4844 case XML_ELEMENT_CONTENT_SEQ:
4846 * Small optimization.
4848 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4849 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4850 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4851 if ((NODE == NULL) ||
4852 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4857 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4858 ret = (CONT->c1->prefix == NULL);
4859 } else if (CONT->c1->prefix == NULL) {
4862 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4876 * At this point handle going up in the tree
4879 DEBUG_VALID_MSG("error found returning");
4883 while (CONT != NULL) {
4885 * First do the analysis depending on the occurrence model at
4889 switch (CONT->ocur) {
4892 case XML_ELEMENT_CONTENT_ONCE:
4893 cur = ctxt->vstate->node;
4894 DEBUG_VALID_MSG("Once branch failed, rollback");
4895 if (vstateVPop(ctxt) < 0 ) {
4896 DEBUG_VALID_MSG("exhaustion, failed");
4899 if (cur != ctxt->vstate->node)
4902 case XML_ELEMENT_CONTENT_PLUS:
4903 if (OCCURRENCE == 0) {
4904 cur = ctxt->vstate->node;
4905 DEBUG_VALID_MSG("Plus branch failed, rollback");
4906 if (vstateVPop(ctxt) < 0 ) {
4907 DEBUG_VALID_MSG("exhaustion, failed");
4910 if (cur != ctxt->vstate->node)
4914 DEBUG_VALID_MSG("Plus branch found");
4917 case XML_ELEMENT_CONTENT_MULT:
4918 #ifdef DEBUG_VALID_ALGO
4919 if (OCCURRENCE == 0) {
4920 DEBUG_VALID_MSG("Mult branch failed");
4922 DEBUG_VALID_MSG("Mult branch found");
4927 case XML_ELEMENT_CONTENT_OPT:
4928 DEBUG_VALID_MSG("Option branch failed");
4933 switch (CONT->ocur) {
4934 case XML_ELEMENT_CONTENT_OPT:
4935 DEBUG_VALID_MSG("Option branch succeeded");
4938 case XML_ELEMENT_CONTENT_ONCE:
4939 DEBUG_VALID_MSG("Once branch succeeded");
4942 case XML_ELEMENT_CONTENT_PLUS:
4943 if (STATE == ROLLBACK_PARENT) {
4944 DEBUG_VALID_MSG("Plus branch rollback");
4949 DEBUG_VALID_MSG("Plus branch exhausted");
4953 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
4956 case XML_ELEMENT_CONTENT_MULT:
4957 if (STATE == ROLLBACK_PARENT) {
4958 DEBUG_VALID_MSG("Mult branch rollback");
4963 DEBUG_VALID_MSG("Mult branch exhausted");
4967 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
4968 /* SET_OCCURRENCE; */
4975 * Then act accordingly at the parent level
4978 if (CONT->parent == NULL)
4981 switch (CONT->parent->type) {
4982 case XML_ELEMENT_CONTENT_PCDATA:
4983 DEBUG_VALID_MSG("Error: parent pcdata");
4985 case XML_ELEMENT_CONTENT_ELEMENT:
4986 DEBUG_VALID_MSG("Error: parent element");
4988 case XML_ELEMENT_CONTENT_OR:
4990 DEBUG_VALID_MSG("Or succeeded");
4991 CONT = CONT->parent;
4994 DEBUG_VALID_MSG("Or failed");
4995 CONT = CONT->parent;
4999 case XML_ELEMENT_CONTENT_SEQ:
5001 DEBUG_VALID_MSG("Sequence failed");
5002 CONT = CONT->parent;
5004 } else if (CONT == CONT->parent->c1) {
5005 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5006 CONT = CONT->parent->c2;
5009 DEBUG_VALID_MSG("Sequence succeeded");
5010 CONT = CONT->parent;
5018 cur = ctxt->vstate->node;
5019 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5020 if (vstateVPop(ctxt) < 0 ) {
5021 DEBUG_VALID_MSG("exhaustion, failed");
5024 if (cur != ctxt->vstate->node)
5031 cur = ctxt->vstate->node;
5032 DEBUG_VALID_MSG("Failure, rollback");
5033 if (vstateVPop(ctxt) < 0 ) {
5034 DEBUG_VALID_MSG("exhaustion, failed");
5037 if (cur != ctxt->vstate->node)
5041 return(determinist);
5046 * xmlSnprintfElements:
5047 * @buf: an output buffer
5048 * @size: the size of the buffer
5049 * @content: An element
5050 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5052 * This will dump the list of elements to the buffer
5053 * Intended just for the debug routine
5056 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
5060 if (node == NULL) return;
5061 if (glob) strcat(buf, "(");
5063 while (cur != NULL) {
5065 if (size - len < 50) {
5066 if ((size - len > 4) && (buf[len - 1] != '.'))
5067 strcat(buf, " ...");
5070 switch (cur->type) {
5071 case XML_ELEMENT_NODE:
5072 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5073 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
5074 if ((size - len > 4) && (buf[len - 1] != '.'))
5075 strcat(buf, " ...");
5078 strcat(buf, (char *) cur->ns->prefix);
5081 if (size - len < xmlStrlen(cur->name) + 10) {
5082 if ((size - len > 4) && (buf[len - 1] != '.'))
5083 strcat(buf, " ...");
5086 strcat(buf, (char *) cur->name);
5087 if (cur->next != NULL)
5091 if (xmlIsBlankNode(cur))
5093 case XML_CDATA_SECTION_NODE:
5094 case XML_ENTITY_REF_NODE:
5095 strcat(buf, "CDATA");
5096 if (cur->next != NULL)
5099 case XML_ATTRIBUTE_NODE:
5100 case XML_DOCUMENT_NODE:
5101 #ifdef LIBXML_DOCB_ENABLED
5102 case XML_DOCB_DOCUMENT_NODE:
5104 case XML_HTML_DOCUMENT_NODE:
5105 case XML_DOCUMENT_TYPE_NODE:
5106 case XML_DOCUMENT_FRAG_NODE:
5107 case XML_NOTATION_NODE:
5108 case XML_NAMESPACE_DECL:
5110 if (cur->next != NULL)
5113 case XML_ENTITY_NODE:
5116 case XML_COMMENT_NODE:
5117 case XML_ELEMENT_DECL:
5118 case XML_ATTRIBUTE_DECL:
5119 case XML_ENTITY_DECL:
5120 case XML_XINCLUDE_START:
5121 case XML_XINCLUDE_END:
5126 if (glob) strcat(buf, ")");
5130 * xmlValidateElementContent:
5131 * @ctxt: the validation context
5132 * @child: the child list
5133 * @elemDecl: pointer to the element declaration
5134 * @warn: emit the error message
5135 * @parent: the parent element (for error reporting)
5137 * Try to validate the content model of an element
5139 * returns 1 if valid or 0 if not and -1 in case of error
5143 xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
5144 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5146 #ifndef LIBXML_REGEXP_ENABLED
5147 xmlNodePtr repl = NULL, last = NULL, tmp;
5150 xmlElementContentPtr cont;
5151 const xmlChar *name;
5153 if (elemDecl == NULL)
5155 cont = elemDecl->content;
5156 name = elemDecl->name;
5158 #ifdef LIBXML_REGEXP_ENABLED
5159 /* Build the regexp associated to the content model */
5160 if (elemDecl->contModel == NULL)
5161 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5162 if (elemDecl->contModel == NULL) {
5165 xmlRegExecCtxtPtr exec;
5167 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5172 ctxt->nodeTab = NULL;
5173 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5176 while (cur != NULL) {
5177 switch (cur->type) {
5178 case XML_ENTITY_REF_NODE:
5180 * Push the current node to be able to roll back
5181 * and process within the entity
5183 if ((cur->children != NULL) &&
5184 (cur->children->children != NULL)) {
5185 nodeVPush(ctxt, cur);
5186 cur = cur->children->children;
5191 if (xmlIsBlankNode(cur))
5195 case XML_CDATA_SECTION_NODE:
5199 case XML_ELEMENT_NODE:
5200 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5204 fullname = xmlBuildQName(cur->name,
5205 cur->ns->prefix, fn, 50);
5206 if (fullname == NULL) {
5210 ret = xmlRegExecPushString(exec, fullname, NULL);
5211 if ((fullname != fn) && (fullname != cur->name))
5214 ret = xmlRegExecPushString(exec, cur->name, NULL);
5221 * Switch to next element
5224 while (cur == NULL) {
5225 cur = nodeVPop(ctxt);
5231 ret = xmlRegExecPushString(exec, NULL, NULL);
5233 xmlRegFreeExecCtxt(exec);
5236 #else /* LIBXML_REGEXP_ENABLED */
5238 * Allocate the stack
5240 ctxt->vstateMax = 8;
5241 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5242 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5243 if (ctxt->vstateTab == NULL) {
5244 xmlVErrMemory(ctxt, "malloc failed");
5248 * The first entry in the stack is reserved to the current state
5252 ctxt->nodeTab = NULL;
5253 ctxt->vstate = &ctxt->vstateTab[0];
5260 ret = xmlValidateElementType(ctxt);
5261 if ((ret == -3) && (warn)) {
5262 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5263 "Content model for Element %s is ambiguous\n",
5265 } else if (ret == -2) {
5267 * An entities reference appeared at this level.
5268 * Buid a minimal representation of this node content
5269 * sufficient to run the validation process on it
5271 DEBUG_VALID_MSG("Found an entity reference, linearizing");
5273 while (cur != NULL) {
5274 switch (cur->type) {
5275 case XML_ENTITY_REF_NODE:
5277 * Push the current node to be able to roll back
5278 * and process within the entity
5280 if ((cur->children != NULL) &&
5281 (cur->children->children != NULL)) {
5282 nodeVPush(ctxt, cur);
5283 cur = cur->children->children;
5288 if (xmlIsBlankNode(cur))
5290 /* no break on purpose */
5291 case XML_CDATA_SECTION_NODE:
5292 /* no break on purpose */
5293 case XML_ELEMENT_NODE:
5295 * Allocate a new node and minimally fills in
5298 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5300 xmlVErrMemory(ctxt, "malloc failed");
5301 xmlFreeNodeList(repl);
5305 tmp->type = cur->type;
5306 tmp->name = cur->name;
5309 tmp->content = NULL;
5316 if (cur->type == XML_CDATA_SECTION_NODE) {
5318 * E59 spaces in CDATA does not match the
5321 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5328 * Switch to next element
5331 while (cur == NULL) {
5332 cur = nodeVPop(ctxt);
5340 * Relaunch the validation
5342 ctxt->vstate = &ctxt->vstateTab[0];
5349 ret = xmlValidateElementType(ctxt);
5351 #endif /* LIBXML_REGEXP_ENABLED */
5352 if ((warn) && ((ret != 1) && (ret != -3))) {
5358 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
5360 #ifndef LIBXML_REGEXP_ENABLED
5362 xmlSnprintfElements(&list[0], 5000, repl, 1);
5364 #endif /* LIBXML_REGEXP_ENABLED */
5365 xmlSnprintfElements(&list[0], 5000, child, 1);
5368 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5369 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5370 name, BAD_CAST expr, BAD_CAST list);
5372 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5373 "Element content does not follow the DTD, expecting %s, got %s\n",
5374 BAD_CAST expr, BAD_CAST list, NULL);
5378 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5379 "Element %s content does not follow the DTD\n",
5382 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5383 "Element content does not follow the DTD\n",
5392 #ifndef LIBXML_REGEXP_ENABLED
5395 * Deallocate the copy if done, and free up the validation stack
5397 while (repl != NULL) {
5402 ctxt->vstateMax = 0;
5403 if (ctxt->vstateTab != NULL) {
5404 xmlFree(ctxt->vstateTab);
5405 ctxt->vstateTab = NULL;
5410 if (ctxt->nodeTab != NULL) {
5411 xmlFree(ctxt->nodeTab);
5412 ctxt->nodeTab = NULL;
5419 * xmlValidateCdataElement:
5420 * @ctxt: the validation context
5421 * @doc: a document instance
5422 * @elem: an element instance
5424 * Check that an element follows #CDATA
5426 * returns 1 if valid or 0 otherwise
5429 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5432 xmlNodePtr cur, child;
5434 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
5437 child = elem->children;
5440 while (cur != NULL) {
5441 switch (cur->type) {
5442 case XML_ENTITY_REF_NODE:
5444 * Push the current node to be able to roll back
5445 * and process within the entity
5447 if ((cur->children != NULL) &&
5448 (cur->children->children != NULL)) {
5449 nodeVPush(ctxt, cur);
5450 cur = cur->children->children;
5454 case XML_COMMENT_NODE:
5457 case XML_CDATA_SECTION_NODE:
5464 * Switch to next element
5467 while (cur == NULL) {
5468 cur = nodeVPop(ctxt);
5477 if (ctxt->nodeTab != NULL) {
5478 xmlFree(ctxt->nodeTab);
5479 ctxt->nodeTab = NULL;
5485 * xmlValidateCheckMixed:
5486 * @ctxt: the validation context
5487 * @cont: the mixed content model
5488 * @qname: the qualified name as appearing in the serialization
5490 * Check if the given node is part of the content model.
5492 * Returns 1 if yes, 0 if no, -1 in case of error
5495 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
5496 xmlElementContentPtr cont, const xmlChar *qname) {
5497 const xmlChar *name;
5499 name = xmlSplitQName3(qname, &plen);
5502 while (cont != NULL) {
5503 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5504 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5506 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5507 (cont->c1 != NULL) &&
5508 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5509 if ((cont->c1->prefix == NULL) &&
5510 (xmlStrEqual(cont->c1->name, qname)))
5512 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5513 (cont->c1 == NULL) ||
5514 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5515 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5516 "Internal: MIXED struct corrupted\n",
5523 while (cont != NULL) {
5524 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5525 if ((cont->prefix != NULL) &&
5526 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5527 (xmlStrEqual(cont->name, name)))
5529 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5530 (cont->c1 != NULL) &&
5531 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5532 if ((cont->c1->prefix != NULL) &&
5533 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5534 (xmlStrEqual(cont->c1->name, name)))
5536 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5537 (cont->c1 == NULL) ||
5538 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5539 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5540 "Internal: MIXED struct corrupted\n",
5551 * xmlValidGetElemDecl:
5552 * @ctxt: the validation context
5553 * @doc: a document instance
5554 * @elem: an element instance
5555 * @extsubset: pointer, (out) indicate if the declaration was found
5556 * in the external subset.
5558 * Finds a declaration associated to an element in the document.
5560 * returns the pointer to the declaration or NULL if not found.
5562 static xmlElementPtr
5563 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5564 xmlNodePtr elem, int *extsubset) {
5565 xmlElementPtr elemDecl = NULL;
5566 const xmlChar *prefix = NULL;
5568 if ((ctxt == NULL) || (doc == NULL) ||
5569 (elem == NULL) || (elem->name == NULL))
5571 if (extsubset != NULL)
5575 * Fetch the declaration for the qualified name
5577 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5578 prefix = elem->ns->prefix;
5580 if (prefix != NULL) {
5581 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5582 elem->name, prefix);
5583 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5584 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5585 elem->name, prefix);
5586 if ((elemDecl != NULL) && (extsubset != NULL))
5592 * Fetch the declaration for the non qualified name
5593 * This is "non-strict" validation should be done on the
5594 * full QName but in that case being flexible makes sense.
5596 if (elemDecl == NULL) {
5597 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5598 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5599 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5600 if ((elemDecl != NULL) && (extsubset != NULL))
5604 if (elemDecl == NULL) {
5605 xmlErrValidNode(ctxt, elem,
5606 XML_DTD_UNKNOWN_ELEM,
5607 "No declaration for element %s\n",
5608 elem->name, NULL, NULL);
5613 #ifdef LIBXML_REGEXP_ENABLED
5615 * xmlValidatePushElement:
5616 * @ctxt: the validation context
5617 * @doc: a document instance
5618 * @elem: an element instance
5619 * @qname: the qualified name as appearing in the serialization
5621 * Push a new element start on the validation stack.
5623 * returns 1 if no validation problem was found or 0 otherwise
5626 xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5627 xmlNodePtr elem, const xmlChar *qname) {
5629 xmlElementPtr eDecl;
5634 /* printf("PushElem %s\n", qname); */
5635 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5636 xmlValidStatePtr state = ctxt->vstate;
5637 xmlElementPtr elemDecl;
5640 * Check the new element agaisnt the content model of the new elem.
5642 if (state->elemDecl != NULL) {
5643 elemDecl = state->elemDecl;
5645 switch(elemDecl->etype) {
5646 case XML_ELEMENT_TYPE_UNDEFINED:
5649 case XML_ELEMENT_TYPE_EMPTY:
5650 xmlErrValidNode(ctxt, state->node,
5652 "Element %s was declared EMPTY this one has content\n",
5653 state->node->name, NULL, NULL);
5656 case XML_ELEMENT_TYPE_ANY:
5657 /* I don't think anything is required then */
5659 case XML_ELEMENT_TYPE_MIXED:
5660 /* simple case of declared as #PCDATA */
5661 if ((elemDecl->content != NULL) &&
5662 (elemDecl->content->type ==
5663 XML_ELEMENT_CONTENT_PCDATA)) {
5664 xmlErrValidNode(ctxt, state->node,
5666 "Element %s was declared #PCDATA but contains non text nodes\n",
5667 state->node->name, NULL, NULL);
5670 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5673 xmlErrValidNode(ctxt, state->node,
5674 XML_DTD_INVALID_CHILD,
5675 "Element %s is not declared in %s list of possible children\n",
5676 qname, state->node->name, NULL);
5680 case XML_ELEMENT_TYPE_ELEMENT:
5683 * VC: Standalone Document Declaration
5684 * - element types with element content, if white space
5685 * occurs directly within any instance of those types.
5687 if (state->exec != NULL) {
5688 ret = xmlRegExecPushString(state->exec, qname, NULL);
5690 xmlErrValidNode(ctxt, state->node,
5691 XML_DTD_CONTENT_MODEL,
5692 "Element %s content does not follow the DTD, Misplaced %s\n",
5693 state->node->name, qname, NULL);
5703 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5704 vstateVPush(ctxt, eDecl, elem);
5709 * xmlValidatePushCData:
5710 * @ctxt: the validation context
5711 * @data: some character data read
5712 * @len: the lenght of the data
5714 * check the CData parsed for validation in the current stack
5716 * returns 1 if no validation problem was found or 0 otherwise
5719 xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5722 /* printf("CDATA %s %d\n", data, len); */
5727 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5728 xmlValidStatePtr state = ctxt->vstate;
5729 xmlElementPtr elemDecl;
5732 * Check the new element agaisnt the content model of the new elem.
5734 if (state->elemDecl != NULL) {
5735 elemDecl = state->elemDecl;
5737 switch(elemDecl->etype) {
5738 case XML_ELEMENT_TYPE_UNDEFINED:
5741 case XML_ELEMENT_TYPE_EMPTY:
5742 xmlErrValidNode(ctxt, state->node,
5744 "Element %s was declared EMPTY this one has content\n",
5745 state->node->name, NULL, NULL);
5748 case XML_ELEMENT_TYPE_ANY:
5750 case XML_ELEMENT_TYPE_MIXED:
5752 case XML_ELEMENT_TYPE_ELEMENT:
5756 for (i = 0;i < len;i++) {
5757 if (!IS_BLANK_CH(data[i])) {
5758 xmlErrValidNode(ctxt, state->node,
5759 XML_DTD_CONTENT_MODEL,
5760 "Element %s content does not follow the DTD, Text not allowed\n",
5761 state->node->name, NULL, NULL);
5768 * VC: Standalone Document Declaration
5769 * element types with element content, if white space
5770 * occurs directly within any instance of those types.
5782 * xmlValidatePopElement:
5783 * @ctxt: the validation context
5784 * @doc: a document instance
5785 * @elem: an element instance
5786 * @qname: the qualified name as appearing in the serialization
5788 * Pop the element end from the validation stack.
5790 * returns 1 if no validation problem was found or 0 otherwise
5793 xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
5794 xmlNodePtr elem ATTRIBUTE_UNUSED,
5795 const xmlChar *qname ATTRIBUTE_UNUSED) {
5800 /* printf("PopElem %s\n", qname); */
5801 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5802 xmlValidStatePtr state = ctxt->vstate;
5803 xmlElementPtr elemDecl;
5806 * Check the new element agaisnt the content model of the new elem.
5808 if (state->elemDecl != NULL) {
5809 elemDecl = state->elemDecl;
5811 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5812 if (state->exec != NULL) {
5813 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5815 xmlErrValidNode(ctxt, state->node,
5816 XML_DTD_CONTENT_MODEL,
5817 "Element %s content does not follow the DTD, Expecting more child\n",
5818 state->node->name, NULL,NULL);
5821 * previous validation errors should not generate
5833 #endif /* LIBXML_REGEXP_ENABLED */
5836 * xmlValidateOneElement:
5837 * @ctxt: the validation context
5838 * @doc: a document instance
5839 * @elem: an element instance
5841 * Try to validate a single element and it's attributes,
5842 * basically it does the following checks as described by the
5843 * XML-1.0 recommendation:
5844 * - [ VC: Element Valid ]
5845 * - [ VC: Required Attribute ]
5846 * Then call xmlValidateOneAttribute() for each attribute present.
5848 * The ID/IDREF checkings are done separately
5850 * returns 1 if valid or 0 otherwise
5854 xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5856 xmlElementPtr elemDecl = NULL;
5857 xmlElementContentPtr cont;
5858 xmlAttributePtr attr;
5861 const xmlChar *name;
5866 if (elem == NULL) return(0);
5867 switch (elem->type) {
5868 case XML_ATTRIBUTE_NODE:
5869 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5870 "Attribute element not expected\n", NULL, NULL ,NULL);
5873 if (elem->children != NULL) {
5874 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5875 "Text element has children !\n",
5879 if (elem->ns != NULL) {
5880 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5881 "Text element has namespace !\n",
5885 if (elem->content == NULL) {
5886 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5887 "Text element has no content !\n",
5892 case XML_XINCLUDE_START:
5893 case XML_XINCLUDE_END:
5895 case XML_CDATA_SECTION_NODE:
5896 case XML_ENTITY_REF_NODE:
5898 case XML_COMMENT_NODE:
5900 case XML_ENTITY_NODE:
5901 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5902 "Entity element not expected\n", NULL, NULL ,NULL);
5904 case XML_NOTATION_NODE:
5905 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5906 "Notation element not expected\n", NULL, NULL ,NULL);
5908 case XML_DOCUMENT_NODE:
5909 case XML_DOCUMENT_TYPE_NODE:
5910 case XML_DOCUMENT_FRAG_NODE:
5911 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5912 "Document element not expected\n", NULL, NULL ,NULL);
5914 case XML_HTML_DOCUMENT_NODE:
5915 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5916 "HTML Document not expected\n", NULL, NULL ,NULL);
5918 case XML_ELEMENT_NODE:
5921 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5922 "unknown element type\n", NULL, NULL ,NULL);
5927 * Fetch the declaration
5929 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5930 if (elemDecl == NULL)
5934 * If vstateNr is not zero that means continuous validation is
5935 * activated, do not try to check the content model at that level.
5937 if (ctxt->vstateNr == 0) {
5938 /* Check that the element content matches the definition */
5939 switch (elemDecl->etype) {
5940 case XML_ELEMENT_TYPE_UNDEFINED:
5941 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5942 "No declaration for element %s\n",
5943 elem->name, NULL, NULL);
5945 case XML_ELEMENT_TYPE_EMPTY:
5946 if (elem->children != NULL) {
5947 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
5948 "Element %s was declared EMPTY this one has content\n",
5949 elem->name, NULL, NULL);
5953 case XML_ELEMENT_TYPE_ANY:
5954 /* I don't think anything is required then */
5956 case XML_ELEMENT_TYPE_MIXED:
5958 /* simple case of declared as #PCDATA */
5959 if ((elemDecl->content != NULL) &&
5960 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5961 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5963 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
5964 "Element %s was declared #PCDATA but contains non text nodes\n",
5965 elem->name, NULL, NULL);
5969 child = elem->children;
5970 /* Hum, this start to get messy */
5971 while (child != NULL) {
5972 if (child->type == XML_ELEMENT_NODE) {
5974 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
5978 fullname = xmlBuildQName(child->name, child->ns->prefix,
5980 if (fullname == NULL)
5982 cont = elemDecl->content;
5983 while (cont != NULL) {
5984 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5985 if (xmlStrEqual(cont->name, fullname))
5987 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5988 (cont->c1 != NULL) &&
5989 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5990 if (xmlStrEqual(cont->c1->name, fullname))
5992 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5993 (cont->c1 == NULL) ||
5994 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5995 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5996 "Internal: MIXED struct corrupted\n",
6002 if ((fullname != fn) && (fullname != child->name))
6007 cont = elemDecl->content;
6008 while (cont != NULL) {
6009 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6010 if (xmlStrEqual(cont->name, name)) break;
6011 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6012 (cont->c1 != NULL) &&
6013 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6014 if (xmlStrEqual(cont->c1->name, name)) break;
6015 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6016 (cont->c1 == NULL) ||
6017 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
6018 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6019 "Internal: MIXED struct corrupted\n",
6026 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
6027 "Element %s is not declared in %s list of possible children\n",
6028 name, elem->name, NULL);
6033 child = child->next;
6036 case XML_ELEMENT_TYPE_ELEMENT:
6037 if ((doc->standalone == 1) && (extsubset == 1)) {
6039 * VC: Standalone Document Declaration
6040 * - element types with element content, if white space
6041 * occurs directly within any instance of those types.
6043 child = elem->children;
6044 while (child != NULL) {
6045 if (child->type == XML_TEXT_NODE) {
6046 const xmlChar *content = child->content;
6048 while (IS_BLANK_CH(*content))
6050 if (*content == 0) {
6051 xmlErrValidNode(ctxt, elem,
6052 XML_DTD_STANDALONE_WHITE_SPACE,
6053 "standalone: %s declared in the external subset contains white spaces nodes\n",
6054 elem->name, NULL, NULL);
6062 child = elem->children;
6063 cont = elemDecl->content;
6064 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
6069 } /* not continuous */
6071 /* [ VC: Required Attribute ] */
6072 attr = elemDecl->attributes;
6073 while (attr != NULL) {
6074 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
6077 if ((attr->prefix == NULL) &&
6078 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6082 while (ns != NULL) {
6083 if (ns->prefix == NULL)
6087 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6091 while (ns != NULL) {
6092 if (xmlStrEqual(attr->name, ns->prefix))
6099 attrib = elem->properties;
6100 while (attrib != NULL) {
6101 if (xmlStrEqual(attrib->name, attr->name)) {
6102 if (attr->prefix != NULL) {
6103 xmlNsPtr nameSpace = attrib->ns;
6105 if (nameSpace == NULL)
6106 nameSpace = elem->ns;
6108 * qualified names handling is problematic, having a
6109 * different prefix should be possible but DTDs don't
6110 * allow to define the URI instead of the prefix :-(
6112 if (nameSpace == NULL) {
6115 } else if (!xmlStrEqual(nameSpace->prefix,
6123 * We should allow applications to define namespaces
6124 * for their application even if the DTD doesn't
6125 * carry one, otherwise, basically we would always
6131 attrib = attrib->next;
6134 if (qualified == -1) {
6135 if (attr->prefix == NULL) {
6136 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6137 "Element %s does not carry attribute %s\n",
6138 elem->name, attr->name, NULL);
6141 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6142 "Element %s does not carry attribute %s:%s\n",
6143 elem->name, attr->prefix,attr->name);
6146 } else if (qualified == 0) {
6147 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
6148 "Element %s required attribute %s:%s has no prefix\n",
6149 elem->name, attr->prefix, attr->name);
6150 } else if (qualified == 1) {
6151 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
6152 "Element %s required attribute %s:%s has different prefix\n",
6153 elem->name, attr->prefix, attr->name);
6155 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6157 * Special tests checking #FIXED namespace declarations
6158 * have the right value since this is not done as an
6159 * attribute checking
6161 if ((attr->prefix == NULL) &&
6162 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6166 while (ns != NULL) {
6167 if (ns->prefix == NULL) {
6168 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6169 xmlErrValidNode(ctxt, elem,
6170 XML_DTD_ELEM_DEFAULT_NAMESPACE,
6171 "Element %s namespace name for default namespace does not match the DTD\n",
6172 elem->name, NULL, NULL);
6179 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6183 while (ns != NULL) {
6184 if (xmlStrEqual(attr->name, ns->prefix)) {
6185 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6186 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
6187 "Element %s namespace name for %s does not match the DTD\n",
6188 elem->name, ns->prefix, NULL);
6205 * @ctxt: the validation context
6206 * @doc: a document instance
6208 * Try to validate a the root element
6209 * basically it does the following check as described by the
6210 * XML-1.0 recommendation:
6211 * - [ VC: Root Element Type ]
6212 * it doesn't try to recurse or apply other check to the element
6214 * returns 1 if valid or 0 otherwise
6218 xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6222 if (doc == NULL) return(0);
6224 root = xmlDocGetRootElement(doc);
6225 if ((root == NULL) || (root->name == NULL)) {
6226 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6227 "no root element\n", NULL);
6232 * When doing post validation against a separate DTD, those may
6233 * no internal subset has been generated
6235 if ((doc->intSubset != NULL) &&
6236 (doc->intSubset->name != NULL)) {
6238 * Check first the document root against the NQName
6240 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6241 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
6245 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6246 if (fullname == NULL) {
6247 xmlVErrMemory(ctxt, NULL);
6250 ret = xmlStrEqual(doc->intSubset->name, fullname);
6251 if ((fullname != fn) && (fullname != root->name))
6256 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6257 (xmlStrEqual(root->name, BAD_CAST "html")))
6259 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6260 "root and DTD name do not match '%s' and '%s'\n",
6261 root->name, doc->intSubset->name, NULL);
6271 * xmlValidateElement:
6272 * @ctxt: the validation context
6273 * @doc: a document instance
6274 * @elem: an element instance
6276 * Try to validate the subtree under an element
6278 * returns 1 if valid or 0 otherwise
6282 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6286 const xmlChar *value;
6289 if (elem == NULL) return(0);
6292 * XInclude elements were added after parsing in the infoset,
6293 * they don't really mean anything validation wise.
6295 if ((elem->type == XML_XINCLUDE_START) ||
6296 (elem->type == XML_XINCLUDE_END))
6302 * Entities references have to be handled separately
6304 if (elem->type == XML_ENTITY_REF_NODE) {
6308 ret &= xmlValidateOneElement(ctxt, doc, elem);
6309 if (elem->type == XML_ELEMENT_NODE) {
6310 attr = elem->properties;
6311 while (attr != NULL) {
6312 value = xmlNodeListGetString(doc, attr->children, 0);
6313 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6315 xmlFree((char *)value);
6319 while (ns != NULL) {
6320 if (elem->ns == NULL)
6321 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6324 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6325 elem->ns->prefix, ns, ns->href);
6329 child = elem->children;
6330 while (child != NULL) {
6331 ret &= xmlValidateElement(ctxt, doc, child);
6332 child = child->next;
6340 * @ref: A reference to be validated
6341 * @ctxt: Validation context
6342 * @name: Name of ID we are searching for
6346 xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
6347 const xmlChar *name) {
6353 if ((ref->attr == NULL) && (ref->name == NULL))
6357 xmlChar *dup, *str = NULL, *cur, save;
6359 dup = xmlStrdup(name);
6367 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6370 id = xmlGetID(ctxt->doc, str);
6372 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
6373 "attribute %s line %d references an unknown ID \"%s\"\n",
6374 ref->name, ref->lineno, str);
6380 while (IS_BLANK_CH(*cur)) cur++;
6383 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
6384 id = xmlGetID(ctxt->doc, name);
6386 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6387 "IDREF attribute %s references an unknown ID \"%s\"\n",
6388 attr->name, name, NULL);
6391 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6392 xmlChar *dup, *str = NULL, *cur, save;
6394 dup = xmlStrdup(name);
6396 xmlVErrMemory(ctxt, "IDREFS split");
6403 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6406 id = xmlGetID(ctxt->doc, str);
6408 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6409 "IDREFS attribute %s references an unknown ID \"%s\"\n",
6410 attr->name, str, NULL);
6416 while (IS_BLANK_CH(*cur)) cur++;
6423 * xmlWalkValidateList:
6424 * @data: Contents of current link
6425 * @user: Value supplied by the user
6427 * Returns 0 to abort the walk or 1 to continue
6430 xmlWalkValidateList(const void *data, const void *user)
6432 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6433 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6438 * xmlValidateCheckRefCallback:
6439 * @ref_list: List of references
6440 * @ctxt: Validation context
6441 * @name: Name of ID we are searching for
6445 xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6446 const xmlChar *name) {
6447 xmlValidateMemo memo;
6449 if (ref_list == NULL)
6454 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6459 * xmlValidateDocumentFinal:
6460 * @ctxt: the validation context
6461 * @doc: a document instance
6463 * Does the final step for the document validation once all the
6464 * incremental validation steps have been completed
6466 * basically it does the following checks described by the XML Rec
6468 * Check all the IDREF/IDREFS attributes definition for validity
6470 * returns 1 if valid or 0 otherwise
6474 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6475 xmlRefTablePtr table;
6480 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6481 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
6486 * Check all the NOTATION/NOTATIONS attributes
6489 * Check all the ENTITY/ENTITIES attributes definition for validity
6492 * Check all the IDREF/IDREFS attributes definition for validity
6494 table = (xmlRefTablePtr) doc->refs;
6497 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6498 return(ctxt->valid);
6503 * @ctxt: the validation context
6504 * @doc: a document instance
6505 * @dtd: a dtd instance
6507 * Try to validate the document against the dtd instance
6509 * Basically it does check all the definitions in the DtD.
6510 * Note the the internal subset (if present) is de-coupled
6511 * (i.e. not used), which could give problems if ID or IDREF
6514 * returns 1 if valid or 0 otherwise
6518 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6520 xmlDtdPtr oldExt, oldInt;
6523 if (dtd == NULL) return(0);
6524 if (doc == NULL) return(0);
6525 oldExt = doc->extSubset;
6526 oldInt = doc->intSubset;
6527 doc->extSubset = dtd;
6528 doc->intSubset = NULL;
6529 ret = xmlValidateRoot(ctxt, doc);
6531 doc->extSubset = oldExt;
6532 doc->intSubset = oldInt;
6535 if (doc->ids != NULL) {
6536 xmlFreeIDTable(doc->ids);
6539 if (doc->refs != NULL) {
6540 xmlFreeRefTable(doc->refs);
6543 root = xmlDocGetRootElement(doc);
6544 ret = xmlValidateElement(ctxt, doc, root);
6545 ret &= xmlValidateDocumentFinal(ctxt, doc);
6546 doc->extSubset = oldExt;
6547 doc->intSubset = oldInt;
6552 xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6553 const xmlChar *name ATTRIBUTE_UNUSED) {
6556 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6557 xmlChar *notation = cur->content;
6559 if (notation != NULL) {
6562 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6571 xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
6572 const xmlChar *name ATTRIBUTE_UNUSED) {
6575 xmlElementPtr elem = NULL;
6579 switch (cur->atype) {
6580 case XML_ATTRIBUTE_CDATA:
6581 case XML_ATTRIBUTE_ID:
6582 case XML_ATTRIBUTE_IDREF :
6583 case XML_ATTRIBUTE_IDREFS:
6584 case XML_ATTRIBUTE_NMTOKEN:
6585 case XML_ATTRIBUTE_NMTOKENS:
6586 case XML_ATTRIBUTE_ENUMERATION:
6588 case XML_ATTRIBUTE_ENTITY:
6589 case XML_ATTRIBUTE_ENTITIES:
6590 case XML_ATTRIBUTE_NOTATION:
6591 if (cur->defaultValue != NULL) {
6593 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6594 cur->atype, cur->defaultValue);
6595 if ((ret == 0) && (ctxt->valid == 1))
6598 if (cur->tree != NULL) {
6599 xmlEnumerationPtr tree = cur->tree;
6600 while (tree != NULL) {
6601 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6602 cur->name, cur->atype, tree->name);
6603 if ((ret == 0) && (ctxt->valid == 1))
6609 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6611 if (cur->elem == NULL) {
6612 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
6613 "xmlValidateAttributeCallback(%s): internal error\n",
6614 (const char *) cur->name);
6619 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6620 if ((elem == NULL) && (doc != NULL))
6621 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6622 if ((elem == NULL) && (cur->parent != NULL) &&
6623 (cur->parent->type == XML_DTD_NODE))
6624 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
6626 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
6627 "attribute %s: could not find decl for element %s\n",
6628 cur->name, cur->elem, NULL);
6631 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6632 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
6633 "NOTATION attribute %s declared for EMPTY element %s\n",
6634 cur->name, cur->elem, NULL);
6641 * xmlValidateDtdFinal:
6642 * @ctxt: the validation context
6643 * @doc: a document instance
6645 * Does the final step for the dtds validation once all the
6646 * subsets have been parsed
6648 * basically it does the following checks described by the XML Rec
6649 * - check that ENTITY and ENTITIES type attributes default or
6650 * possible values matches one of the defined entities.
6651 * - check that NOTATION type attributes default or
6652 * possible values matches one of the defined notations.
6654 * returns 1 if valid or 0 if invalid and -1 if not well-formed
6658 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6660 xmlAttributeTablePtr table;
6661 xmlEntitiesTablePtr entities;
6663 if (doc == NULL) return(0);
6664 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6668 dtd = doc->intSubset;
6669 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6670 table = (xmlAttributeTablePtr) dtd->attributes;
6671 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
6673 if ((dtd != NULL) && (dtd->entities != NULL)) {
6674 entities = (xmlEntitiesTablePtr) dtd->entities;
6675 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6678 dtd = doc->extSubset;
6679 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6680 table = (xmlAttributeTablePtr) dtd->attributes;
6681 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
6683 if ((dtd != NULL) && (dtd->entities != NULL)) {
6684 entities = (xmlEntitiesTablePtr) dtd->entities;
6685 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6688 return(ctxt->valid);
6692 * xmlValidateDocument:
6693 * @ctxt: the validation context
6694 * @doc: a document instance
6696 * Try to validate the document instance
6698 * basically it does the all the checks described by the XML Rec
6699 * i.e. validates the internal and external subset (if present)
6700 * and validate the document tree.
6702 * returns 1 if valid or 0 otherwise
6706 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6712 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6713 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6714 "no DTD found!\n", NULL);
6717 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6718 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6720 if (doc->intSubset->SystemID != NULL) {
6721 sysID = xmlBuildURI(doc->intSubset->SystemID,
6723 if (sysID == NULL) {
6724 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6725 "Could not build URI for external subset \"%s\"\n",
6726 (const char *) doc->intSubset->SystemID);
6731 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6732 (const xmlChar *)sysID);
6735 if (doc->extSubset == NULL) {
6736 if (doc->intSubset->SystemID != NULL) {
6737 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6738 "Could not load the external subset \"%s\"\n",
6739 (const char *) doc->intSubset->SystemID);
6741 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6742 "Could not load the external subset \"%s\"\n",
6743 (const char *) doc->intSubset->ExternalID);
6749 if (doc->ids != NULL) {
6750 xmlFreeIDTable(doc->ids);
6753 if (doc->refs != NULL) {
6754 xmlFreeRefTable(doc->refs);
6757 ret = xmlValidateDtdFinal(ctxt, doc);
6758 if (!xmlValidateRoot(ctxt, doc)) return(0);
6760 root = xmlDocGetRootElement(doc);
6761 ret &= xmlValidateElement(ctxt, doc, root);
6762 ret &= xmlValidateDocumentFinal(ctxt, doc);
6766 /************************************************************************
6768 * Routines for dynamic validation editing *
6770 ************************************************************************/
6773 * xmlValidGetPotentialChildren:
6774 * @ctree: an element content tree
6775 * @names: an array to store the list of child names
6776 * @len: a pointer to the number of element in the list
6777 * @max: the size of the array
6779 * Build/extend a list of potential children allowed by the content tree
6781 * returns the number of element in the list, or -1 in case of error.
6785 xmlValidGetPotentialChildren(xmlElementContent *ctree,
6786 const xmlChar **names,
6787 int *len, int max) {
6790 if ((ctree == NULL) || (names == NULL) || (len == NULL))
6792 if (*len >= max) return(*len);
6794 switch (ctree->type) {
6795 case XML_ELEMENT_CONTENT_PCDATA:
6796 for (i = 0; i < *len;i++)
6797 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6798 names[(*len)++] = BAD_CAST "#PCDATA";
6800 case XML_ELEMENT_CONTENT_ELEMENT:
6801 for (i = 0; i < *len;i++)
6802 if (xmlStrEqual(ctree->name, names[i])) return(*len);
6803 names[(*len)++] = ctree->name;
6805 case XML_ELEMENT_CONTENT_SEQ:
6806 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6807 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
6809 case XML_ELEMENT_CONTENT_OR:
6810 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6811 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
6819 * Dummy function to suppress messages while we try out valid elements
6821 static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6822 const char *msg ATTRIBUTE_UNUSED, ...) {
6827 * xmlValidGetValidElements:
6828 * @prev: an element to insert after
6829 * @next: an element to insert next
6830 * @names: an array to store the list of child names
6831 * @max: the size of the array
6833 * This function returns the list of authorized children to insert
6834 * within an existing tree while respecting the validity constraints
6835 * forced by the Dtd. The insertion point is defined using @prev and
6836 * @next in the following ways:
6837 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6838 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6839 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6840 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6841 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6843 * pointers to the element names are inserted at the beginning of the array
6844 * and do not need to be freed.
6846 * returns the number of element in the list, or -1 in case of error. If
6847 * the function returns the value @max the caller is invited to grow the
6848 * receiving array and retry.
6852 xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
6855 int nb_valid_elements = 0;
6856 const xmlChar *elements[256];
6857 int nb_elements = 0, i;
6858 const xmlChar *name;
6866 xmlNode *parent_childs;
6867 xmlNode *parent_last;
6869 xmlElement *element_desc;
6871 if (prev == NULL && next == NULL)
6874 if (names == NULL) return(-1);
6875 if (max <= 0) return(-1);
6877 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6878 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6880 nb_valid_elements = 0;
6881 ref_node = prev ? prev : next;
6882 parent = ref_node->parent;
6885 * Retrieves the parent element declaration
6887 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6889 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6890 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6892 if (element_desc == NULL) return(-1);
6895 * Do a backup of the current tree structure
6897 prev_next = prev ? prev->next : NULL;
6898 next_prev = next ? next->prev : NULL;
6899 parent_childs = parent->children;
6900 parent_last = parent->last;
6903 * Creates a dummy node and insert it into the tree
6905 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
6906 test_node->parent = parent;
6907 test_node->prev = prev;
6908 test_node->next = next;
6909 name = test_node->name;
6911 if (prev) prev->next = test_node;
6912 else parent->children = test_node;
6914 if (next) next->prev = test_node;
6915 else parent->last = test_node;
6918 * Insert each potential child node and check if the parent is
6921 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6922 elements, &nb_elements, 256);
6924 for (i = 0;i < nb_elements;i++) {
6925 test_node->name = elements[i];
6926 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
6929 for (j = 0; j < nb_valid_elements;j++)
6930 if (xmlStrEqual(elements[i], names[j])) break;
6931 names[nb_valid_elements++] = elements[i];
6932 if (nb_valid_elements >= max) break;
6937 * Restore the tree structure
6939 if (prev) prev->next = prev_next;
6940 if (next) next->prev = next_prev;
6941 parent->children = parent_childs;
6942 parent->last = parent_last;
6945 * Free up the dummy node
6947 test_node->name = name;
6948 xmlFreeNode(test_node);
6950 return(nb_valid_elements);
6952 #endif /* LIBXML_VALID_ENABLED */
6954 #define bottom_valid
6955 #include "elfgcchack.h"