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", \
36 * Generic function for accessing stacks in the Validity Context
39 #define PUSH_AND_POP(scope, type, name) \
40 scope int name##VPush(xmlValidCtxtPtr ctxt, type value) { \
41 if (ctxt->name##Max <= 0) { \
42 ctxt->name##Max = 4; \
43 ctxt->name##Tab = (type *) xmlMalloc( \
44 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
45 if (ctxt->name##Tab == NULL) { \
46 xmlGenericError(xmlGenericErrorContext, \
47 "malloc failed !\n"); \
48 ctxt->name##Max = 0; \
52 if (ctxt->name##Nr >= ctxt->name##Max) { \
53 ctxt->name##Max *= 2; \
54 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
55 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
56 if (ctxt->name##Tab == NULL) { \
57 xmlGenericError(xmlGenericErrorContext, \
58 "realloc failed !\n"); \
62 ctxt->name##Tab[ctxt->name##Nr] = value; \
64 return(ctxt->name##Nr++); \
66 scope type name##VPop(xmlValidCtxtPtr ctxt) { \
68 if (ctxt->name##Nr <= 0) return(0); \
70 if (ctxt->name##Nr > 0) \
71 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
74 ret = ctxt->name##Tab[ctxt->name##Nr]; \
75 ctxt->name##Tab[ctxt->name##Nr] = 0; \
80 * I use a home made algorithm less complex and easier to
81 * debug/maintain than a generic NFA -> DFA state based algo. The
82 * only restriction is on the deepness of the tree limited by the
83 * size of the occurs bitfield
85 * this is the content of a saved state for rollbacks
89 #define ROLLBACK_PARENT 1
91 typedef struct _xmlValidState
{
92 xmlElementContentPtr cont
; /* pointer to the content model subtree */
93 xmlNodePtr node
; /* pointer to the current node in the list */
94 long occurs
;/* bitfield for multiple occurrences */
95 unsigned char depth
; /* current depth in the overall tree */
96 unsigned char state
; /* ROLLBACK_XXX */
99 #define MAX_RECURSE 25000
100 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
101 #define CONT ctxt->vstate->cont
102 #define NODE ctxt->vstate->node
103 #define DEPTH ctxt->vstate->depth
104 #define OCCURS ctxt->vstate->occurs
105 #define STATE ctxt->vstate->state
107 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
108 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
110 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
111 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
113 #ifndef LIBXML_REGEXP_ENABLED
115 vstateVPush(xmlValidCtxtPtr ctxt
, xmlElementContentPtr cont
,
116 xmlNodePtr node
, unsigned char depth
, long occurs
,
117 unsigned char state
) {
118 int i
= ctxt
->vstateNr
- 1;
120 if (ctxt
->vstateNr
> MAX_RECURSE
) {
123 if (ctxt
->vstateNr
>= ctxt
->vstateMax
) {
124 ctxt
->vstateMax
*= 2;
125 ctxt
->vstateTab
= (xmlValidState
*) xmlRealloc(ctxt
->vstateTab
,
126 ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
127 if (ctxt
->vstateTab
== NULL
) {
128 xmlGenericError(xmlGenericErrorContext
,
129 "realloc failed !n");
132 ctxt
->vstate
= &ctxt
->vstateTab
[0];
135 * Don't push on the stack a state already here
137 if ((i
>= 0) && (ctxt
->vstateTab
[i
].cont
== cont
) &&
138 (ctxt
->vstateTab
[i
].node
== node
) &&
139 (ctxt
->vstateTab
[i
].depth
== depth
) &&
140 (ctxt
->vstateTab
[i
].occurs
== occurs
) &&
141 (ctxt
->vstateTab
[i
].state
== state
))
142 return(ctxt
->vstateNr
);
143 ctxt
->vstateTab
[ctxt
->vstateNr
].cont
= cont
;
144 ctxt
->vstateTab
[ctxt
->vstateNr
].node
= node
;
145 ctxt
->vstateTab
[ctxt
->vstateNr
].depth
= depth
;
146 ctxt
->vstateTab
[ctxt
->vstateNr
].occurs
= occurs
;
147 ctxt
->vstateTab
[ctxt
->vstateNr
].state
= state
;
148 return(ctxt
->vstateNr
++);
152 vstateVPop(xmlValidCtxtPtr ctxt
) {
153 if (ctxt
->vstateNr
<= 1) return(-1);
155 ctxt
->vstate
= &ctxt
->vstateTab
[0];
156 ctxt
->vstate
->cont
= ctxt
->vstateTab
[ctxt
->vstateNr
].cont
;
157 ctxt
->vstate
->node
= ctxt
->vstateTab
[ctxt
->vstateNr
].node
;
158 ctxt
->vstate
->depth
= ctxt
->vstateTab
[ctxt
->vstateNr
].depth
;
159 ctxt
->vstate
->occurs
= ctxt
->vstateTab
[ctxt
->vstateNr
].occurs
;
160 ctxt
->vstate
->state
= ctxt
->vstateTab
[ctxt
->vstateNr
].state
;
161 return(ctxt
->vstateNr
);
164 #endif /* LIBXML_REGEXP_ENABLED */
166 PUSH_AND_POP(static, xmlNodePtr
, node
)
168 #ifdef DEBUG_VALID_ALGO
170 xmlValidPrintNode(xmlNodePtr cur
) {
172 xmlGenericError(xmlGenericErrorContext
, "null");
176 case XML_ELEMENT_NODE
:
177 xmlGenericError(xmlGenericErrorContext
, "%s ", cur
->name
);
180 xmlGenericError(xmlGenericErrorContext
, "text ");
182 case XML_CDATA_SECTION_NODE
:
183 xmlGenericError(xmlGenericErrorContext
, "cdata ");
185 case XML_ENTITY_REF_NODE
:
186 xmlGenericError(xmlGenericErrorContext
, "&%s; ", cur
->name
);
189 xmlGenericError(xmlGenericErrorContext
, "pi(%s) ", cur
->name
);
191 case XML_COMMENT_NODE
:
192 xmlGenericError(xmlGenericErrorContext
, "comment ");
194 case XML_ATTRIBUTE_NODE
:
195 xmlGenericError(xmlGenericErrorContext
, "?attr? ");
197 case XML_ENTITY_NODE
:
198 xmlGenericError(xmlGenericErrorContext
, "?ent? ");
200 case XML_DOCUMENT_NODE
:
201 xmlGenericError(xmlGenericErrorContext
, "?doc? ");
203 case XML_DOCUMENT_TYPE_NODE
:
204 xmlGenericError(xmlGenericErrorContext
, "?doctype? ");
206 case XML_DOCUMENT_FRAG_NODE
:
207 xmlGenericError(xmlGenericErrorContext
, "?frag? ");
209 case XML_NOTATION_NODE
:
210 xmlGenericError(xmlGenericErrorContext
, "?nota? ");
212 case XML_HTML_DOCUMENT_NODE
:
213 xmlGenericError(xmlGenericErrorContext
, "?html? ");
215 #ifdef LIBXML_DOCB_ENABLED
216 case XML_DOCB_DOCUMENT_NODE
:
217 xmlGenericError(xmlGenericErrorContext
, "?docb? ");
221 xmlGenericError(xmlGenericErrorContext
, "?dtd? ");
223 case XML_ELEMENT_DECL
:
224 xmlGenericError(xmlGenericErrorContext
, "?edecl? ");
226 case XML_ATTRIBUTE_DECL
:
227 xmlGenericError(xmlGenericErrorContext
, "?adecl? ");
229 case XML_ENTITY_DECL
:
230 xmlGenericError(xmlGenericErrorContext
, "?entdecl? ");
232 case XML_NAMESPACE_DECL
:
233 xmlGenericError(xmlGenericErrorContext
, "?nsdecl? ");
235 case XML_XINCLUDE_START
:
236 xmlGenericError(xmlGenericErrorContext
, "incstart ");
238 case XML_XINCLUDE_END
:
239 xmlGenericError(xmlGenericErrorContext
, "incend ");
245 xmlValidPrintNodeList(xmlNodePtr cur
) {
247 xmlGenericError(xmlGenericErrorContext
, "null ");
248 while (cur
!= NULL
) {
249 xmlValidPrintNode(cur
);
255 xmlValidDebug(xmlNodePtr cur
, xmlElementContentPtr cont
) {
259 xmlGenericError(xmlGenericErrorContext
, "valid: ");
260 xmlValidPrintNodeList(cur
);
261 xmlGenericError(xmlGenericErrorContext
, "against ");
262 xmlSnprintfElementContent(expr
, 5000, cont
, 1);
263 xmlGenericError(xmlGenericErrorContext
, "%s\n", expr
);
267 xmlValidDebugState(xmlValidStatePtr state
) {
268 xmlGenericError(xmlGenericErrorContext
, "(");
269 if (state
->cont
== NULL
)
270 xmlGenericError(xmlGenericErrorContext
, "null,");
272 switch (state
->cont
->type
) {
273 case XML_ELEMENT_CONTENT_PCDATA
:
274 xmlGenericError(xmlGenericErrorContext
, "pcdata,");
276 case XML_ELEMENT_CONTENT_ELEMENT
:
277 xmlGenericError(xmlGenericErrorContext
, "%s,",
280 case XML_ELEMENT_CONTENT_SEQ
:
281 xmlGenericError(xmlGenericErrorContext
, "seq,");
283 case XML_ELEMENT_CONTENT_OR
:
284 xmlGenericError(xmlGenericErrorContext
, "or,");
287 xmlValidPrintNode(state
->node
);
288 xmlGenericError(xmlGenericErrorContext
, ",%d,%X,%d)",
289 state
->depth
, state
->occurs
, state
->state
);
293 xmlValidStateDebug(xmlValidCtxtPtr ctxt
) {
296 xmlGenericError(xmlGenericErrorContext
, "state: ");
297 xmlValidDebugState(ctxt
->vstate
);
298 xmlGenericError(xmlGenericErrorContext
, " stack: %d ",
300 for (i
= 0, j
= ctxt
->vstateNr
- 1;(i
< 3) && (j
> 0);i
++,j
--)
301 xmlValidDebugState(&ctxt
->vstateTab
[j
]);
302 xmlGenericError(xmlGenericErrorContext
, "\n");
306 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
309 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
310 #define DEBUG_VALID_MSG(m) \
311 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
314 #define DEBUG_VALID_STATE(n,c)
315 #define DEBUG_VALID_MSG(m)
318 /* TODO: use hash table for accesses to elem and attribute definitions */
320 #define VECTXT(ctxt, node) \
321 if ((ctxt != NULL) && (ctxt->error != NULL) && \
323 xmlChar *base = xmlNodeGetBase(NULL,node); \
324 if (base != NULL) { \
325 ctxt->error(ctxt->userData, "%s:%d: ", base, \
326 (int) (long) node->content); \
329 ctxt->error(ctxt->userData, ":%d: ", \
330 (int) (long) node->content); \
333 #define VWCTXT(ctxt, node) \
334 if ((ctxt != NULL) && (ctxt->warning != NULL) && \
336 xmlChar *base = xmlNodeGetBase(NULL,node); \
337 if (base != NULL) { \
338 ctxt->warning(ctxt->userData, "%s:%d: ", base, \
339 (int) (long) node->content); \
342 ctxt->warning(ctxt->userData, ":%d: ", \
343 (int) (long) node->content); \
347 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
350 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
353 if (doc == NULL) return(0); \
354 else if ((doc->intSubset == NULL) && \
355 (doc->extSubset == NULL)) return(0)
357 static xmlElementPtr
xmlGetDtdElementDesc2(xmlDtdPtr dtd
, const xmlChar
*name
,
359 xmlAttributePtr
xmlScanAttributeDecl(xmlDtdPtr dtd
, const xmlChar
*elem
);
361 #ifdef LIBXML_REGEXP_ENABLED
363 /************************************************************************
365 * Content model validation based on the regexps *
367 ************************************************************************/
370 * xmlValidBuildAContentModel:
371 * @content: the content model
372 * @ctxt: the schema parser context
373 * @name: the element name whose content is being built
375 * Generate the automata sequence needed for that type
377 * Returns 1 if successful or 0 in case of error.
380 xmlValidBuildAContentModel(xmlElementContentPtr content
,
381 xmlValidCtxtPtr ctxt
,
382 const xmlChar
*name
) {
383 if (content
== NULL
) {
384 VERROR(ctxt
->userData
,
385 "Found unexpected type = NULL in %s content model\n", name
);
388 switch (content
->type
) {
389 case XML_ELEMENT_CONTENT_PCDATA
:
390 VERROR(ctxt
->userData
, "ContentModel found PCDATA for element %s\n",
394 case XML_ELEMENT_CONTENT_ELEMENT
: {
395 xmlAutomataStatePtr oldstate
= ctxt
->state
;
396 xmlChar
*QName
= NULL
;
397 const xmlChar
*fname
= content
->name
;
399 if (content
->prefix
!= NULL
) {
402 len
= xmlStrlen(content
->name
) +
403 xmlStrlen(content
->prefix
) + 2;
404 QName
= xmlMalloc(len
);
406 VERROR(ctxt
->userData
,
407 "ContentModel %s : alloc failed\n", name
);
410 snprintf((char *) QName
, len
, "%s:%s",
411 (char *)content
->prefix
,
412 (char *)content
->name
);
416 switch (content
->ocur
) {
417 case XML_ELEMENT_CONTENT_ONCE
:
418 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
419 ctxt
->state
, NULL
, fname
, NULL
);
421 case XML_ELEMENT_CONTENT_OPT
:
422 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
423 ctxt
->state
, NULL
, fname
, NULL
);
424 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
426 case XML_ELEMENT_CONTENT_PLUS
:
427 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
428 ctxt
->state
, NULL
, fname
, NULL
);
429 xmlAutomataNewTransition(ctxt
->am
, ctxt
->state
,
430 ctxt
->state
, fname
, NULL
);
432 case XML_ELEMENT_CONTENT_MULT
:
433 xmlAutomataNewTransition(ctxt
->am
, ctxt
->state
,
434 ctxt
->state
, fname
, NULL
);
441 case XML_ELEMENT_CONTENT_SEQ
: {
442 xmlAutomataStatePtr oldstate
, oldend
;
443 xmlElementContentOccur ocur
;
446 * Simply iterate over the content
448 oldstate
= ctxt
->state
;
449 ocur
= content
->ocur
;
451 xmlValidBuildAContentModel(content
->c1
, ctxt
, name
);
452 content
= content
->c2
;
453 } while ((content
->type
== XML_ELEMENT_CONTENT_SEQ
) &&
454 (content
->ocur
== XML_ELEMENT_CONTENT_ONCE
));
455 xmlValidBuildAContentModel(content
, ctxt
, name
);
456 oldend
= ctxt
->state
;
457 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
, oldend
, NULL
);
459 case XML_ELEMENT_CONTENT_ONCE
:
461 case XML_ELEMENT_CONTENT_OPT
:
462 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
464 case XML_ELEMENT_CONTENT_MULT
:
465 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
466 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
468 case XML_ELEMENT_CONTENT_PLUS
:
469 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
474 case XML_ELEMENT_CONTENT_OR
: {
475 xmlAutomataStatePtr oldstate
, oldend
;
476 xmlElementContentOccur ocur
;
478 ocur
= content
->ocur
;
479 if ((ocur
== XML_ELEMENT_CONTENT_PLUS
) ||
480 (ocur
== XML_ELEMENT_CONTENT_MULT
)) {
481 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
,
484 oldstate
= ctxt
->state
;
485 oldend
= xmlAutomataNewState(ctxt
->am
);
488 * iterate over the subtypes and remerge the end with an
492 ctxt
->state
= oldstate
;
493 xmlValidBuildAContentModel(content
->c1
, ctxt
, name
);
494 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldend
);
495 content
= content
->c2
;
496 } while ((content
->type
== XML_ELEMENT_CONTENT_OR
) &&
497 (content
->ocur
== XML_ELEMENT_CONTENT_ONCE
));
498 ctxt
->state
= oldstate
;
499 xmlValidBuildAContentModel(content
, ctxt
, name
);
500 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldend
);
501 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
, oldend
, NULL
);
503 case XML_ELEMENT_CONTENT_ONCE
:
505 case XML_ELEMENT_CONTENT_OPT
:
506 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
508 case XML_ELEMENT_CONTENT_MULT
:
509 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
510 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
512 case XML_ELEMENT_CONTENT_PLUS
:
513 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
519 VERROR(ctxt
->userData
, "ContentModel broken for element %s\n",
526 * xmlValidBuildContentModel:
527 * @ctxt: a validation context
528 * @elem: an element declaration node
530 * (Re)Build the automata associated to the content model of this
533 * Returns 1 in case of success, 0 in case of error
536 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt
, xmlElementPtr elem
) {
537 xmlAutomataStatePtr start
;
539 if ((ctxt
== NULL
) || (elem
== NULL
))
541 if (elem
->type
!= XML_ELEMENT_DECL
)
543 if (elem
->etype
!= XML_ELEMENT_TYPE_ELEMENT
)
545 /* TODO: should we rebuild in this case ? */
546 if (elem
->contModel
!= NULL
)
549 ctxt
->am
= xmlNewAutomata();
550 if (ctxt
->am
== NULL
) {
551 VERROR(ctxt
->userData
, "Cannot create automata for element %s\n",
555 start
= ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
556 xmlValidBuildAContentModel(elem
->content
, ctxt
, elem
->name
);
557 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
558 elem
->contModel
= xmlAutomataCompile(ctxt
->am
);
559 if (!xmlRegexpIsDeterminist(elem
->contModel
)) {
562 xmlSnprintfElementContent(expr
, 5000, elem
->content
, 1);
563 VERROR(ctxt
->userData
, "Content model of %s is not determinist: %s\n",
565 #ifdef DEBUG_REGEXP_ALGO
566 xmlRegexpPrint(stderr
, elem
->contModel
);
571 xmlFreeAutomata(ctxt
->am
);
576 #endif /* LIBXML_REGEXP_ENABLED */
578 /************************************************************************
580 * QName handling helper *
582 ************************************************************************/
586 * @name: an XML parser context
587 * @prefix: a xmlChar **
589 * parse an XML qualified name string
591 * [NS 5] QName ::= (Prefix ':')? LocalPart
593 * [NS 6] Prefix ::= NCName
595 * [NS 7] LocalPart ::= NCName
597 * Returns NULL if not a QName, otherwise the local part, and prefix
598 * is updated to get the Prefix if any.
602 xmlSplitQName2(const xmlChar
*name
, xmlChar
**prefix
) {
608 #ifndef XML_XML_NAMESPACE
609 /* xml: prefix is not really a namespace */
610 if ((name
[0] == 'x') && (name
[1] == 'm') &&
611 (name
[2] == 'l') && (name
[3] == ':'))
615 /* nasty but valid */
620 * we are not trying to validate but just to cut, and yes it will
621 * work even if this is as set of UTF-8 encoded chars
623 while ((name
[len
] != 0) && (name
[len
] != ':'))
629 *prefix
= xmlStrndup(name
, len
);
630 ret
= xmlStrdup(&name
[len
+ 1]);
635 /****************************************************************
637 * Util functions for data allocation/deallocation *
639 ****************************************************************/
642 * xmlNewElementContent:
643 * @name: the subelement name or NULL
644 * @type: the type of element content decl
646 * Allocate an element content structure.
648 * Returns NULL if not, otherwise the new element content structure
651 xmlNewElementContent(xmlChar
*name
, xmlElementContentType type
) {
652 xmlElementContentPtr ret
;
655 case XML_ELEMENT_CONTENT_ELEMENT
:
657 xmlGenericError(xmlGenericErrorContext
,
658 "xmlNewElementContent : name == NULL !\n");
661 case XML_ELEMENT_CONTENT_PCDATA
:
662 case XML_ELEMENT_CONTENT_SEQ
:
663 case XML_ELEMENT_CONTENT_OR
:
665 xmlGenericError(xmlGenericErrorContext
,
666 "xmlNewElementContent : name != NULL !\n");
670 xmlGenericError(xmlGenericErrorContext
,
671 "xmlNewElementContent: unknown type %d\n", type
);
674 ret
= (xmlElementContentPtr
) xmlMalloc(sizeof(xmlElementContent
));
676 xmlGenericError(xmlGenericErrorContext
,
677 "xmlNewElementContent : out of memory!\n");
680 memset(ret
, 0, sizeof(xmlElementContent
));
682 ret
->ocur
= XML_ELEMENT_CONTENT_ONCE
;
684 xmlChar
*prefix
= NULL
;
685 ret
->name
= xmlSplitQName2(name
, &prefix
);
686 if (ret
->name
== NULL
)
687 ret
->name
= xmlStrdup(name
);
688 ret
->prefix
= prefix
;
693 ret
->c1
= ret
->c2
= ret
->parent
= NULL
;
698 * xmlCopyElementContent:
699 * @content: An element content pointer.
701 * Build a copy of an element content description.
703 * Returns the new xmlElementContentPtr or NULL in case of error.
706 xmlCopyElementContent(xmlElementContentPtr cur
) {
707 xmlElementContentPtr ret
;
709 if (cur
== NULL
) return(NULL
);
710 ret
= xmlNewElementContent((xmlChar
*) cur
->name
, cur
->type
);
712 xmlGenericError(xmlGenericErrorContext
,
713 "xmlCopyElementContent : out of memory\n");
716 if (cur
->prefix
!= NULL
)
717 ret
->prefix
= xmlStrdup(cur
->prefix
);
718 ret
->ocur
= cur
->ocur
;
719 if (cur
->c1
!= NULL
) ret
->c1
= xmlCopyElementContent(cur
->c1
);
721 ret
->c1
->parent
= ret
;
722 if (cur
->c2
!= NULL
) ret
->c2
= xmlCopyElementContent(cur
->c2
);
724 ret
->c2
->parent
= ret
;
729 * xmlFreeElementContent:
730 * @cur: the element content tree to free
732 * Free an element content structure. This is a recursive call !
735 xmlFreeElementContent(xmlElementContentPtr cur
) {
736 if (cur
== NULL
) return;
738 case XML_ELEMENT_CONTENT_PCDATA
:
739 case XML_ELEMENT_CONTENT_ELEMENT
:
740 case XML_ELEMENT_CONTENT_SEQ
:
741 case XML_ELEMENT_CONTENT_OR
:
744 xmlGenericError(xmlGenericErrorContext
,
745 "xmlFreeElementContent : type %d\n", cur
->type
);
748 if (cur
->c1
!= NULL
) xmlFreeElementContent(cur
->c1
);
749 if (cur
->c2
!= NULL
) xmlFreeElementContent(cur
->c2
);
750 if (cur
->name
!= NULL
) xmlFree((xmlChar
*) cur
->name
);
751 if (cur
->prefix
!= NULL
) xmlFree((xmlChar
*) cur
->prefix
);
756 * xmlDumpElementContent:
757 * @buf: An XML buffer
758 * @content: An element table
759 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
761 * This will dump the content of the element table as an XML DTD definition
764 xmlDumpElementContent(xmlBufferPtr buf
, xmlElementContentPtr content
, int glob
) {
765 if (content
== NULL
) return;
767 if (glob
) xmlBufferWriteChar(buf
, "(");
768 switch (content
->type
) {
769 case XML_ELEMENT_CONTENT_PCDATA
:
770 xmlBufferWriteChar(buf
, "#PCDATA");
772 case XML_ELEMENT_CONTENT_ELEMENT
:
773 if (content
->prefix
!= NULL
) {
774 xmlBufferWriteCHAR(buf
, content
->prefix
);
775 xmlBufferWriteChar(buf
, ":");
777 xmlBufferWriteCHAR(buf
, content
->name
);
779 case XML_ELEMENT_CONTENT_SEQ
:
780 if ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
781 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
))
782 xmlDumpElementContent(buf
, content
->c1
, 1);
784 xmlDumpElementContent(buf
, content
->c1
, 0);
785 xmlBufferWriteChar(buf
, " , ");
786 if (content
->c2
->type
== XML_ELEMENT_CONTENT_OR
)
787 xmlDumpElementContent(buf
, content
->c2
, 1);
789 xmlDumpElementContent(buf
, content
->c2
, 0);
791 case XML_ELEMENT_CONTENT_OR
:
792 if ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
793 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
))
794 xmlDumpElementContent(buf
, content
->c1
, 1);
796 xmlDumpElementContent(buf
, content
->c1
, 0);
797 xmlBufferWriteChar(buf
, " | ");
798 if (content
->c2
->type
== XML_ELEMENT_CONTENT_SEQ
)
799 xmlDumpElementContent(buf
, content
->c2
, 1);
801 xmlDumpElementContent(buf
, content
->c2
, 0);
804 xmlGenericError(xmlGenericErrorContext
,
805 "xmlDumpElementContent: unknown type %d\n",
809 xmlBufferWriteChar(buf
, ")");
810 switch (content
->ocur
) {
811 case XML_ELEMENT_CONTENT_ONCE
:
813 case XML_ELEMENT_CONTENT_OPT
:
814 xmlBufferWriteChar(buf
, "?");
816 case XML_ELEMENT_CONTENT_MULT
:
817 xmlBufferWriteChar(buf
, "*");
819 case XML_ELEMENT_CONTENT_PLUS
:
820 xmlBufferWriteChar(buf
, "+");
826 * xmlSprintfElementContent:
827 * @buf: an output buffer
828 * @content: An element table
829 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
831 * Deprecated, unsafe, use xmlSnprintfElementContent
834 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED
,
835 xmlElementContentPtr content ATTRIBUTE_UNUSED
,
836 int glob ATTRIBUTE_UNUSED
) {
840 * xmlSnprintfElementContent:
841 * @buf: an output buffer
842 * @size: the buffer size
843 * @content: An element table
844 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
846 * This will dump the content of the element content definition
847 * Intended just for the debug routine
850 xmlSnprintfElementContent(char *buf
, int size
, xmlElementContentPtr content
, int glob
) {
853 if (content
== NULL
) return;
855 if (size
- len
< 50) {
856 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
860 if (glob
) strcat(buf
, "(");
861 switch (content
->type
) {
862 case XML_ELEMENT_CONTENT_PCDATA
:
863 strcat(buf
, "#PCDATA");
865 case XML_ELEMENT_CONTENT_ELEMENT
:
866 if (content
->prefix
!= NULL
) {
867 if (size
- len
< xmlStrlen(content
->prefix
) + 10) {
871 strcat(buf
, (char *) content
->prefix
);
874 if (size
- len
< xmlStrlen(content
->name
) + 10) {
878 strcat(buf
, (char *) content
->name
);
880 case XML_ELEMENT_CONTENT_SEQ
:
881 if ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
882 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
))
883 xmlSnprintfElementContent(buf
, size
, content
->c1
, 1);
885 xmlSnprintfElementContent(buf
, size
, content
->c1
, 0);
887 if (size
- len
< 50) {
888 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
893 if (((content
->c2
->type
== XML_ELEMENT_CONTENT_OR
) ||
894 (content
->c2
->ocur
!= XML_ELEMENT_CONTENT_ONCE
)) &&
895 (content
->c2
->type
!= XML_ELEMENT_CONTENT_ELEMENT
))
896 xmlSnprintfElementContent(buf
, size
, content
->c2
, 1);
898 xmlSnprintfElementContent(buf
, size
, content
->c2
, 0);
900 case XML_ELEMENT_CONTENT_OR
:
901 if ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
902 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
))
903 xmlSnprintfElementContent(buf
, size
, content
->c1
, 1);
905 xmlSnprintfElementContent(buf
, size
, content
->c1
, 0);
907 if (size
- len
< 50) {
908 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
913 if (((content
->c2
->type
== XML_ELEMENT_CONTENT_SEQ
) ||
914 (content
->c2
->ocur
!= XML_ELEMENT_CONTENT_ONCE
)) &&
915 (content
->c2
->type
!= XML_ELEMENT_CONTENT_ELEMENT
))
916 xmlSnprintfElementContent(buf
, size
, content
->c2
, 1);
918 xmlSnprintfElementContent(buf
, size
, content
->c2
, 0);
923 switch (content
->ocur
) {
924 case XML_ELEMENT_CONTENT_ONCE
:
926 case XML_ELEMENT_CONTENT_OPT
:
929 case XML_ELEMENT_CONTENT_MULT
:
932 case XML_ELEMENT_CONTENT_PLUS
:
938 /****************************************************************
940 * Registration of DTD declarations *
942 ****************************************************************/
945 * xmlCreateElementTable:
947 * create and initialize an empty element hash table.
949 * Returns the xmlElementTablePtr just created or NULL in case of error.
951 static xmlElementTablePtr
952 xmlCreateElementTable(void) {
953 return(xmlHashCreate(0));
960 * Deallocate the memory used by an element definition
963 xmlFreeElement(xmlElementPtr elem
) {
964 if (elem
== NULL
) return;
965 xmlUnlinkNode((xmlNodePtr
) elem
);
966 xmlFreeElementContent(elem
->content
);
967 if (elem
->name
!= NULL
)
968 xmlFree((xmlChar
*) elem
->name
);
969 if (elem
->prefix
!= NULL
)
970 xmlFree((xmlChar
*) elem
->prefix
);
971 #ifdef LIBXML_REGEXP_ENABLED
972 if (elem
->contModel
!= NULL
)
973 xmlRegFreeRegexp(elem
->contModel
);
981 * @ctxt: the validation context
982 * @dtd: pointer to the DTD
983 * @name: the entity name
984 * @type: the element type
985 * @content: the element content tree or NULL
987 * Register a new element declaration
989 * Returns NULL if not, otherwise the entity
992 xmlAddElementDecl(xmlValidCtxtPtr ctxt
, xmlDtdPtr dtd
, const xmlChar
*name
,
993 xmlElementTypeVal type
,
994 xmlElementContentPtr content
) {
996 xmlElementTablePtr table
;
997 xmlAttributePtr oldAttributes
= NULL
;
998 xmlChar
*ns
, *uqname
;
1001 xmlGenericError(xmlGenericErrorContext
,
1002 "xmlAddElementDecl: dtd == NULL\n");
1006 xmlGenericError(xmlGenericErrorContext
,
1007 "xmlAddElementDecl: name == NULL\n");
1011 case XML_ELEMENT_TYPE_EMPTY
:
1012 if (content
!= NULL
) {
1013 xmlGenericError(xmlGenericErrorContext
,
1014 "xmlAddElementDecl: content != NULL for EMPTY\n");
1018 case XML_ELEMENT_TYPE_ANY
:
1019 if (content
!= NULL
) {
1020 xmlGenericError(xmlGenericErrorContext
,
1021 "xmlAddElementDecl: content != NULL for ANY\n");
1025 case XML_ELEMENT_TYPE_MIXED
:
1026 if (content
== NULL
) {
1027 xmlGenericError(xmlGenericErrorContext
,
1028 "xmlAddElementDecl: content == NULL for MIXED\n");
1032 case XML_ELEMENT_TYPE_ELEMENT
:
1033 if (content
== NULL
) {
1034 xmlGenericError(xmlGenericErrorContext
,
1035 "xmlAddElementDecl: content == NULL for ELEMENT\n");
1040 xmlGenericError(xmlGenericErrorContext
,
1041 "xmlAddElementDecl: unknown type %d\n", type
);
1046 * check if name is a QName
1048 uqname
= xmlSplitQName2(name
, &ns
);
1053 * Create the Element table if needed.
1055 table
= (xmlElementTablePtr
) dtd
->elements
;
1056 if (table
== NULL
) {
1057 table
= xmlCreateElementTable();
1058 dtd
->elements
= (void *) table
;
1060 if (table
== NULL
) {
1061 xmlGenericError(xmlGenericErrorContext
,
1062 "xmlAddElementDecl: Table creation failed!\n");
1067 * lookup old attributes inserted on an undefined element in the
1070 if ((dtd
->doc
!= NULL
) && (dtd
->doc
->intSubset
!= NULL
)) {
1071 ret
= xmlHashLookup2(dtd
->doc
->intSubset
->elements
, name
, ns
);
1072 if ((ret
!= NULL
) && (ret
->etype
== XML_ELEMENT_TYPE_UNDEFINED
)) {
1073 oldAttributes
= ret
->attributes
;
1074 ret
->attributes
= NULL
;
1075 xmlHashRemoveEntry2(dtd
->doc
->intSubset
->elements
, name
, ns
, NULL
);
1076 xmlFreeElement(ret
);
1081 * The element may already be present if one of its attribute
1082 * was registered first
1084 ret
= xmlHashLookup2(table
, name
, ns
);
1086 if (ret
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
) {
1088 * The element is already defined in this DTD.
1090 VERROR(ctxt
->userData
, "Redefinition of element %s\n", name
);
1096 ret
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
1098 xmlGenericError(xmlGenericErrorContext
,
1099 "xmlAddElementDecl: out of memory\n");
1102 memset(ret
, 0, sizeof(xmlElement
));
1103 ret
->type
= XML_ELEMENT_DECL
;
1106 * fill the structure.
1108 ret
->name
= xmlStrdup(name
);
1113 * Insertion must not fail
1115 if (xmlHashAddEntry2(table
, name
, ns
, ret
)) {
1117 * The element is already defined in this DTD.
1119 VERROR(ctxt
->userData
, "Redefinition of element %s\n", name
);
1120 xmlFreeElement(ret
);
1128 * Finish to fill the structure.
1131 ret
->content
= xmlCopyElementContent(content
);
1132 ret
->attributes
= oldAttributes
;
1135 * Link it to the DTD
1138 ret
->doc
= dtd
->doc
;
1139 if (dtd
->last
== NULL
) {
1140 dtd
->children
= dtd
->last
= (xmlNodePtr
) ret
;
1142 dtd
->last
->next
= (xmlNodePtr
) ret
;
1143 ret
->prev
= dtd
->last
;
1144 dtd
->last
= (xmlNodePtr
) ret
;
1152 * xmlFreeElementTable:
1153 * @table: An element table
1155 * Deallocate the memory used by an element hash table.
1158 xmlFreeElementTable(xmlElementTablePtr table
) {
1159 xmlHashFree(table
, (xmlHashDeallocator
) xmlFreeElement
);
1166 * Build a copy of an element.
1168 * Returns the new xmlElementPtr or NULL in case of error.
1170 static xmlElementPtr
1171 xmlCopyElement(xmlElementPtr elem
) {
1174 cur
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
1176 xmlGenericError(xmlGenericErrorContext
,
1177 "xmlCopyElement: out of memory !\n");
1180 memset(cur
, 0, sizeof(xmlElement
));
1181 cur
->type
= XML_ELEMENT_DECL
;
1182 cur
->etype
= elem
->etype
;
1183 if (elem
->name
!= NULL
)
1184 cur
->name
= xmlStrdup(elem
->name
);
1187 if (elem
->prefix
!= NULL
)
1188 cur
->prefix
= xmlStrdup(elem
->prefix
);
1191 cur
->content
= xmlCopyElementContent(elem
->content
);
1192 /* TODO : rebuild the attribute list on the copy */
1193 cur
->attributes
= NULL
;
1198 * xmlCopyElementTable:
1199 * @table: An element table
1201 * Build a copy of an element table.
1203 * Returns the new xmlElementTablePtr or NULL in case of error.
1206 xmlCopyElementTable(xmlElementTablePtr table
) {
1207 return((xmlElementTablePtr
) xmlHashCopy(table
,
1208 (xmlHashCopier
) xmlCopyElement
));
1212 * xmlDumpElementDecl:
1213 * @buf: the XML buffer output
1214 * @elem: An element table
1216 * This will dump the content of the element declaration as an XML
1220 xmlDumpElementDecl(xmlBufferPtr buf
, xmlElementPtr elem
) {
1221 switch (elem
->etype
) {
1222 case XML_ELEMENT_TYPE_EMPTY
:
1223 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1224 if (elem
->prefix
!= NULL
) {
1225 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1226 xmlBufferWriteChar(buf
, ":");
1228 xmlBufferWriteCHAR(buf
, elem
->name
);
1229 xmlBufferWriteChar(buf
, " EMPTY>\n");
1231 case XML_ELEMENT_TYPE_ANY
:
1232 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1233 if (elem
->prefix
!= NULL
) {
1234 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1235 xmlBufferWriteChar(buf
, ":");
1237 xmlBufferWriteCHAR(buf
, elem
->name
);
1238 xmlBufferWriteChar(buf
, " ANY>\n");
1240 case XML_ELEMENT_TYPE_MIXED
:
1241 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1242 if (elem
->prefix
!= NULL
) {
1243 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1244 xmlBufferWriteChar(buf
, ":");
1246 xmlBufferWriteCHAR(buf
, elem
->name
);
1247 xmlBufferWriteChar(buf
, " ");
1248 xmlDumpElementContent(buf
, elem
->content
, 1);
1249 xmlBufferWriteChar(buf
, ">\n");
1251 case XML_ELEMENT_TYPE_ELEMENT
:
1252 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1253 if (elem
->prefix
!= NULL
) {
1254 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1255 xmlBufferWriteChar(buf
, ":");
1257 xmlBufferWriteCHAR(buf
, elem
->name
);
1258 xmlBufferWriteChar(buf
, " ");
1259 xmlDumpElementContent(buf
, elem
->content
, 1);
1260 xmlBufferWriteChar(buf
, ">\n");
1263 xmlGenericError(xmlGenericErrorContext
,
1264 "xmlDumpElementDecl: internal: unknown type %d\n",
1270 * xmlDumpElementTable:
1271 * @buf: the XML buffer output
1272 * @table: An element table
1274 * This will dump the content of the element table as an XML DTD definition
1277 xmlDumpElementTable(xmlBufferPtr buf
, xmlElementTablePtr table
) {
1278 xmlHashScan(table
, (xmlHashScanner
) xmlDumpElementDecl
, buf
);
1282 * xmlCreateEnumeration:
1283 * @name: the enumeration name or NULL
1285 * create and initialize an enumeration attribute node.
1287 * Returns the xmlEnumerationPtr just created or NULL in case
1291 xmlCreateEnumeration(xmlChar
*name
) {
1292 xmlEnumerationPtr ret
;
1294 ret
= (xmlEnumerationPtr
) xmlMalloc(sizeof(xmlEnumeration
));
1296 xmlGenericError(xmlGenericErrorContext
,
1297 "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
1298 (long)sizeof(xmlEnumeration
));
1301 memset(ret
, 0, sizeof(xmlEnumeration
));
1304 ret
->name
= xmlStrdup(name
);
1309 * xmlFreeEnumeration:
1310 * @cur: the tree to free.
1312 * free an enumeration attribute node (recursive).
1315 xmlFreeEnumeration(xmlEnumerationPtr cur
) {
1316 if (cur
== NULL
) return;
1318 if (cur
->next
!= NULL
) xmlFreeEnumeration(cur
->next
);
1320 if (cur
->name
!= NULL
) xmlFree((xmlChar
*) cur
->name
);
1325 * xmlCopyEnumeration:
1326 * @cur: the tree to copy.
1328 * Copy an enumeration attribute node (recursive).
1330 * Returns the xmlEnumerationPtr just created or NULL in case
1334 xmlCopyEnumeration(xmlEnumerationPtr cur
) {
1335 xmlEnumerationPtr ret
;
1337 if (cur
== NULL
) return(NULL
);
1338 ret
= xmlCreateEnumeration((xmlChar
*) cur
->name
);
1340 if (cur
->next
!= NULL
) ret
->next
= xmlCopyEnumeration(cur
->next
);
1341 else ret
->next
= NULL
;
1347 * xmlDumpEnumeration:
1348 * @buf: the XML buffer output
1349 * @enum: An enumeration
1351 * This will dump the content of the enumeration
1354 xmlDumpEnumeration(xmlBufferPtr buf
, xmlEnumerationPtr cur
) {
1355 if (cur
== NULL
) return;
1357 xmlBufferWriteCHAR(buf
, cur
->name
);
1358 if (cur
->next
== NULL
)
1359 xmlBufferWriteChar(buf
, ")");
1361 xmlBufferWriteChar(buf
, " | ");
1362 xmlDumpEnumeration(buf
, cur
->next
);
1367 * xmlCreateAttributeTable:
1369 * create and initialize an empty attribute hash table.
1371 * Returns the xmlAttributeTablePtr just created or NULL in case
1374 static xmlAttributeTablePtr
1375 xmlCreateAttributeTable(void) {
1376 return(xmlHashCreate(0));
1380 * xmlScanAttributeDeclCallback:
1381 * @attr: the attribute decl
1382 * @list: the list to update
1384 * Callback called by xmlScanAttributeDecl when a new attribute
1385 * has to be entered in the list.
1388 xmlScanAttributeDeclCallback(xmlAttributePtr attr
, xmlAttributePtr
*list
,
1389 const xmlChar
* name ATTRIBUTE_UNUSED
) {
1390 attr
->nexth
= *list
;
1395 * xmlScanAttributeDecl:
1396 * @dtd: pointer to the DTD
1397 * @elem: the element name
1399 * When inserting a new element scan the DtD for existing attributes
1400 * for that element and initialize the Attribute chain
1402 * Returns the pointer to the first attribute decl in the chain,
1406 xmlScanAttributeDecl(xmlDtdPtr dtd
, const xmlChar
*elem
) {
1407 xmlAttributePtr ret
= NULL
;
1408 xmlAttributeTablePtr table
;
1411 xmlGenericError(xmlGenericErrorContext
,
1412 "xmlScanAttributeDecl: dtd == NULL\n");
1416 xmlGenericError(xmlGenericErrorContext
,
1417 "xmlScanAttributeDecl: elem == NULL\n");
1420 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
1425 xmlHashScan3(table
, NULL
, NULL
, elem
,
1426 (xmlHashScanner
) xmlScanAttributeDeclCallback
, &ret
);
1431 * xmlScanIDAttributeDecl:
1432 * @ctxt: the validation context
1433 * @elem: the element name
1435 * Verify that the element don't have too many ID attributes
1438 * Returns the number of ID attributes found.
1441 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt
, xmlElementPtr elem
) {
1442 xmlAttributePtr cur
;
1445 if (elem
== NULL
) return(0);
1446 cur
= elem
->attributes
;
1447 while (cur
!= NULL
) {
1448 if (cur
->atype
== XML_ATTRIBUTE_ID
) {
1451 VERROR(ctxt
->userData
,
1452 "Element %s has too many ID attributes defined : %s\n",
1453 elem
->name
, cur
->name
);
1462 * @elem: An attribute
1464 * Deallocate the memory used by an attribute definition
1467 xmlFreeAttribute(xmlAttributePtr attr
) {
1468 if (attr
== NULL
) return;
1469 xmlUnlinkNode((xmlNodePtr
) attr
);
1470 if (attr
->tree
!= NULL
)
1471 xmlFreeEnumeration(attr
->tree
);
1472 if (attr
->elem
!= NULL
)
1473 xmlFree((xmlChar
*) attr
->elem
);
1474 if (attr
->name
!= NULL
)
1475 xmlFree((xmlChar
*) attr
->name
);
1476 if (attr
->defaultValue
!= NULL
)
1477 xmlFree((xmlChar
*) attr
->defaultValue
);
1478 if (attr
->prefix
!= NULL
)
1479 xmlFree((xmlChar
*) attr
->prefix
);
1485 * xmlAddAttributeDecl:
1486 * @ctxt: the validation context
1487 * @dtd: pointer to the DTD
1488 * @elem: the element name
1489 * @name: the attribute name
1490 * @ns: the attribute namespace prefix
1491 * @type: the attribute type
1492 * @def: the attribute default type
1493 * @defaultValue: the attribute default value
1494 * @tree: if it's an enumeration, the associated list
1496 * Register a new attribute declaration
1497 * Note that @tree becomes the ownership of the DTD
1499 * Returns NULL if not new, otherwise the attribute decl
1502 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt
, xmlDtdPtr dtd
, const xmlChar
*elem
,
1503 const xmlChar
*name
, const xmlChar
*ns
,
1504 xmlAttributeType type
, xmlAttributeDefault def
,
1505 const xmlChar
*defaultValue
, xmlEnumerationPtr tree
) {
1506 xmlAttributePtr ret
;
1507 xmlAttributeTablePtr table
;
1508 xmlElementPtr elemDef
;
1511 xmlGenericError(xmlGenericErrorContext
,
1512 "xmlAddAttributeDecl: dtd == NULL\n");
1513 xmlFreeEnumeration(tree
);
1517 xmlGenericError(xmlGenericErrorContext
,
1518 "xmlAddAttributeDecl: name == NULL\n");
1519 xmlFreeEnumeration(tree
);
1523 xmlGenericError(xmlGenericErrorContext
,
1524 "xmlAddAttributeDecl: elem == NULL\n");
1525 xmlFreeEnumeration(tree
);
1530 * Check the type and possibly the default value.
1533 case XML_ATTRIBUTE_CDATA
:
1535 case XML_ATTRIBUTE_ID
:
1537 case XML_ATTRIBUTE_IDREF
:
1539 case XML_ATTRIBUTE_IDREFS
:
1541 case XML_ATTRIBUTE_ENTITY
:
1543 case XML_ATTRIBUTE_ENTITIES
:
1545 case XML_ATTRIBUTE_NMTOKEN
:
1547 case XML_ATTRIBUTE_NMTOKENS
:
1549 case XML_ATTRIBUTE_ENUMERATION
:
1551 case XML_ATTRIBUTE_NOTATION
:
1554 xmlGenericError(xmlGenericErrorContext
,
1555 "xmlAddAttributeDecl: unknown type %d\n", type
);
1556 xmlFreeEnumeration(tree
);
1559 if ((defaultValue
!= NULL
) &&
1560 (!xmlValidateAttributeValue(type
, defaultValue
))) {
1561 VERROR(ctxt
->userData
, "Attribute %s of %s: invalid default value\n",
1562 elem
, name
, defaultValue
);
1563 defaultValue
= NULL
;
1568 * Check first that an attribute defined in the external subset wasn't
1569 * already defined in the internal subset
1571 if ((dtd
->doc
!= NULL
) && (dtd
->doc
->extSubset
== dtd
) &&
1572 (dtd
->doc
->intSubset
!= NULL
) &&
1573 (dtd
->doc
->intSubset
->attributes
!= NULL
)) {
1574 ret
= xmlHashLookup3(dtd
->doc
->intSubset
->attributes
, name
, ns
, elem
);
1580 * Create the Attribute table if needed.
1582 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
1583 if (table
== NULL
) {
1584 table
= xmlCreateAttributeTable();
1585 dtd
->attributes
= (void *) table
;
1587 if (table
== NULL
) {
1588 xmlGenericError(xmlGenericErrorContext
,
1589 "xmlAddAttributeDecl: Table creation failed!\n");
1594 ret
= (xmlAttributePtr
) xmlMalloc(sizeof(xmlAttribute
));
1596 xmlGenericError(xmlGenericErrorContext
,
1597 "xmlAddAttributeDecl: out of memory\n");
1600 memset(ret
, 0, sizeof(xmlAttribute
));
1601 ret
->type
= XML_ATTRIBUTE_DECL
;
1604 * fill the structure.
1607 ret
->name
= xmlStrdup(name
);
1608 ret
->prefix
= xmlStrdup(ns
);
1609 ret
->elem
= xmlStrdup(elem
);
1612 if (defaultValue
!= NULL
)
1613 ret
->defaultValue
= xmlStrdup(defaultValue
);
1617 * Search the DTD for previous declarations of the ATTLIST
1619 if (xmlHashAddEntry3(table
, name
, ns
, elem
, ret
) < 0) {
1621 * The attribute is already defined in this DTD.
1623 VWARNING(ctxt
->userData
,
1624 "Attribute %s of element %s: already defined\n",
1626 xmlFreeAttribute(ret
);
1632 * Multiple ID per element
1634 elemDef
= xmlGetDtdElementDesc2(dtd
, elem
, 1);
1635 if (elemDef
!= NULL
) {
1637 if ((type
== XML_ATTRIBUTE_ID
) &&
1638 (xmlScanIDAttributeDecl(NULL
, elemDef
) != 0)) {
1639 VERROR(ctxt
->userData
,
1640 "Element %s has too may ID attributes defined : %s\n",
1646 * Insert namespace default def first they need to be
1649 if ((xmlStrEqual(ret
->name
, BAD_CAST
"xmlns")) ||
1650 ((ret
->prefix
!= NULL
&&
1651 (xmlStrEqual(ret
->prefix
, BAD_CAST
"xmlns"))))) {
1652 ret
->nexth
= elemDef
->attributes
;
1653 elemDef
->attributes
= ret
;
1655 xmlAttributePtr tmp
= elemDef
->attributes
;
1657 while ((tmp
!= NULL
) &&
1658 ((xmlStrEqual(tmp
->name
, BAD_CAST
"xmlns")) ||
1659 ((ret
->prefix
!= NULL
&&
1660 (xmlStrEqual(ret
->prefix
, BAD_CAST
"xmlns")))))) {
1661 if (tmp
->nexth
== NULL
)
1666 ret
->nexth
= tmp
->nexth
;
1669 ret
->nexth
= elemDef
->attributes
;
1670 elemDef
->attributes
= ret
;
1676 * Link it to the DTD
1679 ret
->doc
= dtd
->doc
;
1680 if (dtd
->last
== NULL
) {
1681 dtd
->children
= dtd
->last
= (xmlNodePtr
) ret
;
1683 dtd
->last
->next
= (xmlNodePtr
) ret
;
1684 ret
->prev
= dtd
->last
;
1685 dtd
->last
= (xmlNodePtr
) ret
;
1691 * xmlFreeAttributeTable:
1692 * @table: An attribute table
1694 * Deallocate the memory used by an entities hash table.
1697 xmlFreeAttributeTable(xmlAttributeTablePtr table
) {
1698 xmlHashFree(table
, (xmlHashDeallocator
) xmlFreeAttribute
);
1703 * @attr: An attribute
1705 * Build a copy of an attribute.
1707 * Returns the new xmlAttributePtr or NULL in case of error.
1709 static xmlAttributePtr
1710 xmlCopyAttribute(xmlAttributePtr attr
) {
1711 xmlAttributePtr cur
;
1713 cur
= (xmlAttributePtr
) xmlMalloc(sizeof(xmlAttribute
));
1715 xmlGenericError(xmlGenericErrorContext
,
1716 "xmlCopyAttribute: out of memory !\n");
1719 memset(cur
, 0, sizeof(xmlAttribute
));
1720 cur
->type
= XML_ATTRIBUTE_DECL
;
1721 cur
->atype
= attr
->atype
;
1722 cur
->def
= attr
->def
;
1723 cur
->tree
= xmlCopyEnumeration(attr
->tree
);
1724 if (attr
->elem
!= NULL
)
1725 cur
->elem
= xmlStrdup(attr
->elem
);
1726 if (attr
->name
!= NULL
)
1727 cur
->name
= xmlStrdup(attr
->name
);
1728 if (attr
->prefix
!= NULL
)
1729 cur
->prefix
= xmlStrdup(attr
->prefix
);
1730 if (attr
->defaultValue
!= NULL
)
1731 cur
->defaultValue
= xmlStrdup(attr
->defaultValue
);
1736 * xmlCopyAttributeTable:
1737 * @table: An attribute table
1739 * Build a copy of an attribute table.
1741 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1743 xmlAttributeTablePtr
1744 xmlCopyAttributeTable(xmlAttributeTablePtr table
) {
1745 return((xmlAttributeTablePtr
) xmlHashCopy(table
,
1746 (xmlHashCopier
) xmlCopyAttribute
));
1750 * xmlDumpAttributeDecl:
1751 * @buf: the XML buffer output
1752 * @attr: An attribute declaration
1754 * This will dump the content of the attribute declaration as an XML
1758 xmlDumpAttributeDecl(xmlBufferPtr buf
, xmlAttributePtr attr
) {
1759 xmlBufferWriteChar(buf
, "<!ATTLIST ");
1760 xmlBufferWriteCHAR(buf
, attr
->elem
);
1761 xmlBufferWriteChar(buf
, " ");
1762 if (attr
->prefix
!= NULL
) {
1763 xmlBufferWriteCHAR(buf
, attr
->prefix
);
1764 xmlBufferWriteChar(buf
, ":");
1766 xmlBufferWriteCHAR(buf
, attr
->name
);
1767 switch (attr
->atype
) {
1768 case XML_ATTRIBUTE_CDATA
:
1769 xmlBufferWriteChar(buf
, " CDATA");
1771 case XML_ATTRIBUTE_ID
:
1772 xmlBufferWriteChar(buf
, " ID");
1774 case XML_ATTRIBUTE_IDREF
:
1775 xmlBufferWriteChar(buf
, " IDREF");
1777 case XML_ATTRIBUTE_IDREFS
:
1778 xmlBufferWriteChar(buf
, " IDREFS");
1780 case XML_ATTRIBUTE_ENTITY
:
1781 xmlBufferWriteChar(buf
, " ENTITY");
1783 case XML_ATTRIBUTE_ENTITIES
:
1784 xmlBufferWriteChar(buf
, " ENTITIES");
1786 case XML_ATTRIBUTE_NMTOKEN
:
1787 xmlBufferWriteChar(buf
, " NMTOKEN");
1789 case XML_ATTRIBUTE_NMTOKENS
:
1790 xmlBufferWriteChar(buf
, " NMTOKENS");
1792 case XML_ATTRIBUTE_ENUMERATION
:
1793 xmlBufferWriteChar(buf
, " (");
1794 xmlDumpEnumeration(buf
, attr
->tree
);
1796 case XML_ATTRIBUTE_NOTATION
:
1797 xmlBufferWriteChar(buf
, " NOTATION (");
1798 xmlDumpEnumeration(buf
, attr
->tree
);
1801 xmlGenericError(xmlGenericErrorContext
,
1802 "xmlDumpAttributeDecl: internal: unknown type %d\n",
1805 switch (attr
->def
) {
1806 case XML_ATTRIBUTE_NONE
:
1808 case XML_ATTRIBUTE_REQUIRED
:
1809 xmlBufferWriteChar(buf
, " #REQUIRED");
1811 case XML_ATTRIBUTE_IMPLIED
:
1812 xmlBufferWriteChar(buf
, " #IMPLIED");
1814 case XML_ATTRIBUTE_FIXED
:
1815 xmlBufferWriteChar(buf
, " #FIXED");
1818 xmlGenericError(xmlGenericErrorContext
,
1819 "xmlDumpAttributeDecl: internal: unknown default %d\n",
1822 if (attr
->defaultValue
!= NULL
) {
1823 xmlBufferWriteChar(buf
, " ");
1824 xmlBufferWriteQuotedString(buf
, attr
->defaultValue
);
1826 xmlBufferWriteChar(buf
, ">\n");
1830 * xmlDumpAttributeTable:
1831 * @buf: the XML buffer output
1832 * @table: An attribute table
1834 * This will dump the content of the attribute table as an XML DTD definition
1837 xmlDumpAttributeTable(xmlBufferPtr buf
, xmlAttributeTablePtr table
) {
1838 xmlHashScan(table
, (xmlHashScanner
) xmlDumpAttributeDecl
, buf
);
1841 /************************************************************************
1845 ************************************************************************/
1847 * xmlCreateNotationTable:
1849 * create and initialize an empty notation hash table.
1851 * Returns the xmlNotationTablePtr just created or NULL in case
1854 static xmlNotationTablePtr
1855 xmlCreateNotationTable(void) {
1856 return(xmlHashCreate(0));
1863 * Deallocate the memory used by an notation definition
1866 xmlFreeNotation(xmlNotationPtr nota
) {
1867 if (nota
== NULL
) return;
1868 if (nota
->name
!= NULL
)
1869 xmlFree((xmlChar
*) nota
->name
);
1870 if (nota
->PublicID
!= NULL
)
1871 xmlFree((xmlChar
*) nota
->PublicID
);
1872 if (nota
->SystemID
!= NULL
)
1873 xmlFree((xmlChar
*) nota
->SystemID
);
1879 * xmlAddNotationDecl:
1880 * @dtd: pointer to the DTD
1881 * @ctxt: the validation context
1882 * @name: the entity name
1883 * @PublicID: the public identifier or NULL
1884 * @SystemID: the system identifier or NULL
1886 * Register a new notation declaration
1888 * Returns NULL if not, otherwise the entity
1891 xmlAddNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED
, xmlDtdPtr dtd
,
1892 const xmlChar
*name
,
1893 const xmlChar
*PublicID
, const xmlChar
*SystemID
) {
1895 xmlNotationTablePtr table
;
1898 xmlGenericError(xmlGenericErrorContext
,
1899 "xmlAddNotationDecl: dtd == NULL\n");
1903 xmlGenericError(xmlGenericErrorContext
,
1904 "xmlAddNotationDecl: name == NULL\n");
1907 if ((PublicID
== NULL
) && (SystemID
== NULL
)) {
1908 xmlGenericError(xmlGenericErrorContext
,
1909 "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1914 * Create the Notation table if needed.
1916 table
= (xmlNotationTablePtr
) dtd
->notations
;
1918 dtd
->notations
= table
= xmlCreateNotationTable();
1919 if (table
== NULL
) {
1920 xmlGenericError(xmlGenericErrorContext
,
1921 "xmlAddNotationDecl: Table creation failed!\n");
1925 ret
= (xmlNotationPtr
) xmlMalloc(sizeof(xmlNotation
));
1927 xmlGenericError(xmlGenericErrorContext
,
1928 "xmlAddNotationDecl: out of memory\n");
1931 memset(ret
, 0, sizeof(xmlNotation
));
1934 * fill the structure.
1936 ret
->name
= xmlStrdup(name
);
1937 if (SystemID
!= NULL
)
1938 ret
->SystemID
= xmlStrdup(SystemID
);
1939 if (PublicID
!= NULL
)
1940 ret
->PublicID
= xmlStrdup(PublicID
);
1944 * Check the DTD for previous declarations of the ATTLIST
1946 if (xmlHashAddEntry(table
, name
, ret
)) {
1947 xmlGenericError(xmlGenericErrorContext
,
1948 "xmlAddNotationDecl: %s already defined\n", name
);
1949 xmlFreeNotation(ret
);
1956 * xmlFreeNotationTable:
1957 * @table: An notation table
1959 * Deallocate the memory used by an entities hash table.
1962 xmlFreeNotationTable(xmlNotationTablePtr table
) {
1963 xmlHashFree(table
, (xmlHashDeallocator
) xmlFreeNotation
);
1970 * Build a copy of a notation.
1972 * Returns the new xmlNotationPtr or NULL in case of error.
1974 static xmlNotationPtr
1975 xmlCopyNotation(xmlNotationPtr nota
) {
1978 cur
= (xmlNotationPtr
) xmlMalloc(sizeof(xmlNotation
));
1980 xmlGenericError(xmlGenericErrorContext
,
1981 "xmlCopyNotation: out of memory !\n");
1984 if (nota
->name
!= NULL
)
1985 cur
->name
= xmlStrdup(nota
->name
);
1988 if (nota
->PublicID
!= NULL
)
1989 cur
->PublicID
= xmlStrdup(nota
->PublicID
);
1991 cur
->PublicID
= NULL
;
1992 if (nota
->SystemID
!= NULL
)
1993 cur
->SystemID
= xmlStrdup(nota
->SystemID
);
1995 cur
->SystemID
= NULL
;
2000 * xmlCopyNotationTable:
2001 * @table: A notation table
2003 * Build a copy of a notation table.
2005 * Returns the new xmlNotationTablePtr or NULL in case of error.
2008 xmlCopyNotationTable(xmlNotationTablePtr table
) {
2009 return((xmlNotationTablePtr
) xmlHashCopy(table
,
2010 (xmlHashCopier
) xmlCopyNotation
));
2014 * xmlDumpNotationDecl:
2015 * @buf: the XML buffer output
2016 * @nota: A notation declaration
2018 * This will dump the content the notation declaration as an XML DTD definition
2021 xmlDumpNotationDecl(xmlBufferPtr buf
, xmlNotationPtr nota
) {
2022 xmlBufferWriteChar(buf
, "<!NOTATION ");
2023 xmlBufferWriteCHAR(buf
, nota
->name
);
2024 if (nota
->PublicID
!= NULL
) {
2025 xmlBufferWriteChar(buf
, " PUBLIC ");
2026 xmlBufferWriteQuotedString(buf
, nota
->PublicID
);
2027 if (nota
->SystemID
!= NULL
) {
2028 xmlBufferWriteChar(buf
, " ");
2029 xmlBufferWriteCHAR(buf
, nota
->SystemID
);
2032 xmlBufferWriteChar(buf
, " SYSTEM ");
2033 xmlBufferWriteCHAR(buf
, nota
->SystemID
);
2035 xmlBufferWriteChar(buf
, " >\n");
2039 * xmlDumpNotationTable:
2040 * @buf: the XML buffer output
2041 * @table: A notation table
2043 * This will dump the content of the notation table as an XML DTD definition
2046 xmlDumpNotationTable(xmlBufferPtr buf
, xmlNotationTablePtr table
) {
2047 xmlHashScan(table
, (xmlHashScanner
) xmlDumpNotationDecl
, buf
);
2050 /************************************************************************
2054 ************************************************************************/
2058 * create and initialize an empty id hash table.
2060 * Returns the xmlIDTablePtr just created or NULL in case
2063 static xmlIDTablePtr
2064 xmlCreateIDTable(void) {
2065 return(xmlHashCreate(0));
2072 * Deallocate the memory used by an id definition
2075 xmlFreeID(xmlIDPtr id
) {
2076 if (id
== NULL
) return;
2077 if (id
->value
!= NULL
)
2078 xmlFree((xmlChar
*) id
->value
);
2084 * @ctxt: the validation context
2085 * @doc: pointer to the document
2086 * @value: the value name
2087 * @attr: the attribute holding the ID
2089 * Register a new id declaration
2091 * Returns NULL if not, otherwise the new xmlIDPtr
2094 xmlAddID(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, const xmlChar
*value
,
2097 xmlIDTablePtr table
;
2100 xmlGenericError(xmlGenericErrorContext
,
2101 "xmlAddID: doc == NULL\n");
2104 if (value
== NULL
) {
2105 xmlGenericError(xmlGenericErrorContext
,
2106 "xmlAddID: value == NULL\n");
2110 xmlGenericError(xmlGenericErrorContext
,
2111 "xmlAddID: attr == NULL\n");
2116 * Create the ID table if needed.
2118 table
= (xmlIDTablePtr
) doc
->ids
;
2120 doc
->ids
= table
= xmlCreateIDTable();
2121 if (table
== NULL
) {
2122 xmlGenericError(xmlGenericErrorContext
,
2123 "xmlAddID: Table creation failed!\n");
2127 ret
= (xmlIDPtr
) xmlMalloc(sizeof(xmlID
));
2129 xmlGenericError(xmlGenericErrorContext
,
2130 "xmlAddID: out of memory\n");
2135 * fill the structure.
2137 ret
->value
= xmlStrdup(value
);
2140 if (xmlHashAddEntry(table
, value
, ret
) < 0) {
2142 * The id is already defined in this DTD.
2145 VECTXT(ctxt
, attr
->parent
);
2146 VERROR(ctxt
->userData
, "ID %s already defined\n", value
);
2156 * @table: An id table
2158 * Deallocate the memory used by an ID hash table.
2161 xmlFreeIDTable(xmlIDTablePtr table
) {
2162 xmlHashFree(table
, (xmlHashDeallocator
) xmlFreeID
);
2167 * @doc: the document
2168 * @elem: the element carrying the attribute
2169 * @attr: the attribute
2171 * Determine whether an attribute is of type ID. In case we have DTD(s)
2172 * then this is done if DTD loading has been requested. In the case
2173 * of HTML documents parsed with the HTML parser, then ID detection is
2174 * done systematically.
2176 * Returns 0 or 1 depending on the lookup result
2179 xmlIsID(xmlDocPtr doc
, xmlNodePtr elem
, xmlAttrPtr attr
) {
2180 if (doc
== NULL
) return(0);
2181 if (attr
== NULL
) return(0);
2182 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
)) {
2184 } else if (doc
->type
== XML_HTML_DOCUMENT_NODE
) {
2185 if ((xmlStrEqual(BAD_CAST
"id", attr
->name
)) ||
2186 (xmlStrEqual(BAD_CAST
"name", attr
->name
)))
2190 xmlAttributePtr attrDecl
;
2192 if (elem
== NULL
) return(0);
2193 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
2195 * TODO: this sucks ... recomputing this every time is stupid
2197 int len
= xmlStrlen(elem
->name
) + xmlStrlen(elem
->ns
->prefix
) + 2;
2200 fullname
= xmlMalloc(len
);
2201 if (fullname
== NULL
)
2203 snprintf((char *) fullname
, len
, "%s:%s", (char *) elem
->ns
->prefix
,
2204 (char *) elem
->name
);
2205 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullname
,
2207 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
2208 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, fullname
,
2212 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
,
2214 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
2215 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, elem
->name
,
2219 if ((attrDecl
!= NULL
) && (attrDecl
->atype
== XML_ATTRIBUTE_ID
))
2227 * @doc: the document
2228 * @attr: the attribute
2230 * Remove the given attribute from the ID table maintained internally.
2232 * Returns -1 if the lookup failed and 0 otherwise
2235 xmlRemoveID(xmlDocPtr doc
, xmlAttrPtr attr
) {
2237 xmlIDTablePtr table
;
2240 if (doc
== NULL
) return(-1);
2241 if (attr
== NULL
) return(-1);
2242 table
= (xmlIDTablePtr
) doc
->ids
;
2248 ID
= xmlNodeListGetString(doc
, attr
->children
, 1);
2251 cur
= xmlHashLookup(table
, ID
);
2256 xmlHashUpdateEntry(table
, ID
, NULL
, (xmlHashDeallocator
) xmlFreeID
);
2263 * @doc: pointer to the document
2266 * Search the attribute declaring the given ID
2268 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2271 xmlGetID(xmlDocPtr doc
, const xmlChar
*ID
) {
2272 xmlIDTablePtr table
;
2276 xmlGenericError(xmlGenericErrorContext
, "xmlGetID: doc == NULL\n");
2281 xmlGenericError(xmlGenericErrorContext
, "xmlGetID: ID == NULL\n");
2285 table
= (xmlIDTablePtr
) doc
->ids
;
2289 id
= xmlHashLookup(table
, ID
);
2295 /************************************************************************
2299 ************************************************************************/
2300 typedef struct xmlRemoveMemo_t
2306 typedef xmlRemoveMemo
*xmlRemoveMemoPtr
;
2308 typedef struct xmlValidateMemo_t
2310 xmlValidCtxtPtr ctxt
;
2311 const xmlChar
*name
;
2314 typedef xmlValidateMemo
*xmlValidateMemoPtr
;
2317 * xmlCreateRefTable:
2319 * create and initialize an empty ref hash table.
2321 * Returns the xmlRefTablePtr just created or NULL in case
2324 static xmlRefTablePtr
2325 xmlCreateRefTable(void) {
2326 return(xmlHashCreate(0));
2333 * Deallocate the memory used by a ref definition
2336 xmlFreeRef(xmlLinkPtr lk
) {
2337 xmlRefPtr ref
= (xmlRefPtr
)xmlLinkGetData(lk
);
2338 if (ref
== NULL
) return;
2339 if (ref
->value
!= NULL
)
2340 xmlFree((xmlChar
*)ref
->value
);
2346 * @list_ref: A list of references.
2348 * Deallocate the memory used by a list of references
2351 xmlFreeRefList(xmlListPtr list_ref
) {
2352 if (list_ref
== NULL
) return;
2353 xmlListDelete(list_ref
);
2358 * @data: Contents of current link
2359 * @user: Value supplied by the user
2361 * Returns 0 to abort the walk or 1 to continue
2364 xmlWalkRemoveRef(const void *data
, const void *user
)
2366 xmlAttrPtr attr0
= ((xmlRefPtr
)data
)->attr
;
2367 xmlAttrPtr attr1
= ((xmlRemoveMemoPtr
)user
)->ap
;
2368 xmlListPtr ref_list
= ((xmlRemoveMemoPtr
)user
)->l
;
2370 if (attr0
== attr1
) { /* Matched: remove and terminate walk */
2371 xmlListRemoveFirst(ref_list
, (void *)data
);
2379 * @ctxt: the validation context
2380 * @doc: pointer to the document
2381 * @value: the value name
2382 * @attr: the attribute holding the Ref
2384 * Register a new ref declaration
2386 * Returns NULL if not, otherwise the new xmlRefPtr
2389 xmlAddRef(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED
, xmlDocPtr doc
, const xmlChar
*value
,
2392 xmlRefTablePtr table
;
2393 xmlListPtr ref_list
;
2396 xmlGenericError(xmlGenericErrorContext
,
2397 "xmlAddRef: doc == NULL\n");
2400 if (value
== NULL
) {
2401 xmlGenericError(xmlGenericErrorContext
,
2402 "xmlAddRef: value == NULL\n");
2406 xmlGenericError(xmlGenericErrorContext
,
2407 "xmlAddRef: attr == NULL\n");
2412 * Create the Ref table if needed.
2414 table
= (xmlRefTablePtr
) doc
->refs
;
2416 doc
->refs
= table
= xmlCreateRefTable();
2417 if (table
== NULL
) {
2418 xmlGenericError(xmlGenericErrorContext
,
2419 "xmlAddRef: Table creation failed!\n");
2423 ret
= (xmlRefPtr
) xmlMalloc(sizeof(xmlRef
));
2425 xmlGenericError(xmlGenericErrorContext
,
2426 "xmlAddRef: out of memory\n");
2431 * fill the structure.
2433 ret
->value
= xmlStrdup(value
);
2436 /* To add a reference :-
2437 * References are maintained as a list of references,
2438 * Lookup the entry, if no entry create new nodelist
2439 * Add the owning node to the NodeList
2443 if (NULL
== (ref_list
= xmlHashLookup(table
, value
))) {
2444 if (NULL
== (ref_list
= xmlListCreate(xmlFreeRef
, NULL
))) {
2445 xmlGenericError(xmlGenericErrorContext
,
2446 "xmlAddRef: Reference list creation failed!\n");
2449 if (xmlHashAddEntry(table
, value
, ref_list
) < 0) {
2450 xmlListDelete(ref_list
);
2451 xmlGenericError(xmlGenericErrorContext
,
2452 "xmlAddRef: Reference list insertion failed!\n");
2456 xmlListInsert(ref_list
, ret
);
2462 * @table: An ref table
2464 * Deallocate the memory used by an Ref hash table.
2467 xmlFreeRefTable(xmlRefTablePtr table
) {
2468 xmlHashFree(table
, (xmlHashDeallocator
) xmlFreeRefList
);
2473 * @doc: the document
2474 * @elem: the element carrying the attribute
2475 * @attr: the attribute
2477 * Determine whether an attribute is of type Ref. In case we have DTD(s)
2478 * then this is simple, otherwise we use an heuristic: name Ref (upper
2481 * Returns 0 or 1 depending on the lookup result
2484 xmlIsRef(xmlDocPtr doc
, xmlNodePtr elem
, xmlAttrPtr attr
) {
2485 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
)) {
2487 } else if (doc
->type
== XML_HTML_DOCUMENT_NODE
) {
2491 xmlAttributePtr attrDecl
;
2493 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, attr
->name
);
2494 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
2495 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
2496 elem
->name
, attr
->name
);
2498 if ((attrDecl
!= NULL
) &&
2499 (attrDecl
->atype
== XML_ATTRIBUTE_IDREF
||
2500 attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
))
2508 * @doc: the document
2509 * @attr: the attribute
2511 * Remove the given attribute from the Ref table maintained internally.
2513 * Returns -1 if the lookup failed and 0 otherwise
2516 xmlRemoveRef(xmlDocPtr doc
, xmlAttrPtr attr
) {
2517 xmlListPtr ref_list
;
2518 xmlRefTablePtr table
;
2520 xmlRemoveMemo target
;
2522 if (doc
== NULL
) return(-1);
2523 if (attr
== NULL
) return(-1);
2524 table
= (xmlRefTablePtr
) doc
->refs
;
2530 ID
= xmlNodeListGetString(doc
, attr
->children
, 1);
2533 ref_list
= xmlHashLookup(table
, ID
);
2535 if(ref_list
== NULL
) {
2539 /* At this point, ref_list refers to a list of references which
2540 * have the same key as the supplied attr. Our list of references
2541 * is ordered by reference address and we don't have that information
2542 * here to use when removing. We'll have to walk the list and
2543 * check for a matching attribute, when we find one stop the walk
2544 * and remove the entry.
2545 * The list is ordered by reference, so that means we don't have the
2546 * key. Passing the list and the reference to the walker means we
2547 * will have enough data to be able to remove the entry.
2549 target
.l
= ref_list
;
2552 /* Remove the supplied attr from our list */
2553 xmlListWalk(ref_list
, xmlWalkRemoveRef
, &target
);
2555 /*If the list is empty then remove the list entry in the hash */
2556 if (xmlListEmpty(ref_list
))
2557 xmlHashUpdateEntry(table
, ID
, NULL
, (xmlHashDeallocator
)
2565 * @doc: pointer to the document
2568 * Find the set of references for the supplied ID.
2570 * Returns NULL if not found, otherwise node set for the ID.
2573 xmlGetRefs(xmlDocPtr doc
, const xmlChar
*ID
) {
2574 xmlRefTablePtr table
;
2577 xmlGenericError(xmlGenericErrorContext
, "xmlGetRefs: doc == NULL\n");
2582 xmlGenericError(xmlGenericErrorContext
, "xmlGetRefs: ID == NULL\n");
2586 table
= (xmlRefTablePtr
) doc
->refs
;
2590 return (xmlHashLookup(table
, ID
));
2593 /************************************************************************
2595 * Routines for validity checking *
2597 ************************************************************************/
2600 * xmlGetDtdElementDesc:
2601 * @dtd: a pointer to the DtD to search
2602 * @name: the element name
2604 * Search the DTD for the description of this element
2606 * returns the xmlElementPtr if found or NULL
2610 xmlGetDtdElementDesc(xmlDtdPtr dtd
, const xmlChar
*name
) {
2611 xmlElementTablePtr table
;
2613 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
2615 if (dtd
== NULL
) return(NULL
);
2616 if (dtd
->elements
== NULL
)
2618 table
= (xmlElementTablePtr
) dtd
->elements
;
2620 uqname
= xmlSplitQName2(name
, &prefix
);
2623 cur
= xmlHashLookup2(table
, name
, prefix
);
2624 if (prefix
!= NULL
) xmlFree(prefix
);
2625 if (uqname
!= NULL
) xmlFree(uqname
);
2629 * xmlGetDtdElementDesc2:
2630 * @dtd: a pointer to the DtD to search
2631 * @name: the element name
2632 * @create: create an empty description if not found
2634 * Search the DTD for the description of this element
2636 * returns the xmlElementPtr if found or NULL
2639 static xmlElementPtr
2640 xmlGetDtdElementDesc2(xmlDtdPtr dtd
, const xmlChar
*name
, int create
) {
2641 xmlElementTablePtr table
;
2643 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
2645 if (dtd
== NULL
) return(NULL
);
2646 if (dtd
->elements
== NULL
) {
2650 * Create the Element table if needed.
2652 table
= (xmlElementTablePtr
) dtd
->elements
;
2653 if (table
== NULL
) {
2654 table
= xmlCreateElementTable();
2655 dtd
->elements
= (void *) table
;
2657 if (table
== NULL
) {
2658 xmlGenericError(xmlGenericErrorContext
,
2659 "xmlGetDtdElementDesc2: Table creation failed!\n");
2663 table
= (xmlElementTablePtr
) dtd
->elements
;
2665 uqname
= xmlSplitQName2(name
, &prefix
);
2668 cur
= xmlHashLookup2(table
, name
, prefix
);
2669 if ((cur
== NULL
) && (create
)) {
2670 cur
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
2672 xmlGenericError(xmlGenericErrorContext
,
2673 "xmlGetDtdElementDesc2: out of memory\n");
2676 memset(cur
, 0, sizeof(xmlElement
));
2677 cur
->type
= XML_ELEMENT_DECL
;
2680 * fill the structure.
2682 cur
->name
= xmlStrdup(name
);
2683 cur
->prefix
= xmlStrdup(prefix
);
2684 cur
->etype
= XML_ELEMENT_TYPE_UNDEFINED
;
2686 xmlHashAddEntry2(table
, name
, prefix
, cur
);
2688 if (prefix
!= NULL
) xmlFree(prefix
);
2689 if (uqname
!= NULL
) xmlFree(uqname
);
2694 * xmlGetDtdQElementDesc:
2695 * @dtd: a pointer to the DtD to search
2696 * @name: the element name
2697 * @prefix: the element namespace prefix
2699 * Search the DTD for the description of this element
2701 * returns the xmlElementPtr if found or NULL
2705 xmlGetDtdQElementDesc(xmlDtdPtr dtd
, const xmlChar
*name
,
2706 const xmlChar
*prefix
) {
2707 xmlElementTablePtr table
;
2709 if (dtd
== NULL
) return(NULL
);
2710 if (dtd
->elements
== NULL
) return(NULL
);
2711 table
= (xmlElementTablePtr
) dtd
->elements
;
2713 return(xmlHashLookup2(table
, name
, prefix
));
2717 * xmlGetDtdAttrDesc:
2718 * @dtd: a pointer to the DtD to search
2719 * @elem: the element name
2720 * @name: the attribute name
2722 * Search the DTD for the description of this attribute on
2725 * returns the xmlAttributePtr if found or NULL
2729 xmlGetDtdAttrDesc(xmlDtdPtr dtd
, const xmlChar
*elem
, const xmlChar
*name
) {
2730 xmlAttributeTablePtr table
;
2731 xmlAttributePtr cur
;
2732 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
2734 if (dtd
== NULL
) return(NULL
);
2735 if (dtd
->attributes
== NULL
) return(NULL
);
2737 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
2741 uqname
= xmlSplitQName2(name
, &prefix
);
2743 if (uqname
!= NULL
) {
2744 cur
= xmlHashLookup3(table
, uqname
, prefix
, elem
);
2745 if (prefix
!= NULL
) xmlFree(prefix
);
2746 if (uqname
!= NULL
) xmlFree(uqname
);
2748 cur
= xmlHashLookup3(table
, name
, NULL
, elem
);
2753 * xmlGetDtdQAttrDesc:
2754 * @dtd: a pointer to the DtD to search
2755 * @elem: the element name
2756 * @name: the attribute name
2757 * @prefix: the attribute namespace prefix
2759 * Search the DTD for the description of this qualified attribute on
2762 * returns the xmlAttributePtr if found or NULL
2766 xmlGetDtdQAttrDesc(xmlDtdPtr dtd
, const xmlChar
*elem
, const xmlChar
*name
,
2767 const xmlChar
*prefix
) {
2768 xmlAttributeTablePtr table
;
2770 if (dtd
== NULL
) return(NULL
);
2771 if (dtd
->attributes
== NULL
) return(NULL
);
2772 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
2774 return(xmlHashLookup3(table
, name
, prefix
, elem
));
2778 * xmlGetDtdNotationDesc:
2779 * @dtd: a pointer to the DtD to search
2780 * @name: the notation name
2782 * Search the DTD for the description of this notation
2784 * returns the xmlNotationPtr if found or NULL
2788 xmlGetDtdNotationDesc(xmlDtdPtr dtd
, const xmlChar
*name
) {
2789 xmlNotationTablePtr table
;
2791 if (dtd
== NULL
) return(NULL
);
2792 if (dtd
->notations
== NULL
) return(NULL
);
2793 table
= (xmlNotationTablePtr
) dtd
->notations
;
2795 return(xmlHashLookup(table
, name
));
2799 * xmlValidateNotationUse:
2800 * @ctxt: the validation context
2801 * @doc: the document
2802 * @notationName: the notation name to check
2804 * Validate that the given name match a notation declaration.
2805 * - [ VC: Notation Declared ]
2807 * returns 1 if valid or 0 otherwise
2811 xmlValidateNotationUse(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
2812 const xmlChar
*notationName
) {
2813 xmlNotationPtr notaDecl
;
2814 if ((doc
== NULL
) || (doc
->intSubset
== NULL
)) return(-1);
2816 notaDecl
= xmlGetDtdNotationDesc(doc
->intSubset
, notationName
);
2817 if ((notaDecl
== NULL
) && (doc
->extSubset
!= NULL
))
2818 notaDecl
= xmlGetDtdNotationDesc(doc
->extSubset
, notationName
);
2820 if (notaDecl
== NULL
) {
2821 VERROR(ctxt
->userData
, "NOTATION %s is not declared\n",
2830 * @doc: the document
2831 * @name: the element name
2833 * Search in the DtDs whether an element accept Mixed content (or ANY)
2834 * basically if it is supposed to accept text childs
2836 * returns 0 if no, 1 if yes, and -1 if no element description is available
2840 xmlIsMixedElement(xmlDocPtr doc
, const xmlChar
*name
) {
2841 xmlElementPtr elemDecl
;
2843 if ((doc
== NULL
) || (doc
->intSubset
== NULL
)) return(-1);
2845 elemDecl
= xmlGetDtdElementDesc(doc
->intSubset
, name
);
2846 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
))
2847 elemDecl
= xmlGetDtdElementDesc(doc
->extSubset
, name
);
2848 if (elemDecl
== NULL
) return(-1);
2849 switch (elemDecl
->etype
) {
2850 case XML_ELEMENT_TYPE_UNDEFINED
:
2852 case XML_ELEMENT_TYPE_ELEMENT
:
2854 case XML_ELEMENT_TYPE_EMPTY
:
2856 * return 1 for EMPTY since we want VC error to pop up
2857 * on <empty> </empty> for example
2859 case XML_ELEMENT_TYPE_ANY
:
2860 case XML_ELEMENT_TYPE_MIXED
:
2867 * xmlValidateNameValue:
2868 * @value: an Name value
2870 * Validate that the given value match Name production
2872 * returns 1 if valid or 0 otherwise
2876 xmlValidateNameValue(const xmlChar
*value
) {
2880 if (value
== NULL
) return(0);
2882 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2884 if (!IS_LETTER(val
) && (val
!= '_') &&
2889 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2891 while ((IS_LETTER(val
)) || (IS_DIGIT(val
)) ||
2892 (val
== '.') || (val
== '-') ||
2893 (val
== '_') || (val
== ':') ||
2894 (IS_COMBINING(val
)) ||
2895 (IS_EXTENDER(val
))) {
2896 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2900 if (val
!= 0) return(0);
2906 * xmlValidateNamesValue:
2907 * @value: an Names value
2909 * Validate that the given value match Names production
2911 * returns 1 if valid or 0 otherwise
2915 xmlValidateNamesValue(const xmlChar
*value
) {
2919 if (value
== NULL
) return(0);
2921 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2924 if (!IS_LETTER(val
) && (val
!= '_') &&
2929 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2931 while ((IS_LETTER(val
)) || (IS_DIGIT(val
)) ||
2932 (val
== '.') || (val
== '-') ||
2933 (val
== '_') || (val
== ':') ||
2934 (IS_COMBINING(val
)) ||
2935 (IS_EXTENDER(val
))) {
2936 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2940 while (IS_BLANK(val
)) {
2941 while (IS_BLANK(val
)) {
2942 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2946 if (!IS_LETTER(val
) && (val
!= '_') &&
2950 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2953 while ((IS_LETTER(val
)) || (IS_DIGIT(val
)) ||
2954 (val
== '.') || (val
== '-') ||
2955 (val
== '_') || (val
== ':') ||
2956 (IS_COMBINING(val
)) ||
2957 (IS_EXTENDER(val
))) {
2958 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2963 if (val
!= 0) return(0);
2969 * xmlValidateNmtokenValue:
2970 * @value: an Nmtoken value
2972 * Validate that the given value match Nmtoken production
2974 * [ VC: Name Token ]
2976 * returns 1 if valid or 0 otherwise
2980 xmlValidateNmtokenValue(const xmlChar
*value
) {
2984 if (value
== NULL
) return(0);
2986 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
2989 if (!IS_LETTER(val
) && !IS_DIGIT(val
) &&
2990 (val
!= '.') && (val
!= '-') &&
2991 (val
!= '_') && (val
!= ':') &&
2992 (!IS_COMBINING(val
)) &&
2993 (!IS_EXTENDER(val
)))
2996 while ((IS_LETTER(val
)) || (IS_DIGIT(val
)) ||
2997 (val
== '.') || (val
== '-') ||
2998 (val
== '_') || (val
== ':') ||
2999 (IS_COMBINING(val
)) ||
3000 (IS_EXTENDER(val
))) {
3001 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3005 if (val
!= 0) return(0);
3011 * xmlValidateNmtokensValue:
3012 * @value: an Nmtokens value
3014 * Validate that the given value match Nmtokens production
3016 * [ VC: Name Token ]
3018 * returns 1 if valid or 0 otherwise
3022 xmlValidateNmtokensValue(const xmlChar
*value
) {
3026 if (value
== NULL
) return(0);
3028 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3031 while (IS_BLANK(val
)) {
3032 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3036 if (!IS_LETTER(val
) && !IS_DIGIT(val
) &&
3037 (val
!= '.') && (val
!= '-') &&
3038 (val
!= '_') && (val
!= ':') &&
3039 (!IS_COMBINING(val
)) &&
3040 (!IS_EXTENDER(val
)))
3043 while ((IS_LETTER(val
)) || (IS_DIGIT(val
)) ||
3044 (val
== '.') || (val
== '-') ||
3045 (val
== '_') || (val
== ':') ||
3046 (IS_COMBINING(val
)) ||
3047 (IS_EXTENDER(val
))) {
3048 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3052 while (IS_BLANK(val
)) {
3053 while (IS_BLANK(val
)) {
3054 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3057 if (val
== 0) return(1);
3059 if (!IS_LETTER(val
) && !IS_DIGIT(val
) &&
3060 (val
!= '.') && (val
!= '-') &&
3061 (val
!= '_') && (val
!= ':') &&
3062 (!IS_COMBINING(val
)) &&
3063 (!IS_EXTENDER(val
)))
3066 while ((IS_LETTER(val
)) || (IS_DIGIT(val
)) ||
3067 (val
== '.') || (val
== '-') ||
3068 (val
== '_') || (val
== ':') ||
3069 (IS_COMBINING(val
)) ||
3070 (IS_EXTENDER(val
))) {
3071 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3076 if (val
!= 0) return(0);
3082 * xmlValidateNotationDecl:
3083 * @ctxt: the validation context
3084 * @doc: a document instance
3085 * @nota: a notation definition
3087 * Try to validate a single notation definition
3088 * basically it does the following checks as described by the
3089 * XML-1.0 recommendation:
3090 * - it seems that no validity constraint exists on notation declarations
3091 * But this function get called anyway ...
3093 * returns 1 if valid or 0 otherwise
3097 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED
, xmlDocPtr doc ATTRIBUTE_UNUSED
,
3098 xmlNotationPtr nota ATTRIBUTE_UNUSED
) {
3105 * xmlValidateAttributeValue:
3106 * @type: an attribute type
3107 * @value: an attribute value
3109 * Validate that the given attribute value match the proper production
3112 * Values of type ID must match the Name production....
3115 * Values of type IDREF must match the Name production, and values
3116 * of type IDREFS must match Names ...
3118 * [ VC: Entity Name ]
3119 * Values of type ENTITY must match the Name production, values
3120 * of type ENTITIES must match Names ...
3122 * [ VC: Name Token ]
3123 * Values of type NMTOKEN must match the Nmtoken production; values
3124 * of type NMTOKENS must match Nmtokens.
3126 * returns 1 if valid or 0 otherwise
3130 xmlValidateAttributeValue(xmlAttributeType type
, const xmlChar
*value
) {
3132 case XML_ATTRIBUTE_ENTITIES
:
3133 case XML_ATTRIBUTE_IDREFS
:
3134 return(xmlValidateNamesValue(value
));
3135 case XML_ATTRIBUTE_ENTITY
:
3136 case XML_ATTRIBUTE_IDREF
:
3137 case XML_ATTRIBUTE_ID
:
3138 case XML_ATTRIBUTE_NOTATION
:
3139 return(xmlValidateNameValue(value
));
3140 case XML_ATTRIBUTE_NMTOKENS
:
3141 case XML_ATTRIBUTE_ENUMERATION
:
3142 return(xmlValidateNmtokensValue(value
));
3143 case XML_ATTRIBUTE_NMTOKEN
:
3144 return(xmlValidateNmtokenValue(value
));
3145 case XML_ATTRIBUTE_CDATA
:
3152 * xmlValidateAttributeValue2:
3153 * @ctxt: the validation context
3154 * @doc: the document
3155 * @name: the attribute name (used for error reporting only)
3156 * @type: the attribute type
3157 * @value: the attribute value
3159 * Validate that the given attribute value match a given type.
3160 * This typically cannot be done before having finished parsing
3164 * Values of type IDREF must match one of the declared IDs
3165 * Values of type IDREFS must match a sequence of the declared IDs
3166 * each Name must match the value of an ID attribute on some element
3167 * in the XML document; i.e. IDREF values must match the value of
3170 * [ VC: Entity Name ]
3171 * Values of type ENTITY must match one declared entity
3172 * Values of type ENTITIES must match a sequence of declared entities
3174 * [ VC: Notation Attributes ]
3175 * all notation names in the declaration must be declared.
3177 * returns 1 if valid or 0 otherwise
3181 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3182 const xmlChar
*name
, xmlAttributeType type
, const xmlChar
*value
) {
3185 case XML_ATTRIBUTE_IDREFS
:
3186 case XML_ATTRIBUTE_IDREF
:
3187 case XML_ATTRIBUTE_ID
:
3188 case XML_ATTRIBUTE_NMTOKENS
:
3189 case XML_ATTRIBUTE_ENUMERATION
:
3190 case XML_ATTRIBUTE_NMTOKEN
:
3191 case XML_ATTRIBUTE_CDATA
:
3193 case XML_ATTRIBUTE_ENTITY
: {
3196 ent
= xmlGetDocEntity(doc
, value
);
3197 if ((ent
== NULL
) && (doc
->standalone
== 1)) {
3198 doc
->standalone
= 0;
3199 ent
= xmlGetDocEntity(doc
, value
);
3201 VERROR(ctxt
->userData
,
3202 "standalone problem: attribute %s reference entity \"%s\" in external subset\n",
3204 /* WAIT to get answer from the Core WG on this
3210 VERROR(ctxt
->userData
,
3211 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3214 } else if (ent
->etype
!= XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
3215 VERROR(ctxt
->userData
,
3216 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3222 case XML_ATTRIBUTE_ENTITIES
: {
3223 xmlChar
*dup
, *nam
= NULL
, *cur
, save
;
3226 dup
= xmlStrdup(value
);
3232 while ((*cur
!= 0) && (!IS_BLANK(*cur
))) cur
++;
3235 ent
= xmlGetDocEntity(doc
, nam
);
3237 VERROR(ctxt
->userData
,
3238 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3241 } else if (ent
->etype
!= XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
3242 VERROR(ctxt
->userData
,
3243 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3250 while (IS_BLANK(*cur
)) cur
++;
3255 case XML_ATTRIBUTE_NOTATION
: {
3256 xmlNotationPtr nota
;
3258 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
3259 if ((nota
== NULL
) && (doc
->extSubset
!= NULL
))
3260 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
3263 VERROR(ctxt
->userData
,
3264 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3275 * xmlValidCtxtNormalizeAttributeValue:
3276 * @ctxt: the validation context
3277 * @doc: the document
3279 * @name: the attribute name
3280 * @value: the attribute value
3281 * @ctxt: the validation context or NULL
3283 * Does the validation related extra step of the normalization of attribute
3286 * If the declared value is not CDATA, then the XML processor must further
3287 * process the normalized attribute value by discarding any leading and
3288 * trailing space (#x20) characters, and by replacing sequences of space
3289 * (#x20) characters by single space (#x20) character.
3291 * Also check VC: Standalone Document Declaration in P32, and update
3292 * ctxt->valid accordingly
3294 * returns a new normalized string if normalization is needed, NULL otherwise
3295 * the caller must free the returned value.
3299 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3300 xmlNodePtr elem
, const xmlChar
*name
, const xmlChar
*value
) {
3303 xmlAttributePtr attrDecl
= NULL
;
3306 if (doc
== NULL
) return(NULL
);
3307 if (elem
== NULL
) return(NULL
);
3308 if (name
== NULL
) return(NULL
);
3309 if (value
== NULL
) return(NULL
);
3311 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
3313 snprintf((char *) qname
, sizeof(qname
), "%s:%s",
3314 elem
->ns
->prefix
, elem
->name
);
3315 qname
[sizeof(qname
) - 1] = 0;
3316 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, qname
, name
);
3317 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
3318 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, qname
, name
);
3319 if (attrDecl
!= NULL
)
3323 if ((attrDecl
== NULL
) && (doc
->intSubset
!= NULL
))
3324 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, name
);
3325 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
3326 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, elem
->name
, name
);
3327 if (attrDecl
!= NULL
)
3331 if (attrDecl
== NULL
)
3333 if (attrDecl
->atype
== XML_ATTRIBUTE_CDATA
)
3336 ret
= xmlStrdup(value
);
3341 while (*src
== 0x20) src
++;
3344 while (*src
== 0x20) src
++;
3352 if ((doc
->standalone
) && (extsubset
== 1) && (!xmlStrEqual(value
, ret
))) {
3353 VERROR(ctxt
->userData
,
3354 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
3362 * xmlValidNormalizeAttributeValue:
3363 * @doc: the document
3365 * @name: the attribute name
3366 * @value: the attribute value
3367 * @ctxt: the validation context or NULL
3369 * Does the validation related extra step of the normalization of attribute
3372 * If the declared value is not CDATA, then the XML processor must further
3373 * process the normalized attribute value by discarding any leading and
3374 * trailing space (#x20) characters, and by replacing sequences of space
3375 * (#x20) characters by single space (#x20) character.
3377 * returns a new normalized string if normalization is needed, NULL otherwise
3378 * the caller must free the returned value.
3382 xmlValidNormalizeAttributeValue(xmlDocPtr doc
, xmlNodePtr elem
,
3383 const xmlChar
*name
, const xmlChar
*value
) {
3386 xmlAttributePtr attrDecl
= NULL
;
3388 if (doc
== NULL
) return(NULL
);
3389 if (elem
== NULL
) return(NULL
);
3390 if (name
== NULL
) return(NULL
);
3391 if (value
== NULL
) return(NULL
);
3393 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
3395 snprintf((char *) qname
, sizeof(qname
), "%s:%s",
3396 elem
->ns
->prefix
, elem
->name
);
3397 qname
[sizeof(qname
) - 1] = 0;
3398 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, qname
, name
);
3399 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3400 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, qname
, name
);
3402 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, name
);
3403 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3404 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, elem
->name
, name
);
3406 if (attrDecl
== NULL
)
3408 if (attrDecl
->atype
== XML_ATTRIBUTE_CDATA
)
3411 ret
= xmlStrdup(value
);
3416 while (*src
== 0x20) src
++;
3419 while (*src
== 0x20) src
++;
3431 xmlValidateAttributeIdCallback(xmlAttributePtr attr
, int *count
,
3432 const xmlChar
* name ATTRIBUTE_UNUSED
) {
3433 if (attr
->atype
== XML_ATTRIBUTE_ID
) (*count
)++;
3437 * xmlValidateAttributeDecl:
3438 * @ctxt: the validation context
3439 * @doc: a document instance
3440 * @attr: an attribute definition
3442 * Try to validate a single attribute definition
3443 * basically it does the following checks as described by the
3444 * XML-1.0 recommendation:
3445 * - [ VC: Attribute Default Legal ]
3446 * - [ VC: Enumeration ]
3447 * - [ VC: ID Attribute Default ]
3449 * The ID/IDREF uniqueness and matching are done separately
3451 * returns 1 if valid or 0 otherwise
3455 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3456 xmlAttributePtr attr
) {
3460 if(attr
== NULL
) return(1);
3462 /* Attribute Default Legal */
3464 if (attr
->defaultValue
!= NULL
) {
3465 val
= xmlValidateAttributeValue(attr
->atype
, attr
->defaultValue
);
3467 VERROR(ctxt
->userData
,
3468 "Syntax of default value for attribute %s of %s is not valid\n",
3469 attr
->name
, attr
->elem
);
3474 /* ID Attribute Default */
3475 if ((attr
->atype
== XML_ATTRIBUTE_ID
)&&
3476 (attr
->def
!= XML_ATTRIBUTE_IMPLIED
) &&
3477 (attr
->def
!= XML_ATTRIBUTE_REQUIRED
)) {
3478 VERROR(ctxt
->userData
,
3479 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
3480 attr
->name
, attr
->elem
);
3484 /* One ID per Element Type */
3485 if (attr
->atype
== XML_ATTRIBUTE_ID
) {
3488 /* the trick is that we parse DtD as their own internal subset */
3489 xmlElementPtr elem
= xmlGetDtdElementDesc(doc
->intSubset
,
3492 nbId
= xmlScanIDAttributeDecl(NULL
, elem
);
3494 xmlAttributeTablePtr table
;
3497 * The attribute may be declared in the internal subset and the
3498 * element in the external subset.
3501 table
= (xmlAttributeTablePtr
) doc
->intSubset
->attributes
;
3502 xmlHashScan3(table
, NULL
, NULL
, attr
->elem
, (xmlHashScanner
)
3503 xmlValidateAttributeIdCallback
, &nbId
);
3506 VERROR(ctxt
->userData
,
3507 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3508 attr
->elem
, nbId
, attr
->name
);
3509 } else if (doc
->extSubset
!= NULL
) {
3511 elem
= xmlGetDtdElementDesc(doc
->extSubset
, attr
->elem
);
3513 extId
= xmlScanIDAttributeDecl(NULL
, elem
);
3516 VERROR(ctxt
->userData
,
3517 "Element %s has %d ID attribute defined in the external subset : %s\n",
3518 attr
->elem
, extId
, attr
->name
);
3519 } else if (extId
+ nbId
> 1) {
3520 VERROR(ctxt
->userData
,
3521 "Element %s has ID attributes defined in the internal and external subset : %s\n",
3522 attr
->elem
, attr
->name
);
3527 /* Validity Constraint: Enumeration */
3528 if ((attr
->defaultValue
!= NULL
) && (attr
->tree
!= NULL
)) {
3529 xmlEnumerationPtr tree
= attr
->tree
;
3530 while (tree
!= NULL
) {
3531 if (xmlStrEqual(tree
->name
, attr
->defaultValue
)) break;
3535 VERROR(ctxt
->userData
,
3536 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
3537 attr
->defaultValue
, attr
->name
, attr
->elem
);
3546 * xmlValidateElementDecl:
3547 * @ctxt: the validation context
3548 * @doc: a document instance
3549 * @elem: an element definition
3551 * Try to validate a single element definition
3552 * basically it does the following checks as described by the
3553 * XML-1.0 recommendation:
3554 * - [ VC: One ID per Element Type ]
3555 * - [ VC: No Duplicate Types ]
3556 * - [ VC: Unique Element Type Declaration ]
3558 * returns 1 if valid or 0 otherwise
3562 xmlValidateElementDecl(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3563 xmlElementPtr elem
) {
3569 if (elem
== NULL
) return(1);
3572 #ifdef LIBXML_REGEXP_ENABLED
3573 /* Build the regexp associated to the content model */
3574 ret
= xmlValidBuildContentModel(ctxt
, elem
);
3578 /* No Duplicate Types */
3579 if (elem
->etype
== XML_ELEMENT_TYPE_MIXED
) {
3580 xmlElementContentPtr cur
, next
;
3581 const xmlChar
*name
;
3583 cur
= elem
->content
;
3584 while (cur
!= NULL
) {
3585 if (cur
->type
!= XML_ELEMENT_CONTENT_OR
) break;
3586 if (cur
->c1
== NULL
) break;
3587 if (cur
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
3588 name
= cur
->c1
->name
;
3590 while (next
!= NULL
) {
3591 if (next
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
3592 if (xmlStrEqual(next
->name
, name
)) {
3593 VERROR(ctxt
->userData
,
3594 "Definition of %s has duplicate references of %s\n",
3600 if (next
->c1
== NULL
) break;
3601 if (next
->c1
->type
!= XML_ELEMENT_CONTENT_ELEMENT
) break;
3602 if (xmlStrEqual(next
->c1
->name
, name
)) {
3603 VERROR(ctxt
->userData
,
3604 "Definition of %s has duplicate references of %s\n",
3615 /* VC: Unique Element Type Declaration */
3616 tst
= xmlGetDtdElementDesc(doc
->intSubset
, elem
->name
);
3617 if ((tst
!= NULL
) && (tst
!= elem
) &&
3618 ((tst
->prefix
== elem
->prefix
) ||
3619 (xmlStrEqual(tst
->prefix
, elem
->prefix
))) &&
3620 (tst
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
)) {
3621 VERROR(ctxt
->userData
, "Redefinition of element %s\n",
3625 tst
= xmlGetDtdElementDesc(doc
->extSubset
, elem
->name
);
3626 if ((tst
!= NULL
) && (tst
!= elem
) &&
3627 ((tst
->prefix
== elem
->prefix
) ||
3628 (xmlStrEqual(tst
->prefix
, elem
->prefix
))) &&
3629 (tst
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
)) {
3630 VERROR(ctxt
->userData
, "Redefinition of element %s\n",
3634 /* One ID per Element Type
3635 * already done when registering the attribute
3636 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3643 * xmlValidateOneAttribute:
3644 * @ctxt: the validation context
3645 * @doc: a document instance
3646 * @elem: an element instance
3647 * @attr: an attribute instance
3648 * @value: the attribute value (without entities processing)
3650 * Try to validate a single attribute for an element
3651 * basically it does the following checks as described by the
3652 * XML-1.0 recommendation:
3653 * - [ VC: Attribute Value Type ]
3654 * - [ VC: Fixed Attribute Default ]
3655 * - [ VC: Entity Name ]
3656 * - [ VC: Name Token ]
3659 * - [ VC: Entity Name ]
3660 * - [ VC: Notation Attributes ]
3662 * The ID/IDREF uniqueness and matching are done separately
3664 * returns 1 if valid or 0 otherwise
3668 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3669 xmlNodePtr elem
, xmlAttrPtr attr
, const xmlChar
*value
) {
3670 /* xmlElementPtr elemDecl; */
3671 xmlAttributePtr attrDecl
= NULL
;
3676 if ((elem
== NULL
) || (elem
->name
== NULL
)) return(0);
3677 if ((attr
== NULL
) || (attr
->name
== NULL
)) return(0);
3679 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
3681 snprintf((char *) qname
, sizeof(qname
), "%s:%s",
3682 elem
->ns
->prefix
, elem
->name
);
3683 qname
[sizeof(qname
) - 1] = 0;
3684 if (attr
->ns
!= NULL
) {
3685 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, qname
,
3686 attr
->name
, attr
->ns
->prefix
);
3687 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3688 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, qname
,
3689 attr
->name
, attr
->ns
->prefix
);
3691 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, qname
, attr
->name
);
3692 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3693 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
3697 if (attrDecl
== NULL
) {
3698 if (attr
->ns
!= NULL
) {
3699 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, elem
->name
,
3700 attr
->name
, attr
->ns
->prefix
);
3701 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3702 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, elem
->name
,
3703 attr
->name
, attr
->ns
->prefix
);
3705 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
,
3706 elem
->name
, attr
->name
);
3707 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3708 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
3709 elem
->name
, attr
->name
);
3714 /* Validity Constraint: Attribute Value Type */
3715 if (attrDecl
== NULL
) {
3717 VERROR(ctxt
->userData
,
3718 "No declaration for attribute %s of element %s\n",
3719 attr
->name
, elem
->name
);
3722 attr
->atype
= attrDecl
->atype
;
3724 val
= xmlValidateAttributeValue(attrDecl
->atype
, value
);
3727 VERROR(ctxt
->userData
,
3728 "Syntax of value for attribute %s of %s is not valid\n",
3729 attr
->name
, elem
->name
);
3733 /* Validity constraint: Fixed Attribute Default */
3734 if (attrDecl
->def
== XML_ATTRIBUTE_FIXED
) {
3735 if (!xmlStrEqual(value
, attrDecl
->defaultValue
)) {
3737 VERROR(ctxt
->userData
,
3738 "Value for attribute %s of %s is different from default \"%s\"\n",
3739 attr
->name
, elem
->name
, attrDecl
->defaultValue
);
3744 /* Validity Constraint: ID uniqueness */
3745 if (attrDecl
->atype
== XML_ATTRIBUTE_ID
) {
3746 if (xmlAddID(ctxt
, doc
, value
, attr
) == NULL
)
3750 if ((attrDecl
->atype
== XML_ATTRIBUTE_IDREF
) ||
3751 (attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
)) {
3752 if (xmlAddRef(ctxt
, doc
, value
, attr
) == NULL
)
3756 /* Validity Constraint: Notation Attributes */
3757 if (attrDecl
->atype
== XML_ATTRIBUTE_NOTATION
) {
3758 xmlEnumerationPtr tree
= attrDecl
->tree
;
3759 xmlNotationPtr nota
;
3761 /* First check that the given NOTATION was declared */
3762 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
3764 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
3768 VERROR(ctxt
->userData
,
3769 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
3770 value
, attr
->name
, elem
->name
);
3774 /* Second, verify that it's among the list */
3775 while (tree
!= NULL
) {
3776 if (xmlStrEqual(tree
->name
, value
)) break;
3781 VERROR(ctxt
->userData
,
3782 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
3783 value
, attr
->name
, elem
->name
);
3788 /* Validity Constraint: Enumeration */
3789 if (attrDecl
->atype
== XML_ATTRIBUTE_ENUMERATION
) {
3790 xmlEnumerationPtr tree
= attrDecl
->tree
;
3791 while (tree
!= NULL
) {
3792 if (xmlStrEqual(tree
->name
, value
)) break;
3797 VERROR(ctxt
->userData
,
3798 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
3799 value
, attr
->name
, elem
->name
);
3804 /* Fixed Attribute Default */
3805 if ((attrDecl
->def
== XML_ATTRIBUTE_FIXED
) &&
3806 (!xmlStrEqual(attrDecl
->defaultValue
, value
))) {
3808 VERROR(ctxt
->userData
,
3809 "Value for attribute %s of %s must be \"%s\"\n",
3810 attr
->name
, elem
->name
, attrDecl
->defaultValue
);
3814 /* Extra check for the attribute value */
3815 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, attr
->name
,
3816 attrDecl
->atype
, value
);
3822 * xmlValidateOneNamespace:
3823 * @ctxt: the validation context
3824 * @doc: a document instance
3825 * @elem: an element instance
3826 * @ns: an namespace declaration instance
3827 * @value: the attribute value (without entities processing)
3829 * Try to validate a single namespace declaration for an element
3830 * basically it does the following checks as described by the
3831 * XML-1.0 recommendation:
3832 * - [ VC: Attribute Value Type ]
3833 * - [ VC: Fixed Attribute Default ]
3834 * - [ VC: Entity Name ]
3835 * - [ VC: Name Token ]
3838 * - [ VC: Entity Name ]
3839 * - [ VC: Notation Attributes ]
3841 * The ID/IDREF uniqueness and matching are done separately
3843 * returns 1 if valid or 0 otherwise
3847 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3848 xmlNodePtr elem
, const xmlChar
*prefix
, xmlNsPtr ns
, const xmlChar
*value
) {
3849 /* xmlElementPtr elemDecl; */
3850 xmlAttributePtr attrDecl
= NULL
;
3855 if ((elem
== NULL
) || (elem
->name
== NULL
)) return(0);
3856 if ((ns
== NULL
) || (ns
->href
== NULL
)) return(0);
3858 if (prefix
!= NULL
) {
3860 snprintf((char *) qname
, sizeof(qname
), "%s:%s",
3861 prefix
, elem
->name
);
3862 qname
[sizeof(qname
) - 1] = 0;
3863 if (ns
->prefix
!= NULL
) {
3864 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, qname
,
3865 ns
->prefix
, BAD_CAST
"xmlns");
3866 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3867 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, qname
,
3868 ns
->prefix
, BAD_CAST
"xmlns");
3870 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, qname
,
3872 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3873 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, qname
,
3877 if (attrDecl
== NULL
) {
3878 if (ns
->prefix
!= NULL
) {
3879 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, elem
->name
,
3880 ns
->prefix
, BAD_CAST
"xmlns");
3881 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3882 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, elem
->name
,
3883 ns
->prefix
, BAD_CAST
"xmlns");
3885 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
,
3886 elem
->name
, BAD_CAST
"xmlns");
3887 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3888 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
3889 elem
->name
, BAD_CAST
"xmlns");
3894 /* Validity Constraint: Attribute Value Type */
3895 if (attrDecl
== NULL
) {
3897 if (ns
->prefix
!= NULL
) {
3898 VERROR(ctxt
->userData
,
3899 "No declaration for attribute xmlns:%s of element %s\n",
3900 ns
->prefix
, elem
->name
);
3902 VERROR(ctxt
->userData
,
3903 "No declaration for attribute xmlns of element %s\n",
3909 val
= xmlValidateAttributeValue(attrDecl
->atype
, value
);
3912 if (ns
->prefix
!= NULL
) {
3913 VERROR(ctxt
->userData
,
3914 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
3915 ns
->prefix
, elem
->name
);
3917 VERROR(ctxt
->userData
,
3918 "Syntax of value for attribute xmlns of %s is not valid\n",
3924 /* Validity constraint: Fixed Attribute Default */
3925 if (attrDecl
->def
== XML_ATTRIBUTE_FIXED
) {
3926 if (!xmlStrEqual(value
, attrDecl
->defaultValue
)) {
3928 if (ns
->prefix
!= NULL
) {
3929 VERROR(ctxt
->userData
,
3930 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
3931 ns
->prefix
, elem
->name
, attrDecl
->defaultValue
);
3933 VERROR(ctxt
->userData
,
3934 "Value for attribute xmlns of %s is different from default \"%s\"\n",
3935 elem
->name
, attrDecl
->defaultValue
);
3941 /* Validity Constraint: ID uniqueness */
3942 if (attrDecl
->atype
== XML_ATTRIBUTE_ID
) {
3943 if (xmlAddID(ctxt
, doc
, value
, (xmlAttrPtr
) ns
) == NULL
)
3947 if ((attrDecl
->atype
== XML_ATTRIBUTE_IDREF
) ||
3948 (attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
)) {
3949 if (xmlAddRef(ctxt
, doc
, value
, (xmlAttrPtr
) ns
) == NULL
)
3953 /* Validity Constraint: Notation Attributes */
3954 if (attrDecl
->atype
== XML_ATTRIBUTE_NOTATION
) {
3955 xmlEnumerationPtr tree
= attrDecl
->tree
;
3956 xmlNotationPtr nota
;
3958 /* First check that the given NOTATION was declared */
3959 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
3961 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
3965 if (ns
->prefix
!= NULL
) {
3966 VERROR(ctxt
->userData
,
3967 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
3968 value
, ns
->prefix
, elem
->name
);
3970 VERROR(ctxt
->userData
,
3971 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
3977 /* Second, verify that it's among the list */
3978 while (tree
!= NULL
) {
3979 if (xmlStrEqual(tree
->name
, value
)) break;
3984 if (ns
->prefix
!= NULL
) {
3985 VERROR(ctxt
->userData
,
3986 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
3987 value
, ns
->prefix
, elem
->name
);
3989 VERROR(ctxt
->userData
,
3990 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
3997 /* Validity Constraint: Enumeration */
3998 if (attrDecl
->atype
== XML_ATTRIBUTE_ENUMERATION
) {
3999 xmlEnumerationPtr tree
= attrDecl
->tree
;
4000 while (tree
!= NULL
) {
4001 if (xmlStrEqual(tree
->name
, value
)) break;
4006 if (ns
->prefix
!= NULL
) {
4007 VERROR(ctxt
->userData
,
4008 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4009 value
, ns
->prefix
, elem
->name
);
4011 VERROR(ctxt
->userData
,
4012 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4019 /* Fixed Attribute Default */
4020 if ((attrDecl
->def
== XML_ATTRIBUTE_FIXED
) &&
4021 (!xmlStrEqual(attrDecl
->defaultValue
, value
))) {
4023 if (ns
->prefix
!= NULL
) {
4024 VERROR(ctxt
->userData
,
4025 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4026 ns
->prefix
, elem
->name
, attrDecl
->defaultValue
);
4028 VERROR(ctxt
->userData
,
4029 "Value for attribute xmlns of %s must be \"%s\"\n",
4030 elem
->name
, attrDecl
->defaultValue
);
4035 /* Extra check for the attribute value */
4036 if (ns
->prefix
!= NULL
) {
4037 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, ns
->prefix
,
4038 attrDecl
->atype
, value
);
4040 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, BAD_CAST
"xmlns",
4041 attrDecl
->atype
, value
);
4047 #ifndef LIBXML_REGEXP_ENABLED
4049 * xmlValidateSkipIgnorable:
4050 * @ctxt: the validation context
4051 * @child: the child list
4053 * Skip ignorable elements w.r.t. the validation process
4055 * returns the first element to consider for validation of the content model
4059 xmlValidateSkipIgnorable(xmlNodePtr child
) {
4060 while (child
!= NULL
) {
4061 switch (child
->type
) {
4062 /* These things are ignored (skipped) during validation. */
4064 case XML_COMMENT_NODE
:
4065 case XML_XINCLUDE_START
:
4066 case XML_XINCLUDE_END
:
4067 child
= child
->next
;
4070 if (xmlIsBlankNode(child
))
4071 child
= child
->next
;
4075 /* keep current node */
4084 * xmlValidateElementType:
4085 * @ctxt: the validation context
4087 * Try to validate the content model of an element internal function
4089 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4090 * reference is found and -3 if the validation succeeded but
4091 * the content model is not determinist.
4095 xmlValidateElementType(xmlValidCtxtPtr ctxt
) {
4097 int determinist
= 1;
4099 NODE
= xmlValidateSkipIgnorable(NODE
);
4100 if ((NODE
== NULL
) && (CONT
== NULL
))
4102 if ((NODE
== NULL
) &&
4103 ((CONT
->ocur
== XML_ELEMENT_CONTENT_MULT
) ||
4104 (CONT
->ocur
== XML_ELEMENT_CONTENT_OPT
))) {
4107 if (CONT
== NULL
) return(-1);
4108 if ((NODE
!= NULL
) && (NODE
->type
== XML_ENTITY_REF_NODE
))
4112 * We arrive here when more states need to be examined
4117 * We just recovered from a rollback generated by a possible
4118 * epsilon transition, go directly to the analysis phase
4120 if (STATE
== ROLLBACK_PARENT
) {
4121 DEBUG_VALID_MSG("restored parent branch");
4122 DEBUG_VALID_STATE(NODE
, CONT
)
4127 DEBUG_VALID_STATE(NODE
, CONT
)
4129 * we may have to save a backup state here. This is the equivalent
4130 * of handling epsilon transition in NFAs.
4132 if ((CONT
!= NULL
) &&
4133 ((CONT
->parent
== NULL
) ||
4134 (CONT
->parent
->type
!= XML_ELEMENT_CONTENT_OR
)) &&
4135 ((CONT
->ocur
== XML_ELEMENT_CONTENT_MULT
) ||
4136 (CONT
->ocur
== XML_ELEMENT_CONTENT_OPT
) ||
4137 ((CONT
->ocur
== XML_ELEMENT_CONTENT_PLUS
) && (OCCURRENCE
)))) {
4138 DEBUG_VALID_MSG("saving parent branch");
4139 if (vstateVPush(ctxt
, CONT
, NODE
, DEPTH
, OCCURS
, ROLLBACK_PARENT
) < 0)
4145 * Check first if the content matches
4147 switch (CONT
->type
) {
4148 case XML_ELEMENT_CONTENT_PCDATA
:
4150 DEBUG_VALID_MSG("pcdata failed no node");
4154 if (NODE
->type
== XML_TEXT_NODE
) {
4155 DEBUG_VALID_MSG("pcdata found, skip to next");
4157 * go to next element in the content model
4158 * skipping ignorable elems
4162 NODE
= xmlValidateSkipIgnorable(NODE
);
4163 if ((NODE
!= NULL
) &&
4164 (NODE
->type
== XML_ENTITY_REF_NODE
))
4166 } while ((NODE
!= NULL
) &&
4167 ((NODE
->type
!= XML_ELEMENT_NODE
) &&
4168 (NODE
->type
!= XML_TEXT_NODE
) &&
4169 (NODE
->type
!= XML_CDATA_SECTION_NODE
)));
4173 DEBUG_VALID_MSG("pcdata failed");
4178 case XML_ELEMENT_CONTENT_ELEMENT
:
4180 DEBUG_VALID_MSG("element failed no node");
4184 ret
= ((NODE
->type
== XML_ELEMENT_NODE
) &&
4185 (xmlStrEqual(NODE
->name
, CONT
->name
)));
4187 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
4188 ret
= (CONT
->prefix
== NULL
);
4189 } else if (CONT
->prefix
== NULL
) {
4192 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->prefix
);
4196 DEBUG_VALID_MSG("element found, skip to next");
4198 * go to next element in the content model
4199 * skipping ignorable elems
4203 NODE
= xmlValidateSkipIgnorable(NODE
);
4204 if ((NODE
!= NULL
) &&
4205 (NODE
->type
== XML_ENTITY_REF_NODE
))
4207 } while ((NODE
!= NULL
) &&
4208 ((NODE
->type
!= XML_ELEMENT_NODE
) &&
4209 (NODE
->type
!= XML_TEXT_NODE
) &&
4210 (NODE
->type
!= XML_CDATA_SECTION_NODE
)));
4212 DEBUG_VALID_MSG("element failed");
4217 case XML_ELEMENT_CONTENT_OR
:
4219 * Small optimization.
4221 if (CONT
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
4222 if ((NODE
== NULL
) ||
4223 (!xmlStrEqual(NODE
->name
, CONT
->c1
->name
))) {
4228 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
4229 ret
= (CONT
->c1
->prefix
== NULL
);
4230 } else if (CONT
->c1
->prefix
== NULL
) {
4233 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->c1
->prefix
);
4243 * save the second branch 'or' branch
4245 DEBUG_VALID_MSG("saving 'or' branch");
4246 if (vstateVPush(ctxt
, CONT
->c2
, NODE
, (unsigned char)(DEPTH
+ 1),
4247 OCCURS
, ROLLBACK_OR
) < 0)
4252 case XML_ELEMENT_CONTENT_SEQ
:
4254 * Small optimization.
4256 if ((CONT
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) &&
4257 ((CONT
->c1
->ocur
== XML_ELEMENT_CONTENT_OPT
) ||
4258 (CONT
->c1
->ocur
== XML_ELEMENT_CONTENT_MULT
))) {
4259 if ((NODE
== NULL
) ||
4260 (!xmlStrEqual(NODE
->name
, CONT
->c1
->name
))) {
4265 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
4266 ret
= (CONT
->c1
->prefix
== NULL
);
4267 } else if (CONT
->c1
->prefix
== NULL
) {
4270 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->c1
->prefix
);
4284 * At this point handle going up in the tree
4287 DEBUG_VALID_MSG("error found returning");
4291 while (CONT
!= NULL
) {
4293 * First do the analysis depending on the occurrence model at
4297 switch (CONT
->ocur
) {
4300 case XML_ELEMENT_CONTENT_ONCE
:
4301 cur
= ctxt
->vstate
->node
;
4302 DEBUG_VALID_MSG("Once branch failed, rollback");
4303 if (vstateVPop(ctxt
) < 0 ) {
4304 DEBUG_VALID_MSG("exhaustion, failed");
4307 if (cur
!= ctxt
->vstate
->node
)
4310 case XML_ELEMENT_CONTENT_PLUS
:
4311 if (OCCURRENCE
== 0) {
4312 cur
= ctxt
->vstate
->node
;
4313 DEBUG_VALID_MSG("Plus branch failed, rollback");
4314 if (vstateVPop(ctxt
) < 0 ) {
4315 DEBUG_VALID_MSG("exhaustion, failed");
4318 if (cur
!= ctxt
->vstate
->node
)
4322 DEBUG_VALID_MSG("Plus branch found");
4325 case XML_ELEMENT_CONTENT_MULT
:
4326 #ifdef DEBUG_VALID_ALGO
4327 if (OCCURRENCE
== 0) {
4328 DEBUG_VALID_MSG("Mult branch failed");
4330 DEBUG_VALID_MSG("Mult branch found");
4335 case XML_ELEMENT_CONTENT_OPT
:
4336 DEBUG_VALID_MSG("Option branch failed");
4341 switch (CONT
->ocur
) {
4342 case XML_ELEMENT_CONTENT_OPT
:
4343 DEBUG_VALID_MSG("Option branch succeeded");
4346 case XML_ELEMENT_CONTENT_ONCE
:
4347 DEBUG_VALID_MSG("Once branch succeeded");
4350 case XML_ELEMENT_CONTENT_PLUS
:
4351 if (STATE
== ROLLBACK_PARENT
) {
4352 DEBUG_VALID_MSG("Plus branch rollback");
4357 DEBUG_VALID_MSG("Plus branch exhausted");
4361 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
4364 case XML_ELEMENT_CONTENT_MULT
:
4365 if (STATE
== ROLLBACK_PARENT
) {
4366 DEBUG_VALID_MSG("Mult branch rollback");
4371 DEBUG_VALID_MSG("Mult branch exhausted");
4375 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
4376 /* SET_OCCURRENCE; */
4383 * Then act accordingly at the parent level
4386 if (CONT
->parent
== NULL
)
4389 switch (CONT
->parent
->type
) {
4390 case XML_ELEMENT_CONTENT_PCDATA
:
4391 DEBUG_VALID_MSG("Error: parent pcdata");
4393 case XML_ELEMENT_CONTENT_ELEMENT
:
4394 DEBUG_VALID_MSG("Error: parent element");
4396 case XML_ELEMENT_CONTENT_OR
:
4398 DEBUG_VALID_MSG("Or succeeded");
4399 CONT
= CONT
->parent
;
4402 DEBUG_VALID_MSG("Or failed");
4403 CONT
= CONT
->parent
;
4407 case XML_ELEMENT_CONTENT_SEQ
:
4409 DEBUG_VALID_MSG("Sequence failed");
4410 CONT
= CONT
->parent
;
4412 } else if (CONT
== CONT
->parent
->c1
) {
4413 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4414 CONT
= CONT
->parent
->c2
;
4417 DEBUG_VALID_MSG("Sequence succeeded");
4418 CONT
= CONT
->parent
;
4426 cur
= ctxt
->vstate
->node
;
4427 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4428 if (vstateVPop(ctxt
) < 0 ) {
4429 DEBUG_VALID_MSG("exhaustion, failed");
4432 if (cur
!= ctxt
->vstate
->node
)
4439 cur
= ctxt
->vstate
->node
;
4440 DEBUG_VALID_MSG("Failure, rollback");
4441 if (vstateVPop(ctxt
) < 0 ) {
4442 DEBUG_VALID_MSG("exhaustion, failed");
4445 if (cur
!= ctxt
->vstate
->node
)
4449 return(determinist
);
4454 * xmlSnprintfElements:
4455 * @buf: an output buffer
4456 * @size: the size of the buffer
4457 * @content: An element
4458 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4460 * This will dump the list of elements to the buffer
4461 * Intended just for the debug routine
4464 xmlSnprintfElements(char *buf
, int size
, xmlNodePtr node
, int glob
) {
4468 if (node
== NULL
) return;
4469 if (glob
) strcat(buf
, "(");
4471 while (cur
!= NULL
) {
4473 if (size
- len
< 50) {
4474 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
4475 strcat(buf
, " ...");
4478 switch (cur
->type
) {
4479 case XML_ELEMENT_NODE
:
4480 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
4481 if (size
- len
< xmlStrlen(cur
->ns
->prefix
) + 10) {
4482 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
4483 strcat(buf
, " ...");
4486 strcat(buf
, (char *) cur
->ns
->prefix
);
4489 if (size
- len
< xmlStrlen(cur
->name
) + 10) {
4490 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
4491 strcat(buf
, " ...");
4494 strcat(buf
, (char *) cur
->name
);
4495 if (cur
->next
!= NULL
)
4499 if (xmlIsBlankNode(cur
))
4501 case XML_CDATA_SECTION_NODE
:
4502 case XML_ENTITY_REF_NODE
:
4503 strcat(buf
, "CDATA");
4504 if (cur
->next
!= NULL
)
4507 case XML_ATTRIBUTE_NODE
:
4508 case XML_DOCUMENT_NODE
:
4509 #ifdef LIBXML_DOCB_ENABLED
4510 case XML_DOCB_DOCUMENT_NODE
:
4512 case XML_HTML_DOCUMENT_NODE
:
4513 case XML_DOCUMENT_TYPE_NODE
:
4514 case XML_DOCUMENT_FRAG_NODE
:
4515 case XML_NOTATION_NODE
:
4516 case XML_NAMESPACE_DECL
:
4518 if (cur
->next
!= NULL
)
4521 case XML_ENTITY_NODE
:
4524 case XML_COMMENT_NODE
:
4525 case XML_ELEMENT_DECL
:
4526 case XML_ATTRIBUTE_DECL
:
4527 case XML_ENTITY_DECL
:
4528 case XML_XINCLUDE_START
:
4529 case XML_XINCLUDE_END
:
4534 if (glob
) strcat(buf
, ")");
4538 * xmlValidateElementContent:
4539 * @ctxt: the validation context
4540 * @child: the child list
4541 * @elemDecl: pointer to the element declaration
4542 * @warn: emit the error message
4543 * @parent: the parent element (for error reporting)
4545 * Try to validate the content model of an element
4547 * returns 1 if valid or 0 if not and -1 in case of error
4551 xmlValidateElementContent(xmlValidCtxtPtr ctxt
, xmlNodePtr child
,
4552 xmlElementPtr elemDecl
, int warn
, xmlNodePtr parent
) {
4554 #ifndef LIBXML_REGEXP_ENABLED
4555 xmlNodePtr repl
= NULL
, last
= NULL
, tmp
;
4558 xmlElementContentPtr cont
;
4559 const xmlChar
*name
;
4561 if (elemDecl
== NULL
)
4563 cont
= elemDecl
->content
;
4564 name
= elemDecl
->name
;
4566 #ifdef LIBXML_REGEXP_ENABLED
4567 /* Build the regexp associated to the content model */
4568 if (elemDecl
->contModel
== NULL
)
4569 ret
= xmlValidBuildContentModel(ctxt
, elemDecl
);
4570 if (elemDecl
->contModel
== NULL
) {
4573 xmlRegExecCtxtPtr exec
;
4577 ctxt
->nodeTab
= NULL
;
4578 exec
= xmlRegNewExecCtxt(elemDecl
->contModel
, NULL
, NULL
);
4581 while (cur
!= NULL
) {
4582 switch (cur
->type
) {
4583 case XML_ENTITY_REF_NODE
:
4585 * Push the current node to be able to roll back
4586 * and process within the entity
4588 if ((cur
->children
!= NULL
) &&
4589 (cur
->children
->children
!= NULL
)) {
4590 nodeVPush(ctxt
, cur
);
4591 cur
= cur
->children
->children
;
4596 if (xmlIsBlankNode(cur
))
4600 case XML_CDATA_SECTION_NODE
:
4604 case XML_ELEMENT_NODE
:
4605 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
4609 len
= xmlStrlen(cur
->name
) +
4610 xmlStrlen(cur
->ns
->prefix
) + 2;
4611 QName
= xmlMalloc(len
);
4612 if (QName
== NULL
) {
4616 snprintf((char *) QName
, len
, "%s:%s",
4617 (char *)cur
->ns
->prefix
,
4619 ret
= xmlRegExecPushString(exec
, QName
, NULL
);
4622 ret
= xmlRegExecPushString(exec
, cur
->name
, NULL
);
4629 * Switch to next element
4632 while (cur
== NULL
) {
4633 cur
= nodeVPop(ctxt
);
4639 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
4641 xmlRegFreeExecCtxt(exec
);
4644 #else /* LIBXML_REGEXP_ENABLED */
4646 * Allocate the stack
4648 ctxt
->vstateMax
= 8;
4649 ctxt
->vstateTab
= (xmlValidState
*) xmlMalloc(
4650 ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
4651 if (ctxt
->vstateTab
== NULL
) {
4652 xmlGenericError(xmlGenericErrorContext
,
4653 "malloc failed !n");
4657 * The first entry in the stack is reserved to the current state
4661 ctxt
->nodeTab
= NULL
;
4662 ctxt
->vstate
= &ctxt
->vstateTab
[0];
4669 ret
= xmlValidateElementType(ctxt
);
4670 if ((ret
== -3) && (warn
)) {
4671 VWARNING(ctxt
->userData
,
4672 "Content model for Element %s is ambiguous\n", name
);
4673 } else if (ret
== -2) {
4675 * An entities reference appeared at this level.
4676 * Buid a minimal representation of this node content
4677 * sufficient to run the validation process on it
4679 DEBUG_VALID_MSG("Found an entity reference, linearizing");
4681 while (cur
!= NULL
) {
4682 switch (cur
->type
) {
4683 case XML_ENTITY_REF_NODE
:
4685 * Push the current node to be able to roll back
4686 * and process within the entity
4688 if ((cur
->children
!= NULL
) &&
4689 (cur
->children
->children
!= NULL
)) {
4690 nodeVPush(ctxt
, cur
);
4691 cur
= cur
->children
->children
;
4696 if (xmlIsBlankNode(cur
))
4698 /* no break on purpose */
4699 case XML_CDATA_SECTION_NODE
:
4700 /* no break on purpose */
4701 case XML_ELEMENT_NODE
:
4703 * Allocate a new node and minimally fills in
4706 tmp
= (xmlNodePtr
) xmlMalloc(sizeof(xmlNode
));
4708 xmlGenericError(xmlGenericErrorContext
,
4709 "xmlValidateElementContent : malloc failed\n");
4710 xmlFreeNodeList(repl
);
4714 tmp
->type
= cur
->type
;
4715 tmp
->name
= cur
->name
;
4718 tmp
->content
= NULL
;
4725 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
4727 * E59 spaces in CDATA does not match the
4730 tmp
->content
= xmlStrdup(BAD_CAST
"CDATA");
4737 * Switch to next element
4740 while (cur
== NULL
) {
4741 cur
= nodeVPop(ctxt
);
4749 * Relaunch the validation
4751 ctxt
->vstate
= &ctxt
->vstateTab
[0];
4758 ret
= xmlValidateElementType(ctxt
);
4760 #endif /* LIBXML_REGEXP_ENABLED */
4761 if ((warn
) && ((ret
!= 1) && (ret
!= -3))) {
4762 if ((ctxt
!= NULL
) && (ctxt
->warning
!= NULL
)) {
4767 xmlSnprintfElementContent(expr
, 5000, cont
, 1);
4769 #ifndef LIBXML_REGEXP_ENABLED
4771 xmlSnprintfElements(list
, 5000, repl
, 1);
4773 #endif /* LIBXML_REGEXP_ENABLED */
4774 xmlSnprintfElements(list
, 5000, child
, 1);
4777 if (parent
!= NULL
) VECTXT(ctxt
, parent
);
4778 VERROR(ctxt
->userData
,
4779 "Element %s content does not follow the DTD\nExpecting %s, got %s\n",
4782 if (parent
!= NULL
) VECTXT(ctxt
, parent
);
4783 VERROR(ctxt
->userData
,
4784 "Element content does not follow the DTD\nExpecting %s, got %s\n",
4789 if (parent
!= NULL
) VECTXT(ctxt
, parent
);
4790 VERROR(ctxt
->userData
,
4791 "Element %s content does not follow the DTD\n",
4794 if (parent
!= NULL
) VECTXT(ctxt
, parent
);
4795 VERROR(ctxt
->userData
,
4796 "Element content does not follow the DTD\n");
4804 #ifndef LIBXML_REGEXP_ENABLED
4807 * Deallocate the copy if done, and free up the validation stack
4809 while (repl
!= NULL
) {
4814 ctxt
->vstateMax
= 0;
4815 if (ctxt
->vstateTab
!= NULL
) {
4816 xmlFree(ctxt
->vstateTab
);
4817 ctxt
->vstateTab
= NULL
;
4822 if (ctxt
->nodeTab
!= NULL
) {
4823 xmlFree(ctxt
->nodeTab
);
4824 ctxt
->nodeTab
= NULL
;
4831 * xmlValidateCdataElement:
4832 * @ctxt: the validation context
4833 * @doc: a document instance
4834 * @elem: an element instance
4836 * Check that an element follows #CDATA
4838 * returns 1 if valid or 0 otherwise
4841 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4844 xmlNodePtr cur
, child
;
4846 if ((ctxt
== NULL
) || (doc
== NULL
) || (elem
== NULL
))
4849 child
= elem
->children
;
4852 while (cur
!= NULL
) {
4853 switch (cur
->type
) {
4854 case XML_ENTITY_REF_NODE
:
4856 * Push the current node to be able to roll back
4857 * and process within the entity
4859 if ((cur
->children
!= NULL
) &&
4860 (cur
->children
->children
!= NULL
)) {
4861 nodeVPush(ctxt
, cur
);
4862 cur
= cur
->children
->children
;
4866 case XML_COMMENT_NODE
:
4869 case XML_CDATA_SECTION_NODE
:
4876 * Switch to next element
4879 while (cur
== NULL
) {
4880 cur
= nodeVPop(ctxt
);
4889 if (ctxt
->nodeTab
!= NULL
) {
4890 xmlFree(ctxt
->nodeTab
);
4891 ctxt
->nodeTab
= NULL
;
4897 * xmlValidateOneElement:
4898 * @ctxt: the validation context
4899 * @doc: a document instance
4900 * @elem: an element instance
4902 * Try to validate a single element and it's attributes,
4903 * basically it does the following checks as described by the
4904 * XML-1.0 recommendation:
4905 * - [ VC: Element Valid ]
4906 * - [ VC: Required Attribute ]
4907 * Then call xmlValidateOneAttribute() for each attribute present.
4909 * The ID/IDREF checkings are done separately
4911 * returns 1 if valid or 0 otherwise
4915 xmlValidateOneElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4917 xmlElementPtr elemDecl
= NULL
;
4918 xmlElementContentPtr cont
;
4919 xmlAttributePtr attr
;
4922 const xmlChar
*name
;
4923 const xmlChar
*prefix
= NULL
;
4928 if (elem
== NULL
) return(0);
4929 switch (elem
->type
) {
4930 case XML_ATTRIBUTE_NODE
:
4932 VERROR(ctxt
->userData
,
4933 "Attribute element not expected here\n");
4936 if (elem
->children
!= NULL
) {
4938 VERROR(ctxt
->userData
, "Text element has childs !\n");
4941 if (elem
->properties
!= NULL
) {
4943 VERROR(ctxt
->userData
, "Text element has attributes !\n");
4946 if (elem
->ns
!= NULL
) {
4948 VERROR(ctxt
->userData
, "Text element has namespace !\n");
4951 if (elem
->nsDef
!= NULL
) {
4953 VERROR(ctxt
->userData
,
4954 "Text element carries namespace definitions !\n");
4957 if (elem
->content
== NULL
) {
4959 VERROR(ctxt
->userData
,
4960 "Text element has no content !\n");
4964 case XML_XINCLUDE_START
:
4965 case XML_XINCLUDE_END
:
4967 case XML_CDATA_SECTION_NODE
:
4968 case XML_ENTITY_REF_NODE
:
4970 case XML_COMMENT_NODE
:
4972 case XML_ENTITY_NODE
:
4974 VERROR(ctxt
->userData
,
4975 "Entity element not expected here\n");
4977 case XML_NOTATION_NODE
:
4979 VERROR(ctxt
->userData
,
4980 "Notation element not expected here\n");
4982 case XML_DOCUMENT_NODE
:
4983 case XML_DOCUMENT_TYPE_NODE
:
4984 case XML_DOCUMENT_FRAG_NODE
:
4986 VERROR(ctxt
->userData
,
4987 "Document element not expected here\n");
4989 case XML_HTML_DOCUMENT_NODE
:
4991 VERROR(ctxt
->userData
,
4994 case XML_ELEMENT_NODE
:
4998 VERROR(ctxt
->userData
,
4999 "unknown element type %d\n", elem
->type
);
5002 if (elem
->name
== NULL
) return(0);
5005 * Fetch the declaration for the qualified name
5007 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
))
5008 prefix
= elem
->ns
->prefix
;
5010 if (prefix
!= NULL
) {
5011 elemDecl
= xmlGetDtdQElementDesc(doc
->intSubset
,
5012 elem
->name
, prefix
);
5013 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
5014 elemDecl
= xmlGetDtdQElementDesc(doc
->extSubset
,
5015 elem
->name
, prefix
);
5016 if (elemDecl
!= NULL
)
5022 * Fetch the declaration for the non qualified name
5023 * This is "non-strict" validation should be done on the
5024 * full QName but in that case being flexible makes sense.
5026 if (elemDecl
== NULL
) {
5027 elemDecl
= xmlGetDtdElementDesc(doc
->intSubset
, elem
->name
);
5028 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
5029 elemDecl
= xmlGetDtdElementDesc(doc
->extSubset
, elem
->name
);
5030 if (elemDecl
!= NULL
)
5034 if (elemDecl
== NULL
) {
5036 VERROR(ctxt
->userData
, "No declaration for element %s\n",
5041 /* Check that the element content matches the definition */
5042 switch (elemDecl
->etype
) {
5043 case XML_ELEMENT_TYPE_UNDEFINED
:
5045 VERROR(ctxt
->userData
, "No declaration for element %s\n",
5048 case XML_ELEMENT_TYPE_EMPTY
:
5049 if (elem
->children
!= NULL
) {
5051 VERROR(ctxt
->userData
,
5052 "Element %s was declared EMPTY this one has content\n",
5057 case XML_ELEMENT_TYPE_ANY
:
5058 /* I don't think anything is required then */
5060 case XML_ELEMENT_TYPE_MIXED
:
5062 /* simple case of declared as #PCDATA */
5063 if ((elemDecl
->content
!= NULL
) &&
5064 (elemDecl
->content
->type
== XML_ELEMENT_CONTENT_PCDATA
)) {
5065 ret
= xmlValidateOneCdataElement(ctxt
, doc
, elem
);
5068 VERROR(ctxt
->userData
,
5069 "Element %s was declared #PCDATA but contains non text nodes\n",
5074 child
= elem
->children
;
5075 /* Hum, this start to get messy */
5076 while (child
!= NULL
) {
5077 if (child
->type
== XML_ELEMENT_NODE
) {
5079 if ((child
->ns
!= NULL
) && (child
->ns
->prefix
!= NULL
)) {
5081 snprintf((char *) qname
, sizeof(qname
), "%s:%s",
5082 child
->ns
->prefix
, child
->name
);
5083 qname
[sizeof(qname
) - 1] = 0;
5084 cont
= elemDecl
->content
;
5085 while (cont
!= NULL
) {
5086 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
5087 if (xmlStrEqual(cont
->name
, qname
)) break;
5088 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
5089 (cont
->c1
!= NULL
) &&
5090 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)){
5091 if (xmlStrEqual(cont
->c1
->name
, qname
)) break;
5092 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
5093 (cont
->c1
== NULL
) ||
5094 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)){
5095 /* Internal error !!! */
5096 xmlGenericError(xmlGenericErrorContext
,
5097 "Internal: MIXED struct bad\n");
5105 cont
= elemDecl
->content
;
5106 while (cont
!= NULL
) {
5107 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
5108 if (xmlStrEqual(cont
->name
, name
)) break;
5109 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
5110 (cont
->c1
!= NULL
) &&
5111 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)) {
5112 if (xmlStrEqual(cont
->c1
->name
, name
)) break;
5113 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
5114 (cont
->c1
== NULL
) ||
5115 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)) {
5116 /* Internal error !!! */
5117 xmlGenericError(xmlGenericErrorContext
,
5118 "Internal: MIXED struct bad\n");
5125 VERROR(ctxt
->userData
,
5126 "Element %s is not declared in %s list of possible children\n",
5132 child
= child
->next
;
5135 case XML_ELEMENT_TYPE_ELEMENT
:
5136 if ((doc
->standalone
== 1) && (extsubset
== 1)) {
5138 * VC: Standalone Document Declaration
5139 * - element types with element content, if white space
5140 * occurs directly within any instance of those types.
5142 child
= elem
->children
;
5143 while (child
!= NULL
) {
5144 if (child
->type
== XML_TEXT_NODE
) {
5145 const xmlChar
*content
= child
->content
;
5147 while (IS_BLANK(*content
))
5149 if (*content
== 0) {
5151 VERROR(ctxt
->userData
,
5152 "standalone: %s declared in the external subset contains white spaces nodes\n",
5161 child
= elem
->children
;
5162 cont
= elemDecl
->content
;
5163 tmp
= xmlValidateElementContent(ctxt
, child
, elemDecl
, 1, elem
);
5169 /* [ VC: Required Attribute ] */
5170 attr
= elemDecl
->attributes
;
5171 while (attr
!= NULL
) {
5172 if (attr
->def
== XML_ATTRIBUTE_REQUIRED
) {
5175 if ((attr
->prefix
== NULL
) &&
5176 (xmlStrEqual(attr
->name
, BAD_CAST
"xmlns"))) {
5180 while (ns
!= NULL
) {
5181 if (ns
->prefix
== NULL
)
5185 } else if (xmlStrEqual(attr
->prefix
, BAD_CAST
"xmlns")) {
5189 while (ns
!= NULL
) {
5190 if (xmlStrEqual(attr
->name
, ns
->prefix
))
5197 attrib
= elem
->properties
;
5198 while (attrib
!= NULL
) {
5199 if (xmlStrEqual(attrib
->name
, attr
->name
)) {
5200 if (attr
->prefix
!= NULL
) {
5201 xmlNsPtr nameSpace
= attrib
->ns
;
5203 if (nameSpace
== NULL
)
5204 nameSpace
= elem
->ns
;
5206 * qualified names handling is problematic, having a
5207 * different prefix should be possible but DTDs don't
5208 * allow to define the URI instead of the prefix :-(
5210 if (nameSpace
== NULL
) {
5213 } else if (!xmlStrEqual(nameSpace
->prefix
,
5221 * We should allow applications to define namespaces
5222 * for their application even if the DTD doesn't
5223 * carry one, otherwise, basically we would always
5229 attrib
= attrib
->next
;
5232 if (qualified
== -1) {
5233 if (attr
->prefix
== NULL
) {
5235 VERROR(ctxt
->userData
,
5236 "Element %s does not carry attribute %s\n",
5237 elem
->name
, attr
->name
);
5241 VERROR(ctxt
->userData
,
5242 "Element %s does not carry attribute %s:%s\n",
5243 elem
->name
, attr
->prefix
,attr
->name
);
5246 } else if (qualified
== 0) {
5247 VWARNING(ctxt
->userData
,
5248 "Element %s required attribute %s:%s has no prefix\n",
5249 elem
->name
, attr
->prefix
,attr
->name
);
5250 } else if (qualified
== 1) {
5251 VWARNING(ctxt
->userData
,
5252 "Element %s required attribute %s:%s has different prefix\n",
5253 elem
->name
, attr
->prefix
,attr
->name
);
5255 } else if (attr
->def
== XML_ATTRIBUTE_FIXED
) {
5257 * Special tests checking #FIXED namespace declarations
5258 * have the right value since this is not done as an
5259 * attribute checking
5261 if ((attr
->prefix
== NULL
) &&
5262 (xmlStrEqual(attr
->name
, BAD_CAST
"xmlns"))) {
5266 while (ns
!= NULL
) {
5267 if (ns
->prefix
== NULL
) {
5268 if (!xmlStrEqual(attr
->defaultValue
, ns
->href
)) {
5270 VERROR(ctxt
->userData
,
5271 "Element %s namespace name for default namespace does not match the DTD\n",
5279 } else if (xmlStrEqual(attr
->prefix
, BAD_CAST
"xmlns")) {
5283 while (ns
!= NULL
) {
5284 if (xmlStrEqual(attr
->name
, ns
->prefix
)) {
5285 if (!xmlStrEqual(attr
->defaultValue
, ns
->href
)) {
5287 VERROR(ctxt
->userData
,
5288 "Element %s namespace name for %s does not match the DTD\n",
5289 elem
->name
, ns
->prefix
);
5306 * @ctxt: the validation context
5307 * @doc: a document instance
5309 * Try to validate a the root element
5310 * basically it does the following check as described by the
5311 * XML-1.0 recommendation:
5312 * - [ VC: Root Element Type ]
5313 * it doesn't try to recurse or apply other check to the element
5315 * returns 1 if valid or 0 otherwise
5319 xmlValidateRoot(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
5321 if (doc
== NULL
) return(0);
5323 root
= xmlDocGetRootElement(doc
);
5324 if ((root
== NULL
) || (root
->name
== NULL
)) {
5325 VERROR(ctxt
->userData
, "Not valid: no root element\n");
5330 * When doing post validation against a separate DTD, those may
5331 * no internal subset has been generated
5333 if ((doc
->intSubset
!= NULL
) &&
5334 (doc
->intSubset
->name
!= NULL
)) {
5336 * Check first the document root against the NQName
5338 if (!xmlStrEqual(doc
->intSubset
->name
, root
->name
)) {
5339 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
)) {
5341 snprintf((char *) qname
, sizeof(qname
), "%s:%s",
5342 root
->ns
->prefix
, root
->name
);
5343 qname
[sizeof(qname
) - 1] = 0;
5344 if (xmlStrEqual(doc
->intSubset
->name
, qname
))
5347 if ((xmlStrEqual(doc
->intSubset
->name
, BAD_CAST
"HTML")) &&
5348 (xmlStrEqual(root
->name
, BAD_CAST
"html")))
5351 VERROR(ctxt
->userData
,
5352 "Not valid: root and DTD name do not match '%s' and '%s'\n",
5353 root
->name
, doc
->intSubset
->name
);
5364 * xmlValidateElement:
5365 * @ctxt: the validation context
5366 * @doc: a document instance
5367 * @elem: an element instance
5369 * Try to validate the subtree under an element
5371 * returns 1 if valid or 0 otherwise
5375 xmlValidateElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, xmlNodePtr elem
) {
5381 if (elem
== NULL
) return(0);
5384 * XInclude elements were added after parsing in the infoset,
5385 * they don't really mean anything validation wise.
5387 if ((elem
->type
== XML_XINCLUDE_START
) ||
5388 (elem
->type
== XML_XINCLUDE_END
))
5394 * Entities references have to be handled separately
5396 if (elem
->type
== XML_ENTITY_REF_NODE
) {
5400 ret
&= xmlValidateOneElement(ctxt
, doc
, elem
);
5401 attr
= elem
->properties
;
5402 while(attr
!= NULL
) {
5403 value
= xmlNodeListGetString(doc
, attr
->children
, 0);
5404 ret
&= xmlValidateOneAttribute(ctxt
, doc
, elem
, attr
, value
);
5409 child
= elem
->children
;
5410 while (child
!= NULL
) {
5411 ret
&= xmlValidateElement(ctxt
, doc
, child
);
5412 child
= child
->next
;
5420 * @ref: A reference to be validated
5421 * @ctxt: Validation context
5422 * @name: Name of ID we are searching for
5426 xmlValidateRef(xmlRefPtr ref
, xmlValidCtxtPtr ctxt
,
5427 const xmlChar
*name
) {
5436 if (attr
->atype
== XML_ATTRIBUTE_IDREF
) {
5437 id
= xmlGetID(ctxt
->doc
, name
);
5439 VECTXT(ctxt
, attr
->parent
);
5440 VERROR(ctxt
->userData
,
5441 "IDREF attribute %s references an unknown ID \"%s\"\n",
5445 } else if (attr
->atype
== XML_ATTRIBUTE_IDREFS
) {
5446 xmlChar
*dup
, *str
= NULL
, *cur
, save
;
5448 dup
= xmlStrdup(name
);
5456 while ((*cur
!= 0) && (!IS_BLANK(*cur
))) cur
++;
5459 id
= xmlGetID(ctxt
->doc
, str
);
5461 VECTXT(ctxt
, attr
->parent
);
5462 VERROR(ctxt
->userData
,
5463 "IDREFS attribute %s references an unknown ID \"%s\"\n",
5470 while (IS_BLANK(*cur
)) cur
++;
5477 * xmlWalkValidateList:
5478 * @data: Contents of current link
5479 * @user: Value supplied by the user
5481 * Returns 0 to abort the walk or 1 to continue
5484 xmlWalkValidateList(const void *data
, const void *user
)
5486 xmlValidateMemoPtr memo
= (xmlValidateMemoPtr
)user
;
5487 xmlValidateRef((xmlRefPtr
)data
, memo
->ctxt
, memo
->name
);
5492 * xmlValidateCheckRefCallback:
5493 * @ref_list: List of references
5494 * @ctxt: Validation context
5495 * @name: Name of ID we are searching for
5499 xmlValidateCheckRefCallback(xmlListPtr ref_list
, xmlValidCtxtPtr ctxt
,
5500 const xmlChar
*name
) {
5501 xmlValidateMemo memo
;
5503 if (ref_list
== NULL
)
5508 xmlListWalk(ref_list
, xmlWalkValidateList
, &memo
);
5513 * xmlValidateDocumentFinal:
5514 * @ctxt: the validation context
5515 * @doc: a document instance
5517 * Does the final step for the document validation once all the
5518 * incremental validation steps have been completed
5520 * basically it does the following checks described by the XML Rec
5523 * returns 1 if valid or 0 otherwise
5527 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
5528 xmlRefTablePtr table
;
5531 xmlGenericError(xmlGenericErrorContext
,
5532 "xmlValidateDocumentFinal: doc == NULL\n");
5537 * Check all the NOTATION/NOTATIONS attributes
5540 * Check all the ENTITY/ENTITIES attributes definition for validity
5543 * Check all the IDREF/IDREFS attributes definition for validity
5545 table
= (xmlRefTablePtr
) doc
->refs
;
5548 xmlHashScan(table
, (xmlHashScanner
) xmlValidateCheckRefCallback
, ctxt
);
5549 return(ctxt
->valid
);
5554 * @ctxt: the validation context
5555 * @doc: a document instance
5556 * @dtd: a dtd instance
5558 * Try to validate the document against the dtd instance
5560 * basically it does check all the definitions in the DtD.
5562 * returns 1 if valid or 0 otherwise
5566 xmlValidateDtd(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, xmlDtdPtr dtd
) {
5571 if (dtd
== NULL
) return(0);
5572 if (doc
== NULL
) return(0);
5573 oldExt
= doc
->extSubset
;
5574 doc
->extSubset
= dtd
;
5575 ret
= xmlValidateRoot(ctxt
, doc
);
5577 doc
->extSubset
= oldExt
;
5580 if (doc
->ids
!= NULL
) {
5581 xmlFreeIDTable(doc
->ids
);
5584 if (doc
->refs
!= NULL
) {
5585 xmlFreeRefTable(doc
->refs
);
5588 root
= xmlDocGetRootElement(doc
);
5589 ret
= xmlValidateElement(ctxt
, doc
, root
);
5590 ret
&= xmlValidateDocumentFinal(ctxt
, doc
);
5591 doc
->extSubset
= oldExt
;
5596 xmlValidateNotationCallback(xmlEntityPtr cur
, xmlValidCtxtPtr ctxt
,
5597 const xmlChar
*name ATTRIBUTE_UNUSED
) {
5600 if (cur
->etype
== XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
5601 xmlChar
*notation
= cur
->content
;
5603 if (notation
!= NULL
) {
5606 ret
= xmlValidateNotationUse(ctxt
, cur
->doc
, notation
);
5615 xmlValidateAttributeCallback(xmlAttributePtr cur
, xmlValidCtxtPtr ctxt
,
5616 const xmlChar
*name ATTRIBUTE_UNUSED
) {
5623 switch (cur
->atype
) {
5624 case XML_ATTRIBUTE_CDATA
:
5625 case XML_ATTRIBUTE_ID
:
5626 case XML_ATTRIBUTE_IDREF
:
5627 case XML_ATTRIBUTE_IDREFS
:
5628 case XML_ATTRIBUTE_NMTOKEN
:
5629 case XML_ATTRIBUTE_NMTOKENS
:
5630 case XML_ATTRIBUTE_ENUMERATION
:
5632 case XML_ATTRIBUTE_ENTITY
:
5633 case XML_ATTRIBUTE_ENTITIES
:
5634 case XML_ATTRIBUTE_NOTATION
:
5635 if (cur
->defaultValue
!= NULL
) {
5637 ret
= xmlValidateAttributeValue2(ctxt
, ctxt
->doc
, cur
->name
,
5638 cur
->atype
, cur
->defaultValue
);
5639 if ((ret
== 0) && (ctxt
->valid
== 1))
5642 if (cur
->tree
!= NULL
) {
5643 xmlEnumerationPtr tree
= cur
->tree
;
5644 while (tree
!= NULL
) {
5645 ret
= xmlValidateAttributeValue2(ctxt
, ctxt
->doc
,
5646 cur
->name
, cur
->atype
, tree
->name
);
5647 if ((ret
== 0) && (ctxt
->valid
== 1))
5653 if (cur
->atype
== XML_ATTRIBUTE_NOTATION
) {
5655 if ((doc
== NULL
) || (cur
->elem
== NULL
)) {
5656 VERROR(ctxt
->userData
,
5657 "xmlValidateAttributeCallback(%s): internal error\n",
5661 elem
= xmlGetDtdElementDesc(doc
->intSubset
, cur
->elem
);
5663 elem
= xmlGetDtdElementDesc(doc
->extSubset
, cur
->elem
);
5665 VERROR(ctxt
->userData
,
5666 "attribute %s: could not find decl for element %s\n",
5667 cur
->name
, cur
->elem
);
5670 if (elem
->etype
== XML_ELEMENT_TYPE_EMPTY
) {
5671 VERROR(ctxt
->userData
,
5672 "NOTATION attribute %s declared for EMPTY element %s\n",
5673 cur
->name
, cur
->elem
);
5680 * xmlValidateDtdFinal:
5681 * @ctxt: the validation context
5682 * @doc: a document instance
5684 * Does the final step for the dtds validation once all the
5685 * subsets have been parsed
5687 * basically it does the following checks described by the XML Rec
5688 * - check that ENTITY and ENTITIES type attributes default or
5689 * possible values matches one of the defined entities.
5690 * - check that NOTATION type attributes default or
5691 * possible values matches one of the defined notations.
5693 * returns 1 if valid or 0 if invalid and -1 if not well-formed
5697 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
5699 xmlAttributeTablePtr table
;
5700 xmlEntitiesTablePtr entities
;
5702 if (doc
== NULL
) return(0);
5703 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
))
5707 dtd
= doc
->intSubset
;
5708 if ((dtd
!= NULL
) && (dtd
->attributes
!= NULL
)) {
5709 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
5710 xmlHashScan(table
, (xmlHashScanner
) xmlValidateAttributeCallback
, ctxt
);
5712 if ((dtd
!= NULL
) && (dtd
->entities
!= NULL
)) {
5713 entities
= (xmlEntitiesTablePtr
) dtd
->entities
;
5714 xmlHashScan(entities
, (xmlHashScanner
) xmlValidateNotationCallback
,
5717 dtd
= doc
->extSubset
;
5718 if ((dtd
!= NULL
) && (dtd
->attributes
!= NULL
)) {
5719 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
5720 xmlHashScan(table
, (xmlHashScanner
) xmlValidateAttributeCallback
, ctxt
);
5722 if ((dtd
!= NULL
) && (dtd
->entities
!= NULL
)) {
5723 entities
= (xmlEntitiesTablePtr
) dtd
->entities
;
5724 xmlHashScan(entities
, (xmlHashScanner
) xmlValidateNotationCallback
,
5727 return(ctxt
->valid
);
5731 * xmlValidateDocument:
5732 * @ctxt: the validation context
5733 * @doc: a document instance
5735 * Try to validate the document instance
5737 * basically it does the all the checks described by the XML Rec
5738 * i.e. validates the internal and external subset (if present)
5739 * and validate the document tree.
5741 * returns 1 if valid or 0 otherwise
5745 xmlValidateDocument(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
5749 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
)) {
5750 VERROR(ctxt
->userData
, "no DTD found!\n" );
5753 if ((doc
->intSubset
!= NULL
) && ((doc
->intSubset
->SystemID
!= NULL
) ||
5754 (doc
->intSubset
->ExternalID
!= NULL
)) && (doc
->extSubset
== NULL
)) {
5755 doc
->extSubset
= xmlParseDTD(doc
->intSubset
->ExternalID
,
5756 doc
->intSubset
->SystemID
);
5757 if (doc
->extSubset
== NULL
) {
5758 if (doc
->intSubset
->SystemID
!= NULL
) {
5759 VERROR(ctxt
->userData
,
5760 "Could not load the external subset \"%s\"\n",
5761 doc
->intSubset
->SystemID
);
5763 VERROR(ctxt
->userData
,
5764 "Could not load the external subset \"%s\"\n",
5765 doc
->intSubset
->ExternalID
);
5771 if (doc
->ids
!= NULL
) {
5772 xmlFreeIDTable(doc
->ids
);
5775 if (doc
->refs
!= NULL
) {
5776 xmlFreeRefTable(doc
->refs
);
5779 ret
= xmlValidateDtdFinal(ctxt
, doc
);
5780 if (!xmlValidateRoot(ctxt
, doc
)) return(0);
5782 root
= xmlDocGetRootElement(doc
);
5783 ret
&= xmlValidateElement(ctxt
, doc
, root
);
5784 ret
&= xmlValidateDocumentFinal(ctxt
, doc
);
5789 /************************************************************************
5791 * Routines for dynamic validation editing *
5793 ************************************************************************/
5796 * xmlValidGetPotentialChildren:
5797 * @ctree: an element content tree
5798 * @list: an array to store the list of child names
5799 * @len: a pointer to the number of element in the list
5800 * @max: the size of the array
5802 * Build/extend a list of potential children allowed by the content tree
5804 * returns the number of element in the list, or -1 in case of error.
5808 xmlValidGetPotentialChildren(xmlElementContent
*ctree
, const xmlChar
**list
,
5809 int *len
, int max
) {
5812 if ((ctree
== NULL
) || (list
== NULL
) || (len
== NULL
))
5814 if (*len
>= max
) return(*len
);
5816 switch (ctree
->type
) {
5817 case XML_ELEMENT_CONTENT_PCDATA
:
5818 for (i
= 0; i
< *len
;i
++)
5819 if (xmlStrEqual(BAD_CAST
"#PCDATA", list
[i
])) return(*len
);
5820 list
[(*len
)++] = BAD_CAST
"#PCDATA";
5822 case XML_ELEMENT_CONTENT_ELEMENT
:
5823 for (i
= 0; i
< *len
;i
++)
5824 if (xmlStrEqual(ctree
->name
, list
[i
])) return(*len
);
5825 list
[(*len
)++] = ctree
->name
;
5827 case XML_ELEMENT_CONTENT_SEQ
:
5828 xmlValidGetPotentialChildren(ctree
->c1
, list
, len
, max
);
5829 xmlValidGetPotentialChildren(ctree
->c2
, list
, len
, max
);
5831 case XML_ELEMENT_CONTENT_OR
:
5832 xmlValidGetPotentialChildren(ctree
->c1
, list
, len
, max
);
5833 xmlValidGetPotentialChildren(ctree
->c2
, list
, len
, max
);
5841 * xmlValidGetValidElements:
5842 * @prev: an element to insert after
5843 * @next: an element to insert next
5844 * @list: an array to store the list of child names
5845 * @max: the size of the array
5847 * This function returns the list of authorized children to insert
5848 * within an existing tree while respecting the validity constraints
5849 * forced by the Dtd. The insertion point is defined using @prev and
5850 * @next in the following ways:
5851 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
5852 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
5853 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
5854 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
5855 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
5857 * pointers to the element names are inserted at the beginning of the array
5858 * and do not need to be freed.
5860 * returns the number of element in the list, or -1 in case of error. If
5861 * the function returns the value @max the caller is invited to grow the
5862 * receiving array and retry.
5866 xmlValidGetValidElements(xmlNode
*prev
, xmlNode
*next
, const xmlChar
**list
,
5869 int nb_valid_elements
= 0;
5870 const xmlChar
*elements
[256];
5871 int nb_elements
= 0, i
;
5872 const xmlChar
*name
;
5880 xmlNode
*parent_childs
;
5881 xmlNode
*parent_last
;
5883 xmlElement
*element_desc
;
5885 memset(&vctxt
, 0, sizeof (xmlValidCtxt
));
5887 if (prev
== NULL
&& next
== NULL
)
5890 if (list
== NULL
) return(-1);
5891 if (max
<= 0) return(-1);
5893 nb_valid_elements
= 0;
5894 ref_node
= prev
? prev
: next
;
5895 parent
= ref_node
->parent
;
5898 * Retrieves the parent element declaration
5900 element_desc
= xmlGetDtdElementDesc(parent
->doc
->intSubset
,
5902 if ((element_desc
== NULL
) && (parent
->doc
->extSubset
!= NULL
))
5903 element_desc
= xmlGetDtdElementDesc(parent
->doc
->extSubset
,
5905 if (element_desc
== NULL
) return(-1);
5908 * Do a backup of the current tree structure
5910 prev_next
= prev
? prev
->next
: NULL
;
5911 next_prev
= next
? next
->prev
: NULL
;
5912 parent_childs
= parent
->children
;
5913 parent_last
= parent
->last
;
5916 * Creates a dummy node and insert it into the tree
5918 test_node
= xmlNewNode (NULL
, BAD_CAST
"<!dummy?>");
5919 test_node
->doc
= ref_node
->doc
;
5920 test_node
->parent
= parent
;
5921 test_node
->prev
= prev
;
5922 test_node
->next
= next
;
5923 name
= test_node
->name
;
5925 if (prev
) prev
->next
= test_node
;
5926 else parent
->children
= test_node
;
5928 if (next
) next
->prev
= test_node
;
5929 else parent
->last
= test_node
;
5932 * Insert each potential child node and check if the parent is
5935 nb_elements
= xmlValidGetPotentialChildren(element_desc
->content
,
5936 elements
, &nb_elements
, 256);
5938 for (i
= 0;i
< nb_elements
;i
++) {
5939 test_node
->name
= elements
[i
];
5940 if (xmlValidateOneElement(&vctxt
, parent
->doc
, parent
)) {
5943 for (j
= 0; j
< nb_valid_elements
;j
++)
5944 if (xmlStrEqual(elements
[i
], list
[j
])) break;
5945 list
[nb_valid_elements
++] = elements
[i
];
5946 if (nb_valid_elements
>= max
) break;
5951 * Restore the tree structure
5953 if (prev
) prev
->next
= prev_next
;
5954 if (next
) next
->prev
= next_prev
;
5955 parent
->children
= parent_childs
;
5956 parent
->last
= parent_last
;
5959 * Free up the dummy node
5961 test_node
->name
= name
;
5962 xmlFreeNode(test_node
);
5964 return(nb_valid_elements
);