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/valid.h>
22 #include <libxml/parser.h>
23 #include <libxml/parserInternals.h>
24 #include <libxml/xmlerror.h>
25 #include <libxml/list.h>
26 #include <libxml/globals.h>
28 /* #define DEBUG_VALID_ALGO */
29 /* #define DEBUG_REGEXP_ALGO */
32 xmlGenericError(xmlGenericErrorContext, \
33 "Unimplemented block at %s:%d\n", \
37 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
40 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
43 #ifdef LIBXML_REGEXP_ENABLED
45 * If regexp are enabled we can do continuous validation without the
46 * need of a tree to validate the content model. this is done in each
48 * Each xmlValidState represent the validation state associated to the
49 * set of nodes currently open from the document root to the current element.
53 typedef struct _xmlValidState {
54 xmlElementPtr elemDecl; /* pointer to the content model */
55 xmlNodePtr node; /* pointer to the current node */
56 xmlRegExecCtxtPtr exec; /* regexp runtime */
61 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
62 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
64 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
65 sizeof(ctxt->vstateTab[0]));
66 if (ctxt->vstateTab == NULL) {
67 VERROR(ctxt->userData, "malloc failed !n");
72 if (ctxt->vstateNr >= ctxt->vstateMax) {
75 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
76 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
78 VERROR(ctxt->userData, "realloc failed !n");
82 ctxt->vstateTab = tmp;
84 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
85 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
86 ctxt->vstateTab[ctxt->vstateNr].node = node;
87 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
88 if (elemDecl->contModel == NULL)
89 xmlValidBuildContentModel(ctxt, elemDecl);
90 if (elemDecl->contModel != NULL) {
91 ctxt->vstateTab[ctxt->vstateNr].exec =
92 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
94 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
95 VERROR(ctxt->userData,
96 "Failed to build content model regexp for %s", node->name);
99 return(ctxt->vstateNr++);
103 vstateVPop(xmlValidCtxtPtr ctxt) {
104 xmlElementPtr elemDecl;
106 if (ctxt->vstateNr < 1) return(-1);
108 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
109 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
110 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
111 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
112 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
114 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
115 if (ctxt->vstateNr >= 1)
116 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
119 return(ctxt->vstateNr);
122 #else /* not LIBXML_REGEXP_ENABLED */
124 * If regexp are not enabled, it uses a home made algorithm less
125 * complex and easier to
126 * debug/maintain than a generic NFA -> DFA state based algo. The
127 * only restriction is on the deepness of the tree limited by the
128 * size of the occurs bitfield
130 * this is the content of a saved state for rollbacks
133 #define ROLLBACK_OR 0
134 #define ROLLBACK_PARENT 1
136 typedef struct _xmlValidState {
137 xmlElementContentPtr cont; /* pointer to the content model subtree */
138 xmlNodePtr node; /* pointer to the current node in the list */
139 long occurs;/* bitfield for multiple occurrences */
140 unsigned char depth; /* current depth in the overall tree */
141 unsigned char state; /* ROLLBACK_XXX */
144 #define MAX_RECURSE 25000
145 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
146 #define CONT ctxt->vstate->cont
147 #define NODE ctxt->vstate->node
148 #define DEPTH ctxt->vstate->depth
149 #define OCCURS ctxt->vstate->occurs
150 #define STATE ctxt->vstate->state
152 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
153 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
155 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
156 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
159 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
160 xmlNodePtr node, unsigned char depth, long occurs,
161 unsigned char state) {
162 int i = ctxt->vstateNr - 1;
164 if (ctxt->vstateNr > MAX_RECURSE) {
167 if (ctxt->vstateTab == NULL) {
169 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
170 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
171 if (ctxt->vstateTab == NULL) {
172 xmlGenericError(xmlGenericErrorContext,
177 if (ctxt->vstateNr >= ctxt->vstateMax) {
180 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
181 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
183 xmlGenericError(xmlGenericErrorContext,
184 "realloc failed !n");
187 ctxt->vstateMax *= 2;
188 ctxt->vstateTab = tmp;
189 ctxt->vstate = &ctxt->vstateTab[0];
192 * Don't push on the stack a state already here
194 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
195 (ctxt->vstateTab[i].node == node) &&
196 (ctxt->vstateTab[i].depth == depth) &&
197 (ctxt->vstateTab[i].occurs == occurs) &&
198 (ctxt->vstateTab[i].state == state))
199 return(ctxt->vstateNr);
200 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
201 ctxt->vstateTab[ctxt->vstateNr].node = node;
202 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
203 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
204 ctxt->vstateTab[ctxt->vstateNr].state = state;
205 return(ctxt->vstateNr++);
209 vstateVPop(xmlValidCtxtPtr ctxt) {
210 if (ctxt->vstateNr <= 1) return(-1);
212 ctxt->vstate = &ctxt->vstateTab[0];
213 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
214 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
215 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
216 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
217 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
218 return(ctxt->vstateNr);
221 #endif /* LIBXML_REGEXP_ENABLED */
224 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
226 if (ctxt->nodeMax <= 0) {
229 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
230 sizeof(ctxt->nodeTab[0]));
231 if (ctxt->nodeTab == NULL) {
232 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
237 if (ctxt->nodeNr >= ctxt->nodeMax) {
239 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
240 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
242 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
248 ctxt->nodeTab[ctxt->nodeNr] = value;
250 return (ctxt->nodeNr++);
253 nodeVPop(xmlValidCtxtPtr ctxt)
257 if (ctxt->nodeNr <= 0)
260 if (ctxt->nodeNr > 0)
261 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
264 ret = ctxt->nodeTab[ctxt->nodeNr];
265 ctxt->nodeTab[ctxt->nodeNr] = 0;
269 #ifdef DEBUG_VALID_ALGO
271 xmlValidPrintNode(xmlNodePtr cur) {
273 xmlGenericError(xmlGenericErrorContext, "null");
277 case XML_ELEMENT_NODE:
278 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
281 xmlGenericError(xmlGenericErrorContext, "text ");
283 case XML_CDATA_SECTION_NODE:
284 xmlGenericError(xmlGenericErrorContext, "cdata ");
286 case XML_ENTITY_REF_NODE:
287 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
290 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
292 case XML_COMMENT_NODE:
293 xmlGenericError(xmlGenericErrorContext, "comment ");
295 case XML_ATTRIBUTE_NODE:
296 xmlGenericError(xmlGenericErrorContext, "?attr? ");
298 case XML_ENTITY_NODE:
299 xmlGenericError(xmlGenericErrorContext, "?ent? ");
301 case XML_DOCUMENT_NODE:
302 xmlGenericError(xmlGenericErrorContext, "?doc? ");
304 case XML_DOCUMENT_TYPE_NODE:
305 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
307 case XML_DOCUMENT_FRAG_NODE:
308 xmlGenericError(xmlGenericErrorContext, "?frag? ");
310 case XML_NOTATION_NODE:
311 xmlGenericError(xmlGenericErrorContext, "?nota? ");
313 case XML_HTML_DOCUMENT_NODE:
314 xmlGenericError(xmlGenericErrorContext, "?html? ");
316 #ifdef LIBXML_DOCB_ENABLED
317 case XML_DOCB_DOCUMENT_NODE:
318 xmlGenericError(xmlGenericErrorContext, "?docb? ");
322 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
324 case XML_ELEMENT_DECL:
325 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
327 case XML_ATTRIBUTE_DECL:
328 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
330 case XML_ENTITY_DECL:
331 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
333 case XML_NAMESPACE_DECL:
334 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
336 case XML_XINCLUDE_START:
337 xmlGenericError(xmlGenericErrorContext, "incstart ");
339 case XML_XINCLUDE_END:
340 xmlGenericError(xmlGenericErrorContext, "incend ");
346 xmlValidPrintNodeList(xmlNodePtr cur) {
348 xmlGenericError(xmlGenericErrorContext, "null ");
349 while (cur != NULL) {
350 xmlValidPrintNode(cur);
356 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
360 xmlGenericError(xmlGenericErrorContext, "valid: ");
361 xmlValidPrintNodeList(cur);
362 xmlGenericError(xmlGenericErrorContext, "against ");
363 xmlSnprintfElementContent(expr, 5000, cont, 1);
364 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
368 xmlValidDebugState(xmlValidStatePtr state) {
369 xmlGenericError(xmlGenericErrorContext, "(");
370 if (state->cont == NULL)
371 xmlGenericError(xmlGenericErrorContext, "null,");
373 switch (state->cont->type) {
374 case XML_ELEMENT_CONTENT_PCDATA:
375 xmlGenericError(xmlGenericErrorContext, "pcdata,");
377 case XML_ELEMENT_CONTENT_ELEMENT:
378 xmlGenericError(xmlGenericErrorContext, "%s,",
381 case XML_ELEMENT_CONTENT_SEQ:
382 xmlGenericError(xmlGenericErrorContext, "seq,");
384 case XML_ELEMENT_CONTENT_OR:
385 xmlGenericError(xmlGenericErrorContext, "or,");
388 xmlValidPrintNode(state->node);
389 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
390 state->depth, state->occurs, state->state);
394 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
397 xmlGenericError(xmlGenericErrorContext, "state: ");
398 xmlValidDebugState(ctxt->vstate);
399 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
401 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
402 xmlValidDebugState(&ctxt->vstateTab[j]);
403 xmlGenericError(xmlGenericErrorContext, "\n");
407 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
410 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
411 #define DEBUG_VALID_MSG(m) \
412 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
415 #define DEBUG_VALID_STATE(n,c)
416 #define DEBUG_VALID_MSG(m)
419 /* TODO: use hash table for accesses to elem and attribute definitions */
421 #define VECTXT(ctxt, node) \
422 if ((ctxt != NULL) && (ctxt->error != NULL) && \
424 xmlChar *base = xmlNodeGetBase(NULL,node); \
425 if (base != NULL) { \
426 ctxt->error(ctxt->userData, "%s:%d: ", base, \
427 (int) (long) node->content); \
430 ctxt->error(ctxt->userData, ":%d: ", \
431 (int) (long) node->content); \
434 #define VWCTXT(ctxt, node) \
435 if ((ctxt != NULL) && (ctxt->warning != NULL) && \
437 xmlChar *base = xmlNodeGetBase(NULL,node); \
438 if (base != NULL) { \
439 ctxt->warning(ctxt->userData, "%s:%d: ", base, \
440 (int) (long) node->content); \
443 ctxt->warning(ctxt->userData, ":%d: ", \
444 (int) (long) node->content); \
448 if (doc == NULL) return(0); \
449 else if ((doc->intSubset == NULL) && \
450 (doc->extSubset == NULL)) return(0)
452 static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
454 xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
456 #ifdef LIBXML_REGEXP_ENABLED
458 /************************************************************************
460 * Content model validation based on the regexps *
462 ************************************************************************/
465 * xmlValidBuildAContentModel:
466 * @content: the content model
467 * @ctxt: the schema parser context
468 * @name: the element name whose content is being built
470 * Generate the automata sequence needed for that type
472 * Returns 1 if successful or 0 in case of error.
475 xmlValidBuildAContentModel(xmlElementContentPtr content,
476 xmlValidCtxtPtr ctxt,
477 const xmlChar *name) {
478 if (content == NULL) {
479 VERROR(ctxt->userData,
480 "Found unexpected type = NULL in %s content model\n", name);
483 switch (content->type) {
484 case XML_ELEMENT_CONTENT_PCDATA:
485 VERROR(ctxt->userData, "ContentModel found PCDATA for element %s\n",
489 case XML_ELEMENT_CONTENT_ELEMENT: {
490 xmlAutomataStatePtr oldstate = ctxt->state;
494 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
495 if (fullname == NULL) {
496 VERROR(ctxt->userData, "Out of memory\n");
500 switch (content->ocur) {
501 case XML_ELEMENT_CONTENT_ONCE:
502 ctxt->state = xmlAutomataNewTransition(ctxt->am,
503 ctxt->state, NULL, fullname, NULL);
505 case XML_ELEMENT_CONTENT_OPT:
506 ctxt->state = xmlAutomataNewTransition(ctxt->am,
507 ctxt->state, NULL, fullname, NULL);
508 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
510 case XML_ELEMENT_CONTENT_PLUS:
511 ctxt->state = xmlAutomataNewTransition(ctxt->am,
512 ctxt->state, NULL, fullname, NULL);
513 xmlAutomataNewTransition(ctxt->am, ctxt->state,
514 ctxt->state, fullname, NULL);
516 case XML_ELEMENT_CONTENT_MULT:
517 xmlAutomataNewTransition(ctxt->am, ctxt->state,
518 ctxt->state, fullname, NULL);
519 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
523 if ((fullname != fn) && (fullname != content->name))
527 case XML_ELEMENT_CONTENT_SEQ: {
528 xmlAutomataStatePtr oldstate, oldend;
529 xmlElementContentOccur ocur;
532 * Simply iterate over the content
534 oldstate = ctxt->state;
535 ocur = content->ocur;
536 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
537 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
538 oldstate = ctxt->state;
541 xmlValidBuildAContentModel(content->c1, ctxt, name);
542 content = content->c2;
543 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
544 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
545 xmlValidBuildAContentModel(content, ctxt, name);
546 oldend = ctxt->state;
547 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
549 case XML_ELEMENT_CONTENT_ONCE:
551 case XML_ELEMENT_CONTENT_OPT:
552 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
554 case XML_ELEMENT_CONTENT_MULT:
555 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
556 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
558 case XML_ELEMENT_CONTENT_PLUS:
559 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
564 case XML_ELEMENT_CONTENT_OR: {
565 xmlAutomataStatePtr oldstate, oldend;
566 xmlElementContentOccur ocur;
568 ocur = content->ocur;
569 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
570 (ocur == XML_ELEMENT_CONTENT_MULT)) {
571 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
574 oldstate = ctxt->state;
575 oldend = xmlAutomataNewState(ctxt->am);
578 * iterate over the subtypes and remerge the end with an
582 ctxt->state = oldstate;
583 xmlValidBuildAContentModel(content->c1, ctxt, name);
584 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
585 content = content->c2;
586 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
587 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
588 ctxt->state = oldstate;
589 xmlValidBuildAContentModel(content, ctxt, name);
590 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
591 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
593 case XML_ELEMENT_CONTENT_ONCE:
595 case XML_ELEMENT_CONTENT_OPT:
596 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
598 case XML_ELEMENT_CONTENT_MULT:
599 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
600 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
602 case XML_ELEMENT_CONTENT_PLUS:
603 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
609 VERROR(ctxt->userData, "ContentModel broken for element %s\n",
616 * xmlValidBuildContentModel:
617 * @ctxt: a validation context
618 * @elem: an element declaration node
620 * (Re)Build the automata associated to the content model of this
623 * Returns 1 in case of success, 0 in case of error
626 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
628 if ((ctxt == NULL) || (elem == NULL))
630 if (elem->type != XML_ELEMENT_DECL)
632 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
634 /* TODO: should we rebuild in this case ? */
635 if (elem->contModel != NULL) {
636 if (!xmlRegexpIsDeterminist(elem->contModel)) {
643 ctxt->am = xmlNewAutomata();
644 if (ctxt->am == NULL) {
645 VERROR(ctxt->userData, "Cannot create automata for element %s\n",
649 ctxt->state = xmlAutomataGetInitState(ctxt->am);
650 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
651 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
652 elem->contModel = xmlAutomataCompile(ctxt->am);
653 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
656 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
657 VERROR(ctxt->userData, "Content model of %s is not determinist: %s\n",
659 #ifdef DEBUG_REGEXP_ALGO
660 xmlRegexpPrint(stderr, elem->contModel);
664 xmlFreeAutomata(ctxt->am);
669 xmlFreeAutomata(ctxt->am);
674 #endif /* LIBXML_REGEXP_ENABLED */
676 /****************************************************************
678 * Util functions for data allocation/deallocation *
680 ****************************************************************/
685 * Allocate a validation context structure.
687 * Returns NULL if not, otherwise the new validation context structure
690 xmlNewValidCtxt(void) {
693 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL)
696 (void) memset(ret, 0, sizeof (xmlValidCtxt));
703 * @cur: the validation context to free
705 * Free a validation context structure.
708 xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
713 * xmlNewElementContent:
714 * @name: the subelement name or NULL
715 * @type: the type of element content decl
717 * Allocate an element content structure.
719 * Returns NULL if not, otherwise the new element content structure
722 xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
723 xmlElementContentPtr ret;
726 case XML_ELEMENT_CONTENT_ELEMENT:
728 xmlGenericError(xmlGenericErrorContext,
729 "xmlNewElementContent : name == NULL !\n");
732 case XML_ELEMENT_CONTENT_PCDATA:
733 case XML_ELEMENT_CONTENT_SEQ:
734 case XML_ELEMENT_CONTENT_OR:
736 xmlGenericError(xmlGenericErrorContext,
737 "xmlNewElementContent : name != NULL !\n");
741 xmlGenericError(xmlGenericErrorContext,
742 "xmlNewElementContent: unknown type %d\n", type);
745 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
747 xmlGenericError(xmlGenericErrorContext,
748 "xmlNewElementContent : out of memory!\n");
751 memset(ret, 0, sizeof(xmlElementContent));
753 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
755 xmlChar *prefix = NULL;
756 ret->name = xmlSplitQName2(name, &prefix);
757 if (ret->name == NULL)
758 ret->name = xmlStrdup(name);
759 ret->prefix = prefix;
764 ret->c1 = ret->c2 = ret->parent = NULL;
769 * xmlCopyElementContent:
770 * @cur: An element content pointer.
772 * Build a copy of an element content description.
774 * Returns the new xmlElementContentPtr or NULL in case of error.
777 xmlCopyElementContent(xmlElementContentPtr cur) {
778 xmlElementContentPtr ret;
780 if (cur == NULL) return(NULL);
781 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
783 xmlGenericError(xmlGenericErrorContext,
784 "xmlCopyElementContent : out of memory\n");
787 if (cur->prefix != NULL)
788 ret->prefix = xmlStrdup(cur->prefix);
789 ret->ocur = cur->ocur;
790 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
792 ret->c1->parent = ret;
793 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
795 ret->c2->parent = ret;
800 * xmlFreeElementContent:
801 * @cur: the element content tree to free
803 * Free an element content structure. This is a recursive call !
806 xmlFreeElementContent(xmlElementContentPtr cur) {
807 if (cur == NULL) return;
809 case XML_ELEMENT_CONTENT_PCDATA:
810 case XML_ELEMENT_CONTENT_ELEMENT:
811 case XML_ELEMENT_CONTENT_SEQ:
812 case XML_ELEMENT_CONTENT_OR:
815 xmlGenericError(xmlGenericErrorContext,
816 "xmlFreeElementContent : type %d\n", cur->type);
819 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
820 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
821 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
822 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
827 * xmlDumpElementContent:
828 * @buf: An XML buffer
829 * @content: An element table
830 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
832 * This will dump the content of the element table as an XML DTD definition
835 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
836 if (content == NULL) return;
838 if (glob) xmlBufferWriteChar(buf, "(");
839 switch (content->type) {
840 case XML_ELEMENT_CONTENT_PCDATA:
841 xmlBufferWriteChar(buf, "#PCDATA");
843 case XML_ELEMENT_CONTENT_ELEMENT:
844 if (content->prefix != NULL) {
845 xmlBufferWriteCHAR(buf, content->prefix);
846 xmlBufferWriteChar(buf, ":");
848 xmlBufferWriteCHAR(buf, content->name);
850 case XML_ELEMENT_CONTENT_SEQ:
851 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
852 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
853 xmlDumpElementContent(buf, content->c1, 1);
855 xmlDumpElementContent(buf, content->c1, 0);
856 xmlBufferWriteChar(buf, " , ");
857 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
858 xmlDumpElementContent(buf, content->c2, 1);
860 xmlDumpElementContent(buf, content->c2, 0);
862 case XML_ELEMENT_CONTENT_OR:
863 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
864 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
865 xmlDumpElementContent(buf, content->c1, 1);
867 xmlDumpElementContent(buf, content->c1, 0);
868 xmlBufferWriteChar(buf, " | ");
869 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
870 xmlDumpElementContent(buf, content->c2, 1);
872 xmlDumpElementContent(buf, content->c2, 0);
875 xmlGenericError(xmlGenericErrorContext,
876 "xmlDumpElementContent: unknown type %d\n",
880 xmlBufferWriteChar(buf, ")");
881 switch (content->ocur) {
882 case XML_ELEMENT_CONTENT_ONCE:
884 case XML_ELEMENT_CONTENT_OPT:
885 xmlBufferWriteChar(buf, "?");
887 case XML_ELEMENT_CONTENT_MULT:
888 xmlBufferWriteChar(buf, "*");
890 case XML_ELEMENT_CONTENT_PLUS:
891 xmlBufferWriteChar(buf, "+");
897 * xmlSprintfElementContent:
898 * @buf: an output buffer
899 * @content: An element table
900 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
902 * Deprecated, unsafe, use xmlSnprintfElementContent
905 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
906 xmlElementContentPtr content ATTRIBUTE_UNUSED,
907 int glob ATTRIBUTE_UNUSED) {
911 * xmlSnprintfElementContent:
912 * @buf: an output buffer
913 * @size: the buffer size
914 * @content: An element table
915 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
917 * This will dump the content of the element content definition
918 * Intended just for the debug routine
921 xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
924 if (content == NULL) return;
926 if (size - len < 50) {
927 if ((size - len > 4) && (buf[len - 1] != '.'))
931 if (glob) strcat(buf, "(");
932 switch (content->type) {
933 case XML_ELEMENT_CONTENT_PCDATA:
934 strcat(buf, "#PCDATA");
936 case XML_ELEMENT_CONTENT_ELEMENT:
937 if (content->prefix != NULL) {
938 if (size - len < xmlStrlen(content->prefix) + 10) {
942 strcat(buf, (char *) content->prefix);
945 if (size - len < xmlStrlen(content->name) + 10) {
949 if (content->name != NULL)
950 strcat(buf, (char *) content->name);
952 case XML_ELEMENT_CONTENT_SEQ:
953 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
954 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
955 xmlSnprintfElementContent(buf, size, content->c1, 1);
957 xmlSnprintfElementContent(buf, size, content->c1, 0);
959 if (size - len < 50) {
960 if ((size - len > 4) && (buf[len - 1] != '.'))
965 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
966 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
967 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
968 xmlSnprintfElementContent(buf, size, content->c2, 1);
970 xmlSnprintfElementContent(buf, size, content->c2, 0);
972 case XML_ELEMENT_CONTENT_OR:
973 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
974 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
975 xmlSnprintfElementContent(buf, size, content->c1, 1);
977 xmlSnprintfElementContent(buf, size, content->c1, 0);
979 if (size - len < 50) {
980 if ((size - len > 4) && (buf[len - 1] != '.'))
985 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
986 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
987 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
988 xmlSnprintfElementContent(buf, size, content->c2, 1);
990 xmlSnprintfElementContent(buf, size, content->c2, 0);
995 switch (content->ocur) {
996 case XML_ELEMENT_CONTENT_ONCE:
998 case XML_ELEMENT_CONTENT_OPT:
1001 case XML_ELEMENT_CONTENT_MULT:
1004 case XML_ELEMENT_CONTENT_PLUS:
1010 /****************************************************************
1012 * Registration of DTD declarations *
1014 ****************************************************************/
1017 * xmlCreateElementTable:
1019 * create and initialize an empty element hash table.
1021 * Returns the xmlElementTablePtr just created or NULL in case of error.
1023 static xmlElementTablePtr
1024 xmlCreateElementTable(void) {
1025 return(xmlHashCreate(0));
1032 * Deallocate the memory used by an element definition
1035 xmlFreeElement(xmlElementPtr elem) {
1036 if (elem == NULL) return;
1037 xmlUnlinkNode((xmlNodePtr) elem);
1038 xmlFreeElementContent(elem->content);
1039 if (elem->name != NULL)
1040 xmlFree((xmlChar *) elem->name);
1041 if (elem->prefix != NULL)
1042 xmlFree((xmlChar *) elem->prefix);
1043 #ifdef LIBXML_REGEXP_ENABLED
1044 if (elem->contModel != NULL)
1045 xmlRegFreeRegexp(elem->contModel);
1052 * xmlAddElementDecl:
1053 * @ctxt: the validation context
1054 * @dtd: pointer to the DTD
1055 * @name: the entity name
1056 * @type: the element type
1057 * @content: the element content tree or NULL
1059 * Register a new element declaration
1061 * Returns NULL if not, otherwise the entity
1064 xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1065 xmlElementTypeVal type,
1066 xmlElementContentPtr content) {
1068 xmlElementTablePtr table;
1069 xmlAttributePtr oldAttributes = NULL;
1070 xmlChar *ns, *uqname;
1073 xmlGenericError(xmlGenericErrorContext,
1074 "xmlAddElementDecl: dtd == NULL\n");
1078 xmlGenericError(xmlGenericErrorContext,
1079 "xmlAddElementDecl: name == NULL\n");
1083 case XML_ELEMENT_TYPE_EMPTY:
1084 if (content != NULL) {
1085 xmlGenericError(xmlGenericErrorContext,
1086 "xmlAddElementDecl: content != NULL for EMPTY\n");
1090 case XML_ELEMENT_TYPE_ANY:
1091 if (content != NULL) {
1092 xmlGenericError(xmlGenericErrorContext,
1093 "xmlAddElementDecl: content != NULL for ANY\n");
1097 case XML_ELEMENT_TYPE_MIXED:
1098 if (content == NULL) {
1099 xmlGenericError(xmlGenericErrorContext,
1100 "xmlAddElementDecl: content == NULL for MIXED\n");
1104 case XML_ELEMENT_TYPE_ELEMENT:
1105 if (content == NULL) {
1106 xmlGenericError(xmlGenericErrorContext,
1107 "xmlAddElementDecl: content == NULL for ELEMENT\n");
1112 xmlGenericError(xmlGenericErrorContext,
1113 "xmlAddElementDecl: unknown type %d\n", type);
1118 * check if name is a QName
1120 uqname = xmlSplitQName2(name, &ns);
1125 * Create the Element table if needed.
1127 table = (xmlElementTablePtr) dtd->elements;
1128 if (table == NULL) {
1129 table = xmlCreateElementTable();
1130 dtd->elements = (void *) table;
1132 if (table == NULL) {
1133 xmlGenericError(xmlGenericErrorContext,
1134 "xmlAddElementDecl: Table creation failed!\n");
1143 * lookup old attributes inserted on an undefined element in the
1146 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1147 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1148 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1149 oldAttributes = ret->attributes;
1150 ret->attributes = NULL;
1151 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1152 xmlFreeElement(ret);
1157 * The element may already be present if one of its attribute
1158 * was registered first
1160 ret = xmlHashLookup2(table, name, ns);
1162 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1164 * The element is already defined in this DTD.
1166 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1174 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1176 xmlGenericError(xmlGenericErrorContext,
1177 "xmlAddElementDecl: out of memory\n");
1184 memset(ret, 0, sizeof(xmlElement));
1185 ret->type = XML_ELEMENT_DECL;
1188 * fill the structure.
1190 ret->name = xmlStrdup(name);
1191 if (ret->name == NULL) {
1192 xmlGenericError(xmlGenericErrorContext,
1193 "xmlAddElementDecl: out of memory\n");
1205 * Insertion must not fail
1207 if (xmlHashAddEntry2(table, name, ns, ret)) {
1209 * The element is already defined in this DTD.
1211 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1212 xmlFreeElement(ret);
1220 * Finish to fill the structure.
1223 ret->content = xmlCopyElementContent(content);
1224 ret->attributes = oldAttributes;
1227 * Link it to the DTD
1230 ret->doc = dtd->doc;
1231 if (dtd->last == NULL) {
1232 dtd->children = dtd->last = (xmlNodePtr) ret;
1234 dtd->last->next = (xmlNodePtr) ret;
1235 ret->prev = dtd->last;
1236 dtd->last = (xmlNodePtr) ret;
1244 * xmlFreeElementTable:
1245 * @table: An element table
1247 * Deallocate the memory used by an element hash table.
1250 xmlFreeElementTable(xmlElementTablePtr table) {
1251 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1258 * Build a copy of an element.
1260 * Returns the new xmlElementPtr or NULL in case of error.
1262 static xmlElementPtr
1263 xmlCopyElement(xmlElementPtr elem) {
1266 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1268 xmlGenericError(xmlGenericErrorContext,
1269 "xmlCopyElement: out of memory !\n");
1272 memset(cur, 0, sizeof(xmlElement));
1273 cur->type = XML_ELEMENT_DECL;
1274 cur->etype = elem->etype;
1275 if (elem->name != NULL)
1276 cur->name = xmlStrdup(elem->name);
1279 if (elem->prefix != NULL)
1280 cur->prefix = xmlStrdup(elem->prefix);
1283 cur->content = xmlCopyElementContent(elem->content);
1284 /* TODO : rebuild the attribute list on the copy */
1285 cur->attributes = NULL;
1290 * xmlCopyElementTable:
1291 * @table: An element table
1293 * Build a copy of an element table.
1295 * Returns the new xmlElementTablePtr or NULL in case of error.
1298 xmlCopyElementTable(xmlElementTablePtr table) {
1299 return((xmlElementTablePtr) xmlHashCopy(table,
1300 (xmlHashCopier) xmlCopyElement));
1304 * xmlDumpElementDecl:
1305 * @buf: the XML buffer output
1306 * @elem: An element table
1308 * This will dump the content of the element declaration as an XML
1312 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1313 switch (elem->etype) {
1314 case XML_ELEMENT_TYPE_EMPTY:
1315 xmlBufferWriteChar(buf, "<!ELEMENT ");
1316 if (elem->prefix != NULL) {
1317 xmlBufferWriteCHAR(buf, elem->prefix);
1318 xmlBufferWriteChar(buf, ":");
1320 xmlBufferWriteCHAR(buf, elem->name);
1321 xmlBufferWriteChar(buf, " EMPTY>\n");
1323 case XML_ELEMENT_TYPE_ANY:
1324 xmlBufferWriteChar(buf, "<!ELEMENT ");
1325 if (elem->prefix != NULL) {
1326 xmlBufferWriteCHAR(buf, elem->prefix);
1327 xmlBufferWriteChar(buf, ":");
1329 xmlBufferWriteCHAR(buf, elem->name);
1330 xmlBufferWriteChar(buf, " ANY>\n");
1332 case XML_ELEMENT_TYPE_MIXED:
1333 xmlBufferWriteChar(buf, "<!ELEMENT ");
1334 if (elem->prefix != NULL) {
1335 xmlBufferWriteCHAR(buf, elem->prefix);
1336 xmlBufferWriteChar(buf, ":");
1338 xmlBufferWriteCHAR(buf, elem->name);
1339 xmlBufferWriteChar(buf, " ");
1340 xmlDumpElementContent(buf, elem->content, 1);
1341 xmlBufferWriteChar(buf, ">\n");
1343 case XML_ELEMENT_TYPE_ELEMENT:
1344 xmlBufferWriteChar(buf, "<!ELEMENT ");
1345 if (elem->prefix != NULL) {
1346 xmlBufferWriteCHAR(buf, elem->prefix);
1347 xmlBufferWriteChar(buf, ":");
1349 xmlBufferWriteCHAR(buf, elem->name);
1350 xmlBufferWriteChar(buf, " ");
1351 xmlDumpElementContent(buf, elem->content, 1);
1352 xmlBufferWriteChar(buf, ">\n");
1355 xmlGenericError(xmlGenericErrorContext,
1356 "xmlDumpElementDecl: internal: unknown type %d\n",
1362 * xmlDumpElementTable:
1363 * @buf: the XML buffer output
1364 * @table: An element table
1366 * This will dump the content of the element table as an XML DTD definition
1369 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1370 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDecl, buf);
1374 * xmlCreateEnumeration:
1375 * @name: the enumeration name or NULL
1377 * create and initialize an enumeration attribute node.
1379 * Returns the xmlEnumerationPtr just created or NULL in case
1383 xmlCreateEnumeration(xmlChar *name) {
1384 xmlEnumerationPtr ret;
1386 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1388 xmlGenericError(xmlGenericErrorContext,
1389 "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
1390 (long)sizeof(xmlEnumeration));
1393 memset(ret, 0, sizeof(xmlEnumeration));
1396 ret->name = xmlStrdup(name);
1401 * xmlFreeEnumeration:
1402 * @cur: the tree to free.
1404 * free an enumeration attribute node (recursive).
1407 xmlFreeEnumeration(xmlEnumerationPtr cur) {
1408 if (cur == NULL) return;
1410 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1412 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1417 * xmlCopyEnumeration:
1418 * @cur: the tree to copy.
1420 * Copy an enumeration attribute node (recursive).
1422 * Returns the xmlEnumerationPtr just created or NULL in case
1426 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1427 xmlEnumerationPtr ret;
1429 if (cur == NULL) return(NULL);
1430 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1432 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1433 else ret->next = NULL;
1439 * xmlDumpEnumeration:
1440 * @buf: the XML buffer output
1441 * @enum: An enumeration
1443 * This will dump the content of the enumeration
1446 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1447 if (cur == NULL) return;
1449 xmlBufferWriteCHAR(buf, cur->name);
1450 if (cur->next == NULL)
1451 xmlBufferWriteChar(buf, ")");
1453 xmlBufferWriteChar(buf, " | ");
1454 xmlDumpEnumeration(buf, cur->next);
1459 * xmlCreateAttributeTable:
1461 * create and initialize an empty attribute hash table.
1463 * Returns the xmlAttributeTablePtr just created or NULL in case
1466 static xmlAttributeTablePtr
1467 xmlCreateAttributeTable(void) {
1468 return(xmlHashCreate(0));
1472 * xmlScanAttributeDeclCallback:
1473 * @attr: the attribute decl
1474 * @list: the list to update
1476 * Callback called by xmlScanAttributeDecl when a new attribute
1477 * has to be entered in the list.
1480 xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
1481 const xmlChar* name ATTRIBUTE_UNUSED) {
1482 attr->nexth = *list;
1487 * xmlScanAttributeDecl:
1488 * @dtd: pointer to the DTD
1489 * @elem: the element name
1491 * When inserting a new element scan the DtD for existing attributes
1492 * for that element and initialize the Attribute chain
1494 * Returns the pointer to the first attribute decl in the chain,
1498 xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1499 xmlAttributePtr ret = NULL;
1500 xmlAttributeTablePtr table;
1503 xmlGenericError(xmlGenericErrorContext,
1504 "xmlScanAttributeDecl: dtd == NULL\n");
1508 xmlGenericError(xmlGenericErrorContext,
1509 "xmlScanAttributeDecl: elem == NULL\n");
1512 table = (xmlAttributeTablePtr) dtd->attributes;
1517 xmlHashScan3(table, NULL, NULL, elem,
1518 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1523 * xmlScanIDAttributeDecl:
1524 * @ctxt: the validation context
1525 * @elem: the element name
1527 * Verify that the element don't have too many ID attributes
1530 * Returns the number of ID attributes found.
1533 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1534 xmlAttributePtr cur;
1537 if (elem == NULL) return(0);
1538 cur = elem->attributes;
1539 while (cur != NULL) {
1540 if (cur->atype == XML_ATTRIBUTE_ID) {
1543 VERROR(ctxt->userData,
1544 "Element %s has too many ID attributes defined : %s\n",
1545 elem->name, cur->name);
1554 * @elem: An attribute
1556 * Deallocate the memory used by an attribute definition
1559 xmlFreeAttribute(xmlAttributePtr attr) {
1560 if (attr == NULL) return;
1561 xmlUnlinkNode((xmlNodePtr) attr);
1562 if (attr->tree != NULL)
1563 xmlFreeEnumeration(attr->tree);
1564 if (attr->elem != NULL)
1565 xmlFree((xmlChar *) attr->elem);
1566 if (attr->name != NULL)
1567 xmlFree((xmlChar *) attr->name);
1568 if (attr->defaultValue != NULL)
1569 xmlFree((xmlChar *) attr->defaultValue);
1570 if (attr->prefix != NULL)
1571 xmlFree((xmlChar *) attr->prefix);
1577 * xmlAddAttributeDecl:
1578 * @ctxt: the validation context
1579 * @dtd: pointer to the DTD
1580 * @elem: the element name
1581 * @name: the attribute name
1582 * @ns: the attribute namespace prefix
1583 * @type: the attribute type
1584 * @def: the attribute default type
1585 * @defaultValue: the attribute default value
1586 * @tree: if it's an enumeration, the associated list
1588 * Register a new attribute declaration
1589 * Note that @tree becomes the ownership of the DTD
1591 * Returns NULL if not new, otherwise the attribute decl
1594 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
1595 const xmlChar *name, const xmlChar *ns,
1596 xmlAttributeType type, xmlAttributeDefault def,
1597 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1598 xmlAttributePtr ret;
1599 xmlAttributeTablePtr table;
1600 xmlElementPtr elemDef;
1603 xmlGenericError(xmlGenericErrorContext,
1604 "xmlAddAttributeDecl: dtd == NULL\n");
1605 xmlFreeEnumeration(tree);
1609 xmlGenericError(xmlGenericErrorContext,
1610 "xmlAddAttributeDecl: name == NULL\n");
1611 xmlFreeEnumeration(tree);
1615 xmlGenericError(xmlGenericErrorContext,
1616 "xmlAddAttributeDecl: elem == NULL\n");
1617 xmlFreeEnumeration(tree);
1622 * Check the type and possibly the default value.
1625 case XML_ATTRIBUTE_CDATA:
1627 case XML_ATTRIBUTE_ID:
1629 case XML_ATTRIBUTE_IDREF:
1631 case XML_ATTRIBUTE_IDREFS:
1633 case XML_ATTRIBUTE_ENTITY:
1635 case XML_ATTRIBUTE_ENTITIES:
1637 case XML_ATTRIBUTE_NMTOKEN:
1639 case XML_ATTRIBUTE_NMTOKENS:
1641 case XML_ATTRIBUTE_ENUMERATION:
1643 case XML_ATTRIBUTE_NOTATION:
1646 xmlGenericError(xmlGenericErrorContext,
1647 "xmlAddAttributeDecl: unknown type %d\n", type);
1648 xmlFreeEnumeration(tree);
1651 if ((defaultValue != NULL) &&
1652 (!xmlValidateAttributeValue(type, defaultValue))) {
1653 VERROR(ctxt->userData, "Attribute %s of %s: invalid default value\n",
1654 elem, name, defaultValue);
1655 defaultValue = NULL;
1660 * Check first that an attribute defined in the external subset wasn't
1661 * already defined in the internal subset
1663 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1664 (dtd->doc->intSubset != NULL) &&
1665 (dtd->doc->intSubset->attributes != NULL)) {
1666 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1672 * Create the Attribute table if needed.
1674 table = (xmlAttributeTablePtr) dtd->attributes;
1675 if (table == NULL) {
1676 table = xmlCreateAttributeTable();
1677 dtd->attributes = (void *) table;
1679 if (table == NULL) {
1680 xmlGenericError(xmlGenericErrorContext,
1681 "xmlAddAttributeDecl: Table creation failed!\n");
1686 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1688 xmlGenericError(xmlGenericErrorContext,
1689 "xmlAddAttributeDecl: out of memory\n");
1692 memset(ret, 0, sizeof(xmlAttribute));
1693 ret->type = XML_ATTRIBUTE_DECL;
1696 * fill the structure.
1699 ret->name = xmlStrdup(name);
1700 ret->prefix = xmlStrdup(ns);
1701 ret->elem = xmlStrdup(elem);
1704 if (defaultValue != NULL)
1705 ret->defaultValue = xmlStrdup(defaultValue);
1709 * Search the DTD for previous declarations of the ATTLIST
1711 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
1713 * The attribute is already defined in this DTD.
1715 VWARNING(ctxt->userData,
1716 "Attribute %s of element %s: already defined\n",
1718 xmlFreeAttribute(ret);
1724 * Multiple ID per element
1726 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
1727 if (elemDef != NULL) {
1729 if ((type == XML_ATTRIBUTE_ID) &&
1730 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
1731 VERROR(ctxt->userData,
1732 "Element %s has too may ID attributes defined : %s\n",
1738 * Insert namespace default def first they need to be
1741 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1742 ((ret->prefix != NULL &&
1743 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1744 ret->nexth = elemDef->attributes;
1745 elemDef->attributes = ret;
1747 xmlAttributePtr tmp = elemDef->attributes;
1749 while ((tmp != NULL) &&
1750 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1751 ((ret->prefix != NULL &&
1752 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1753 if (tmp->nexth == NULL)
1758 ret->nexth = tmp->nexth;
1761 ret->nexth = elemDef->attributes;
1762 elemDef->attributes = ret;
1768 * Link it to the DTD
1771 ret->doc = dtd->doc;
1772 if (dtd->last == NULL) {
1773 dtd->children = dtd->last = (xmlNodePtr) ret;
1775 dtd->last->next = (xmlNodePtr) ret;
1776 ret->prev = dtd->last;
1777 dtd->last = (xmlNodePtr) ret;
1783 * xmlFreeAttributeTable:
1784 * @table: An attribute table
1786 * Deallocate the memory used by an entities hash table.
1789 xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1790 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1795 * @attr: An attribute
1797 * Build a copy of an attribute.
1799 * Returns the new xmlAttributePtr or NULL in case of error.
1801 static xmlAttributePtr
1802 xmlCopyAttribute(xmlAttributePtr attr) {
1803 xmlAttributePtr cur;
1805 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1807 xmlGenericError(xmlGenericErrorContext,
1808 "xmlCopyAttribute: out of memory !\n");
1811 memset(cur, 0, sizeof(xmlAttribute));
1812 cur->type = XML_ATTRIBUTE_DECL;
1813 cur->atype = attr->atype;
1814 cur->def = attr->def;
1815 cur->tree = xmlCopyEnumeration(attr->tree);
1816 if (attr->elem != NULL)
1817 cur->elem = xmlStrdup(attr->elem);
1818 if (attr->name != NULL)
1819 cur->name = xmlStrdup(attr->name);
1820 if (attr->prefix != NULL)
1821 cur->prefix = xmlStrdup(attr->prefix);
1822 if (attr->defaultValue != NULL)
1823 cur->defaultValue = xmlStrdup(attr->defaultValue);
1828 * xmlCopyAttributeTable:
1829 * @table: An attribute table
1831 * Build a copy of an attribute table.
1833 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1835 xmlAttributeTablePtr
1836 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1837 return((xmlAttributeTablePtr) xmlHashCopy(table,
1838 (xmlHashCopier) xmlCopyAttribute));
1842 * xmlDumpAttributeDecl:
1843 * @buf: the XML buffer output
1844 * @attr: An attribute declaration
1846 * This will dump the content of the attribute declaration as an XML
1850 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1851 xmlBufferWriteChar(buf, "<!ATTLIST ");
1852 xmlBufferWriteCHAR(buf, attr->elem);
1853 xmlBufferWriteChar(buf, " ");
1854 if (attr->prefix != NULL) {
1855 xmlBufferWriteCHAR(buf, attr->prefix);
1856 xmlBufferWriteChar(buf, ":");
1858 xmlBufferWriteCHAR(buf, attr->name);
1859 switch (attr->atype) {
1860 case XML_ATTRIBUTE_CDATA:
1861 xmlBufferWriteChar(buf, " CDATA");
1863 case XML_ATTRIBUTE_ID:
1864 xmlBufferWriteChar(buf, " ID");
1866 case XML_ATTRIBUTE_IDREF:
1867 xmlBufferWriteChar(buf, " IDREF");
1869 case XML_ATTRIBUTE_IDREFS:
1870 xmlBufferWriteChar(buf, " IDREFS");
1872 case XML_ATTRIBUTE_ENTITY:
1873 xmlBufferWriteChar(buf, " ENTITY");
1875 case XML_ATTRIBUTE_ENTITIES:
1876 xmlBufferWriteChar(buf, " ENTITIES");
1878 case XML_ATTRIBUTE_NMTOKEN:
1879 xmlBufferWriteChar(buf, " NMTOKEN");
1881 case XML_ATTRIBUTE_NMTOKENS:
1882 xmlBufferWriteChar(buf, " NMTOKENS");
1884 case XML_ATTRIBUTE_ENUMERATION:
1885 xmlBufferWriteChar(buf, " (");
1886 xmlDumpEnumeration(buf, attr->tree);
1888 case XML_ATTRIBUTE_NOTATION:
1889 xmlBufferWriteChar(buf, " NOTATION (");
1890 xmlDumpEnumeration(buf, attr->tree);
1893 xmlGenericError(xmlGenericErrorContext,
1894 "xmlDumpAttributeDecl: internal: unknown type %d\n",
1897 switch (attr->def) {
1898 case XML_ATTRIBUTE_NONE:
1900 case XML_ATTRIBUTE_REQUIRED:
1901 xmlBufferWriteChar(buf, " #REQUIRED");
1903 case XML_ATTRIBUTE_IMPLIED:
1904 xmlBufferWriteChar(buf, " #IMPLIED");
1906 case XML_ATTRIBUTE_FIXED:
1907 xmlBufferWriteChar(buf, " #FIXED");
1910 xmlGenericError(xmlGenericErrorContext,
1911 "xmlDumpAttributeDecl: internal: unknown default %d\n",
1914 if (attr->defaultValue != NULL) {
1915 xmlBufferWriteChar(buf, " ");
1916 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1918 xmlBufferWriteChar(buf, ">\n");
1922 * xmlDumpAttributeTable:
1923 * @buf: the XML buffer output
1924 * @table: An attribute table
1926 * This will dump the content of the attribute table as an XML DTD definition
1929 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1930 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDecl, buf);
1933 /************************************************************************
1937 ************************************************************************/
1939 * xmlCreateNotationTable:
1941 * create and initialize an empty notation hash table.
1943 * Returns the xmlNotationTablePtr just created or NULL in case
1946 static xmlNotationTablePtr
1947 xmlCreateNotationTable(void) {
1948 return(xmlHashCreate(0));
1955 * Deallocate the memory used by an notation definition
1958 xmlFreeNotation(xmlNotationPtr nota) {
1959 if (nota == NULL) return;
1960 if (nota->name != NULL)
1961 xmlFree((xmlChar *) nota->name);
1962 if (nota->PublicID != NULL)
1963 xmlFree((xmlChar *) nota->PublicID);
1964 if (nota->SystemID != NULL)
1965 xmlFree((xmlChar *) nota->SystemID);
1971 * xmlAddNotationDecl:
1972 * @dtd: pointer to the DTD
1973 * @ctxt: the validation context
1974 * @name: the entity name
1975 * @PublicID: the public identifier or NULL
1976 * @SystemID: the system identifier or NULL
1978 * Register a new notation declaration
1980 * Returns NULL if not, otherwise the entity
1983 xmlAddNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDtdPtr dtd,
1984 const xmlChar *name,
1985 const xmlChar *PublicID, const xmlChar *SystemID) {
1987 xmlNotationTablePtr table;
1990 xmlGenericError(xmlGenericErrorContext,
1991 "xmlAddNotationDecl: dtd == NULL\n");
1995 xmlGenericError(xmlGenericErrorContext,
1996 "xmlAddNotationDecl: name == NULL\n");
1999 if ((PublicID == NULL) && (SystemID == NULL)) {
2000 xmlGenericError(xmlGenericErrorContext,
2001 "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
2006 * Create the Notation table if needed.
2008 table = (xmlNotationTablePtr) dtd->notations;
2010 dtd->notations = table = xmlCreateNotationTable();
2011 if (table == NULL) {
2012 xmlGenericError(xmlGenericErrorContext,
2013 "xmlAddNotationDecl: Table creation failed!\n");
2017 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlAddNotationDecl: out of memory\n");
2023 memset(ret, 0, sizeof(xmlNotation));
2026 * fill the structure.
2028 ret->name = xmlStrdup(name);
2029 if (SystemID != NULL)
2030 ret->SystemID = xmlStrdup(SystemID);
2031 if (PublicID != NULL)
2032 ret->PublicID = xmlStrdup(PublicID);
2036 * Check the DTD for previous declarations of the ATTLIST
2038 if (xmlHashAddEntry(table, name, ret)) {
2039 xmlGenericError(xmlGenericErrorContext,
2040 "xmlAddNotationDecl: %s already defined\n", name);
2041 xmlFreeNotation(ret);
2048 * xmlFreeNotationTable:
2049 * @table: An notation table
2051 * Deallocate the memory used by an entities hash table.
2054 xmlFreeNotationTable(xmlNotationTablePtr table) {
2055 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2062 * Build a copy of a notation.
2064 * Returns the new xmlNotationPtr or NULL in case of error.
2066 static xmlNotationPtr
2067 xmlCopyNotation(xmlNotationPtr nota) {
2070 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2072 xmlGenericError(xmlGenericErrorContext,
2073 "xmlCopyNotation: out of memory !\n");
2076 if (nota->name != NULL)
2077 cur->name = xmlStrdup(nota->name);
2080 if (nota->PublicID != NULL)
2081 cur->PublicID = xmlStrdup(nota->PublicID);
2083 cur->PublicID = NULL;
2084 if (nota->SystemID != NULL)
2085 cur->SystemID = xmlStrdup(nota->SystemID);
2087 cur->SystemID = NULL;
2092 * xmlCopyNotationTable:
2093 * @table: A notation table
2095 * Build a copy of a notation table.
2097 * Returns the new xmlNotationTablePtr or NULL in case of error.
2100 xmlCopyNotationTable(xmlNotationTablePtr table) {
2101 return((xmlNotationTablePtr) xmlHashCopy(table,
2102 (xmlHashCopier) xmlCopyNotation));
2106 * xmlDumpNotationDecl:
2107 * @buf: the XML buffer output
2108 * @nota: A notation declaration
2110 * This will dump the content the notation declaration as an XML DTD definition
2113 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2114 xmlBufferWriteChar(buf, "<!NOTATION ");
2115 xmlBufferWriteCHAR(buf, nota->name);
2116 if (nota->PublicID != NULL) {
2117 xmlBufferWriteChar(buf, " PUBLIC ");
2118 xmlBufferWriteQuotedString(buf, nota->PublicID);
2119 if (nota->SystemID != NULL) {
2120 xmlBufferWriteChar(buf, " ");
2121 xmlBufferWriteCHAR(buf, nota->SystemID);
2124 xmlBufferWriteChar(buf, " SYSTEM ");
2125 xmlBufferWriteCHAR(buf, nota->SystemID);
2127 xmlBufferWriteChar(buf, " >\n");
2131 * xmlDumpNotationTable:
2132 * @buf: the XML buffer output
2133 * @table: A notation table
2135 * This will dump the content of the notation table as an XML DTD definition
2138 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2139 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDecl, buf);
2142 /************************************************************************
2146 ************************************************************************/
2150 * create and initialize an empty id hash table.
2152 * Returns the xmlIDTablePtr just created or NULL in case
2155 static xmlIDTablePtr
2156 xmlCreateIDTable(void) {
2157 return(xmlHashCreate(0));
2164 * Deallocate the memory used by an id definition
2167 xmlFreeID(xmlIDPtr id) {
2168 if (id == NULL) return;
2169 if (id->value != NULL)
2170 xmlFree((xmlChar *) id->value);
2171 if (id->name != NULL)
2172 xmlFree((xmlChar *) id->name);
2178 * @ctxt: the validation context
2179 * @doc: pointer to the document
2180 * @value: the value name
2181 * @attr: the attribute holding the ID
2183 * Register a new id declaration
2185 * Returns NULL if not, otherwise the new xmlIDPtr
2188 xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2191 xmlIDTablePtr table;
2194 xmlGenericError(xmlGenericErrorContext,
2195 "xmlAddID: doc == NULL\n");
2198 if (value == NULL) {
2199 xmlGenericError(xmlGenericErrorContext,
2200 "xmlAddID: value == NULL\n");
2204 xmlGenericError(xmlGenericErrorContext,
2205 "xmlAddID: attr == NULL\n");
2210 * Create the ID table if needed.
2212 table = (xmlIDTablePtr) doc->ids;
2214 doc->ids = table = xmlCreateIDTable();
2215 if (table == NULL) {
2216 xmlGenericError(xmlGenericErrorContext,
2217 "xmlAddID: Table creation failed!\n");
2221 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2223 xmlGenericError(xmlGenericErrorContext,
2224 "xmlAddID: out of memory\n");
2229 * fill the structure.
2231 ret->value = xmlStrdup(value);
2232 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2234 * Operating in streaming mode, attr is gonna disapear
2236 ret->name = xmlStrdup(attr->name);
2242 ret->lineno = xmlGetLineNo(attr->parent);
2244 if (xmlHashAddEntry(table, value, ret) < 0) {
2246 * The id is already defined in this DTD.
2249 VECTXT(ctxt, attr->parent);
2250 VERROR(ctxt->userData, "ID %s already defined\n", value);
2256 attr->atype = XML_ATTRIBUTE_ID;
2262 * @table: An id table
2264 * Deallocate the memory used by an ID hash table.
2267 xmlFreeIDTable(xmlIDTablePtr table) {
2268 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2273 * @doc: the document
2274 * @elem: the element carrying the attribute
2275 * @attr: the attribute
2277 * Determine whether an attribute is of type ID. In case we have DTD(s)
2278 * then this is done if DTD loading has been requested. In the case
2279 * of HTML documents parsed with the HTML parser, then ID detection is
2280 * done systematically.
2282 * Returns 0 or 1 depending on the lookup result
2285 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2286 if (doc == NULL) return(0);
2287 if (attr == NULL) return(0);
2288 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2290 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2291 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2292 (xmlStrEqual(BAD_CAST "name", attr->name)))
2296 xmlAttributePtr attrDecl;
2298 if (elem == NULL) return(0);
2299 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2303 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
2304 if (fullname == NULL)
2306 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2308 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2309 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2311 if ((fullname != fn) && (fullname != elem->name))
2314 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2316 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2317 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2321 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2329 * @doc: the document
2330 * @attr: the attribute
2332 * Remove the given attribute from the ID table maintained internally.
2334 * Returns -1 if the lookup failed and 0 otherwise
2337 xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2339 xmlIDTablePtr table;
2342 if (doc == NULL) return(-1);
2343 if (attr == NULL) return(-1);
2344 table = (xmlIDTablePtr) doc->ids;
2350 ID = xmlNodeListGetString(doc, attr->children, 1);
2353 cur = xmlHashLookup(table, ID);
2358 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2365 * @doc: pointer to the document
2368 * Search the attribute declaring the given ID
2370 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2373 xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2374 xmlIDTablePtr table;
2378 xmlGenericError(xmlGenericErrorContext, "xmlGetID: doc == NULL\n");
2383 xmlGenericError(xmlGenericErrorContext, "xmlGetID: ID == NULL\n");
2387 table = (xmlIDTablePtr) doc->ids;
2391 id = xmlHashLookup(table, ID);
2394 if (id->attr == NULL) {
2396 * We are operating on a stream, return a well known reference
2397 * since the attribute node doesn't exist anymore
2399 return((xmlAttrPtr) doc);
2404 /************************************************************************
2408 ************************************************************************/
2409 typedef struct xmlRemoveMemo_t
2415 typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2417 typedef struct xmlValidateMemo_t
2419 xmlValidCtxtPtr ctxt;
2420 const xmlChar *name;
2423 typedef xmlValidateMemo *xmlValidateMemoPtr;
2426 * xmlCreateRefTable:
2428 * create and initialize an empty ref hash table.
2430 * Returns the xmlRefTablePtr just created or NULL in case
2433 static xmlRefTablePtr
2434 xmlCreateRefTable(void) {
2435 return(xmlHashCreate(0));
2442 * Deallocate the memory used by a ref definition
2445 xmlFreeRef(xmlLinkPtr lk) {
2446 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2447 if (ref == NULL) return;
2448 if (ref->value != NULL)
2449 xmlFree((xmlChar *)ref->value);
2450 if (ref->name != NULL)
2451 xmlFree((xmlChar *)ref->name);
2457 * @list_ref: A list of references.
2459 * Deallocate the memory used by a list of references
2462 xmlFreeRefList(xmlListPtr list_ref) {
2463 if (list_ref == NULL) return;
2464 xmlListDelete(list_ref);
2469 * @data: Contents of current link
2470 * @user: Value supplied by the user
2472 * Returns 0 to abort the walk or 1 to continue
2475 xmlWalkRemoveRef(const void *data, const void *user)
2477 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2478 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2479 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2481 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2482 xmlListRemoveFirst(ref_list, (void *)data);
2490 * @ctxt: the validation context
2491 * @doc: pointer to the document
2492 * @value: the value name
2493 * @attr: the attribute holding the Ref
2495 * Register a new ref declaration
2497 * Returns NULL if not, otherwise the new xmlRefPtr
2500 xmlAddRef(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc, const xmlChar *value,
2503 xmlRefTablePtr table;
2504 xmlListPtr ref_list;
2507 xmlGenericError(xmlGenericErrorContext,
2508 "xmlAddRef: doc == NULL\n");
2511 if (value == NULL) {
2512 xmlGenericError(xmlGenericErrorContext,
2513 "xmlAddRef: value == NULL\n");
2517 xmlGenericError(xmlGenericErrorContext,
2518 "xmlAddRef: attr == NULL\n");
2523 * Create the Ref table if needed.
2525 table = (xmlRefTablePtr) doc->refs;
2527 doc->refs = table = xmlCreateRefTable();
2528 if (table == NULL) {
2529 xmlGenericError(xmlGenericErrorContext,
2530 "xmlAddRef: Table creation failed!\n");
2534 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2536 xmlGenericError(xmlGenericErrorContext,
2537 "xmlAddRef: out of memory\n");
2542 * fill the structure.
2544 ret->value = xmlStrdup(value);
2545 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2547 * Operating in streaming mode, attr is gonna disapear
2549 ret->name = xmlStrdup(attr->name);
2555 ret->lineno = xmlGetLineNo(attr->parent);
2557 /* To add a reference :-
2558 * References are maintained as a list of references,
2559 * Lookup the entry, if no entry create new nodelist
2560 * Add the owning node to the NodeList
2564 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2565 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
2566 xmlGenericError(xmlGenericErrorContext,
2567 "xmlAddRef: Reference list creation failed!\n");
2570 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2571 xmlListDelete(ref_list);
2572 xmlGenericError(xmlGenericErrorContext,
2573 "xmlAddRef: Reference list insertion failed!\n");
2577 xmlListInsert(ref_list, ret);
2583 * @table: An ref table
2585 * Deallocate the memory used by an Ref hash table.
2588 xmlFreeRefTable(xmlRefTablePtr table) {
2589 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
2594 * @doc: the document
2595 * @elem: the element carrying the attribute
2596 * @attr: the attribute
2598 * Determine whether an attribute is of type Ref. In case we have DTD(s)
2599 * then this is simple, otherwise we use an heuristic: name Ref (upper
2602 * Returns 0 or 1 depending on the lookup result
2605 xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2606 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2608 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2612 xmlAttributePtr attrDecl;
2614 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2615 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2616 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2617 elem->name, attr->name);
2619 if ((attrDecl != NULL) &&
2620 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2621 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2629 * @doc: the document
2630 * @attr: the attribute
2632 * Remove the given attribute from the Ref table maintained internally.
2634 * Returns -1 if the lookup failed and 0 otherwise
2637 xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
2638 xmlListPtr ref_list;
2639 xmlRefTablePtr table;
2641 xmlRemoveMemo target;
2643 if (doc == NULL) return(-1);
2644 if (attr == NULL) return(-1);
2645 table = (xmlRefTablePtr) doc->refs;
2651 ID = xmlNodeListGetString(doc, attr->children, 1);
2654 ref_list = xmlHashLookup(table, ID);
2656 if(ref_list == NULL) {
2660 /* At this point, ref_list refers to a list of references which
2661 * have the same key as the supplied attr. Our list of references
2662 * is ordered by reference address and we don't have that information
2663 * here to use when removing. We'll have to walk the list and
2664 * check for a matching attribute, when we find one stop the walk
2665 * and remove the entry.
2666 * The list is ordered by reference, so that means we don't have the
2667 * key. Passing the list and the reference to the walker means we
2668 * will have enough data to be able to remove the entry.
2670 target.l = ref_list;
2673 /* Remove the supplied attr from our list */
2674 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
2676 /*If the list is empty then remove the list entry in the hash */
2677 if (xmlListEmpty(ref_list))
2678 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2686 * @doc: pointer to the document
2689 * Find the set of references for the supplied ID.
2691 * Returns NULL if not found, otherwise node set for the ID.
2694 xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
2695 xmlRefTablePtr table;
2698 xmlGenericError(xmlGenericErrorContext, "xmlGetRefs: doc == NULL\n");
2703 xmlGenericError(xmlGenericErrorContext, "xmlGetRefs: ID == NULL\n");
2707 table = (xmlRefTablePtr) doc->refs;
2711 return (xmlHashLookup(table, ID));
2714 /************************************************************************
2716 * Routines for validity checking *
2718 ************************************************************************/
2721 * xmlGetDtdElementDesc:
2722 * @dtd: a pointer to the DtD to search
2723 * @name: the element name
2725 * Search the DTD for the description of this element
2727 * returns the xmlElementPtr if found or NULL
2731 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2732 xmlElementTablePtr table;
2734 xmlChar *uqname = NULL, *prefix = NULL;
2736 if ((dtd == NULL) || (name == NULL)) return(NULL);
2737 if (dtd->elements == NULL)
2739 table = (xmlElementTablePtr) dtd->elements;
2741 uqname = xmlSplitQName2(name, &prefix);
2744 cur = xmlHashLookup2(table, name, prefix);
2745 if (prefix != NULL) xmlFree(prefix);
2746 if (uqname != NULL) xmlFree(uqname);
2750 * xmlGetDtdElementDesc2:
2751 * @dtd: a pointer to the DtD to search
2752 * @name: the element name
2753 * @create: create an empty description if not found
2755 * Search the DTD for the description of this element
2757 * returns the xmlElementPtr if found or NULL
2760 static xmlElementPtr
2761 xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2762 xmlElementTablePtr table;
2764 xmlChar *uqname = NULL, *prefix = NULL;
2766 if (dtd == NULL) return(NULL);
2767 if (dtd->elements == NULL) {
2771 * Create the Element table if needed.
2773 table = (xmlElementTablePtr) dtd->elements;
2774 if (table == NULL) {
2775 table = xmlCreateElementTable();
2776 dtd->elements = (void *) table;
2778 if (table == NULL) {
2779 xmlGenericError(xmlGenericErrorContext,
2780 "xmlGetDtdElementDesc2: Table creation failed!\n");
2784 table = (xmlElementTablePtr) dtd->elements;
2786 uqname = xmlSplitQName2(name, &prefix);
2789 cur = xmlHashLookup2(table, name, prefix);
2790 if ((cur == NULL) && (create)) {
2791 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
2793 xmlGenericError(xmlGenericErrorContext,
2794 "xmlGetDtdElementDesc2: out of memory\n");
2797 memset(cur, 0, sizeof(xmlElement));
2798 cur->type = XML_ELEMENT_DECL;
2801 * fill the structure.
2803 cur->name = xmlStrdup(name);
2804 cur->prefix = xmlStrdup(prefix);
2805 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
2807 xmlHashAddEntry2(table, name, prefix, cur);
2809 if (prefix != NULL) xmlFree(prefix);
2810 if (uqname != NULL) xmlFree(uqname);
2815 * xmlGetDtdQElementDesc:
2816 * @dtd: a pointer to the DtD to search
2817 * @name: the element name
2818 * @prefix: the element namespace prefix
2820 * Search the DTD for the description of this element
2822 * returns the xmlElementPtr if found or NULL
2826 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2827 const xmlChar *prefix) {
2828 xmlElementTablePtr table;
2830 if (dtd == NULL) return(NULL);
2831 if (dtd->elements == NULL) return(NULL);
2832 table = (xmlElementTablePtr) dtd->elements;
2834 return(xmlHashLookup2(table, name, prefix));
2838 * xmlGetDtdAttrDesc:
2839 * @dtd: a pointer to the DtD to search
2840 * @elem: the element name
2841 * @name: the attribute name
2843 * Search the DTD for the description of this attribute on
2846 * returns the xmlAttributePtr if found or NULL
2850 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
2851 xmlAttributeTablePtr table;
2852 xmlAttributePtr cur;
2853 xmlChar *uqname = NULL, *prefix = NULL;
2855 if (dtd == NULL) return(NULL);
2856 if (dtd->attributes == NULL) return(NULL);
2858 table = (xmlAttributeTablePtr) dtd->attributes;
2862 uqname = xmlSplitQName2(name, &prefix);
2864 if (uqname != NULL) {
2865 cur = xmlHashLookup3(table, uqname, prefix, elem);
2866 if (prefix != NULL) xmlFree(prefix);
2867 if (uqname != NULL) xmlFree(uqname);
2869 cur = xmlHashLookup3(table, name, NULL, elem);
2874 * xmlGetDtdQAttrDesc:
2875 * @dtd: a pointer to the DtD to search
2876 * @elem: the element name
2877 * @name: the attribute name
2878 * @prefix: the attribute namespace prefix
2880 * Search the DTD for the description of this qualified attribute on
2883 * returns the xmlAttributePtr if found or NULL
2887 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2888 const xmlChar *prefix) {
2889 xmlAttributeTablePtr table;
2891 if (dtd == NULL) return(NULL);
2892 if (dtd->attributes == NULL) return(NULL);
2893 table = (xmlAttributeTablePtr) dtd->attributes;
2895 return(xmlHashLookup3(table, name, prefix, elem));
2899 * xmlGetDtdNotationDesc:
2900 * @dtd: a pointer to the DtD to search
2901 * @name: the notation name
2903 * Search the DTD for the description of this notation
2905 * returns the xmlNotationPtr if found or NULL
2909 xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
2910 xmlNotationTablePtr table;
2912 if (dtd == NULL) return(NULL);
2913 if (dtd->notations == NULL) return(NULL);
2914 table = (xmlNotationTablePtr) dtd->notations;
2916 return(xmlHashLookup(table, name));
2920 * xmlValidateNotationUse:
2921 * @ctxt: the validation context
2922 * @doc: the document
2923 * @notationName: the notation name to check
2925 * Validate that the given name match a notation declaration.
2926 * - [ VC: Notation Declared ]
2928 * returns 1 if valid or 0 otherwise
2932 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2933 const xmlChar *notationName) {
2934 xmlNotationPtr notaDecl;
2935 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2937 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2938 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2939 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2941 if ((notaDecl == NULL) && (ctxt != NULL)) {
2942 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2950 * xmlIsMixedElement:
2951 * @doc: the document
2952 * @name: the element name
2954 * Search in the DtDs whether an element accept Mixed content (or ANY)
2955 * basically if it is supposed to accept text childs
2957 * returns 0 if no, 1 if yes, and -1 if no element description is available
2961 xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
2962 xmlElementPtr elemDecl;
2964 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2966 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2967 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2968 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2969 if (elemDecl == NULL) return(-1);
2970 switch (elemDecl->etype) {
2971 case XML_ELEMENT_TYPE_UNDEFINED:
2973 case XML_ELEMENT_TYPE_ELEMENT:
2975 case XML_ELEMENT_TYPE_EMPTY:
2977 * return 1 for EMPTY since we want VC error to pop up
2978 * on <empty> </empty> for example
2980 case XML_ELEMENT_TYPE_ANY:
2981 case XML_ELEMENT_TYPE_MIXED:
2988 * xmlValidateNameValue:
2989 * @value: an Name value
2991 * Validate that the given value match Name production
2993 * returns 1 if valid or 0 otherwise
2997 xmlValidateNameValue(const xmlChar *value) {
3001 if (value == NULL) return(0);
3003 val = xmlStringCurrentChar(NULL, cur, &len);
3005 if (!IS_LETTER(val) && (val != '_') &&
3010 val = xmlStringCurrentChar(NULL, cur, &len);
3012 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3013 (val == '.') || (val == '-') ||
3014 (val == '_') || (val == ':') ||
3015 (IS_COMBINING(val)) ||
3016 (IS_EXTENDER(val))) {
3017 val = xmlStringCurrentChar(NULL, cur, &len);
3021 if (val != 0) return(0);
3027 * xmlValidateNamesValue:
3028 * @value: an Names value
3030 * Validate that the given value match Names production
3032 * returns 1 if valid or 0 otherwise
3036 xmlValidateNamesValue(const xmlChar *value) {
3040 if (value == NULL) return(0);
3042 val = xmlStringCurrentChar(NULL, cur, &len);
3045 if (!IS_LETTER(val) && (val != '_') &&
3050 val = xmlStringCurrentChar(NULL, cur, &len);
3052 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3053 (val == '.') || (val == '-') ||
3054 (val == '_') || (val == ':') ||
3055 (IS_COMBINING(val)) ||
3056 (IS_EXTENDER(val))) {
3057 val = xmlStringCurrentChar(NULL, cur, &len);
3061 while (IS_BLANK(val)) {
3062 while (IS_BLANK(val)) {
3063 val = xmlStringCurrentChar(NULL, cur, &len);
3067 if (!IS_LETTER(val) && (val != '_') &&
3071 val = xmlStringCurrentChar(NULL, cur, &len);
3074 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3075 (val == '.') || (val == '-') ||
3076 (val == '_') || (val == ':') ||
3077 (IS_COMBINING(val)) ||
3078 (IS_EXTENDER(val))) {
3079 val = xmlStringCurrentChar(NULL, cur, &len);
3084 if (val != 0) return(0);
3090 * xmlValidateNmtokenValue:
3091 * @value: an Nmtoken value
3093 * Validate that the given value match Nmtoken production
3095 * [ VC: Name Token ]
3097 * returns 1 if valid or 0 otherwise
3101 xmlValidateNmtokenValue(const xmlChar *value) {
3105 if (value == NULL) return(0);
3107 val = xmlStringCurrentChar(NULL, cur, &len);
3110 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3111 (val != '.') && (val != '-') &&
3112 (val != '_') && (val != ':') &&
3113 (!IS_COMBINING(val)) &&
3114 (!IS_EXTENDER(val)))
3117 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3118 (val == '.') || (val == '-') ||
3119 (val == '_') || (val == ':') ||
3120 (IS_COMBINING(val)) ||
3121 (IS_EXTENDER(val))) {
3122 val = xmlStringCurrentChar(NULL, cur, &len);
3126 if (val != 0) return(0);
3132 * xmlValidateNmtokensValue:
3133 * @value: an Nmtokens value
3135 * Validate that the given value match Nmtokens production
3137 * [ VC: Name Token ]
3139 * returns 1 if valid or 0 otherwise
3143 xmlValidateNmtokensValue(const xmlChar *value) {
3147 if (value == NULL) return(0);
3149 val = xmlStringCurrentChar(NULL, cur, &len);
3152 while (IS_BLANK(val)) {
3153 val = xmlStringCurrentChar(NULL, cur, &len);
3157 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3158 (val != '.') && (val != '-') &&
3159 (val != '_') && (val != ':') &&
3160 (!IS_COMBINING(val)) &&
3161 (!IS_EXTENDER(val)))
3164 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3165 (val == '.') || (val == '-') ||
3166 (val == '_') || (val == ':') ||
3167 (IS_COMBINING(val)) ||
3168 (IS_EXTENDER(val))) {
3169 val = xmlStringCurrentChar(NULL, cur, &len);
3173 while (IS_BLANK(val)) {
3174 while (IS_BLANK(val)) {
3175 val = xmlStringCurrentChar(NULL, cur, &len);
3178 if (val == 0) return(1);
3180 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3181 (val != '.') && (val != '-') &&
3182 (val != '_') && (val != ':') &&
3183 (!IS_COMBINING(val)) &&
3184 (!IS_EXTENDER(val)))
3187 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3188 (val == '.') || (val == '-') ||
3189 (val == '_') || (val == ':') ||
3190 (IS_COMBINING(val)) ||
3191 (IS_EXTENDER(val))) {
3192 val = xmlStringCurrentChar(NULL, cur, &len);
3197 if (val != 0) return(0);
3203 * xmlValidateNotationDecl:
3204 * @ctxt: the validation context
3205 * @doc: a document instance
3206 * @nota: a notation definition
3208 * Try to validate a single notation definition
3209 * basically it does the following checks as described by the
3210 * XML-1.0 recommendation:
3211 * - it seems that no validity constraint exists on notation declarations
3212 * But this function get called anyway ...
3214 * returns 1 if valid or 0 otherwise
3218 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3219 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3226 * xmlValidateAttributeValue:
3227 * @type: an attribute type
3228 * @value: an attribute value
3230 * Validate that the given attribute value match the proper production
3233 * Values of type ID must match the Name production....
3236 * Values of type IDREF must match the Name production, and values
3237 * of type IDREFS must match Names ...
3239 * [ VC: Entity Name ]
3240 * Values of type ENTITY must match the Name production, values
3241 * of type ENTITIES must match Names ...
3243 * [ VC: Name Token ]
3244 * Values of type NMTOKEN must match the Nmtoken production; values
3245 * of type NMTOKENS must match Nmtokens.
3247 * returns 1 if valid or 0 otherwise
3251 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3253 case XML_ATTRIBUTE_ENTITIES:
3254 case XML_ATTRIBUTE_IDREFS:
3255 return(xmlValidateNamesValue(value));
3256 case XML_ATTRIBUTE_ENTITY:
3257 case XML_ATTRIBUTE_IDREF:
3258 case XML_ATTRIBUTE_ID:
3259 case XML_ATTRIBUTE_NOTATION:
3260 return(xmlValidateNameValue(value));
3261 case XML_ATTRIBUTE_NMTOKENS:
3262 case XML_ATTRIBUTE_ENUMERATION:
3263 return(xmlValidateNmtokensValue(value));
3264 case XML_ATTRIBUTE_NMTOKEN:
3265 return(xmlValidateNmtokenValue(value));
3266 case XML_ATTRIBUTE_CDATA:
3273 * xmlValidateAttributeValue2:
3274 * @ctxt: the validation context
3275 * @doc: the document
3276 * @name: the attribute name (used for error reporting only)
3277 * @type: the attribute type
3278 * @value: the attribute value
3280 * Validate that the given attribute value match a given type.
3281 * This typically cannot be done before having finished parsing
3285 * Values of type IDREF must match one of the declared IDs
3286 * Values of type IDREFS must match a sequence of the declared IDs
3287 * each Name must match the value of an ID attribute on some element
3288 * in the XML document; i.e. IDREF values must match the value of
3291 * [ VC: Entity Name ]
3292 * Values of type ENTITY must match one declared entity
3293 * Values of type ENTITIES must match a sequence of declared entities
3295 * [ VC: Notation Attributes ]
3296 * all notation names in the declaration must be declared.
3298 * returns 1 if valid or 0 otherwise
3302 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3303 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3306 case XML_ATTRIBUTE_IDREFS:
3307 case XML_ATTRIBUTE_IDREF:
3308 case XML_ATTRIBUTE_ID:
3309 case XML_ATTRIBUTE_NMTOKENS:
3310 case XML_ATTRIBUTE_ENUMERATION:
3311 case XML_ATTRIBUTE_NMTOKEN:
3312 case XML_ATTRIBUTE_CDATA:
3314 case XML_ATTRIBUTE_ENTITY: {
3317 ent = xmlGetDocEntity(doc, value);
3318 if ((ent == NULL) && (doc->standalone == 1)) {
3319 doc->standalone = 0;
3320 ent = xmlGetDocEntity(doc, value);
3322 VERROR(ctxt->userData,
3323 "standalone problem: attribute %s reference entity \"%s\" in external subset\n",
3325 /* WAIT to get answer from the Core WG on this
3331 VERROR(ctxt->userData,
3332 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3335 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3336 VERROR(ctxt->userData,
3337 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3343 case XML_ATTRIBUTE_ENTITIES: {
3344 xmlChar *dup, *nam = NULL, *cur, save;
3347 dup = xmlStrdup(value);
3353 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3356 ent = xmlGetDocEntity(doc, nam);
3358 VERROR(ctxt->userData,
3359 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3362 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3363 VERROR(ctxt->userData,
3364 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3371 while (IS_BLANK(*cur)) cur++;
3376 case XML_ATTRIBUTE_NOTATION: {
3377 xmlNotationPtr nota;
3379 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3380 if ((nota == NULL) && (doc->extSubset != NULL))
3381 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3384 VERROR(ctxt->userData,
3385 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3396 * xmlValidCtxtNormalizeAttributeValue:
3397 * @ctxt: the validation context
3398 * @doc: the document
3400 * @name: the attribute name
3401 * @value: the attribute value
3402 * @ctxt: the validation context or NULL
3404 * Does the validation related extra step of the normalization of attribute
3407 * If the declared value is not CDATA, then the XML processor must further
3408 * process the normalized attribute value by discarding any leading and
3409 * trailing space (#x20) characters, and by replacing sequences of space
3410 * (#x20) characters by single space (#x20) character.
3412 * Also check VC: Standalone Document Declaration in P32, and update
3413 * ctxt->valid accordingly
3415 * returns a new normalized string if normalization is needed, NULL otherwise
3416 * the caller must free the returned value.
3420 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3421 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3424 xmlAttributePtr attrDecl = NULL;
3427 if (doc == NULL) return(NULL);
3428 if (elem == NULL) return(NULL);
3429 if (name == NULL) return(NULL);
3430 if (value == NULL) return(NULL);
3432 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3436 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3437 if (fullname == NULL)
3439 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
3440 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3441 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3442 if (attrDecl != NULL)
3445 if ((fullname != fn) && (fullname != elem->name))
3448 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3449 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3450 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3451 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3452 if (attrDecl != NULL)
3456 if (attrDecl == NULL)
3458 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3461 ret = xmlStrdup(value);
3466 while (*src == 0x20) src++;
3469 while (*src == 0x20) src++;
3477 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
3478 VERROR(ctxt->userData,
3479 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
3487 * xmlValidNormalizeAttributeValue:
3488 * @doc: the document
3490 * @name: the attribute name
3491 * @value: the attribute value
3493 * Does the validation related extra step of the normalization of attribute
3496 * If the declared value is not CDATA, then the XML processor must further
3497 * process the normalized attribute value by discarding any leading and
3498 * trailing space (#x20) characters, and by replacing sequences of space
3499 * (#x20) characters by single space (#x20) character.
3501 * returns a new normalized string if normalization is needed, NULL otherwise
3502 * the caller must free the returned value.
3506 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3507 const xmlChar *name, const xmlChar *value) {
3510 xmlAttributePtr attrDecl = NULL;
3512 if (doc == NULL) return(NULL);
3513 if (elem == NULL) return(NULL);
3514 if (name == NULL) return(NULL);
3515 if (value == NULL) return(NULL);
3517 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3521 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3522 if (fullname == NULL)
3524 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
3525 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3526 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3527 if ((fullname != fn) && (fullname != elem->name))
3530 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3531 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3532 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3534 if (attrDecl == NULL)
3536 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3539 ret = xmlStrdup(value);
3544 while (*src == 0x20) src++;
3547 while (*src == 0x20) src++;
3559 xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
3560 const xmlChar* name ATTRIBUTE_UNUSED) {
3561 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3565 * xmlValidateAttributeDecl:
3566 * @ctxt: the validation context
3567 * @doc: a document instance
3568 * @attr: an attribute definition
3570 * Try to validate a single attribute definition
3571 * basically it does the following checks as described by the
3572 * XML-1.0 recommendation:
3573 * - [ VC: Attribute Default Legal ]
3574 * - [ VC: Enumeration ]
3575 * - [ VC: ID Attribute Default ]
3577 * The ID/IDREF uniqueness and matching are done separately
3579 * returns 1 if valid or 0 otherwise
3583 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3584 xmlAttributePtr attr) {
3588 if(attr == NULL) return(1);
3590 /* Attribute Default Legal */
3592 if (attr->defaultValue != NULL) {
3593 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3595 VERROR(ctxt->userData,
3596 "Syntax of default value for attribute %s of %s is not valid\n",
3597 attr->name, attr->elem);
3602 /* ID Attribute Default */
3603 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3604 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3605 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
3606 VERROR(ctxt->userData,
3607 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
3608 attr->name, attr->elem);
3612 /* One ID per Element Type */
3613 if (attr->atype == XML_ATTRIBUTE_ID) {
3616 /* the trick is that we parse DtD as their own internal subset */
3617 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3620 nbId = xmlScanIDAttributeDecl(NULL, elem);
3622 xmlAttributeTablePtr table;
3625 * The attribute may be declared in the internal subset and the
3626 * element in the external subset.
3629 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3630 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3631 xmlValidateAttributeIdCallback, &nbId);
3634 VERROR(ctxt->userData,
3635 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3636 attr->elem, nbId, attr->name);
3637 } else if (doc->extSubset != NULL) {
3639 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3641 extId = xmlScanIDAttributeDecl(NULL, elem);
3644 VERROR(ctxt->userData,
3645 "Element %s has %d ID attribute defined in the external subset : %s\n",
3646 attr->elem, extId, attr->name);
3647 } else if (extId + nbId > 1) {
3648 VERROR(ctxt->userData,
3649 "Element %s has ID attributes defined in the internal and external subset : %s\n",
3650 attr->elem, attr->name);
3655 /* Validity Constraint: Enumeration */
3656 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3657 xmlEnumerationPtr tree = attr->tree;
3658 while (tree != NULL) {
3659 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3663 VERROR(ctxt->userData,
3664 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
3665 attr->defaultValue, attr->name, attr->elem);
3674 * xmlValidateElementDecl:
3675 * @ctxt: the validation context
3676 * @doc: a document instance
3677 * @elem: an element definition
3679 * Try to validate a single element definition
3680 * basically it does the following checks as described by the
3681 * XML-1.0 recommendation:
3682 * - [ VC: One ID per Element Type ]
3683 * - [ VC: No Duplicate Types ]
3684 * - [ VC: Unique Element Type Declaration ]
3686 * returns 1 if valid or 0 otherwise
3690 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3691 xmlElementPtr elem) {
3697 if (elem == NULL) return(1);
3700 #ifdef LIBXML_REGEXP_ENABLED
3701 /* Build the regexp associated to the content model */
3702 ret = xmlValidBuildContentModel(ctxt, elem);
3706 /* No Duplicate Types */
3707 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3708 xmlElementContentPtr cur, next;
3709 const xmlChar *name;
3711 cur = elem->content;
3712 while (cur != NULL) {
3713 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3714 if (cur->c1 == NULL) break;
3715 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3716 name = cur->c1->name;
3718 while (next != NULL) {
3719 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
3720 if ((xmlStrEqual(next->name, name)) &&
3721 (xmlStrEqual(next->prefix, cur->prefix))) {
3722 if (cur->prefix == NULL) {
3723 VERROR(ctxt->userData,
3724 "Definition of %s has duplicate references of %s\n",
3727 VERROR(ctxt->userData,
3728 "Definition of %s has duplicate references of %s:%s\n",
3729 elem->name, cur->prefix, name);
3735 if (next->c1 == NULL) break;
3736 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
3737 if ((xmlStrEqual(next->c1->name, name)) &&
3738 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3739 if (cur->prefix == NULL) {
3740 VERROR(ctxt->userData,
3741 "Definition of %s has duplicate references to %s\n",
3744 VERROR(ctxt->userData,
3745 "Definition of %s has duplicate references to %s:%s\n",
3746 elem->name, cur->prefix, name);
3757 /* VC: Unique Element Type Declaration */
3758 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3759 if ((tst != NULL ) && (tst != elem) &&
3760 ((tst->prefix == elem->prefix) ||
3761 (xmlStrEqual(tst->prefix, elem->prefix))) &&
3762 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
3763 VERROR(ctxt->userData, "Redefinition of element %s\n",
3767 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3768 if ((tst != NULL ) && (tst != elem) &&
3769 ((tst->prefix == elem->prefix) ||
3770 (xmlStrEqual(tst->prefix, elem->prefix))) &&
3771 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
3772 VERROR(ctxt->userData, "Redefinition of element %s\n",
3776 /* One ID per Element Type
3777 * already done when registering the attribute
3778 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3785 * xmlValidateOneAttribute:
3786 * @ctxt: the validation context
3787 * @doc: a document instance
3788 * @elem: an element instance
3789 * @attr: an attribute instance
3790 * @value: the attribute value (without entities processing)
3792 * Try to validate a single attribute for an element
3793 * basically it does the following checks as described by the
3794 * XML-1.0 recommendation:
3795 * - [ VC: Attribute Value Type ]
3796 * - [ VC: Fixed Attribute Default ]
3797 * - [ VC: Entity Name ]
3798 * - [ VC: Name Token ]
3801 * - [ VC: Entity Name ]
3802 * - [ VC: Notation Attributes ]
3804 * The ID/IDREF uniqueness and matching are done separately
3806 * returns 1 if valid or 0 otherwise
3810 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3811 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
3812 /* xmlElementPtr elemDecl; */
3813 xmlAttributePtr attrDecl = NULL;
3818 if ((elem == NULL) || (elem->name == NULL)) return(0);
3819 if ((attr == NULL) || (attr->name == NULL)) return(0);
3821 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3825 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3826 if (fullname == NULL)
3828 if (attr->ns != NULL) {
3829 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
3830 attr->name, attr->ns->prefix);
3831 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3832 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
3833 attr->name, attr->ns->prefix);
3835 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
3836 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3837 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3838 fullname, attr->name);
3840 if ((fullname != fn) && (fullname != elem->name))
3843 if (attrDecl == NULL) {
3844 if (attr->ns != NULL) {
3845 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3846 attr->name, attr->ns->prefix);
3847 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3848 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3849 attr->name, attr->ns->prefix);
3851 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3852 elem->name, attr->name);
3853 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3854 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3855 elem->name, attr->name);
3860 /* Validity Constraint: Attribute Value Type */
3861 if (attrDecl == NULL) {
3863 VERROR(ctxt->userData,
3864 "No declaration for attribute %s of element %s\n",
3865 attr->name, elem->name);
3868 attr->atype = attrDecl->atype;
3870 val = xmlValidateAttributeValue(attrDecl->atype, value);
3873 VERROR(ctxt->userData,
3874 "Syntax of value for attribute %s of %s is not valid\n",
3875 attr->name, elem->name);
3879 /* Validity constraint: Fixed Attribute Default */
3880 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3881 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
3883 VERROR(ctxt->userData,
3884 "Value for attribute %s of %s is different from default \"%s\"\n",
3885 attr->name, elem->name, attrDecl->defaultValue);
3890 /* Validity Constraint: ID uniqueness */
3891 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
3892 if (xmlAddID(ctxt, doc, value, attr) == NULL)
3896 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3897 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
3898 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
3902 /* Validity Constraint: Notation Attributes */
3903 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
3904 xmlEnumerationPtr tree = attrDecl->tree;
3905 xmlNotationPtr nota;
3907 /* First check that the given NOTATION was declared */
3908 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3910 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3914 VERROR(ctxt->userData,
3915 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
3916 value, attr->name, elem->name);
3920 /* Second, verify that it's among the list */
3921 while (tree != NULL) {
3922 if (xmlStrEqual(tree->name, value)) break;
3927 VERROR(ctxt->userData,
3928 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
3929 value, attr->name, elem->name);
3934 /* Validity Constraint: Enumeration */
3935 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
3936 xmlEnumerationPtr tree = attrDecl->tree;
3937 while (tree != NULL) {
3938 if (xmlStrEqual(tree->name, value)) break;
3943 VERROR(ctxt->userData,
3944 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
3945 value, attr->name, elem->name);
3950 /* Fixed Attribute Default */
3951 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3952 (!xmlStrEqual(attrDecl->defaultValue, value))) {
3954 VERROR(ctxt->userData,
3955 "Value for attribute %s of %s must be \"%s\"\n",
3956 attr->name, elem->name, attrDecl->defaultValue);
3960 /* Extra check for the attribute value */
3961 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3962 attrDecl->atype, value);
3968 * xmlValidateOneNamespace:
3969 * @ctxt: the validation context
3970 * @doc: a document instance
3971 * @elem: an element instance
3972 * @prefix: the namespace prefix
3973 * @ns: an namespace declaration instance
3974 * @value: the attribute value (without entities processing)
3976 * Try to validate a single namespace declaration for an element
3977 * basically it does the following checks as described by the
3978 * XML-1.0 recommendation:
3979 * - [ VC: Attribute Value Type ]
3980 * - [ VC: Fixed Attribute Default ]
3981 * - [ VC: Entity Name ]
3982 * - [ VC: Name Token ]
3985 * - [ VC: Entity Name ]
3986 * - [ VC: Notation Attributes ]
3988 * The ID/IDREF uniqueness and matching are done separately
3990 * returns 1 if valid or 0 otherwise
3994 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3995 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
3996 /* xmlElementPtr elemDecl; */
3997 xmlAttributePtr attrDecl = NULL;
4002 if ((elem == NULL) || (elem->name == NULL)) return(0);
4003 if ((ns == NULL) || (ns->href == NULL)) return(0);
4005 if (prefix != NULL) {
4009 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4010 if (fullname == NULL) {
4011 VERROR(ctxt->userData, "Out of memory\n");
4014 if (ns->prefix != NULL) {
4015 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4016 ns->prefix, BAD_CAST "xmlns");
4017 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4018 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4019 ns->prefix, BAD_CAST "xmlns");
4021 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4023 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4024 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4027 if ((fullname != fn) && (fullname != elem->name))
4030 if (attrDecl == NULL) {
4031 if (ns->prefix != NULL) {
4032 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4033 ns->prefix, BAD_CAST "xmlns");
4034 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4035 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4036 ns->prefix, BAD_CAST "xmlns");
4038 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4039 elem->name, BAD_CAST "xmlns");
4040 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4041 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4042 elem->name, BAD_CAST "xmlns");
4047 /* Validity Constraint: Attribute Value Type */
4048 if (attrDecl == NULL) {
4050 if (ns->prefix != NULL) {
4051 VERROR(ctxt->userData,
4052 "No declaration for attribute xmlns:%s of element %s\n",
4053 ns->prefix, elem->name);
4055 VERROR(ctxt->userData,
4056 "No declaration for attribute xmlns of element %s\n",
4062 val = xmlValidateAttributeValue(attrDecl->atype, value);
4065 if (ns->prefix != NULL) {
4066 VERROR(ctxt->userData,
4067 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4068 ns->prefix, elem->name);
4070 VERROR(ctxt->userData,
4071 "Syntax of value for attribute xmlns of %s is not valid\n",
4077 /* Validity constraint: Fixed Attribute Default */
4078 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4079 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4081 if (ns->prefix != NULL) {
4082 VERROR(ctxt->userData,
4083 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4084 ns->prefix, elem->name, attrDecl->defaultValue);
4086 VERROR(ctxt->userData,
4087 "Value for attribute xmlns of %s is different from default \"%s\"\n",
4088 elem->name, attrDecl->defaultValue);
4094 /* Validity Constraint: ID uniqueness */
4095 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4096 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4100 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4101 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4102 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4106 /* Validity Constraint: Notation Attributes */
4107 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4108 xmlEnumerationPtr tree = attrDecl->tree;
4109 xmlNotationPtr nota;
4111 /* First check that the given NOTATION was declared */
4112 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4114 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4118 if (ns->prefix != NULL) {
4119 VERROR(ctxt->userData,
4120 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4121 value, ns->prefix, elem->name);
4123 VERROR(ctxt->userData,
4124 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4130 /* Second, verify that it's among the list */
4131 while (tree != NULL) {
4132 if (xmlStrEqual(tree->name, value)) break;
4137 if (ns->prefix != NULL) {
4138 VERROR(ctxt->userData,
4139 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4140 value, ns->prefix, elem->name);
4142 VERROR(ctxt->userData,
4143 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4150 /* Validity Constraint: Enumeration */
4151 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4152 xmlEnumerationPtr tree = attrDecl->tree;
4153 while (tree != NULL) {
4154 if (xmlStrEqual(tree->name, value)) break;
4159 if (ns->prefix != NULL) {
4160 VERROR(ctxt->userData,
4161 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4162 value, ns->prefix, elem->name);
4164 VERROR(ctxt->userData,
4165 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4172 /* Fixed Attribute Default */
4173 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4174 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4176 if (ns->prefix != NULL) {
4177 VERROR(ctxt->userData,
4178 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4179 ns->prefix, elem->name, attrDecl->defaultValue);
4181 VERROR(ctxt->userData,
4182 "Value for attribute xmlns of %s must be \"%s\"\n",
4183 elem->name, attrDecl->defaultValue);
4188 /* Extra check for the attribute value */
4189 if (ns->prefix != NULL) {
4190 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4191 attrDecl->atype, value);
4193 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4194 attrDecl->atype, value);
4200 #ifndef LIBXML_REGEXP_ENABLED
4202 * xmlValidateSkipIgnorable:
4203 * @ctxt: the validation context
4204 * @child: the child list
4206 * Skip ignorable elements w.r.t. the validation process
4208 * returns the first element to consider for validation of the content model
4212 xmlValidateSkipIgnorable(xmlNodePtr child) {
4213 while (child != NULL) {
4214 switch (child->type) {
4215 /* These things are ignored (skipped) during validation. */
4217 case XML_COMMENT_NODE:
4218 case XML_XINCLUDE_START:
4219 case XML_XINCLUDE_END:
4220 child = child->next;
4223 if (xmlIsBlankNode(child))
4224 child = child->next;
4228 /* keep current node */
4237 * xmlValidateElementType:
4238 * @ctxt: the validation context
4240 * Try to validate the content model of an element internal function
4242 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4243 * reference is found and -3 if the validation succeeded but
4244 * the content model is not determinist.
4248 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4250 int determinist = 1;
4252 NODE = xmlValidateSkipIgnorable(NODE);
4253 if ((NODE == NULL) && (CONT == NULL))
4255 if ((NODE == NULL) &&
4256 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4257 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4260 if (CONT == NULL) return(-1);
4261 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4265 * We arrive here when more states need to be examined
4270 * We just recovered from a rollback generated by a possible
4271 * epsilon transition, go directly to the analysis phase
4273 if (STATE == ROLLBACK_PARENT) {
4274 DEBUG_VALID_MSG("restored parent branch");
4275 DEBUG_VALID_STATE(NODE, CONT)
4280 DEBUG_VALID_STATE(NODE, CONT)
4282 * we may have to save a backup state here. This is the equivalent
4283 * of handling epsilon transition in NFAs.
4285 if ((CONT != NULL) &&
4286 ((CONT->parent == NULL) ||
4287 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4288 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4289 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4290 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4291 DEBUG_VALID_MSG("saving parent branch");
4292 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4298 * Check first if the content matches
4300 switch (CONT->type) {
4301 case XML_ELEMENT_CONTENT_PCDATA:
4303 DEBUG_VALID_MSG("pcdata failed no node");
4307 if (NODE->type == XML_TEXT_NODE) {
4308 DEBUG_VALID_MSG("pcdata found, skip to next");
4310 * go to next element in the content model
4311 * skipping ignorable elems
4315 NODE = xmlValidateSkipIgnorable(NODE);
4316 if ((NODE != NULL) &&
4317 (NODE->type == XML_ENTITY_REF_NODE))
4319 } while ((NODE != NULL) &&
4320 ((NODE->type != XML_ELEMENT_NODE) &&
4321 (NODE->type != XML_TEXT_NODE) &&
4322 (NODE->type != XML_CDATA_SECTION_NODE)));
4326 DEBUG_VALID_MSG("pcdata failed");
4331 case XML_ELEMENT_CONTENT_ELEMENT:
4333 DEBUG_VALID_MSG("element failed no node");
4337 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4338 (xmlStrEqual(NODE->name, CONT->name)));
4340 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4341 ret = (CONT->prefix == NULL);
4342 } else if (CONT->prefix == NULL) {
4345 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4349 DEBUG_VALID_MSG("element found, skip to next");
4351 * go to next element in the content model
4352 * skipping ignorable elems
4356 NODE = xmlValidateSkipIgnorable(NODE);
4357 if ((NODE != NULL) &&
4358 (NODE->type == XML_ENTITY_REF_NODE))
4360 } while ((NODE != NULL) &&
4361 ((NODE->type != XML_ELEMENT_NODE) &&
4362 (NODE->type != XML_TEXT_NODE) &&
4363 (NODE->type != XML_CDATA_SECTION_NODE)));
4365 DEBUG_VALID_MSG("element failed");
4370 case XML_ELEMENT_CONTENT_OR:
4372 * Small optimization.
4374 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4375 if ((NODE == NULL) ||
4376 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4381 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4382 ret = (CONT->c1->prefix == NULL);
4383 } else if (CONT->c1->prefix == NULL) {
4386 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4396 * save the second branch 'or' branch
4398 DEBUG_VALID_MSG("saving 'or' branch");
4399 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4400 OCCURS, ROLLBACK_OR) < 0)
4405 case XML_ELEMENT_CONTENT_SEQ:
4407 * Small optimization.
4409 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4410 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4411 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4412 if ((NODE == NULL) ||
4413 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4418 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4419 ret = (CONT->c1->prefix == NULL);
4420 } else if (CONT->c1->prefix == NULL) {
4423 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4437 * At this point handle going up in the tree
4440 DEBUG_VALID_MSG("error found returning");
4444 while (CONT != NULL) {
4446 * First do the analysis depending on the occurrence model at
4450 switch (CONT->ocur) {
4453 case XML_ELEMENT_CONTENT_ONCE:
4454 cur = ctxt->vstate->node;
4455 DEBUG_VALID_MSG("Once branch failed, rollback");
4456 if (vstateVPop(ctxt) < 0 ) {
4457 DEBUG_VALID_MSG("exhaustion, failed");
4460 if (cur != ctxt->vstate->node)
4463 case XML_ELEMENT_CONTENT_PLUS:
4464 if (OCCURRENCE == 0) {
4465 cur = ctxt->vstate->node;
4466 DEBUG_VALID_MSG("Plus branch failed, rollback");
4467 if (vstateVPop(ctxt) < 0 ) {
4468 DEBUG_VALID_MSG("exhaustion, failed");
4471 if (cur != ctxt->vstate->node)
4475 DEBUG_VALID_MSG("Plus branch found");
4478 case XML_ELEMENT_CONTENT_MULT:
4479 #ifdef DEBUG_VALID_ALGO
4480 if (OCCURRENCE == 0) {
4481 DEBUG_VALID_MSG("Mult branch failed");
4483 DEBUG_VALID_MSG("Mult branch found");
4488 case XML_ELEMENT_CONTENT_OPT:
4489 DEBUG_VALID_MSG("Option branch failed");
4494 switch (CONT->ocur) {
4495 case XML_ELEMENT_CONTENT_OPT:
4496 DEBUG_VALID_MSG("Option branch succeeded");
4499 case XML_ELEMENT_CONTENT_ONCE:
4500 DEBUG_VALID_MSG("Once branch succeeded");
4503 case XML_ELEMENT_CONTENT_PLUS:
4504 if (STATE == ROLLBACK_PARENT) {
4505 DEBUG_VALID_MSG("Plus branch rollback");
4510 DEBUG_VALID_MSG("Plus branch exhausted");
4514 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
4517 case XML_ELEMENT_CONTENT_MULT:
4518 if (STATE == ROLLBACK_PARENT) {
4519 DEBUG_VALID_MSG("Mult branch rollback");
4524 DEBUG_VALID_MSG("Mult branch exhausted");
4528 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
4529 /* SET_OCCURRENCE; */
4536 * Then act accordingly at the parent level
4539 if (CONT->parent == NULL)
4542 switch (CONT->parent->type) {
4543 case XML_ELEMENT_CONTENT_PCDATA:
4544 DEBUG_VALID_MSG("Error: parent pcdata");
4546 case XML_ELEMENT_CONTENT_ELEMENT:
4547 DEBUG_VALID_MSG("Error: parent element");
4549 case XML_ELEMENT_CONTENT_OR:
4551 DEBUG_VALID_MSG("Or succeeded");
4552 CONT = CONT->parent;
4555 DEBUG_VALID_MSG("Or failed");
4556 CONT = CONT->parent;
4560 case XML_ELEMENT_CONTENT_SEQ:
4562 DEBUG_VALID_MSG("Sequence failed");
4563 CONT = CONT->parent;
4565 } else if (CONT == CONT->parent->c1) {
4566 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4567 CONT = CONT->parent->c2;
4570 DEBUG_VALID_MSG("Sequence succeeded");
4571 CONT = CONT->parent;
4579 cur = ctxt->vstate->node;
4580 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4581 if (vstateVPop(ctxt) < 0 ) {
4582 DEBUG_VALID_MSG("exhaustion, failed");
4585 if (cur != ctxt->vstate->node)
4592 cur = ctxt->vstate->node;
4593 DEBUG_VALID_MSG("Failure, rollback");
4594 if (vstateVPop(ctxt) < 0 ) {
4595 DEBUG_VALID_MSG("exhaustion, failed");
4598 if (cur != ctxt->vstate->node)
4602 return(determinist);
4607 * xmlSnprintfElements:
4608 * @buf: an output buffer
4609 * @size: the size of the buffer
4610 * @content: An element
4611 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4613 * This will dump the list of elements to the buffer
4614 * Intended just for the debug routine
4617 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
4621 if (node == NULL) return;
4622 if (glob) strcat(buf, "(");
4624 while (cur != NULL) {
4626 if (size - len < 50) {
4627 if ((size - len > 4) && (buf[len - 1] != '.'))
4628 strcat(buf, " ...");
4631 switch (cur->type) {
4632 case XML_ELEMENT_NODE:
4633 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4634 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
4635 if ((size - len > 4) && (buf[len - 1] != '.'))
4636 strcat(buf, " ...");
4639 strcat(buf, (char *) cur->ns->prefix);
4642 if (size - len < xmlStrlen(cur->name) + 10) {
4643 if ((size - len > 4) && (buf[len - 1] != '.'))
4644 strcat(buf, " ...");
4647 strcat(buf, (char *) cur->name);
4648 if (cur->next != NULL)
4652 if (xmlIsBlankNode(cur))
4654 case XML_CDATA_SECTION_NODE:
4655 case XML_ENTITY_REF_NODE:
4656 strcat(buf, "CDATA");
4657 if (cur->next != NULL)
4660 case XML_ATTRIBUTE_NODE:
4661 case XML_DOCUMENT_NODE:
4662 #ifdef LIBXML_DOCB_ENABLED
4663 case XML_DOCB_DOCUMENT_NODE:
4665 case XML_HTML_DOCUMENT_NODE:
4666 case XML_DOCUMENT_TYPE_NODE:
4667 case XML_DOCUMENT_FRAG_NODE:
4668 case XML_NOTATION_NODE:
4669 case XML_NAMESPACE_DECL:
4671 if (cur->next != NULL)
4674 case XML_ENTITY_NODE:
4677 case XML_COMMENT_NODE:
4678 case XML_ELEMENT_DECL:
4679 case XML_ATTRIBUTE_DECL:
4680 case XML_ENTITY_DECL:
4681 case XML_XINCLUDE_START:
4682 case XML_XINCLUDE_END:
4687 if (glob) strcat(buf, ")");
4691 * xmlValidateElementContent:
4692 * @ctxt: the validation context
4693 * @child: the child list
4694 * @elemDecl: pointer to the element declaration
4695 * @warn: emit the error message
4696 * @parent: the parent element (for error reporting)
4698 * Try to validate the content model of an element
4700 * returns 1 if valid or 0 if not and -1 in case of error
4704 xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
4705 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
4707 #ifndef LIBXML_REGEXP_ENABLED
4708 xmlNodePtr repl = NULL, last = NULL, tmp;
4711 xmlElementContentPtr cont;
4712 const xmlChar *name;
4714 if (elemDecl == NULL)
4716 cont = elemDecl->content;
4717 name = elemDecl->name;
4719 #ifdef LIBXML_REGEXP_ENABLED
4720 /* Build the regexp associated to the content model */
4721 if (elemDecl->contModel == NULL)
4722 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4723 if (elemDecl->contModel == NULL) {
4726 xmlRegExecCtxtPtr exec;
4728 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4733 ctxt->nodeTab = NULL;
4734 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4737 while (cur != NULL) {
4738 switch (cur->type) {
4739 case XML_ENTITY_REF_NODE:
4741 * Push the current node to be able to roll back
4742 * and process within the entity
4744 if ((cur->children != NULL) &&
4745 (cur->children->children != NULL)) {
4746 nodeVPush(ctxt, cur);
4747 cur = cur->children->children;
4752 if (xmlIsBlankNode(cur))
4756 case XML_CDATA_SECTION_NODE:
4760 case XML_ELEMENT_NODE:
4761 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
4765 fullname = xmlBuildQName(cur->name,
4766 cur->ns->prefix, fn, 50);
4767 if (fullname == NULL) {
4771 ret = xmlRegExecPushString(exec, fullname, NULL);
4772 if ((fullname != fn) && (fullname != cur->name))
4775 ret = xmlRegExecPushString(exec, cur->name, NULL);
4782 * Switch to next element
4785 while (cur == NULL) {
4786 cur = nodeVPop(ctxt);
4792 ret = xmlRegExecPushString(exec, NULL, NULL);
4794 xmlRegFreeExecCtxt(exec);
4797 #else /* LIBXML_REGEXP_ENABLED */
4799 * Allocate the stack
4801 ctxt->vstateMax = 8;
4802 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
4803 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
4804 if (ctxt->vstateTab == NULL) {
4805 xmlGenericError(xmlGenericErrorContext,
4806 "malloc failed !n");
4810 * The first entry in the stack is reserved to the current state
4814 ctxt->nodeTab = NULL;
4815 ctxt->vstate = &ctxt->vstateTab[0];
4822 ret = xmlValidateElementType(ctxt);
4823 if ((ret == -3) && (warn)) {
4824 VWARNING(ctxt->userData,
4825 "Content model for Element %s is ambiguous\n", name);
4826 } else if (ret == -2) {
4828 * An entities reference appeared at this level.
4829 * Buid a minimal representation of this node content
4830 * sufficient to run the validation process on it
4832 DEBUG_VALID_MSG("Found an entity reference, linearizing");
4834 while (cur != NULL) {
4835 switch (cur->type) {
4836 case XML_ENTITY_REF_NODE:
4838 * Push the current node to be able to roll back
4839 * and process within the entity
4841 if ((cur->children != NULL) &&
4842 (cur->children->children != NULL)) {
4843 nodeVPush(ctxt, cur);
4844 cur = cur->children->children;
4849 if (xmlIsBlankNode(cur))
4851 /* no break on purpose */
4852 case XML_CDATA_SECTION_NODE:
4853 /* no break on purpose */
4854 case XML_ELEMENT_NODE:
4856 * Allocate a new node and minimally fills in
4859 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
4861 xmlGenericError(xmlGenericErrorContext,
4862 "xmlValidateElementContent : malloc failed\n");
4863 xmlFreeNodeList(repl);
4867 tmp->type = cur->type;
4868 tmp->name = cur->name;
4871 tmp->content = NULL;
4878 if (cur->type == XML_CDATA_SECTION_NODE) {
4880 * E59 spaces in CDATA does not match the
4883 tmp->content = xmlStrdup(BAD_CAST "CDATA");
4890 * Switch to next element
4893 while (cur == NULL) {
4894 cur = nodeVPop(ctxt);
4902 * Relaunch the validation
4904 ctxt->vstate = &ctxt->vstateTab[0];
4911 ret = xmlValidateElementType(ctxt);
4913 #endif /* LIBXML_REGEXP_ENABLED */
4914 if ((warn) && ((ret != 1) && (ret != -3))) {
4915 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
4920 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
4922 #ifndef LIBXML_REGEXP_ENABLED
4924 xmlSnprintfElements(&list[0], 5000, repl, 1);
4926 #endif /* LIBXML_REGEXP_ENABLED */
4927 xmlSnprintfElements(&list[0], 5000, child, 1);
4930 if (parent != NULL) VECTXT(ctxt, parent);
4931 VERROR(ctxt->userData,
4932 "Element %s content does not follow the DTD\nExpecting %s, got %s\n",
4935 if (parent != NULL) VECTXT(ctxt, parent);
4936 VERROR(ctxt->userData,
4937 "Element content does not follow the DTD\nExpecting %s, got %s\n",
4942 if (parent != NULL) VECTXT(ctxt, parent);
4943 VERROR(ctxt->userData,
4944 "Element %s content does not follow the DTD\n",
4947 if (parent != NULL) VECTXT(ctxt, parent);
4948 VERROR(ctxt->userData,
4949 "Element content does not follow the DTD\n");
4957 #ifndef LIBXML_REGEXP_ENABLED
4960 * Deallocate the copy if done, and free up the validation stack
4962 while (repl != NULL) {
4967 ctxt->vstateMax = 0;
4968 if (ctxt->vstateTab != NULL) {
4969 xmlFree(ctxt->vstateTab);
4970 ctxt->vstateTab = NULL;
4975 if (ctxt->nodeTab != NULL) {
4976 xmlFree(ctxt->nodeTab);
4977 ctxt->nodeTab = NULL;
4984 * xmlValidateCdataElement:
4985 * @ctxt: the validation context
4986 * @doc: a document instance
4987 * @elem: an element instance
4989 * Check that an element follows #CDATA
4991 * returns 1 if valid or 0 otherwise
4994 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4997 xmlNodePtr cur, child;
4999 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
5002 child = elem->children;
5005 while (cur != NULL) {
5006 switch (cur->type) {
5007 case XML_ENTITY_REF_NODE:
5009 * Push the current node to be able to roll back
5010 * and process within the entity
5012 if ((cur->children != NULL) &&
5013 (cur->children->children != NULL)) {
5014 nodeVPush(ctxt, cur);
5015 cur = cur->children->children;
5019 case XML_COMMENT_NODE:
5022 case XML_CDATA_SECTION_NODE:
5029 * Switch to next element
5032 while (cur == NULL) {
5033 cur = nodeVPop(ctxt);
5042 if (ctxt->nodeTab != NULL) {
5043 xmlFree(ctxt->nodeTab);
5044 ctxt->nodeTab = NULL;
5050 * xmlValidateCheckMixed:
5051 * @ctxt: the validation context
5052 * @cont: the mixed content model
5053 * @qname: the qualified name as appearing in the serialization
5055 * Check if the given node is part of the content model.
5057 * Returns 1 if yes, 0 if no, -1 in case of error
5060 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
5061 xmlElementContentPtr cont, const xmlChar *qname) {
5062 const xmlChar *name;
5064 name = xmlSplitQName3(qname, &plen);
5067 while (cont != NULL) {
5068 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5069 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5071 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5072 (cont->c1 != NULL) &&
5073 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5074 if ((cont->c1->prefix == NULL) &&
5075 (xmlStrEqual(cont->c1->name, qname)))
5077 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5078 (cont->c1 == NULL) ||
5079 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5080 /* Internal error !!! */
5081 xmlGenericError(xmlGenericErrorContext,
5082 "Internal: MIXED struct bad\n");
5088 while (cont != NULL) {
5089 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5090 if ((cont->prefix != NULL) &&
5091 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5092 (xmlStrEqual(cont->name, name)))
5094 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5095 (cont->c1 != NULL) &&
5096 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5097 if ((cont->c1->prefix != NULL) &&
5098 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5099 (xmlStrEqual(cont->c1->name, name)))
5101 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5102 (cont->c1 == NULL) ||
5103 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5104 /* Internal error !!! */
5105 xmlGenericError(xmlGenericErrorContext,
5106 "Internal: MIXED struct bad\n");
5116 * xmlValidGetElemDecl:
5117 * @ctxt: the validation context
5118 * @doc: a document instance
5119 * @elem: an element instance
5120 * @extsubset: pointer, (out) indicate if the declaration was found
5121 * in the external subset.
5123 * Finds a declaration associated to an element in the document.
5125 * returns the pointer to the declaration or NULL if not found.
5127 static xmlElementPtr
5128 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5129 xmlNodePtr elem, int *extsubset) {
5130 xmlElementPtr elemDecl = NULL;
5131 const xmlChar *prefix = NULL;
5133 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5134 if (extsubset != NULL)
5138 * Fetch the declaration for the qualified name
5140 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5141 prefix = elem->ns->prefix;
5143 if (prefix != NULL) {
5144 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5145 elem->name, prefix);
5146 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5147 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5148 elem->name, prefix);
5149 if ((elemDecl != NULL) && (extsubset != NULL))
5155 * Fetch the declaration for the non qualified name
5156 * This is "non-strict" validation should be done on the
5157 * full QName but in that case being flexible makes sense.
5159 if (elemDecl == NULL) {
5160 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5161 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5162 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5163 if ((elemDecl != NULL) && (extsubset != NULL))
5167 if (elemDecl == NULL) {
5169 VERROR(ctxt->userData, "No declaration for element %s\n",
5175 #ifdef LIBXML_REGEXP_ENABLED
5177 * xmlValidatePushElement:
5178 * @ctxt: the validation context
5179 * @doc: a document instance
5180 * @elem: an element instance
5181 * @qname: the qualified name as appearing in the serialization
5183 * Push a new element start on the validation stack.
5185 * returns 1 if no validation problem was found or 0 otherwise
5188 xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5189 xmlNodePtr elem, const xmlChar *qname) {
5191 xmlElementPtr eDecl;
5194 /* printf("PushElem %s\n", qname); */
5195 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5196 xmlValidStatePtr state = ctxt->vstate;
5197 xmlElementPtr elemDecl;
5200 * Check the new element agaisnt the content model of the new elem.
5202 if (state->elemDecl != NULL) {
5203 elemDecl = state->elemDecl;
5205 switch(elemDecl->etype) {
5206 case XML_ELEMENT_TYPE_UNDEFINED:
5209 case XML_ELEMENT_TYPE_EMPTY:
5210 VECTXT(ctxt, state->node);
5211 VERROR(ctxt->userData,
5212 "Element %s was declared EMPTY this one has content\n",
5216 case XML_ELEMENT_TYPE_ANY:
5217 /* I don't think anything is required then */
5219 case XML_ELEMENT_TYPE_MIXED:
5220 /* simple case of declared as #PCDATA */
5221 if ((elemDecl->content != NULL) &&
5222 (elemDecl->content->type ==
5223 XML_ELEMENT_CONTENT_PCDATA)) {
5224 VECTXT(ctxt, state->node);
5225 VERROR(ctxt->userData,
5226 "Element %s was declared #PCDATA but contains non text nodes\n",
5230 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5233 VECTXT(ctxt, state->node);
5234 VERROR(ctxt->userData,
5235 "Element %s is not declared in %s list of possible children\n",
5236 qname, state->node->name);
5240 case XML_ELEMENT_TYPE_ELEMENT:
5243 * VC: Standalone Document Declaration
5244 * - element types with element content, if white space
5245 * occurs directly within any instance of those types.
5247 if (state->exec != NULL) {
5248 ret = xmlRegExecPushString(state->exec, qname, NULL);
5250 VECTXT(ctxt, state->node);
5251 VERROR(ctxt->userData,
5252 "Element %s content does not follow the DTD\nMisplaced %s\n",
5253 state->node->name, qname);
5263 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5264 vstateVPush(ctxt, eDecl, elem);
5269 * xmlValidatePushCData:
5270 * @ctxt: the validation context
5271 * @data: some character data read
5272 * @len: the lenght of the data
5274 * check the CData parsed for validation in the current stack
5276 * returns 1 if no validation problem was found or 0 otherwise
5279 xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5282 /* printf("CDATA %s %d\n", data, len); */
5285 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5286 xmlValidStatePtr state = ctxt->vstate;
5287 xmlElementPtr elemDecl;
5290 * Check the new element agaisnt the content model of the new elem.
5292 if (state->elemDecl != NULL) {
5293 elemDecl = state->elemDecl;
5295 switch(elemDecl->etype) {
5296 case XML_ELEMENT_TYPE_UNDEFINED:
5299 case XML_ELEMENT_TYPE_EMPTY:
5300 VECTXT(ctxt, state->node);
5301 VERROR(ctxt->userData,
5302 "Element %s was declared EMPTY this one has content\n",
5306 case XML_ELEMENT_TYPE_ANY:
5308 case XML_ELEMENT_TYPE_MIXED:
5310 case XML_ELEMENT_TYPE_ELEMENT:
5314 for (i = 0;i < len;i++) {
5315 if (!IS_BLANK(data[i])) {
5316 VECTXT(ctxt, state->node);
5317 VERROR(ctxt->userData,
5318 "Element %s content does not follow the DTD\nText not allowed\n",
5326 * VC: Standalone Document Declaration
5327 * element types with element content, if white space
5328 * occurs directly within any instance of those types.
5340 * xmlValidatePopElement:
5341 * @ctxt: the validation context
5342 * @doc: a document instance
5343 * @elem: an element instance
5344 * @qname: the qualified name as appearing in the serialization
5346 * Pop the element end from the validation stack.
5348 * returns 1 if no validation problem was found or 0 otherwise
5351 xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
5352 xmlNodePtr elem ATTRIBUTE_UNUSED,
5353 const xmlChar *qname ATTRIBUTE_UNUSED) {
5356 /* printf("PopElem %s\n", qname); */
5357 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5358 xmlValidStatePtr state = ctxt->vstate;
5359 xmlElementPtr elemDecl;
5362 * Check the new element agaisnt the content model of the new elem.
5364 if (state->elemDecl != NULL) {
5365 elemDecl = state->elemDecl;
5367 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5368 if (state->exec != NULL) {
5369 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5371 VECTXT(ctxt, state->node);
5372 VERROR(ctxt->userData,
5373 "Element %s content does not follow the DTD\nExpecting more child\n",
5377 * previous validation errors should not generate
5389 #endif /* LIBXML_REGEXP_ENABLED */
5392 * xmlValidateOneElement:
5393 * @ctxt: the validation context
5394 * @doc: a document instance
5395 * @elem: an element instance
5397 * Try to validate a single element and it's attributes,
5398 * basically it does the following checks as described by the
5399 * XML-1.0 recommendation:
5400 * - [ VC: Element Valid ]
5401 * - [ VC: Required Attribute ]
5402 * Then call xmlValidateOneAttribute() for each attribute present.
5404 * The ID/IDREF checkings are done separately
5406 * returns 1 if valid or 0 otherwise
5410 xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5412 xmlElementPtr elemDecl = NULL;
5413 xmlElementContentPtr cont;
5414 xmlAttributePtr attr;
5417 const xmlChar *name;
5422 if (elem == NULL) return(0);
5423 switch (elem->type) {
5424 case XML_ATTRIBUTE_NODE:
5426 VERROR(ctxt->userData,
5427 "Attribute element not expected here\n");
5430 if (elem->children != NULL) {
5432 VERROR(ctxt->userData, "Text element has childs !\n");
5435 if (elem->properties != NULL) {
5437 VERROR(ctxt->userData, "Text element has attributes !\n");
5440 if (elem->ns != NULL) {
5442 VERROR(ctxt->userData, "Text element has namespace !\n");
5445 if (elem->nsDef != NULL) {
5447 VERROR(ctxt->userData,
5448 "Text element carries namespace definitions !\n");
5451 if (elem->content == NULL) {
5453 VERROR(ctxt->userData,
5454 "Text element has no content !\n");
5458 case XML_XINCLUDE_START:
5459 case XML_XINCLUDE_END:
5461 case XML_CDATA_SECTION_NODE:
5462 case XML_ENTITY_REF_NODE:
5464 case XML_COMMENT_NODE:
5466 case XML_ENTITY_NODE:
5468 VERROR(ctxt->userData,
5469 "Entity element not expected here\n");
5471 case XML_NOTATION_NODE:
5473 VERROR(ctxt->userData,
5474 "Notation element not expected here\n");
5476 case XML_DOCUMENT_NODE:
5477 case XML_DOCUMENT_TYPE_NODE:
5478 case XML_DOCUMENT_FRAG_NODE:
5480 VERROR(ctxt->userData,
5481 "Document element not expected here\n");
5483 case XML_HTML_DOCUMENT_NODE:
5485 VERROR(ctxt->userData,
5488 case XML_ELEMENT_NODE:
5492 VERROR(ctxt->userData,
5493 "unknown element type %d\n", elem->type);
5498 * Fetch the declaration
5500 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5501 if (elemDecl == NULL)
5505 * If vstateNr is not zero that means continuous validation is
5506 * activated, do not try to check the content model at that level.
5508 if (ctxt->vstateNr == 0) {
5509 /* Check that the element content matches the definition */
5510 switch (elemDecl->etype) {
5511 case XML_ELEMENT_TYPE_UNDEFINED:
5513 VERROR(ctxt->userData, "No declaration for element %s\n",
5516 case XML_ELEMENT_TYPE_EMPTY:
5517 if (elem->children != NULL) {
5519 VERROR(ctxt->userData,
5520 "Element %s was declared EMPTY this one has content\n",
5525 case XML_ELEMENT_TYPE_ANY:
5526 /* I don't think anything is required then */
5528 case XML_ELEMENT_TYPE_MIXED:
5530 /* simple case of declared as #PCDATA */
5531 if ((elemDecl->content != NULL) &&
5532 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5533 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5536 VERROR(ctxt->userData,
5537 "Element %s was declared #PCDATA but contains non text nodes\n",
5542 child = elem->children;
5543 /* Hum, this start to get messy */
5544 while (child != NULL) {
5545 if (child->type == XML_ELEMENT_NODE) {
5547 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
5551 fullname = xmlBuildQName(child->name, child->ns->prefix,
5553 if (fullname == NULL)
5555 cont = elemDecl->content;
5556 while (cont != NULL) {
5557 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5558 if (xmlStrEqual(cont->name, fullname))
5560 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5561 (cont->c1 != NULL) &&
5562 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5563 if (xmlStrEqual(cont->c1->name, fullname))
5565 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5566 (cont->c1 == NULL) ||
5567 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5568 /* Internal error !!! */
5569 xmlGenericError(xmlGenericErrorContext,
5570 "Internal: MIXED struct bad\n");
5575 if ((fullname != fn) && (fullname != child->name))
5580 cont = elemDecl->content;
5581 while (cont != NULL) {
5582 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5583 if (xmlStrEqual(cont->name, name)) break;
5584 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5585 (cont->c1 != NULL) &&
5586 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5587 if (xmlStrEqual(cont->c1->name, name)) break;
5588 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5589 (cont->c1 == NULL) ||
5590 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
5591 /* Internal error !!! */
5592 xmlGenericError(xmlGenericErrorContext,
5593 "Internal: MIXED struct bad\n");
5600 VERROR(ctxt->userData,
5601 "Element %s is not declared in %s list of possible children\n",
5607 child = child->next;
5610 case XML_ELEMENT_TYPE_ELEMENT:
5611 if ((doc->standalone == 1) && (extsubset == 1)) {
5613 * VC: Standalone Document Declaration
5614 * - element types with element content, if white space
5615 * occurs directly within any instance of those types.
5617 child = elem->children;
5618 while (child != NULL) {
5619 if (child->type == XML_TEXT_NODE) {
5620 const xmlChar *content = child->content;
5622 while (IS_BLANK(*content))
5624 if (*content == 0) {
5626 VERROR(ctxt->userData,
5627 "standalone: %s declared in the external subset contains white spaces nodes\n",
5636 child = elem->children;
5637 cont = elemDecl->content;
5638 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
5643 } /* not continuous */
5645 /* [ VC: Required Attribute ] */
5646 attr = elemDecl->attributes;
5647 while (attr != NULL) {
5648 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
5651 if ((attr->prefix == NULL) &&
5652 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5656 while (ns != NULL) {
5657 if (ns->prefix == NULL)
5661 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5665 while (ns != NULL) {
5666 if (xmlStrEqual(attr->name, ns->prefix))
5673 attrib = elem->properties;
5674 while (attrib != NULL) {
5675 if (xmlStrEqual(attrib->name, attr->name)) {
5676 if (attr->prefix != NULL) {
5677 xmlNsPtr nameSpace = attrib->ns;
5679 if (nameSpace == NULL)
5680 nameSpace = elem->ns;
5682 * qualified names handling is problematic, having a
5683 * different prefix should be possible but DTDs don't
5684 * allow to define the URI instead of the prefix :-(
5686 if (nameSpace == NULL) {
5689 } else if (!xmlStrEqual(nameSpace->prefix,
5697 * We should allow applications to define namespaces
5698 * for their application even if the DTD doesn't
5699 * carry one, otherwise, basically we would always
5705 attrib = attrib->next;
5708 if (qualified == -1) {
5709 if (attr->prefix == NULL) {
5711 VERROR(ctxt->userData,
5712 "Element %s does not carry attribute %s\n",
5713 elem->name, attr->name);
5717 VERROR(ctxt->userData,
5718 "Element %s does not carry attribute %s:%s\n",
5719 elem->name, attr->prefix,attr->name);
5722 } else if (qualified == 0) {
5723 VWARNING(ctxt->userData,
5724 "Element %s required attribute %s:%s has no prefix\n",
5725 elem->name, attr->prefix,attr->name);
5726 } else if (qualified == 1) {
5727 VWARNING(ctxt->userData,
5728 "Element %s required attribute %s:%s has different prefix\n",
5729 elem->name, attr->prefix,attr->name);
5731 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5733 * Special tests checking #FIXED namespace declarations
5734 * have the right value since this is not done as an
5735 * attribute checking
5737 if ((attr->prefix == NULL) &&
5738 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5742 while (ns != NULL) {
5743 if (ns->prefix == NULL) {
5744 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
5746 VERROR(ctxt->userData,
5747 "Element %s namespace name for default namespace does not match the DTD\n",
5755 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5759 while (ns != NULL) {
5760 if (xmlStrEqual(attr->name, ns->prefix)) {
5761 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
5763 VERROR(ctxt->userData,
5764 "Element %s namespace name for %s does not match the DTD\n",
5765 elem->name, ns->prefix);
5782 * @ctxt: the validation context
5783 * @doc: a document instance
5785 * Try to validate a the root element
5786 * basically it does the following check as described by the
5787 * XML-1.0 recommendation:
5788 * - [ VC: Root Element Type ]
5789 * it doesn't try to recurse or apply other check to the element
5791 * returns 1 if valid or 0 otherwise
5795 xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5799 if (doc == NULL) return(0);
5801 root = xmlDocGetRootElement(doc);
5802 if ((root == NULL) || (root->name == NULL)) {
5803 VERROR(ctxt->userData, "Not valid: no root element\n");
5808 * When doing post validation against a separate DTD, those may
5809 * no internal subset has been generated
5811 if ((doc->intSubset != NULL) &&
5812 (doc->intSubset->name != NULL)) {
5814 * Check first the document root against the NQName
5816 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
5817 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
5821 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
5822 if (fullname == NULL) {
5823 VERROR(ctxt->userData, "Out of memory\n");
5826 ret = xmlStrEqual(doc->intSubset->name, fullname);
5827 if ((fullname != fn) && (fullname != root->name))
5832 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
5833 (xmlStrEqual(root->name, BAD_CAST "html")))
5836 VERROR(ctxt->userData,
5837 "Not valid: root and DTD name do not match '%s' and '%s'\n",
5838 root->name, doc->intSubset->name);
5849 * xmlValidateElement:
5850 * @ctxt: the validation context
5851 * @doc: a document instance
5852 * @elem: an element instance
5854 * Try to validate the subtree under an element
5856 * returns 1 if valid or 0 otherwise
5860 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
5866 if (elem == NULL) return(0);
5869 * XInclude elements were added after parsing in the infoset,
5870 * they don't really mean anything validation wise.
5872 if ((elem->type == XML_XINCLUDE_START) ||
5873 (elem->type == XML_XINCLUDE_END))
5879 * Entities references have to be handled separately
5881 if (elem->type == XML_ENTITY_REF_NODE) {
5885 ret &= xmlValidateOneElement(ctxt, doc, elem);
5886 attr = elem->properties;
5887 while(attr != NULL) {
5888 value = xmlNodeListGetString(doc, attr->children, 0);
5889 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
5894 child = elem->children;
5895 while (child != NULL) {
5896 ret &= xmlValidateElement(ctxt, doc, child);
5897 child = child->next;
5905 * @ref: A reference to be validated
5906 * @ctxt: Validation context
5907 * @name: Name of ID we are searching for
5911 xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
5912 const xmlChar *name) {
5918 if ((ref->attr == NULL) && (ref->name == NULL))
5922 xmlChar *dup, *str = NULL, *cur, save;
5924 dup = xmlStrdup(name);
5932 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5935 id = xmlGetID(ctxt->doc, str);
5937 VERROR(ctxt->userData,
5938 "attribute %s line %d references an unknown ID \"%s\"\n",
5939 ref->name, ref->lineno, str);
5945 while (IS_BLANK(*cur)) cur++;
5948 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
5949 id = xmlGetID(ctxt->doc, name);
5951 VECTXT(ctxt, attr->parent);
5952 VERROR(ctxt->userData,
5953 "IDREF attribute %s references an unknown ID \"%s\"\n",
5957 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
5958 xmlChar *dup, *str = NULL, *cur, save;
5960 dup = xmlStrdup(name);
5968 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
5971 id = xmlGetID(ctxt->doc, str);
5973 VECTXT(ctxt, attr->parent);
5974 VERROR(ctxt->userData,
5975 "IDREFS attribute %s references an unknown ID \"%s\"\n",
5982 while (IS_BLANK(*cur)) cur++;
5989 * xmlWalkValidateList:
5990 * @data: Contents of current link
5991 * @user: Value supplied by the user
5993 * Returns 0 to abort the walk or 1 to continue
5996 xmlWalkValidateList(const void *data, const void *user)
5998 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
5999 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6004 * xmlValidateCheckRefCallback:
6005 * @ref_list: List of references
6006 * @ctxt: Validation context
6007 * @name: Name of ID we are searching for
6011 xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6012 const xmlChar *name) {
6013 xmlValidateMemo memo;
6015 if (ref_list == NULL)
6020 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6025 * xmlValidateDocumentFinal:
6026 * @ctxt: the validation context
6027 * @doc: a document instance
6029 * Does the final step for the document validation once all the
6030 * incremental validation steps have been completed
6032 * basically it does the following checks described by the XML Rec
6034 * Check all the IDREF/IDREFS attributes definition for validity
6036 * returns 1 if valid or 0 otherwise
6040 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6041 xmlRefTablePtr table;
6044 xmlGenericError(xmlGenericErrorContext,
6045 "xmlValidateDocumentFinal: doc == NULL\n");
6050 * Check all the NOTATION/NOTATIONS attributes
6053 * Check all the ENTITY/ENTITIES attributes definition for validity
6056 * Check all the IDREF/IDREFS attributes definition for validity
6058 table = (xmlRefTablePtr) doc->refs;
6061 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6062 return(ctxt->valid);
6067 * @ctxt: the validation context
6068 * @doc: a document instance
6069 * @dtd: a dtd instance
6071 * Try to validate the document against the dtd instance
6073 * basically it does check all the definitions in the DtD.
6075 * returns 1 if valid or 0 otherwise
6079 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6084 if (dtd == NULL) return(0);
6085 if (doc == NULL) return(0);
6086 oldExt = doc->extSubset;
6087 doc->extSubset = dtd;
6088 ret = xmlValidateRoot(ctxt, doc);
6090 doc->extSubset = oldExt;
6093 if (doc->ids != NULL) {
6094 xmlFreeIDTable(doc->ids);
6097 if (doc->refs != NULL) {
6098 xmlFreeRefTable(doc->refs);
6101 root = xmlDocGetRootElement(doc);
6102 ret = xmlValidateElement(ctxt, doc, root);
6103 ret &= xmlValidateDocumentFinal(ctxt, doc);
6104 doc->extSubset = oldExt;
6109 xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6110 const xmlChar *name ATTRIBUTE_UNUSED) {
6113 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6114 xmlChar *notation = cur->content;
6116 if (notation != NULL) {
6119 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6128 xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
6129 const xmlChar *name ATTRIBUTE_UNUSED) {
6136 switch (cur->atype) {
6137 case XML_ATTRIBUTE_CDATA:
6138 case XML_ATTRIBUTE_ID:
6139 case XML_ATTRIBUTE_IDREF :
6140 case XML_ATTRIBUTE_IDREFS:
6141 case XML_ATTRIBUTE_NMTOKEN:
6142 case XML_ATTRIBUTE_NMTOKENS:
6143 case XML_ATTRIBUTE_ENUMERATION:
6145 case XML_ATTRIBUTE_ENTITY:
6146 case XML_ATTRIBUTE_ENTITIES:
6147 case XML_ATTRIBUTE_NOTATION:
6148 if (cur->defaultValue != NULL) {
6150 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6151 cur->atype, cur->defaultValue);
6152 if ((ret == 0) && (ctxt->valid == 1))
6155 if (cur->tree != NULL) {
6156 xmlEnumerationPtr tree = cur->tree;
6157 while (tree != NULL) {
6158 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6159 cur->name, cur->atype, tree->name);
6160 if ((ret == 0) && (ctxt->valid == 1))
6166 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6168 if ((doc == NULL) || (cur->elem == NULL)) {
6169 VERROR(ctxt->userData,
6170 "xmlValidateAttributeCallback(%s): internal error\n",
6174 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6176 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6178 VERROR(ctxt->userData,
6179 "attribute %s: could not find decl for element %s\n",
6180 cur->name, cur->elem);
6183 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6184 VERROR(ctxt->userData,
6185 "NOTATION attribute %s declared for EMPTY element %s\n",
6186 cur->name, cur->elem);
6193 * xmlValidateDtdFinal:
6194 * @ctxt: the validation context
6195 * @doc: a document instance
6197 * Does the final step for the dtds validation once all the
6198 * subsets have been parsed
6200 * basically it does the following checks described by the XML Rec
6201 * - check that ENTITY and ENTITIES type attributes default or
6202 * possible values matches one of the defined entities.
6203 * - check that NOTATION type attributes default or
6204 * possible values matches one of the defined notations.
6206 * returns 1 if valid or 0 if invalid and -1 if not well-formed
6210 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6212 xmlAttributeTablePtr table;
6213 xmlEntitiesTablePtr entities;
6215 if (doc == NULL) return(0);
6216 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6220 dtd = doc->intSubset;
6221 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6222 table = (xmlAttributeTablePtr) dtd->attributes;
6223 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
6225 if ((dtd != NULL) && (dtd->entities != NULL)) {
6226 entities = (xmlEntitiesTablePtr) dtd->entities;
6227 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6230 dtd = doc->extSubset;
6231 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6232 table = (xmlAttributeTablePtr) dtd->attributes;
6233 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
6235 if ((dtd != NULL) && (dtd->entities != NULL)) {
6236 entities = (xmlEntitiesTablePtr) dtd->entities;
6237 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6240 return(ctxt->valid);
6244 * xmlValidateDocument:
6245 * @ctxt: the validation context
6246 * @doc: a document instance
6248 * Try to validate the document instance
6250 * basically it does the all the checks described by the XML Rec
6251 * i.e. validates the internal and external subset (if present)
6252 * and validate the document tree.
6254 * returns 1 if valid or 0 otherwise
6258 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6262 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6263 VERROR(ctxt->userData, "no DTD found!\n" );
6266 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6267 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6268 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6269 doc->intSubset->SystemID);
6270 if (doc->extSubset == NULL) {
6271 if (doc->intSubset->SystemID != NULL) {
6272 VERROR(ctxt->userData,
6273 "Could not load the external subset \"%s\"\n",
6274 doc->intSubset->SystemID);
6276 VERROR(ctxt->userData,
6277 "Could not load the external subset \"%s\"\n",
6278 doc->intSubset->ExternalID);
6284 if (doc->ids != NULL) {
6285 xmlFreeIDTable(doc->ids);
6288 if (doc->refs != NULL) {
6289 xmlFreeRefTable(doc->refs);
6292 ret = xmlValidateDtdFinal(ctxt, doc);
6293 if (!xmlValidateRoot(ctxt, doc)) return(0);
6295 root = xmlDocGetRootElement(doc);
6296 ret &= xmlValidateElement(ctxt, doc, root);
6297 ret &= xmlValidateDocumentFinal(ctxt, doc);
6302 /************************************************************************
6304 * Routines for dynamic validation editing *
6306 ************************************************************************/
6309 * xmlValidGetPotentialChildren:
6310 * @ctree: an element content tree
6311 * @list: an array to store the list of child names
6312 * @len: a pointer to the number of element in the list
6313 * @max: the size of the array
6315 * Build/extend a list of potential children allowed by the content tree
6317 * returns the number of element in the list, or -1 in case of error.
6321 xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6322 int *len, int max) {
6325 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6327 if (*len >= max) return(*len);
6329 switch (ctree->type) {
6330 case XML_ELEMENT_CONTENT_PCDATA:
6331 for (i = 0; i < *len;i++)
6332 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6333 list[(*len)++] = BAD_CAST "#PCDATA";
6335 case XML_ELEMENT_CONTENT_ELEMENT:
6336 for (i = 0; i < *len;i++)
6337 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6338 list[(*len)++] = ctree->name;
6340 case XML_ELEMENT_CONTENT_SEQ:
6341 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6342 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6344 case XML_ELEMENT_CONTENT_OR:
6345 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6346 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6354 * xmlValidGetValidElements:
6355 * @prev: an element to insert after
6356 * @next: an element to insert next
6357 * @list: an array to store the list of child names
6358 * @max: the size of the array
6360 * This function returns the list of authorized children to insert
6361 * within an existing tree while respecting the validity constraints
6362 * forced by the Dtd. The insertion point is defined using @prev and
6363 * @next in the following ways:
6364 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6365 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6366 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6367 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6368 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6370 * pointers to the element names are inserted at the beginning of the array
6371 * and do not need to be freed.
6373 * returns the number of element in the list, or -1 in case of error. If
6374 * the function returns the value @max the caller is invited to grow the
6375 * receiving array and retry.
6379 xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
6382 int nb_valid_elements = 0;
6383 const xmlChar *elements[256];
6384 int nb_elements = 0, i;
6385 const xmlChar *name;
6393 xmlNode *parent_childs;
6394 xmlNode *parent_last;
6396 xmlElement *element_desc;
6398 memset(&vctxt, 0, sizeof (xmlValidCtxt));
6400 if (prev == NULL && next == NULL)
6403 if (list == NULL) return(-1);
6404 if (max <= 0) return(-1);
6406 nb_valid_elements = 0;
6407 ref_node = prev ? prev : next;
6408 parent = ref_node->parent;
6411 * Retrieves the parent element declaration
6413 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6415 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6416 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6418 if (element_desc == NULL) return(-1);
6421 * Do a backup of the current tree structure
6423 prev_next = prev ? prev->next : NULL;
6424 next_prev = next ? next->prev : NULL;
6425 parent_childs = parent->children;
6426 parent_last = parent->last;
6429 * Creates a dummy node and insert it into the tree
6431 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6432 test_node->doc = ref_node->doc;
6433 test_node->parent = parent;
6434 test_node->prev = prev;
6435 test_node->next = next;
6436 name = test_node->name;
6438 if (prev) prev->next = test_node;
6439 else parent->children = test_node;
6441 if (next) next->prev = test_node;
6442 else parent->last = test_node;
6445 * Insert each potential child node and check if the parent is
6448 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6449 elements, &nb_elements, 256);
6451 for (i = 0;i < nb_elements;i++) {
6452 test_node->name = elements[i];
6453 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
6456 for (j = 0; j < nb_valid_elements;j++)
6457 if (xmlStrEqual(elements[i], list[j])) break;
6458 list[nb_valid_elements++] = elements[i];
6459 if (nb_valid_elements >= max) break;
6464 * Restore the tree structure
6466 if (prev) prev->next = prev_next;
6467 if (next) next->prev = next_prev;
6468 parent->children = parent_childs;
6469 parent->last = parent_last;
6472 * Free up the dummy node
6474 test_node->name = name;
6475 xmlFreeNode(test_node);
6477 return(nb_valid_elements);