2 * valid.c : part of the code use to do the DTD handling and the validity
5 * See Copyright for the status of this software.
19 #include <libxml/xmlmemory.h>
20 #include <libxml/hash.h>
21 #include <libxml/uri.h>
22 #include <libxml/valid.h>
23 #include <libxml/parser.h>
24 #include <libxml/parserInternals.h>
25 #include <libxml/xmlerror.h>
26 #include <libxml/list.h>
27 #include <libxml/globals.h>
29 static xmlElementPtr
xmlGetDtdElementDesc2(xmlDtdPtr dtd
, const xmlChar
*name
,
31 /* #define DEBUG_VALID_ALGO */
32 /* #define DEBUG_REGEXP_ALGO */
35 xmlGenericError(xmlGenericErrorContext, \
36 "Unimplemented block at %s:%d\n", \
39 #ifdef LIBXML_VALID_ENABLED
41 xmlValidateAttributeValueInternal(xmlDocPtr doc
, xmlAttributeType type
,
42 const xmlChar
*value
);
44 /************************************************************************
46 * Error handling routines *
48 ************************************************************************/
52 * @ctxt: an XML validation parser context
53 * @extra: extra informations
55 * Handle an out of memory error
58 xmlVErrMemory(xmlValidCtxtPtr ctxt
, const char *extra
)
60 xmlGenericErrorFunc channel
= NULL
;
61 xmlParserCtxtPtr pctxt
= NULL
;
65 channel
= ctxt
->error
;
66 data
= ctxt
->userData
;
67 /* Use the special values to detect if it is part of a parsing
69 if ((ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_0
) ||
70 (ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_1
)) {
71 long delta
= (char *) ctxt
- (char *) ctxt
->userData
;
72 if ((delta
> 0) && (delta
< 250))
73 pctxt
= ctxt
->userData
;
77 __xmlRaiseError(NULL
, channel
, data
,
78 pctxt
, NULL
, XML_FROM_VALID
, XML_ERR_NO_MEMORY
,
79 XML_ERR_FATAL
, NULL
, 0, extra
, NULL
, NULL
, 0, 0,
80 "Memory allocation failed : %s\n", extra
);
82 __xmlRaiseError(NULL
, channel
, data
,
83 pctxt
, NULL
, XML_FROM_VALID
, XML_ERR_NO_MEMORY
,
84 XML_ERR_FATAL
, NULL
, 0, NULL
, NULL
, NULL
, 0, 0,
85 "Memory allocation failed\n");
90 * @ctxt: an XML validation parser context
91 * @error: the error number
92 * @extra: extra informations
94 * Handle a validation error
96 static void LIBXML_ATTR_FORMAT(3,0)
97 xmlErrValid(xmlValidCtxtPtr ctxt
, xmlParserErrors error
,
98 const char *msg
, const char *extra
)
100 xmlGenericErrorFunc channel
= NULL
;
101 xmlParserCtxtPtr pctxt
= NULL
;
105 channel
= ctxt
->error
;
106 data
= ctxt
->userData
;
107 /* Use the special values to detect if it is part of a parsing
109 if ((ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_0
) ||
110 (ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_1
)) {
111 long delta
= (char *) ctxt
- (char *) ctxt
->userData
;
112 if ((delta
> 0) && (delta
< 250))
113 pctxt
= ctxt
->userData
;
117 __xmlRaiseError(NULL
, channel
, data
,
118 pctxt
, NULL
, XML_FROM_VALID
, error
,
119 XML_ERR_ERROR
, NULL
, 0, extra
, NULL
, NULL
, 0, 0,
122 __xmlRaiseError(NULL
, channel
, data
,
123 pctxt
, NULL
, XML_FROM_VALID
, error
,
124 XML_ERR_ERROR
, NULL
, 0, NULL
, NULL
, NULL
, 0, 0,
128 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
131 * @ctxt: an XML validation parser context
132 * @node: the node raising the error
133 * @error: the error number
134 * @str1: extra informations
135 * @str2: extra informations
136 * @str3: extra informations
138 * Handle a validation error, provide contextual informations
140 static void LIBXML_ATTR_FORMAT(4,0)
141 xmlErrValidNode(xmlValidCtxtPtr ctxt
,
142 xmlNodePtr node
, xmlParserErrors error
,
143 const char *msg
, const xmlChar
* str1
,
144 const xmlChar
* str2
, const xmlChar
* str3
)
146 xmlStructuredErrorFunc schannel
= NULL
;
147 xmlGenericErrorFunc channel
= NULL
;
148 xmlParserCtxtPtr pctxt
= NULL
;
152 channel
= ctxt
->error
;
153 data
= ctxt
->userData
;
154 /* Use the special values to detect if it is part of a parsing
156 if ((ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_0
) ||
157 (ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_1
)) {
158 long delta
= (char *) ctxt
- (char *) ctxt
->userData
;
159 if ((delta
> 0) && (delta
< 250))
160 pctxt
= ctxt
->userData
;
163 __xmlRaiseError(schannel
, channel
, data
, pctxt
, node
, XML_FROM_VALID
, error
,
164 XML_ERR_ERROR
, NULL
, 0,
167 (const char *) str3
, 0, 0, msg
, str1
, str2
, str3
);
169 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
171 #ifdef LIBXML_VALID_ENABLED
174 * @ctxt: an XML validation parser context
175 * @node: the node raising the error
176 * @error: the error number
177 * @str1: extra informations
178 * @int2: extra informations
179 * @str3: extra informations
181 * Handle a validation error, provide contextual informations
183 static void LIBXML_ATTR_FORMAT(4,0)
184 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt
,
185 xmlNodePtr node
, xmlParserErrors error
,
186 const char *msg
, const xmlChar
* str1
,
187 int int2
, const xmlChar
* str3
)
189 xmlStructuredErrorFunc schannel
= NULL
;
190 xmlGenericErrorFunc channel
= NULL
;
191 xmlParserCtxtPtr pctxt
= NULL
;
195 channel
= ctxt
->error
;
196 data
= ctxt
->userData
;
197 /* Use the special values to detect if it is part of a parsing
199 if ((ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_0
) ||
200 (ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_1
)) {
201 long delta
= (char *) ctxt
- (char *) ctxt
->userData
;
202 if ((delta
> 0) && (delta
< 250))
203 pctxt
= ctxt
->userData
;
206 __xmlRaiseError(schannel
, channel
, data
, pctxt
, node
, XML_FROM_VALID
, error
,
207 XML_ERR_ERROR
, NULL
, 0,
210 NULL
, int2
, 0, msg
, str1
, int2
, str3
);
214 * xmlErrValidWarning:
215 * @ctxt: an XML validation parser context
216 * @node: the node raising the error
217 * @error: the error number
218 * @str1: extra information
219 * @str2: extra information
220 * @str3: extra information
222 * Handle a validation error, provide contextual information
224 static void LIBXML_ATTR_FORMAT(4,0)
225 xmlErrValidWarning(xmlValidCtxtPtr ctxt
,
226 xmlNodePtr node
, xmlParserErrors error
,
227 const char *msg
, const xmlChar
* str1
,
228 const xmlChar
* str2
, const xmlChar
* str3
)
230 xmlStructuredErrorFunc schannel
= NULL
;
231 xmlGenericErrorFunc channel
= NULL
;
232 xmlParserCtxtPtr pctxt
= NULL
;
236 channel
= ctxt
->warning
;
237 data
= ctxt
->userData
;
238 /* Use the special values to detect if it is part of a parsing
240 if ((ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_0
) ||
241 (ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_1
)) {
242 long delta
= (char *) ctxt
- (char *) ctxt
->userData
;
243 if ((delta
> 0) && (delta
< 250))
244 pctxt
= ctxt
->userData
;
247 __xmlRaiseError(schannel
, channel
, data
, pctxt
, node
, XML_FROM_VALID
, error
,
248 XML_ERR_WARNING
, NULL
, 0,
251 (const char *) str3
, 0, 0, msg
, str1
, str2
, str3
);
256 #ifdef LIBXML_REGEXP_ENABLED
258 * If regexp are enabled we can do continuous validation without the
259 * need of a tree to validate the content model. this is done in each
261 * Each xmlValidState represent the validation state associated to the
262 * set of nodes currently open from the document root to the current element.
266 typedef struct _xmlValidState
{
267 xmlElementPtr elemDecl
; /* pointer to the content model */
268 xmlNodePtr node
; /* pointer to the current node */
269 xmlRegExecCtxtPtr exec
; /* regexp runtime */
274 vstateVPush(xmlValidCtxtPtr ctxt
, xmlElementPtr elemDecl
, xmlNodePtr node
) {
275 if ((ctxt
->vstateMax
== 0) || (ctxt
->vstateTab
== NULL
)) {
276 ctxt
->vstateMax
= 10;
277 ctxt
->vstateTab
= (xmlValidState
*) xmlMalloc(ctxt
->vstateMax
*
278 sizeof(ctxt
->vstateTab
[0]));
279 if (ctxt
->vstateTab
== NULL
) {
280 xmlVErrMemory(ctxt
, "malloc failed");
285 if (ctxt
->vstateNr
>= ctxt
->vstateMax
) {
288 tmp
= (xmlValidState
*) xmlRealloc(ctxt
->vstateTab
,
289 2 * ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
291 xmlVErrMemory(ctxt
, "realloc failed");
294 ctxt
->vstateMax
*= 2;
295 ctxt
->vstateTab
= tmp
;
297 ctxt
->vstate
= &ctxt
->vstateTab
[ctxt
->vstateNr
];
298 ctxt
->vstateTab
[ctxt
->vstateNr
].elemDecl
= elemDecl
;
299 ctxt
->vstateTab
[ctxt
->vstateNr
].node
= node
;
300 if ((elemDecl
!= NULL
) && (elemDecl
->etype
== XML_ELEMENT_TYPE_ELEMENT
)) {
301 if (elemDecl
->contModel
== NULL
)
302 xmlValidBuildContentModel(ctxt
, elemDecl
);
303 if (elemDecl
->contModel
!= NULL
) {
304 ctxt
->vstateTab
[ctxt
->vstateNr
].exec
=
305 xmlRegNewExecCtxt(elemDecl
->contModel
, NULL
, NULL
);
307 ctxt
->vstateTab
[ctxt
->vstateNr
].exec
= NULL
;
308 xmlErrValidNode(ctxt
, (xmlNodePtr
) elemDecl
,
309 XML_ERR_INTERNAL_ERROR
,
310 "Failed to build content model regexp for %s\n",
311 node
->name
, NULL
, NULL
);
314 return(ctxt
->vstateNr
++);
318 vstateVPop(xmlValidCtxtPtr ctxt
) {
319 xmlElementPtr elemDecl
;
321 if (ctxt
->vstateNr
< 1) return(-1);
323 elemDecl
= ctxt
->vstateTab
[ctxt
->vstateNr
].elemDecl
;
324 ctxt
->vstateTab
[ctxt
->vstateNr
].elemDecl
= NULL
;
325 ctxt
->vstateTab
[ctxt
->vstateNr
].node
= NULL
;
326 if ((elemDecl
!= NULL
) && (elemDecl
->etype
== XML_ELEMENT_TYPE_ELEMENT
)) {
327 xmlRegFreeExecCtxt(ctxt
->vstateTab
[ctxt
->vstateNr
].exec
);
329 ctxt
->vstateTab
[ctxt
->vstateNr
].exec
= NULL
;
330 if (ctxt
->vstateNr
>= 1)
331 ctxt
->vstate
= &ctxt
->vstateTab
[ctxt
->vstateNr
- 1];
334 return(ctxt
->vstateNr
);
337 #else /* not LIBXML_REGEXP_ENABLED */
339 * If regexp are not enabled, it uses a home made algorithm less
340 * complex and easier to
341 * debug/maintain than a generic NFA -> DFA state based algo. The
342 * only restriction is on the deepness of the tree limited by the
343 * size of the occurs bitfield
345 * this is the content of a saved state for rollbacks
348 #define ROLLBACK_OR 0
349 #define ROLLBACK_PARENT 1
351 typedef struct _xmlValidState
{
352 xmlElementContentPtr cont
; /* pointer to the content model subtree */
353 xmlNodePtr node
; /* pointer to the current node in the list */
354 long occurs
;/* bitfield for multiple occurrences */
355 unsigned char depth
; /* current depth in the overall tree */
356 unsigned char state
; /* ROLLBACK_XXX */
359 #define MAX_RECURSE 25000
360 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
361 #define CONT ctxt->vstate->cont
362 #define NODE ctxt->vstate->node
363 #define DEPTH ctxt->vstate->depth
364 #define OCCURS ctxt->vstate->occurs
365 #define STATE ctxt->vstate->state
367 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
368 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
370 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
371 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
374 vstateVPush(xmlValidCtxtPtr ctxt
, xmlElementContentPtr cont
,
375 xmlNodePtr node
, unsigned char depth
, long occurs
,
376 unsigned char state
) {
377 int i
= ctxt
->vstateNr
- 1;
379 if (ctxt
->vstateNr
> MAX_RECURSE
) {
382 if (ctxt
->vstateTab
== NULL
) {
384 ctxt
->vstateTab
= (xmlValidState
*) xmlMalloc(
385 ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
386 if (ctxt
->vstateTab
== NULL
) {
387 xmlVErrMemory(ctxt
, "malloc failed");
391 if (ctxt
->vstateNr
>= ctxt
->vstateMax
) {
394 tmp
= (xmlValidState
*) xmlRealloc(ctxt
->vstateTab
,
395 2 * ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
397 xmlVErrMemory(ctxt
, "malloc failed");
400 ctxt
->vstateMax
*= 2;
401 ctxt
->vstateTab
= tmp
;
402 ctxt
->vstate
= &ctxt
->vstateTab
[0];
405 * Don't push on the stack a state already here
407 if ((i
>= 0) && (ctxt
->vstateTab
[i
].cont
== cont
) &&
408 (ctxt
->vstateTab
[i
].node
== node
) &&
409 (ctxt
->vstateTab
[i
].depth
== depth
) &&
410 (ctxt
->vstateTab
[i
].occurs
== occurs
) &&
411 (ctxt
->vstateTab
[i
].state
== state
))
412 return(ctxt
->vstateNr
);
413 ctxt
->vstateTab
[ctxt
->vstateNr
].cont
= cont
;
414 ctxt
->vstateTab
[ctxt
->vstateNr
].node
= node
;
415 ctxt
->vstateTab
[ctxt
->vstateNr
].depth
= depth
;
416 ctxt
->vstateTab
[ctxt
->vstateNr
].occurs
= occurs
;
417 ctxt
->vstateTab
[ctxt
->vstateNr
].state
= state
;
418 return(ctxt
->vstateNr
++);
422 vstateVPop(xmlValidCtxtPtr ctxt
) {
423 if (ctxt
->vstateNr
<= 1) return(-1);
425 ctxt
->vstate
= &ctxt
->vstateTab
[0];
426 ctxt
->vstate
->cont
= ctxt
->vstateTab
[ctxt
->vstateNr
].cont
;
427 ctxt
->vstate
->node
= ctxt
->vstateTab
[ctxt
->vstateNr
].node
;
428 ctxt
->vstate
->depth
= ctxt
->vstateTab
[ctxt
->vstateNr
].depth
;
429 ctxt
->vstate
->occurs
= ctxt
->vstateTab
[ctxt
->vstateNr
].occurs
;
430 ctxt
->vstate
->state
= ctxt
->vstateTab
[ctxt
->vstateNr
].state
;
431 return(ctxt
->vstateNr
);
434 #endif /* LIBXML_REGEXP_ENABLED */
437 nodeVPush(xmlValidCtxtPtr ctxt
, xmlNodePtr value
)
439 if (ctxt
->nodeMax
<= 0) {
442 (xmlNodePtr
*) xmlMalloc(ctxt
->nodeMax
*
443 sizeof(ctxt
->nodeTab
[0]));
444 if (ctxt
->nodeTab
== NULL
) {
445 xmlVErrMemory(ctxt
, "malloc failed");
450 if (ctxt
->nodeNr
>= ctxt
->nodeMax
) {
452 tmp
= (xmlNodePtr
*) xmlRealloc(ctxt
->nodeTab
,
453 ctxt
->nodeMax
* 2 * sizeof(ctxt
->nodeTab
[0]));
455 xmlVErrMemory(ctxt
, "realloc failed");
461 ctxt
->nodeTab
[ctxt
->nodeNr
] = value
;
463 return (ctxt
->nodeNr
++);
466 nodeVPop(xmlValidCtxtPtr ctxt
)
470 if (ctxt
->nodeNr
<= 0)
473 if (ctxt
->nodeNr
> 0)
474 ctxt
->node
= ctxt
->nodeTab
[ctxt
->nodeNr
- 1];
477 ret
= ctxt
->nodeTab
[ctxt
->nodeNr
];
478 ctxt
->nodeTab
[ctxt
->nodeNr
] = NULL
;
482 #ifdef DEBUG_VALID_ALGO
484 xmlValidPrintNode(xmlNodePtr cur
) {
486 xmlGenericError(xmlGenericErrorContext
, "null");
490 case XML_ELEMENT_NODE
:
491 xmlGenericError(xmlGenericErrorContext
, "%s ", cur
->name
);
494 xmlGenericError(xmlGenericErrorContext
, "text ");
496 case XML_CDATA_SECTION_NODE
:
497 xmlGenericError(xmlGenericErrorContext
, "cdata ");
499 case XML_ENTITY_REF_NODE
:
500 xmlGenericError(xmlGenericErrorContext
, "&%s; ", cur
->name
);
503 xmlGenericError(xmlGenericErrorContext
, "pi(%s) ", cur
->name
);
505 case XML_COMMENT_NODE
:
506 xmlGenericError(xmlGenericErrorContext
, "comment ");
508 case XML_ATTRIBUTE_NODE
:
509 xmlGenericError(xmlGenericErrorContext
, "?attr? ");
511 case XML_ENTITY_NODE
:
512 xmlGenericError(xmlGenericErrorContext
, "?ent? ");
514 case XML_DOCUMENT_NODE
:
515 xmlGenericError(xmlGenericErrorContext
, "?doc? ");
517 case XML_DOCUMENT_TYPE_NODE
:
518 xmlGenericError(xmlGenericErrorContext
, "?doctype? ");
520 case XML_DOCUMENT_FRAG_NODE
:
521 xmlGenericError(xmlGenericErrorContext
, "?frag? ");
523 case XML_NOTATION_NODE
:
524 xmlGenericError(xmlGenericErrorContext
, "?nota? ");
526 case XML_HTML_DOCUMENT_NODE
:
527 xmlGenericError(xmlGenericErrorContext
, "?html? ");
529 #ifdef LIBXML_DOCB_ENABLED
530 case XML_DOCB_DOCUMENT_NODE
:
531 xmlGenericError(xmlGenericErrorContext
, "?docb? ");
535 xmlGenericError(xmlGenericErrorContext
, "?dtd? ");
537 case XML_ELEMENT_DECL
:
538 xmlGenericError(xmlGenericErrorContext
, "?edecl? ");
540 case XML_ATTRIBUTE_DECL
:
541 xmlGenericError(xmlGenericErrorContext
, "?adecl? ");
543 case XML_ENTITY_DECL
:
544 xmlGenericError(xmlGenericErrorContext
, "?entdecl? ");
546 case XML_NAMESPACE_DECL
:
547 xmlGenericError(xmlGenericErrorContext
, "?nsdecl? ");
549 case XML_XINCLUDE_START
:
550 xmlGenericError(xmlGenericErrorContext
, "incstart ");
552 case XML_XINCLUDE_END
:
553 xmlGenericError(xmlGenericErrorContext
, "incend ");
559 xmlValidPrintNodeList(xmlNodePtr cur
) {
561 xmlGenericError(xmlGenericErrorContext
, "null ");
562 while (cur
!= NULL
) {
563 xmlValidPrintNode(cur
);
569 xmlValidDebug(xmlNodePtr cur
, xmlElementContentPtr cont
) {
573 xmlGenericError(xmlGenericErrorContext
, "valid: ");
574 xmlValidPrintNodeList(cur
);
575 xmlGenericError(xmlGenericErrorContext
, "against ");
576 xmlSnprintfElementContent(expr
, 5000, cont
, 1);
577 xmlGenericError(xmlGenericErrorContext
, "%s\n", expr
);
581 xmlValidDebugState(xmlValidStatePtr state
) {
582 xmlGenericError(xmlGenericErrorContext
, "(");
583 if (state
->cont
== NULL
)
584 xmlGenericError(xmlGenericErrorContext
, "null,");
586 switch (state
->cont
->type
) {
587 case XML_ELEMENT_CONTENT_PCDATA
:
588 xmlGenericError(xmlGenericErrorContext
, "pcdata,");
590 case XML_ELEMENT_CONTENT_ELEMENT
:
591 xmlGenericError(xmlGenericErrorContext
, "%s,",
594 case XML_ELEMENT_CONTENT_SEQ
:
595 xmlGenericError(xmlGenericErrorContext
, "seq,");
597 case XML_ELEMENT_CONTENT_OR
:
598 xmlGenericError(xmlGenericErrorContext
, "or,");
601 xmlValidPrintNode(state
->node
);
602 xmlGenericError(xmlGenericErrorContext
, ",%d,%X,%d)",
603 state
->depth
, state
->occurs
, state
->state
);
607 xmlValidStateDebug(xmlValidCtxtPtr ctxt
) {
610 xmlGenericError(xmlGenericErrorContext
, "state: ");
611 xmlValidDebugState(ctxt
->vstate
);
612 xmlGenericError(xmlGenericErrorContext
, " stack: %d ",
614 for (i
= 0, j
= ctxt
->vstateNr
- 1;(i
< 3) && (j
> 0);i
++,j
--)
615 xmlValidDebugState(&ctxt
->vstateTab
[j
]);
616 xmlGenericError(xmlGenericErrorContext
, "\n");
620 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
623 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
624 #define DEBUG_VALID_MSG(m) \
625 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
628 #define DEBUG_VALID_STATE(n,c)
629 #define DEBUG_VALID_MSG(m)
632 /* TODO: use hash table for accesses to elem and attribute definitions */
636 if (doc == NULL) return(0); \
637 else if ((doc->intSubset == NULL) && \
638 (doc->extSubset == NULL)) return(0)
640 #ifdef LIBXML_REGEXP_ENABLED
642 /************************************************************************
644 * Content model validation based on the regexps *
646 ************************************************************************/
649 * xmlValidBuildAContentModel:
650 * @content: the content model
651 * @ctxt: the schema parser context
652 * @name: the element name whose content is being built
654 * Generate the automata sequence needed for that type
656 * Returns 1 if successful or 0 in case of error.
659 xmlValidBuildAContentModel(xmlElementContentPtr content
,
660 xmlValidCtxtPtr ctxt
,
661 const xmlChar
*name
) {
662 if (content
== NULL
) {
663 xmlErrValidNode(ctxt
, NULL
, XML_ERR_INTERNAL_ERROR
,
664 "Found NULL content in content model of %s\n",
668 switch (content
->type
) {
669 case XML_ELEMENT_CONTENT_PCDATA
:
670 xmlErrValidNode(ctxt
, NULL
, XML_ERR_INTERNAL_ERROR
,
671 "Found PCDATA in content model of %s\n",
675 case XML_ELEMENT_CONTENT_ELEMENT
: {
676 xmlAutomataStatePtr oldstate
= ctxt
->state
;
680 fullname
= xmlBuildQName(content
->name
, content
->prefix
, fn
, 50);
681 if (fullname
== NULL
) {
682 xmlVErrMemory(ctxt
, "Building content model");
686 switch (content
->ocur
) {
687 case XML_ELEMENT_CONTENT_ONCE
:
688 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
689 ctxt
->state
, NULL
, fullname
, NULL
);
691 case XML_ELEMENT_CONTENT_OPT
:
692 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
693 ctxt
->state
, NULL
, fullname
, NULL
);
694 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
696 case XML_ELEMENT_CONTENT_PLUS
:
697 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
698 ctxt
->state
, NULL
, fullname
, NULL
);
699 xmlAutomataNewTransition(ctxt
->am
, ctxt
->state
,
700 ctxt
->state
, fullname
, NULL
);
702 case XML_ELEMENT_CONTENT_MULT
:
703 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
,
705 xmlAutomataNewTransition(ctxt
->am
,
706 ctxt
->state
, ctxt
->state
, fullname
, NULL
);
709 if ((fullname
!= fn
) && (fullname
!= content
->name
))
713 case XML_ELEMENT_CONTENT_SEQ
: {
714 xmlAutomataStatePtr oldstate
, oldend
;
715 xmlElementContentOccur ocur
;
718 * Simply iterate over the content
720 oldstate
= ctxt
->state
;
721 ocur
= content
->ocur
;
722 if (ocur
!= XML_ELEMENT_CONTENT_ONCE
) {
723 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
724 oldstate
= ctxt
->state
;
727 xmlValidBuildAContentModel(content
->c1
, ctxt
, name
);
728 content
= content
->c2
;
729 } while ((content
->type
== XML_ELEMENT_CONTENT_SEQ
) &&
730 (content
->ocur
== XML_ELEMENT_CONTENT_ONCE
));
731 xmlValidBuildAContentModel(content
, ctxt
, name
);
732 oldend
= ctxt
->state
;
733 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
, oldend
, NULL
);
735 case XML_ELEMENT_CONTENT_ONCE
:
737 case XML_ELEMENT_CONTENT_OPT
:
738 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
740 case XML_ELEMENT_CONTENT_MULT
:
741 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
742 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
744 case XML_ELEMENT_CONTENT_PLUS
:
745 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
750 case XML_ELEMENT_CONTENT_OR
: {
751 xmlAutomataStatePtr oldstate
, oldend
;
752 xmlElementContentOccur ocur
;
754 ocur
= content
->ocur
;
755 if ((ocur
== XML_ELEMENT_CONTENT_PLUS
) ||
756 (ocur
== XML_ELEMENT_CONTENT_MULT
)) {
757 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
,
760 oldstate
= ctxt
->state
;
761 oldend
= xmlAutomataNewState(ctxt
->am
);
764 * iterate over the subtypes and remerge the end with an
768 ctxt
->state
= oldstate
;
769 xmlValidBuildAContentModel(content
->c1
, ctxt
, name
);
770 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldend
);
771 content
= content
->c2
;
772 } while ((content
->type
== XML_ELEMENT_CONTENT_OR
) &&
773 (content
->ocur
== XML_ELEMENT_CONTENT_ONCE
));
774 ctxt
->state
= oldstate
;
775 xmlValidBuildAContentModel(content
, ctxt
, name
);
776 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldend
);
777 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
, oldend
, NULL
);
779 case XML_ELEMENT_CONTENT_ONCE
:
781 case XML_ELEMENT_CONTENT_OPT
:
782 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
784 case XML_ELEMENT_CONTENT_MULT
:
785 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
786 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
788 case XML_ELEMENT_CONTENT_PLUS
:
789 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
795 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
796 "ContentModel broken for element %s\n",
797 (const char *) name
);
803 * xmlValidBuildContentModel:
804 * @ctxt: a validation context
805 * @elem: an element declaration node
807 * (Re)Build the automata associated to the content model of this
810 * Returns 1 in case of success, 0 in case of error
813 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt
, xmlElementPtr elem
) {
815 if ((ctxt
== NULL
) || (elem
== NULL
))
817 if (elem
->type
!= XML_ELEMENT_DECL
)
819 if (elem
->etype
!= XML_ELEMENT_TYPE_ELEMENT
)
821 /* TODO: should we rebuild in this case ? */
822 if (elem
->contModel
!= NULL
) {
823 if (!xmlRegexpIsDeterminist(elem
->contModel
)) {
830 ctxt
->am
= xmlNewAutomata();
831 if (ctxt
->am
== NULL
) {
832 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
,
833 XML_ERR_INTERNAL_ERROR
,
834 "Cannot create automata for element %s\n",
835 elem
->name
, NULL
, NULL
);
838 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
839 xmlValidBuildAContentModel(elem
->content
, ctxt
, elem
->name
);
840 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
841 elem
->contModel
= xmlAutomataCompile(ctxt
->am
);
842 if (xmlRegexpIsDeterminist(elem
->contModel
) != 1) {
845 xmlSnprintfElementContent(expr
, 5000, elem
->content
, 1);
846 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
,
847 XML_DTD_CONTENT_NOT_DETERMINIST
,
848 "Content model of %s is not determinist: %s\n",
849 elem
->name
, BAD_CAST expr
, NULL
);
850 #ifdef DEBUG_REGEXP_ALGO
851 xmlRegexpPrint(stderr
, elem
->contModel
);
855 xmlFreeAutomata(ctxt
->am
);
860 xmlFreeAutomata(ctxt
->am
);
865 #endif /* LIBXML_REGEXP_ENABLED */
867 /****************************************************************
869 * Util functions for data allocation/deallocation *
871 ****************************************************************/
876 * Allocate a validation context structure.
878 * Returns NULL if not, otherwise the new validation context structure
880 xmlValidCtxtPtr
xmlNewValidCtxt(void) {
883 if ((ret
= xmlMalloc(sizeof (xmlValidCtxt
))) == NULL
) {
884 xmlVErrMemory(NULL
, "malloc failed");
888 (void) memset(ret
, 0, sizeof (xmlValidCtxt
));
895 * @cur: the validation context to free
897 * Free a validation context structure.
900 xmlFreeValidCtxt(xmlValidCtxtPtr cur
) {
901 if (cur
->vstateTab
!= NULL
)
902 xmlFree(cur
->vstateTab
);
903 if (cur
->nodeTab
!= NULL
)
904 xmlFree(cur
->nodeTab
);
908 #endif /* LIBXML_VALID_ENABLED */
911 * xmlNewDocElementContent:
913 * @name: the subelement name or NULL
914 * @type: the type of element content decl
916 * Allocate an element content structure for the document.
918 * Returns NULL if not, otherwise the new element content structure
921 xmlNewDocElementContent(xmlDocPtr doc
, const xmlChar
*name
,
922 xmlElementContentType type
) {
923 xmlElementContentPtr ret
;
924 xmlDictPtr dict
= NULL
;
930 case XML_ELEMENT_CONTENT_ELEMENT
:
932 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
933 "xmlNewElementContent : name == NULL !\n",
937 case XML_ELEMENT_CONTENT_PCDATA
:
938 case XML_ELEMENT_CONTENT_SEQ
:
939 case XML_ELEMENT_CONTENT_OR
:
941 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
942 "xmlNewElementContent : name != NULL !\n",
947 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
948 "Internal: ELEMENT content corrupted invalid type\n",
952 ret
= (xmlElementContentPtr
) xmlMalloc(sizeof(xmlElementContent
));
954 xmlVErrMemory(NULL
, "malloc failed");
957 memset(ret
, 0, sizeof(xmlElementContent
));
959 ret
->ocur
= XML_ELEMENT_CONTENT_ONCE
;
964 tmp
= xmlSplitQName3(name
, &l
);
967 ret
->name
= xmlStrdup(name
);
969 ret
->name
= xmlDictLookup(dict
, name
, -1);
972 ret
->prefix
= xmlStrndup(name
, l
);
973 ret
->name
= xmlStrdup(tmp
);
975 ret
->prefix
= xmlDictLookup(dict
, name
, l
);
976 ret
->name
= xmlDictLookup(dict
, tmp
, -1);
984 * xmlNewElementContent:
985 * @name: the subelement name or NULL
986 * @type: the type of element content decl
988 * Allocate an element content structure.
989 * Deprecated in favor of xmlNewDocElementContent
991 * Returns NULL if not, otherwise the new element content structure
994 xmlNewElementContent(const xmlChar
*name
, xmlElementContentType type
) {
995 return(xmlNewDocElementContent(NULL
, name
, type
));
999 * xmlCopyDocElementContent:
1000 * @doc: the document owning the element declaration
1001 * @cur: An element content pointer.
1003 * Build a copy of an element content description.
1005 * Returns the new xmlElementContentPtr or NULL in case of error.
1007 xmlElementContentPtr
1008 xmlCopyDocElementContent(xmlDocPtr doc
, xmlElementContentPtr cur
) {
1009 xmlElementContentPtr ret
= NULL
, prev
= NULL
, tmp
;
1010 xmlDictPtr dict
= NULL
;
1012 if (cur
== NULL
) return(NULL
);
1017 ret
= (xmlElementContentPtr
) xmlMalloc(sizeof(xmlElementContent
));
1019 xmlVErrMemory(NULL
, "malloc failed");
1022 memset(ret
, 0, sizeof(xmlElementContent
));
1023 ret
->type
= cur
->type
;
1024 ret
->ocur
= cur
->ocur
;
1025 if (cur
->name
!= NULL
) {
1027 ret
->name
= xmlDictLookup(dict
, cur
->name
, -1);
1029 ret
->name
= xmlStrdup(cur
->name
);
1032 if (cur
->prefix
!= NULL
) {
1034 ret
->prefix
= xmlDictLookup(dict
, cur
->prefix
, -1);
1036 ret
->prefix
= xmlStrdup(cur
->prefix
);
1038 if (cur
->c1
!= NULL
)
1039 ret
->c1
= xmlCopyDocElementContent(doc
, cur
->c1
);
1040 if (ret
->c1
!= NULL
)
1041 ret
->c1
->parent
= ret
;
1042 if (cur
->c2
!= NULL
) {
1045 while (cur
!= NULL
) {
1046 tmp
= (xmlElementContentPtr
) xmlMalloc(sizeof(xmlElementContent
));
1048 xmlVErrMemory(NULL
, "malloc failed");
1051 memset(tmp
, 0, sizeof(xmlElementContent
));
1052 tmp
->type
= cur
->type
;
1053 tmp
->ocur
= cur
->ocur
;
1055 if (cur
->name
!= NULL
) {
1057 tmp
->name
= xmlDictLookup(dict
, cur
->name
, -1);
1059 tmp
->name
= xmlStrdup(cur
->name
);
1062 if (cur
->prefix
!= NULL
) {
1064 tmp
->prefix
= xmlDictLookup(dict
, cur
->prefix
, -1);
1066 tmp
->prefix
= xmlStrdup(cur
->prefix
);
1068 if (cur
->c1
!= NULL
)
1069 tmp
->c1
= xmlCopyDocElementContent(doc
,cur
->c1
);
1070 if (tmp
->c1
!= NULL
)
1071 tmp
->c1
->parent
= ret
;
1080 * xmlCopyElementContent:
1081 * @cur: An element content pointer.
1083 * Build a copy of an element content description.
1084 * Deprecated, use xmlCopyDocElementContent instead
1086 * Returns the new xmlElementContentPtr or NULL in case of error.
1088 xmlElementContentPtr
1089 xmlCopyElementContent(xmlElementContentPtr cur
) {
1090 return(xmlCopyDocElementContent(NULL
, cur
));
1094 * xmlFreeDocElementContent:
1095 * @doc: the document owning the element declaration
1096 * @cur: the element content tree to free
1098 * Free an element content structure. The whole subtree is removed.
1101 xmlFreeDocElementContent(xmlDocPtr doc
, xmlElementContentPtr cur
) {
1102 xmlElementContentPtr next
;
1103 xmlDictPtr dict
= NULL
;
1108 while (cur
!= NULL
) {
1110 switch (cur
->type
) {
1111 case XML_ELEMENT_CONTENT_PCDATA
:
1112 case XML_ELEMENT_CONTENT_ELEMENT
:
1113 case XML_ELEMENT_CONTENT_SEQ
:
1114 case XML_ELEMENT_CONTENT_OR
:
1117 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
1118 "Internal: ELEMENT content corrupted invalid type\n",
1122 if (cur
->c1
!= NULL
) xmlFreeDocElementContent(doc
, cur
->c1
);
1124 if ((cur
->name
!= NULL
) && (!xmlDictOwns(dict
, cur
->name
)))
1125 xmlFree((xmlChar
*) cur
->name
);
1126 if ((cur
->prefix
!= NULL
) && (!xmlDictOwns(dict
, cur
->prefix
)))
1127 xmlFree((xmlChar
*) cur
->prefix
);
1129 if (cur
->name
!= NULL
) xmlFree((xmlChar
*) cur
->name
);
1130 if (cur
->prefix
!= NULL
) xmlFree((xmlChar
*) cur
->prefix
);
1138 * xmlFreeElementContent:
1139 * @cur: the element content tree to free
1141 * Free an element content structure. The whole subtree is removed.
1142 * Deprecated, use xmlFreeDocElementContent instead
1145 xmlFreeElementContent(xmlElementContentPtr cur
) {
1146 xmlFreeDocElementContent(NULL
, cur
);
1149 #ifdef LIBXML_OUTPUT_ENABLED
1151 * xmlDumpElementContent:
1152 * @buf: An XML buffer
1153 * @content: An element table
1154 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1156 * This will dump the content of the element table as an XML DTD definition
1159 xmlDumpElementContent(xmlBufferPtr buf
, xmlElementContentPtr content
, int glob
) {
1160 if (content
== NULL
) return;
1162 if (glob
) xmlBufferWriteChar(buf
, "(");
1163 switch (content
->type
) {
1164 case XML_ELEMENT_CONTENT_PCDATA
:
1165 xmlBufferWriteChar(buf
, "#PCDATA");
1167 case XML_ELEMENT_CONTENT_ELEMENT
:
1168 if (content
->prefix
!= NULL
) {
1169 xmlBufferWriteCHAR(buf
, content
->prefix
);
1170 xmlBufferWriteChar(buf
, ":");
1172 xmlBufferWriteCHAR(buf
, content
->name
);
1174 case XML_ELEMENT_CONTENT_SEQ
:
1175 if ((content
->c1
!= NULL
) &&
1176 ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
1177 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
)))
1178 xmlDumpElementContent(buf
, content
->c1
, 1);
1180 xmlDumpElementContent(buf
, content
->c1
, 0);
1181 xmlBufferWriteChar(buf
, " , ");
1182 if ((content
->c2
!= NULL
) &&
1183 ((content
->c2
->type
== XML_ELEMENT_CONTENT_OR
) ||
1184 ((content
->c2
->type
== XML_ELEMENT_CONTENT_SEQ
) &&
1185 (content
->c2
->ocur
!= XML_ELEMENT_CONTENT_ONCE
))))
1186 xmlDumpElementContent(buf
, content
->c2
, 1);
1188 xmlDumpElementContent(buf
, content
->c2
, 0);
1190 case XML_ELEMENT_CONTENT_OR
:
1191 if ((content
->c1
!= NULL
) &&
1192 ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
1193 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
)))
1194 xmlDumpElementContent(buf
, content
->c1
, 1);
1196 xmlDumpElementContent(buf
, content
->c1
, 0);
1197 xmlBufferWriteChar(buf
, " | ");
1198 if ((content
->c2
!= NULL
) &&
1199 ((content
->c2
->type
== XML_ELEMENT_CONTENT_SEQ
) ||
1200 ((content
->c2
->type
== XML_ELEMENT_CONTENT_OR
) &&
1201 (content
->c2
->ocur
!= XML_ELEMENT_CONTENT_ONCE
))))
1202 xmlDumpElementContent(buf
, content
->c2
, 1);
1204 xmlDumpElementContent(buf
, content
->c2
, 0);
1207 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
1208 "Internal: ELEMENT content corrupted invalid type\n",
1212 xmlBufferWriteChar(buf
, ")");
1213 switch (content
->ocur
) {
1214 case XML_ELEMENT_CONTENT_ONCE
:
1216 case XML_ELEMENT_CONTENT_OPT
:
1217 xmlBufferWriteChar(buf
, "?");
1219 case XML_ELEMENT_CONTENT_MULT
:
1220 xmlBufferWriteChar(buf
, "*");
1222 case XML_ELEMENT_CONTENT_PLUS
:
1223 xmlBufferWriteChar(buf
, "+");
1229 * xmlSprintfElementContent:
1230 * @buf: an output buffer
1231 * @content: An element table
1232 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1234 * Deprecated, unsafe, use xmlSnprintfElementContent
1237 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED
,
1238 xmlElementContentPtr content ATTRIBUTE_UNUSED
,
1239 int englob ATTRIBUTE_UNUSED
) {
1241 #endif /* LIBXML_OUTPUT_ENABLED */
1244 * xmlSnprintfElementContent:
1245 * @buf: an output buffer
1246 * @size: the buffer size
1247 * @content: An element table
1248 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1250 * This will dump the content of the element content definition
1251 * Intended just for the debug routine
1254 xmlSnprintfElementContent(char *buf
, int size
, xmlElementContentPtr content
, int englob
) {
1257 if (content
== NULL
) return;
1259 if (size
- len
< 50) {
1260 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
1261 strcat(buf
, " ...");
1264 if (englob
) strcat(buf
, "(");
1265 switch (content
->type
) {
1266 case XML_ELEMENT_CONTENT_PCDATA
:
1267 strcat(buf
, "#PCDATA");
1269 case XML_ELEMENT_CONTENT_ELEMENT
: {
1270 int qnameLen
= xmlStrlen(content
->name
);
1272 if (content
->prefix
!= NULL
)
1273 qnameLen
+= xmlStrlen(content
->prefix
) + 1;
1274 if (size
- len
< qnameLen
+ 10) {
1275 strcat(buf
, " ...");
1278 if (content
->prefix
!= NULL
) {
1279 strcat(buf
, (char *) content
->prefix
);
1282 if (content
->name
!= NULL
)
1283 strcat(buf
, (char *) content
->name
);
1286 case XML_ELEMENT_CONTENT_SEQ
:
1287 if ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
1288 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
))
1289 xmlSnprintfElementContent(buf
, size
, content
->c1
, 1);
1291 xmlSnprintfElementContent(buf
, size
, content
->c1
, 0);
1293 if (size
- len
< 50) {
1294 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
1295 strcat(buf
, " ...");
1299 if (((content
->c2
->type
== XML_ELEMENT_CONTENT_OR
) ||
1300 (content
->c2
->ocur
!= XML_ELEMENT_CONTENT_ONCE
)) &&
1301 (content
->c2
->type
!= XML_ELEMENT_CONTENT_ELEMENT
))
1302 xmlSnprintfElementContent(buf
, size
, content
->c2
, 1);
1304 xmlSnprintfElementContent(buf
, size
, content
->c2
, 0);
1306 case XML_ELEMENT_CONTENT_OR
:
1307 if ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
1308 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
))
1309 xmlSnprintfElementContent(buf
, size
, content
->c1
, 1);
1311 xmlSnprintfElementContent(buf
, size
, content
->c1
, 0);
1313 if (size
- len
< 50) {
1314 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
1315 strcat(buf
, " ...");
1319 if (((content
->c2
->type
== XML_ELEMENT_CONTENT_SEQ
) ||
1320 (content
->c2
->ocur
!= XML_ELEMENT_CONTENT_ONCE
)) &&
1321 (content
->c2
->type
!= XML_ELEMENT_CONTENT_ELEMENT
))
1322 xmlSnprintfElementContent(buf
, size
, content
->c2
, 1);
1324 xmlSnprintfElementContent(buf
, size
, content
->c2
, 0);
1327 if (size
- strlen(buf
) <= 2) return;
1330 switch (content
->ocur
) {
1331 case XML_ELEMENT_CONTENT_ONCE
:
1333 case XML_ELEMENT_CONTENT_OPT
:
1336 case XML_ELEMENT_CONTENT_MULT
:
1339 case XML_ELEMENT_CONTENT_PLUS
:
1345 /****************************************************************
1347 * Registration of DTD declarations *
1349 ****************************************************************/
1355 * Deallocate the memory used by an element definition
1358 xmlFreeElement(xmlElementPtr elem
) {
1359 if (elem
== NULL
) return;
1360 xmlUnlinkNode((xmlNodePtr
) elem
);
1361 xmlFreeDocElementContent(elem
->doc
, elem
->content
);
1362 if (elem
->name
!= NULL
)
1363 xmlFree((xmlChar
*) elem
->name
);
1364 if (elem
->prefix
!= NULL
)
1365 xmlFree((xmlChar
*) elem
->prefix
);
1366 #ifdef LIBXML_REGEXP_ENABLED
1367 if (elem
->contModel
!= NULL
)
1368 xmlRegFreeRegexp(elem
->contModel
);
1375 * xmlAddElementDecl:
1376 * @ctxt: the validation context
1377 * @dtd: pointer to the DTD
1378 * @name: the entity name
1379 * @type: the element type
1380 * @content: the element content tree or NULL
1382 * Register a new element declaration
1384 * Returns NULL if not, otherwise the entity
1387 xmlAddElementDecl(xmlValidCtxtPtr ctxt
,
1388 xmlDtdPtr dtd
, const xmlChar
*name
,
1389 xmlElementTypeVal type
,
1390 xmlElementContentPtr content
) {
1392 xmlElementTablePtr table
;
1393 xmlAttributePtr oldAttributes
= NULL
;
1394 xmlChar
*ns
, *uqname
;
1404 case XML_ELEMENT_TYPE_EMPTY
:
1405 if (content
!= NULL
) {
1406 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1407 "xmlAddElementDecl: content != NULL for EMPTY\n",
1412 case XML_ELEMENT_TYPE_ANY
:
1413 if (content
!= NULL
) {
1414 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1415 "xmlAddElementDecl: content != NULL for ANY\n",
1420 case XML_ELEMENT_TYPE_MIXED
:
1421 if (content
== NULL
) {
1422 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1423 "xmlAddElementDecl: content == NULL for MIXED\n",
1428 case XML_ELEMENT_TYPE_ELEMENT
:
1429 if (content
== NULL
) {
1430 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1431 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1437 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1438 "Internal: ELEMENT decl corrupted invalid type\n",
1444 * check if name is a QName
1446 uqname
= xmlSplitQName2(name
, &ns
);
1451 * Create the Element table if needed.
1453 table
= (xmlElementTablePtr
) dtd
->elements
;
1454 if (table
== NULL
) {
1455 xmlDictPtr dict
= NULL
;
1457 if (dtd
->doc
!= NULL
)
1458 dict
= dtd
->doc
->dict
;
1459 table
= xmlHashCreateDict(0, dict
);
1460 dtd
->elements
= (void *) table
;
1462 if (table
== NULL
) {
1464 "xmlAddElementDecl: Table creation failed!\n");
1473 * lookup old attributes inserted on an undefined element in the
1476 if ((dtd
->doc
!= NULL
) && (dtd
->doc
->intSubset
!= NULL
)) {
1477 ret
= xmlHashLookup2(dtd
->doc
->intSubset
->elements
, name
, ns
);
1478 if ((ret
!= NULL
) && (ret
->etype
== XML_ELEMENT_TYPE_UNDEFINED
)) {
1479 oldAttributes
= ret
->attributes
;
1480 ret
->attributes
= NULL
;
1481 xmlHashRemoveEntry2(dtd
->doc
->intSubset
->elements
, name
, ns
, NULL
);
1482 xmlFreeElement(ret
);
1487 * The element may already be present if one of its attribute
1488 * was registered first
1490 ret
= xmlHashLookup2(table
, name
, ns
);
1492 if (ret
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
) {
1493 #ifdef LIBXML_VALID_ENABLED
1495 * The element is already defined in this DTD.
1497 xmlErrValidNode(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_ELEM_REDEFINED
,
1498 "Redefinition of element %s\n",
1500 #endif /* LIBXML_VALID_ENABLED */
1512 ret
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
1514 xmlVErrMemory(ctxt
, "malloc failed");
1521 memset(ret
, 0, sizeof(xmlElement
));
1522 ret
->type
= XML_ELEMENT_DECL
;
1525 * fill the structure.
1527 ret
->name
= xmlStrdup(name
);
1528 if (ret
->name
== NULL
) {
1529 xmlVErrMemory(ctxt
, "malloc failed");
1541 * Insertion must not fail
1543 if (xmlHashAddEntry2(table
, name
, ns
, ret
)) {
1544 #ifdef LIBXML_VALID_ENABLED
1546 * The element is already defined in this DTD.
1548 xmlErrValidNode(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_ELEM_REDEFINED
,
1549 "Redefinition of element %s\n",
1551 #endif /* LIBXML_VALID_ENABLED */
1552 xmlFreeElement(ret
);
1558 * For new element, may have attributes from earlier
1559 * definition in internal subset
1561 ret
->attributes
= oldAttributes
;
1565 * Finish to fill the structure.
1569 * Avoid a stupid copy when called by the parser
1570 * and flag it by setting a special parent value
1571 * so the parser doesn't unallocate it.
1573 if ((ctxt
!= NULL
) &&
1574 ((ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_0
) ||
1575 (ctxt
->finishDtd
== XML_CTXT_FINISH_DTD_1
))) {
1576 ret
->content
= content
;
1577 if (content
!= NULL
)
1578 content
->parent
= (xmlElementContentPtr
) 1;
1580 ret
->content
= xmlCopyDocElementContent(dtd
->doc
, content
);
1584 * Link it to the DTD
1587 ret
->doc
= dtd
->doc
;
1588 if (dtd
->last
== NULL
) {
1589 dtd
->children
= dtd
->last
= (xmlNodePtr
) ret
;
1591 dtd
->last
->next
= (xmlNodePtr
) ret
;
1592 ret
->prev
= dtd
->last
;
1593 dtd
->last
= (xmlNodePtr
) ret
;
1601 xmlFreeElementTableEntry(void *elem
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
1602 xmlFreeElement((xmlElementPtr
) elem
);
1606 * xmlFreeElementTable:
1607 * @table: An element table
1609 * Deallocate the memory used by an element hash table.
1612 xmlFreeElementTable(xmlElementTablePtr table
) {
1613 xmlHashFree(table
, xmlFreeElementTableEntry
);
1616 #ifdef LIBXML_TREE_ENABLED
1621 * Build a copy of an element.
1623 * Returns the new xmlElementPtr or NULL in case of error.
1626 xmlCopyElement(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
1627 xmlElementPtr elem
= (xmlElementPtr
) payload
;
1630 cur
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
1632 xmlVErrMemory(NULL
, "malloc failed");
1635 memset(cur
, 0, sizeof(xmlElement
));
1636 cur
->type
= XML_ELEMENT_DECL
;
1637 cur
->etype
= elem
->etype
;
1638 if (elem
->name
!= NULL
)
1639 cur
->name
= xmlStrdup(elem
->name
);
1642 if (elem
->prefix
!= NULL
)
1643 cur
->prefix
= xmlStrdup(elem
->prefix
);
1646 cur
->content
= xmlCopyElementContent(elem
->content
);
1647 /* TODO : rebuild the attribute list on the copy */
1648 cur
->attributes
= NULL
;
1653 * xmlCopyElementTable:
1654 * @table: An element table
1656 * Build a copy of an element table.
1658 * Returns the new xmlElementTablePtr or NULL in case of error.
1661 xmlCopyElementTable(xmlElementTablePtr table
) {
1662 return((xmlElementTablePtr
) xmlHashCopy(table
, xmlCopyElement
));
1664 #endif /* LIBXML_TREE_ENABLED */
1666 #ifdef LIBXML_OUTPUT_ENABLED
1668 * xmlDumpElementDecl:
1669 * @buf: the XML buffer output
1670 * @elem: An element table
1672 * This will dump the content of the element declaration as an XML
1676 xmlDumpElementDecl(xmlBufferPtr buf
, xmlElementPtr elem
) {
1677 if ((buf
== NULL
) || (elem
== NULL
))
1679 switch (elem
->etype
) {
1680 case XML_ELEMENT_TYPE_EMPTY
:
1681 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1682 if (elem
->prefix
!= NULL
) {
1683 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1684 xmlBufferWriteChar(buf
, ":");
1686 xmlBufferWriteCHAR(buf
, elem
->name
);
1687 xmlBufferWriteChar(buf
, " EMPTY>\n");
1689 case XML_ELEMENT_TYPE_ANY
:
1690 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1691 if (elem
->prefix
!= NULL
) {
1692 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1693 xmlBufferWriteChar(buf
, ":");
1695 xmlBufferWriteCHAR(buf
, elem
->name
);
1696 xmlBufferWriteChar(buf
, " ANY>\n");
1698 case XML_ELEMENT_TYPE_MIXED
:
1699 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1700 if (elem
->prefix
!= NULL
) {
1701 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1702 xmlBufferWriteChar(buf
, ":");
1704 xmlBufferWriteCHAR(buf
, elem
->name
);
1705 xmlBufferWriteChar(buf
, " ");
1706 xmlDumpElementContent(buf
, elem
->content
, 1);
1707 xmlBufferWriteChar(buf
, ">\n");
1709 case XML_ELEMENT_TYPE_ELEMENT
:
1710 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1711 if (elem
->prefix
!= NULL
) {
1712 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1713 xmlBufferWriteChar(buf
, ":");
1715 xmlBufferWriteCHAR(buf
, elem
->name
);
1716 xmlBufferWriteChar(buf
, " ");
1717 xmlDumpElementContent(buf
, elem
->content
, 1);
1718 xmlBufferWriteChar(buf
, ">\n");
1721 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
1722 "Internal: ELEMENT struct corrupted invalid type\n",
1728 * xmlDumpElementDeclScan:
1729 * @elem: An element table
1730 * @buf: the XML buffer output
1732 * This routine is used by the hash scan function. It just reverses
1736 xmlDumpElementDeclScan(void *elem
, void *buf
,
1737 const xmlChar
*name ATTRIBUTE_UNUSED
) {
1738 xmlDumpElementDecl((xmlBufferPtr
) buf
, (xmlElementPtr
) elem
);
1742 * xmlDumpElementTable:
1743 * @buf: the XML buffer output
1744 * @table: An element table
1746 * This will dump the content of the element table as an XML DTD definition
1749 xmlDumpElementTable(xmlBufferPtr buf
, xmlElementTablePtr table
) {
1750 if ((buf
== NULL
) || (table
== NULL
))
1752 xmlHashScan(table
, xmlDumpElementDeclScan
, buf
);
1754 #endif /* LIBXML_OUTPUT_ENABLED */
1757 * xmlCreateEnumeration:
1758 * @name: the enumeration name or NULL
1760 * create and initialize an enumeration attribute node.
1762 * Returns the xmlEnumerationPtr just created or NULL in case
1766 xmlCreateEnumeration(const xmlChar
*name
) {
1767 xmlEnumerationPtr ret
;
1769 ret
= (xmlEnumerationPtr
) xmlMalloc(sizeof(xmlEnumeration
));
1771 xmlVErrMemory(NULL
, "malloc failed");
1774 memset(ret
, 0, sizeof(xmlEnumeration
));
1777 ret
->name
= xmlStrdup(name
);
1782 * xmlFreeEnumeration:
1783 * @cur: the tree to free.
1785 * free an enumeration attribute node (recursive).
1788 xmlFreeEnumeration(xmlEnumerationPtr cur
) {
1789 if (cur
== NULL
) return;
1791 if (cur
->next
!= NULL
) xmlFreeEnumeration(cur
->next
);
1793 if (cur
->name
!= NULL
) xmlFree((xmlChar
*) cur
->name
);
1797 #ifdef LIBXML_TREE_ENABLED
1799 * xmlCopyEnumeration:
1800 * @cur: the tree to copy.
1802 * Copy an enumeration attribute node (recursive).
1804 * Returns the xmlEnumerationPtr just created or NULL in case
1808 xmlCopyEnumeration(xmlEnumerationPtr cur
) {
1809 xmlEnumerationPtr ret
;
1811 if (cur
== NULL
) return(NULL
);
1812 ret
= xmlCreateEnumeration((xmlChar
*) cur
->name
);
1813 if (ret
== NULL
) return(NULL
);
1815 if (cur
->next
!= NULL
) ret
->next
= xmlCopyEnumeration(cur
->next
);
1816 else ret
->next
= NULL
;
1820 #endif /* LIBXML_TREE_ENABLED */
1822 #ifdef LIBXML_OUTPUT_ENABLED
1824 * xmlDumpEnumeration:
1825 * @buf: the XML buffer output
1826 * @enum: An enumeration
1828 * This will dump the content of the enumeration
1831 xmlDumpEnumeration(xmlBufferPtr buf
, xmlEnumerationPtr cur
) {
1832 if ((buf
== NULL
) || (cur
== NULL
))
1835 xmlBufferWriteCHAR(buf
, cur
->name
);
1836 if (cur
->next
== NULL
)
1837 xmlBufferWriteChar(buf
, ")");
1839 xmlBufferWriteChar(buf
, " | ");
1840 xmlDumpEnumeration(buf
, cur
->next
);
1843 #endif /* LIBXML_OUTPUT_ENABLED */
1845 #ifdef LIBXML_VALID_ENABLED
1847 * xmlScanIDAttributeDecl:
1848 * @ctxt: the validation context
1849 * @elem: the element name
1850 * @err: whether to raise errors here
1852 * Verify that the element don't have too many ID attributes
1855 * Returns the number of ID attributes found.
1858 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt
, xmlElementPtr elem
, int err
) {
1859 xmlAttributePtr cur
;
1862 if (elem
== NULL
) return(0);
1863 cur
= elem
->attributes
;
1864 while (cur
!= NULL
) {
1865 if (cur
->atype
== XML_ATTRIBUTE_ID
) {
1867 if ((ret
> 1) && (err
))
1868 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_MULTIPLE_ID
,
1869 "Element %s has too many ID attributes defined : %s\n",
1870 elem
->name
, cur
->name
, NULL
);
1876 #endif /* LIBXML_VALID_ENABLED */
1880 * @elem: An attribute
1882 * Deallocate the memory used by an attribute definition
1885 xmlFreeAttribute(xmlAttributePtr attr
) {
1888 if (attr
== NULL
) return;
1889 if (attr
->doc
!= NULL
)
1890 dict
= attr
->doc
->dict
;
1893 xmlUnlinkNode((xmlNodePtr
) attr
);
1894 if (attr
->tree
!= NULL
)
1895 xmlFreeEnumeration(attr
->tree
);
1897 if ((attr
->elem
!= NULL
) && (!xmlDictOwns(dict
, attr
->elem
)))
1898 xmlFree((xmlChar
*) attr
->elem
);
1899 if ((attr
->name
!= NULL
) && (!xmlDictOwns(dict
, attr
->name
)))
1900 xmlFree((xmlChar
*) attr
->name
);
1901 if ((attr
->prefix
!= NULL
) && (!xmlDictOwns(dict
, attr
->prefix
)))
1902 xmlFree((xmlChar
*) attr
->prefix
);
1903 if ((attr
->defaultValue
!= NULL
) &&
1904 (!xmlDictOwns(dict
, attr
->defaultValue
)))
1905 xmlFree((xmlChar
*) attr
->defaultValue
);
1907 if (attr
->elem
!= NULL
)
1908 xmlFree((xmlChar
*) attr
->elem
);
1909 if (attr
->name
!= NULL
)
1910 xmlFree((xmlChar
*) attr
->name
);
1911 if (attr
->defaultValue
!= NULL
)
1912 xmlFree((xmlChar
*) attr
->defaultValue
);
1913 if (attr
->prefix
!= NULL
)
1914 xmlFree((xmlChar
*) attr
->prefix
);
1921 * xmlAddAttributeDecl:
1922 * @ctxt: the validation context
1923 * @dtd: pointer to the DTD
1924 * @elem: the element name
1925 * @name: the attribute name
1926 * @ns: the attribute namespace prefix
1927 * @type: the attribute type
1928 * @def: the attribute default type
1929 * @defaultValue: the attribute default value
1930 * @tree: if it's an enumeration, the associated list
1932 * Register a new attribute declaration
1933 * Note that @tree becomes the ownership of the DTD
1935 * Returns NULL if not new, otherwise the attribute decl
1938 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt
,
1939 xmlDtdPtr dtd
, const xmlChar
*elem
,
1940 const xmlChar
*name
, const xmlChar
*ns
,
1941 xmlAttributeType type
, xmlAttributeDefault def
,
1942 const xmlChar
*defaultValue
, xmlEnumerationPtr tree
) {
1943 xmlAttributePtr ret
;
1944 xmlAttributeTablePtr table
;
1945 xmlElementPtr elemDef
;
1946 xmlDictPtr dict
= NULL
;
1949 xmlFreeEnumeration(tree
);
1953 xmlFreeEnumeration(tree
);
1957 xmlFreeEnumeration(tree
);
1960 if (dtd
->doc
!= NULL
)
1961 dict
= dtd
->doc
->dict
;
1963 #ifdef LIBXML_VALID_ENABLED
1965 * Check the type and possibly the default value.
1968 case XML_ATTRIBUTE_CDATA
:
1970 case XML_ATTRIBUTE_ID
:
1972 case XML_ATTRIBUTE_IDREF
:
1974 case XML_ATTRIBUTE_IDREFS
:
1976 case XML_ATTRIBUTE_ENTITY
:
1978 case XML_ATTRIBUTE_ENTITIES
:
1980 case XML_ATTRIBUTE_NMTOKEN
:
1982 case XML_ATTRIBUTE_NMTOKENS
:
1984 case XML_ATTRIBUTE_ENUMERATION
:
1986 case XML_ATTRIBUTE_NOTATION
:
1989 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1990 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1992 xmlFreeEnumeration(tree
);
1995 if ((defaultValue
!= NULL
) &&
1996 (!xmlValidateAttributeValueInternal(dtd
->doc
, type
, defaultValue
))) {
1997 xmlErrValidNode(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_ATTRIBUTE_DEFAULT
,
1998 "Attribute %s of %s: invalid default value\n",
1999 elem
, name
, defaultValue
);
2000 defaultValue
= NULL
;
2004 #endif /* LIBXML_VALID_ENABLED */
2007 * Check first that an attribute defined in the external subset wasn't
2008 * already defined in the internal subset
2010 if ((dtd
->doc
!= NULL
) && (dtd
->doc
->extSubset
== dtd
) &&
2011 (dtd
->doc
->intSubset
!= NULL
) &&
2012 (dtd
->doc
->intSubset
->attributes
!= NULL
)) {
2013 ret
= xmlHashLookup3(dtd
->doc
->intSubset
->attributes
, name
, ns
, elem
);
2015 xmlFreeEnumeration(tree
);
2021 * Create the Attribute table if needed.
2023 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
2024 if (table
== NULL
) {
2025 table
= xmlHashCreateDict(0, dict
);
2026 dtd
->attributes
= (void *) table
;
2028 if (table
== NULL
) {
2030 "xmlAddAttributeDecl: Table creation failed!\n");
2031 xmlFreeEnumeration(tree
);
2036 ret
= (xmlAttributePtr
) xmlMalloc(sizeof(xmlAttribute
));
2038 xmlVErrMemory(ctxt
, "malloc failed");
2039 xmlFreeEnumeration(tree
);
2042 memset(ret
, 0, sizeof(xmlAttribute
));
2043 ret
->type
= XML_ATTRIBUTE_DECL
;
2046 * fill the structure.
2050 * doc must be set before possible error causes call
2051 * to xmlFreeAttribute (because it's used to check on
2054 ret
->doc
= dtd
->doc
;
2056 ret
->name
= xmlDictLookup(dict
, name
, -1);
2057 ret
->prefix
= xmlDictLookup(dict
, ns
, -1);
2058 ret
->elem
= xmlDictLookup(dict
, elem
, -1);
2060 ret
->name
= xmlStrdup(name
);
2061 ret
->prefix
= xmlStrdup(ns
);
2062 ret
->elem
= xmlStrdup(elem
);
2066 if (defaultValue
!= NULL
) {
2068 ret
->defaultValue
= xmlDictLookup(dict
, defaultValue
, -1);
2070 ret
->defaultValue
= xmlStrdup(defaultValue
);
2075 * Search the DTD for previous declarations of the ATTLIST
2077 if (xmlHashAddEntry3(table
, ret
->name
, ret
->prefix
, ret
->elem
, ret
) < 0) {
2078 #ifdef LIBXML_VALID_ENABLED
2080 * The attribute is already defined in this DTD.
2082 xmlErrValidWarning(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_ATTRIBUTE_REDEFINED
,
2083 "Attribute %s of element %s: already defined\n",
2085 #endif /* LIBXML_VALID_ENABLED */
2086 xmlFreeAttribute(ret
);
2092 * Multiple ID per element
2094 elemDef
= xmlGetDtdElementDesc2(dtd
, elem
, 1);
2095 if (elemDef
!= NULL
) {
2097 #ifdef LIBXML_VALID_ENABLED
2098 if ((type
== XML_ATTRIBUTE_ID
) &&
2099 (xmlScanIDAttributeDecl(NULL
, elemDef
, 1) != 0)) {
2100 xmlErrValidNode(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_MULTIPLE_ID
,
2101 "Element %s has too may ID attributes defined : %s\n",
2106 #endif /* LIBXML_VALID_ENABLED */
2109 * Insert namespace default def first they need to be
2112 if ((xmlStrEqual(ret
->name
, BAD_CAST
"xmlns")) ||
2113 ((ret
->prefix
!= NULL
&&
2114 (xmlStrEqual(ret
->prefix
, BAD_CAST
"xmlns"))))) {
2115 ret
->nexth
= elemDef
->attributes
;
2116 elemDef
->attributes
= ret
;
2118 xmlAttributePtr tmp
= elemDef
->attributes
;
2120 while ((tmp
!= NULL
) &&
2121 ((xmlStrEqual(tmp
->name
, BAD_CAST
"xmlns")) ||
2122 ((ret
->prefix
!= NULL
&&
2123 (xmlStrEqual(ret
->prefix
, BAD_CAST
"xmlns")))))) {
2124 if (tmp
->nexth
== NULL
)
2129 ret
->nexth
= tmp
->nexth
;
2132 ret
->nexth
= elemDef
->attributes
;
2133 elemDef
->attributes
= ret
;
2139 * Link it to the DTD
2142 if (dtd
->last
== NULL
) {
2143 dtd
->children
= dtd
->last
= (xmlNodePtr
) ret
;
2145 dtd
->last
->next
= (xmlNodePtr
) ret
;
2146 ret
->prev
= dtd
->last
;
2147 dtd
->last
= (xmlNodePtr
) ret
;
2153 xmlFreeAttributeTableEntry(void *attr
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2154 xmlFreeAttribute((xmlAttributePtr
) attr
);
2158 * xmlFreeAttributeTable:
2159 * @table: An attribute table
2161 * Deallocate the memory used by an entities hash table.
2164 xmlFreeAttributeTable(xmlAttributeTablePtr table
) {
2165 xmlHashFree(table
, xmlFreeAttributeTableEntry
);
2168 #ifdef LIBXML_TREE_ENABLED
2171 * @attr: An attribute
2173 * Build a copy of an attribute.
2175 * Returns the new xmlAttributePtr or NULL in case of error.
2178 xmlCopyAttribute(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2179 xmlAttributePtr attr
= (xmlAttributePtr
) payload
;
2180 xmlAttributePtr cur
;
2182 cur
= (xmlAttributePtr
) xmlMalloc(sizeof(xmlAttribute
));
2184 xmlVErrMemory(NULL
, "malloc failed");
2187 memset(cur
, 0, sizeof(xmlAttribute
));
2188 cur
->type
= XML_ATTRIBUTE_DECL
;
2189 cur
->atype
= attr
->atype
;
2190 cur
->def
= attr
->def
;
2191 cur
->tree
= xmlCopyEnumeration(attr
->tree
);
2192 if (attr
->elem
!= NULL
)
2193 cur
->elem
= xmlStrdup(attr
->elem
);
2194 if (attr
->name
!= NULL
)
2195 cur
->name
= xmlStrdup(attr
->name
);
2196 if (attr
->prefix
!= NULL
)
2197 cur
->prefix
= xmlStrdup(attr
->prefix
);
2198 if (attr
->defaultValue
!= NULL
)
2199 cur
->defaultValue
= xmlStrdup(attr
->defaultValue
);
2204 * xmlCopyAttributeTable:
2205 * @table: An attribute table
2207 * Build a copy of an attribute table.
2209 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2211 xmlAttributeTablePtr
2212 xmlCopyAttributeTable(xmlAttributeTablePtr table
) {
2213 return((xmlAttributeTablePtr
) xmlHashCopy(table
, xmlCopyAttribute
));
2215 #endif /* LIBXML_TREE_ENABLED */
2217 #ifdef LIBXML_OUTPUT_ENABLED
2219 * xmlDumpAttributeDecl:
2220 * @buf: the XML buffer output
2221 * @attr: An attribute declaration
2223 * This will dump the content of the attribute declaration as an XML
2227 xmlDumpAttributeDecl(xmlBufferPtr buf
, xmlAttributePtr attr
) {
2228 if ((buf
== NULL
) || (attr
== NULL
))
2230 xmlBufferWriteChar(buf
, "<!ATTLIST ");
2231 xmlBufferWriteCHAR(buf
, attr
->elem
);
2232 xmlBufferWriteChar(buf
, " ");
2233 if (attr
->prefix
!= NULL
) {
2234 xmlBufferWriteCHAR(buf
, attr
->prefix
);
2235 xmlBufferWriteChar(buf
, ":");
2237 xmlBufferWriteCHAR(buf
, attr
->name
);
2238 switch (attr
->atype
) {
2239 case XML_ATTRIBUTE_CDATA
:
2240 xmlBufferWriteChar(buf
, " CDATA");
2242 case XML_ATTRIBUTE_ID
:
2243 xmlBufferWriteChar(buf
, " ID");
2245 case XML_ATTRIBUTE_IDREF
:
2246 xmlBufferWriteChar(buf
, " IDREF");
2248 case XML_ATTRIBUTE_IDREFS
:
2249 xmlBufferWriteChar(buf
, " IDREFS");
2251 case XML_ATTRIBUTE_ENTITY
:
2252 xmlBufferWriteChar(buf
, " ENTITY");
2254 case XML_ATTRIBUTE_ENTITIES
:
2255 xmlBufferWriteChar(buf
, " ENTITIES");
2257 case XML_ATTRIBUTE_NMTOKEN
:
2258 xmlBufferWriteChar(buf
, " NMTOKEN");
2260 case XML_ATTRIBUTE_NMTOKENS
:
2261 xmlBufferWriteChar(buf
, " NMTOKENS");
2263 case XML_ATTRIBUTE_ENUMERATION
:
2264 xmlBufferWriteChar(buf
, " (");
2265 xmlDumpEnumeration(buf
, attr
->tree
);
2267 case XML_ATTRIBUTE_NOTATION
:
2268 xmlBufferWriteChar(buf
, " NOTATION (");
2269 xmlDumpEnumeration(buf
, attr
->tree
);
2272 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
2273 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2276 switch (attr
->def
) {
2277 case XML_ATTRIBUTE_NONE
:
2279 case XML_ATTRIBUTE_REQUIRED
:
2280 xmlBufferWriteChar(buf
, " #REQUIRED");
2282 case XML_ATTRIBUTE_IMPLIED
:
2283 xmlBufferWriteChar(buf
, " #IMPLIED");
2285 case XML_ATTRIBUTE_FIXED
:
2286 xmlBufferWriteChar(buf
, " #FIXED");
2289 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
2290 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2293 if (attr
->defaultValue
!= NULL
) {
2294 xmlBufferWriteChar(buf
, " ");
2295 xmlBufferWriteQuotedString(buf
, attr
->defaultValue
);
2297 xmlBufferWriteChar(buf
, ">\n");
2301 * xmlDumpAttributeDeclScan:
2302 * @attr: An attribute declaration
2303 * @buf: the XML buffer output
2305 * This is used with the hash scan function - just reverses arguments
2308 xmlDumpAttributeDeclScan(void *attr
, void *buf
,
2309 const xmlChar
*name ATTRIBUTE_UNUSED
) {
2310 xmlDumpAttributeDecl((xmlBufferPtr
) buf
, (xmlAttributePtr
) attr
);
2314 * xmlDumpAttributeTable:
2315 * @buf: the XML buffer output
2316 * @table: An attribute table
2318 * This will dump the content of the attribute table as an XML DTD definition
2321 xmlDumpAttributeTable(xmlBufferPtr buf
, xmlAttributeTablePtr table
) {
2322 if ((buf
== NULL
) || (table
== NULL
))
2324 xmlHashScan(table
, xmlDumpAttributeDeclScan
, buf
);
2326 #endif /* LIBXML_OUTPUT_ENABLED */
2328 /************************************************************************
2332 ************************************************************************/
2337 * Deallocate the memory used by an notation definition
2340 xmlFreeNotation(xmlNotationPtr nota
) {
2341 if (nota
== NULL
) return;
2342 if (nota
->name
!= NULL
)
2343 xmlFree((xmlChar
*) nota
->name
);
2344 if (nota
->PublicID
!= NULL
)
2345 xmlFree((xmlChar
*) nota
->PublicID
);
2346 if (nota
->SystemID
!= NULL
)
2347 xmlFree((xmlChar
*) nota
->SystemID
);
2353 * xmlAddNotationDecl:
2354 * @dtd: pointer to the DTD
2355 * @ctxt: the validation context
2356 * @name: the entity name
2357 * @PublicID: the public identifier or NULL
2358 * @SystemID: the system identifier or NULL
2360 * Register a new notation declaration
2362 * Returns NULL if not, otherwise the entity
2365 xmlAddNotationDecl(xmlValidCtxtPtr ctxt
, xmlDtdPtr dtd
,
2366 const xmlChar
*name
,
2367 const xmlChar
*PublicID
, const xmlChar
*SystemID
) {
2369 xmlNotationTablePtr table
;
2377 if ((PublicID
== NULL
) && (SystemID
== NULL
)) {
2382 * Create the Notation table if needed.
2384 table
= (xmlNotationTablePtr
) dtd
->notations
;
2385 if (table
== NULL
) {
2386 xmlDictPtr dict
= NULL
;
2387 if (dtd
->doc
!= NULL
)
2388 dict
= dtd
->doc
->dict
;
2390 dtd
->notations
= table
= xmlHashCreateDict(0, dict
);
2392 if (table
== NULL
) {
2394 "xmlAddNotationDecl: Table creation failed!\n");
2398 ret
= (xmlNotationPtr
) xmlMalloc(sizeof(xmlNotation
));
2400 xmlVErrMemory(ctxt
, "malloc failed");
2403 memset(ret
, 0, sizeof(xmlNotation
));
2406 * fill the structure.
2408 ret
->name
= xmlStrdup(name
);
2409 if (SystemID
!= NULL
)
2410 ret
->SystemID
= xmlStrdup(SystemID
);
2411 if (PublicID
!= NULL
)
2412 ret
->PublicID
= xmlStrdup(PublicID
);
2416 * Check the DTD for previous declarations of the ATTLIST
2418 if (xmlHashAddEntry(table
, name
, ret
)) {
2419 #ifdef LIBXML_VALID_ENABLED
2420 xmlErrValid(NULL
, XML_DTD_NOTATION_REDEFINED
,
2421 "xmlAddNotationDecl: %s already defined\n",
2422 (const char *) name
);
2423 #endif /* LIBXML_VALID_ENABLED */
2424 xmlFreeNotation(ret
);
2431 xmlFreeNotationTableEntry(void *nota
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2432 xmlFreeNotation((xmlNotationPtr
) nota
);
2436 * xmlFreeNotationTable:
2437 * @table: An notation table
2439 * Deallocate the memory used by an entities hash table.
2442 xmlFreeNotationTable(xmlNotationTablePtr table
) {
2443 xmlHashFree(table
, xmlFreeNotationTableEntry
);
2446 #ifdef LIBXML_TREE_ENABLED
2451 * Build a copy of a notation.
2453 * Returns the new xmlNotationPtr or NULL in case of error.
2456 xmlCopyNotation(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2457 xmlNotationPtr nota
= (xmlNotationPtr
) payload
;
2460 cur
= (xmlNotationPtr
) xmlMalloc(sizeof(xmlNotation
));
2462 xmlVErrMemory(NULL
, "malloc failed");
2465 if (nota
->name
!= NULL
)
2466 cur
->name
= xmlStrdup(nota
->name
);
2469 if (nota
->PublicID
!= NULL
)
2470 cur
->PublicID
= xmlStrdup(nota
->PublicID
);
2472 cur
->PublicID
= NULL
;
2473 if (nota
->SystemID
!= NULL
)
2474 cur
->SystemID
= xmlStrdup(nota
->SystemID
);
2476 cur
->SystemID
= NULL
;
2481 * xmlCopyNotationTable:
2482 * @table: A notation table
2484 * Build a copy of a notation table.
2486 * Returns the new xmlNotationTablePtr or NULL in case of error.
2489 xmlCopyNotationTable(xmlNotationTablePtr table
) {
2490 return((xmlNotationTablePtr
) xmlHashCopy(table
, xmlCopyNotation
));
2492 #endif /* LIBXML_TREE_ENABLED */
2494 #ifdef LIBXML_OUTPUT_ENABLED
2496 * xmlDumpNotationDecl:
2497 * @buf: the XML buffer output
2498 * @nota: A notation declaration
2500 * This will dump the content the notation declaration as an XML DTD definition
2503 xmlDumpNotationDecl(xmlBufferPtr buf
, xmlNotationPtr nota
) {
2504 if ((buf
== NULL
) || (nota
== NULL
))
2506 xmlBufferWriteChar(buf
, "<!NOTATION ");
2507 xmlBufferWriteCHAR(buf
, nota
->name
);
2508 if (nota
->PublicID
!= NULL
) {
2509 xmlBufferWriteChar(buf
, " PUBLIC ");
2510 xmlBufferWriteQuotedString(buf
, nota
->PublicID
);
2511 if (nota
->SystemID
!= NULL
) {
2512 xmlBufferWriteChar(buf
, " ");
2513 xmlBufferWriteQuotedString(buf
, nota
->SystemID
);
2516 xmlBufferWriteChar(buf
, " SYSTEM ");
2517 xmlBufferWriteQuotedString(buf
, nota
->SystemID
);
2519 xmlBufferWriteChar(buf
, " >\n");
2523 * xmlDumpNotationDeclScan:
2524 * @nota: A notation declaration
2525 * @buf: the XML buffer output
2527 * This is called with the hash scan function, and just reverses args
2530 xmlDumpNotationDeclScan(void *nota
, void *buf
,
2531 const xmlChar
*name ATTRIBUTE_UNUSED
) {
2532 xmlDumpNotationDecl((xmlBufferPtr
) buf
, (xmlNotationPtr
) nota
);
2536 * xmlDumpNotationTable:
2537 * @buf: the XML buffer output
2538 * @table: A notation table
2540 * This will dump the content of the notation table as an XML DTD definition
2543 xmlDumpNotationTable(xmlBufferPtr buf
, xmlNotationTablePtr table
) {
2544 if ((buf
== NULL
) || (table
== NULL
))
2546 xmlHashScan(table
, xmlDumpNotationDeclScan
, buf
);
2548 #endif /* LIBXML_OUTPUT_ENABLED */
2550 /************************************************************************
2554 ************************************************************************/
2559 * Free a string if it is not owned by the "dict" dictionary in the
2562 #define DICT_FREE(str) \
2563 if ((str) && ((!dict) || \
2564 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2565 xmlFree((char *)(str));
2571 * Deallocate the memory used by an id definition
2574 xmlFreeID(xmlIDPtr id
) {
2575 xmlDictPtr dict
= NULL
;
2577 if (id
== NULL
) return;
2579 if (id
->doc
!= NULL
)
2580 dict
= id
->doc
->dict
;
2582 if (id
->value
!= NULL
)
2583 DICT_FREE(id
->value
)
2584 if (id
->name
!= NULL
)
2592 * @ctxt: the validation context
2593 * @doc: pointer to the document
2594 * @value: the value name
2595 * @attr: the attribute holding the ID
2597 * Register a new id declaration
2599 * Returns NULL if not, otherwise the new xmlIDPtr
2602 xmlAddID(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, const xmlChar
*value
,
2605 xmlIDTablePtr table
;
2610 if (value
== NULL
) {
2618 * Create the ID table if needed.
2620 table
= (xmlIDTablePtr
) doc
->ids
;
2621 if (table
== NULL
) {
2622 doc
->ids
= table
= xmlHashCreateDict(0, doc
->dict
);
2624 if (table
== NULL
) {
2626 "xmlAddID: Table creation failed!\n");
2630 ret
= (xmlIDPtr
) xmlMalloc(sizeof(xmlID
));
2632 xmlVErrMemory(ctxt
, "malloc failed");
2637 * fill the structure.
2639 ret
->value
= xmlStrdup(value
);
2641 if ((ctxt
!= NULL
) && (ctxt
->vstateNr
!= 0)) {
2643 * Operating in streaming mode, attr is gonna disapear
2645 if (doc
->dict
!= NULL
)
2646 ret
->name
= xmlDictLookup(doc
->dict
, attr
->name
, -1);
2648 ret
->name
= xmlStrdup(attr
->name
);
2654 ret
->lineno
= xmlGetLineNo(attr
->parent
);
2656 if (xmlHashAddEntry(table
, value
, ret
) < 0) {
2657 #ifdef LIBXML_VALID_ENABLED
2659 * The id is already defined in this DTD.
2662 xmlErrValidNode(ctxt
, attr
->parent
, XML_DTD_ID_REDEFINED
,
2663 "ID %s already defined\n", value
, NULL
, NULL
);
2665 #endif /* LIBXML_VALID_ENABLED */
2670 attr
->atype
= XML_ATTRIBUTE_ID
;
2675 xmlFreeIDTableEntry(void *id
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2676 xmlFreeID((xmlIDPtr
) id
);
2681 * @table: An id table
2683 * Deallocate the memory used by an ID hash table.
2686 xmlFreeIDTable(xmlIDTablePtr table
) {
2687 xmlHashFree(table
, xmlFreeIDTableEntry
);
2692 * @doc: the document
2693 * @elem: the element carrying the attribute
2694 * @attr: the attribute
2696 * Determine whether an attribute is of type ID. In case we have DTD(s)
2697 * then this is done if DTD loading has been requested. In the case
2698 * of HTML documents parsed with the HTML parser, then ID detection is
2699 * done systematically.
2701 * Returns 0 or 1 depending on the lookup result
2704 xmlIsID(xmlDocPtr doc
, xmlNodePtr elem
, xmlAttrPtr attr
) {
2705 if ((attr
== NULL
) || (attr
->name
== NULL
)) return(0);
2706 if ((attr
->ns
!= NULL
) && (attr
->ns
->prefix
!= NULL
) &&
2707 (!strcmp((char *) attr
->name
, "id")) &&
2708 (!strcmp((char *) attr
->ns
->prefix
, "xml")))
2710 if (doc
== NULL
) return(0);
2711 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
) &&
2712 (doc
->type
!= XML_HTML_DOCUMENT_NODE
)) {
2714 } else if (doc
->type
== XML_HTML_DOCUMENT_NODE
) {
2715 if ((xmlStrEqual(BAD_CAST
"id", attr
->name
)) ||
2716 ((xmlStrEqual(BAD_CAST
"name", attr
->name
)) &&
2717 ((elem
== NULL
) || (xmlStrEqual(elem
->name
, BAD_CAST
"a")))))
2720 } else if (elem
== NULL
) {
2723 xmlAttributePtr attrDecl
= NULL
;
2725 xmlChar felem
[50], fattr
[50];
2726 xmlChar
*fullelemname
, *fullattrname
;
2728 fullelemname
= (elem
->ns
!= NULL
&& elem
->ns
->prefix
!= NULL
) ?
2729 xmlBuildQName(elem
->name
, elem
->ns
->prefix
, felem
, 50) :
2730 (xmlChar
*)elem
->name
;
2732 fullattrname
= (attr
->ns
!= NULL
&& attr
->ns
->prefix
!= NULL
) ?
2733 xmlBuildQName(attr
->name
, attr
->ns
->prefix
, fattr
, 50) :
2734 (xmlChar
*)attr
->name
;
2736 if (fullelemname
!= NULL
&& fullattrname
!= NULL
) {
2737 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullelemname
,
2739 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
2740 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, fullelemname
,
2744 if ((fullattrname
!= fattr
) && (fullattrname
!= attr
->name
))
2745 xmlFree(fullattrname
);
2746 if ((fullelemname
!= felem
) && (fullelemname
!= elem
->name
))
2747 xmlFree(fullelemname
);
2749 if ((attrDecl
!= NULL
) && (attrDecl
->atype
== XML_ATTRIBUTE_ID
))
2757 * @doc: the document
2758 * @attr: the attribute
2760 * Remove the given attribute from the ID table maintained internally.
2762 * Returns -1 if the lookup failed and 0 otherwise
2765 xmlRemoveID(xmlDocPtr doc
, xmlAttrPtr attr
) {
2766 xmlIDTablePtr table
;
2770 if (doc
== NULL
) return(-1);
2771 if (attr
== NULL
) return(-1);
2773 table
= (xmlIDTablePtr
) doc
->ids
;
2777 ID
= xmlNodeListGetString(doc
, attr
->children
, 1);
2781 id
= xmlHashLookup(table
, ID
);
2782 if (id
== NULL
|| id
->attr
!= attr
) {
2787 xmlHashRemoveEntry(table
, ID
, xmlFreeIDTableEntry
);
2795 * @doc: pointer to the document
2798 * Search the attribute declaring the given ID
2800 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2803 xmlGetID(xmlDocPtr doc
, const xmlChar
*ID
) {
2804 xmlIDTablePtr table
;
2815 table
= (xmlIDTablePtr
) doc
->ids
;
2819 id
= xmlHashLookup(table
, ID
);
2822 if (id
->attr
== NULL
) {
2824 * We are operating on a stream, return a well known reference
2825 * since the attribute node doesn't exist anymore
2827 return((xmlAttrPtr
) doc
);
2832 /************************************************************************
2836 ************************************************************************/
2837 typedef struct xmlRemoveMemo_t
2843 typedef xmlRemoveMemo
*xmlRemoveMemoPtr
;
2845 typedef struct xmlValidateMemo_t
2847 xmlValidCtxtPtr ctxt
;
2848 const xmlChar
*name
;
2851 typedef xmlValidateMemo
*xmlValidateMemoPtr
;
2857 * Deallocate the memory used by a ref definition
2860 xmlFreeRef(xmlLinkPtr lk
) {
2861 xmlRefPtr ref
= (xmlRefPtr
)xmlLinkGetData(lk
);
2862 if (ref
== NULL
) return;
2863 if (ref
->value
!= NULL
)
2864 xmlFree((xmlChar
*)ref
->value
);
2865 if (ref
->name
!= NULL
)
2866 xmlFree((xmlChar
*)ref
->name
);
2871 * xmlFreeRefTableEntry:
2872 * @list_ref: A list of references.
2874 * Deallocate the memory used by a list of references
2877 xmlFreeRefTableEntry(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2878 xmlListPtr list_ref
= (xmlListPtr
) payload
;
2879 if (list_ref
== NULL
) return;
2880 xmlListDelete(list_ref
);
2885 * @data: Contents of current link
2886 * @user: Value supplied by the user
2888 * Returns 0 to abort the walk or 1 to continue
2891 xmlWalkRemoveRef(const void *data
, void *user
)
2893 xmlAttrPtr attr0
= ((xmlRefPtr
)data
)->attr
;
2894 xmlAttrPtr attr1
= ((xmlRemoveMemoPtr
)user
)->ap
;
2895 xmlListPtr ref_list
= ((xmlRemoveMemoPtr
)user
)->l
;
2897 if (attr0
== attr1
) { /* Matched: remove and terminate walk */
2898 xmlListRemoveFirst(ref_list
, (void *)data
);
2906 * @data0: Value supplied by the user
2907 * @data1: Value supplied by the user
2909 * Do nothing, return 0. Used to create unordered lists.
2912 xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED
,
2913 const void *data1 ATTRIBUTE_UNUSED
)
2920 * @ctxt: the validation context
2921 * @doc: pointer to the document
2922 * @value: the value name
2923 * @attr: the attribute holding the Ref
2925 * Register a new ref declaration
2927 * Returns NULL if not, otherwise the new xmlRefPtr
2930 xmlAddRef(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, const xmlChar
*value
,
2933 xmlRefTablePtr table
;
2934 xmlListPtr ref_list
;
2939 if (value
== NULL
) {
2947 * Create the Ref table if needed.
2949 table
= (xmlRefTablePtr
) doc
->refs
;
2950 if (table
== NULL
) {
2951 doc
->refs
= table
= xmlHashCreateDict(0, doc
->dict
);
2953 if (table
== NULL
) {
2955 "xmlAddRef: Table creation failed!\n");
2959 ret
= (xmlRefPtr
) xmlMalloc(sizeof(xmlRef
));
2961 xmlVErrMemory(ctxt
, "malloc failed");
2966 * fill the structure.
2968 ret
->value
= xmlStrdup(value
);
2969 if ((ctxt
!= NULL
) && (ctxt
->vstateNr
!= 0)) {
2971 * Operating in streaming mode, attr is gonna disapear
2973 ret
->name
= xmlStrdup(attr
->name
);
2979 ret
->lineno
= xmlGetLineNo(attr
->parent
);
2981 /* To add a reference :-
2982 * References are maintained as a list of references,
2983 * Lookup the entry, if no entry create new nodelist
2984 * Add the owning node to the NodeList
2988 if (NULL
== (ref_list
= xmlHashLookup(table
, value
))) {
2989 if (NULL
== (ref_list
= xmlListCreate(xmlFreeRef
, xmlDummyCompare
))) {
2990 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
2991 "xmlAddRef: Reference list creation failed!\n",
2995 if (xmlHashAddEntry(table
, value
, ref_list
) < 0) {
2996 xmlListDelete(ref_list
);
2997 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
2998 "xmlAddRef: Reference list insertion failed!\n",
3003 if (xmlListAppend(ref_list
, ret
) != 0) {
3004 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
3005 "xmlAddRef: Reference list insertion failed!\n",
3012 if (ret
->value
!= NULL
)
3013 xmlFree((char *)ret
->value
);
3014 if (ret
->name
!= NULL
)
3015 xmlFree((char *)ret
->name
);
3023 * @table: An ref table
3025 * Deallocate the memory used by an Ref hash table.
3028 xmlFreeRefTable(xmlRefTablePtr table
) {
3029 xmlHashFree(table
, xmlFreeRefTableEntry
);
3034 * @doc: the document
3035 * @elem: the element carrying the attribute
3036 * @attr: the attribute
3038 * Determine whether an attribute is of type Ref. In case we have DTD(s)
3039 * then this is simple, otherwise we use an heuristic: name Ref (upper
3042 * Returns 0 or 1 depending on the lookup result
3045 xmlIsRef(xmlDocPtr doc
, xmlNodePtr elem
, xmlAttrPtr attr
) {
3050 if (doc
== NULL
) return(0);
3053 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
)) {
3055 } else if (doc
->type
== XML_HTML_DOCUMENT_NODE
) {
3059 xmlAttributePtr attrDecl
;
3061 if (elem
== NULL
) return(0);
3062 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, attr
->name
);
3063 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3064 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
3065 elem
->name
, attr
->name
);
3067 if ((attrDecl
!= NULL
) &&
3068 (attrDecl
->atype
== XML_ATTRIBUTE_IDREF
||
3069 attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
))
3077 * @doc: the document
3078 * @attr: the attribute
3080 * Remove the given attribute from the Ref table maintained internally.
3082 * Returns -1 if the lookup failed and 0 otherwise
3085 xmlRemoveRef(xmlDocPtr doc
, xmlAttrPtr attr
) {
3086 xmlListPtr ref_list
;
3087 xmlRefTablePtr table
;
3089 xmlRemoveMemo target
;
3091 if (doc
== NULL
) return(-1);
3092 if (attr
== NULL
) return(-1);
3094 table
= (xmlRefTablePtr
) doc
->refs
;
3098 ID
= xmlNodeListGetString(doc
, attr
->children
, 1);
3102 ref_list
= xmlHashLookup(table
, ID
);
3103 if(ref_list
== NULL
) {
3108 /* At this point, ref_list refers to a list of references which
3109 * have the same key as the supplied attr. Our list of references
3110 * is ordered by reference address and we don't have that information
3111 * here to use when removing. We'll have to walk the list and
3112 * check for a matching attribute, when we find one stop the walk
3113 * and remove the entry.
3114 * The list is ordered by reference, so that means we don't have the
3115 * key. Passing the list and the reference to the walker means we
3116 * will have enough data to be able to remove the entry.
3118 target
.l
= ref_list
;
3121 /* Remove the supplied attr from our list */
3122 xmlListWalk(ref_list
, xmlWalkRemoveRef
, &target
);
3124 /*If the list is empty then remove the list entry in the hash */
3125 if (xmlListEmpty(ref_list
))
3126 xmlHashUpdateEntry(table
, ID
, NULL
, xmlFreeRefTableEntry
);
3133 * @doc: pointer to the document
3136 * Find the set of references for the supplied ID.
3138 * Returns NULL if not found, otherwise node set for the ID.
3141 xmlGetRefs(xmlDocPtr doc
, const xmlChar
*ID
) {
3142 xmlRefTablePtr table
;
3152 table
= (xmlRefTablePtr
) doc
->refs
;
3156 return (xmlHashLookup(table
, ID
));
3159 /************************************************************************
3161 * Routines for validity checking *
3163 ************************************************************************/
3166 * xmlGetDtdElementDesc:
3167 * @dtd: a pointer to the DtD to search
3168 * @name: the element name
3170 * Search the DTD for the description of this element
3172 * returns the xmlElementPtr if found or NULL
3176 xmlGetDtdElementDesc(xmlDtdPtr dtd
, const xmlChar
*name
) {
3177 xmlElementTablePtr table
;
3179 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
3181 if ((dtd
== NULL
) || (name
== NULL
)) return(NULL
);
3182 if (dtd
->elements
== NULL
)
3184 table
= (xmlElementTablePtr
) dtd
->elements
;
3186 uqname
= xmlSplitQName2(name
, &prefix
);
3189 cur
= xmlHashLookup2(table
, name
, prefix
);
3190 if (prefix
!= NULL
) xmlFree(prefix
);
3191 if (uqname
!= NULL
) xmlFree(uqname
);
3195 * xmlGetDtdElementDesc2:
3196 * @dtd: a pointer to the DtD to search
3197 * @name: the element name
3198 * @create: create an empty description if not found
3200 * Search the DTD for the description of this element
3202 * returns the xmlElementPtr if found or NULL
3205 static xmlElementPtr
3206 xmlGetDtdElementDesc2(xmlDtdPtr dtd
, const xmlChar
*name
, int create
) {
3207 xmlElementTablePtr table
;
3209 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
3211 if (dtd
== NULL
) return(NULL
);
3212 if (dtd
->elements
== NULL
) {
3213 xmlDictPtr dict
= NULL
;
3215 if (dtd
->doc
!= NULL
)
3216 dict
= dtd
->doc
->dict
;
3221 * Create the Element table if needed.
3223 table
= (xmlElementTablePtr
) dtd
->elements
;
3224 if (table
== NULL
) {
3225 table
= xmlHashCreateDict(0, dict
);
3226 dtd
->elements
= (void *) table
;
3228 if (table
== NULL
) {
3229 xmlVErrMemory(NULL
, "element table allocation failed");
3233 table
= (xmlElementTablePtr
) dtd
->elements
;
3235 uqname
= xmlSplitQName2(name
, &prefix
);
3238 cur
= xmlHashLookup2(table
, name
, prefix
);
3239 if ((cur
== NULL
) && (create
)) {
3240 cur
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
3242 xmlVErrMemory(NULL
, "malloc failed");
3245 memset(cur
, 0, sizeof(xmlElement
));
3246 cur
->type
= XML_ELEMENT_DECL
;
3249 * fill the structure.
3251 cur
->name
= xmlStrdup(name
);
3252 cur
->prefix
= xmlStrdup(prefix
);
3253 cur
->etype
= XML_ELEMENT_TYPE_UNDEFINED
;
3255 xmlHashAddEntry2(table
, name
, prefix
, cur
);
3257 if (prefix
!= NULL
) xmlFree(prefix
);
3258 if (uqname
!= NULL
) xmlFree(uqname
);
3263 * xmlGetDtdQElementDesc:
3264 * @dtd: a pointer to the DtD to search
3265 * @name: the element name
3266 * @prefix: the element namespace prefix
3268 * Search the DTD for the description of this element
3270 * returns the xmlElementPtr if found or NULL
3274 xmlGetDtdQElementDesc(xmlDtdPtr dtd
, const xmlChar
*name
,
3275 const xmlChar
*prefix
) {
3276 xmlElementTablePtr table
;
3278 if (dtd
== NULL
) return(NULL
);
3279 if (dtd
->elements
== NULL
) return(NULL
);
3280 table
= (xmlElementTablePtr
) dtd
->elements
;
3282 return(xmlHashLookup2(table
, name
, prefix
));
3286 * xmlGetDtdAttrDesc:
3287 * @dtd: a pointer to the DtD to search
3288 * @elem: the element name
3289 * @name: the attribute name
3291 * Search the DTD for the description of this attribute on
3294 * returns the xmlAttributePtr if found or NULL
3298 xmlGetDtdAttrDesc(xmlDtdPtr dtd
, const xmlChar
*elem
, const xmlChar
*name
) {
3299 xmlAttributeTablePtr table
;
3300 xmlAttributePtr cur
;
3301 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
3303 if (dtd
== NULL
) return(NULL
);
3304 if (dtd
->attributes
== NULL
) return(NULL
);
3306 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
3310 uqname
= xmlSplitQName2(name
, &prefix
);
3312 if (uqname
!= NULL
) {
3313 cur
= xmlHashLookup3(table
, uqname
, prefix
, elem
);
3314 if (prefix
!= NULL
) xmlFree(prefix
);
3315 if (uqname
!= NULL
) xmlFree(uqname
);
3317 cur
= xmlHashLookup3(table
, name
, NULL
, elem
);
3322 * xmlGetDtdQAttrDesc:
3323 * @dtd: a pointer to the DtD to search
3324 * @elem: the element name
3325 * @name: the attribute name
3326 * @prefix: the attribute namespace prefix
3328 * Search the DTD for the description of this qualified attribute on
3331 * returns the xmlAttributePtr if found or NULL
3335 xmlGetDtdQAttrDesc(xmlDtdPtr dtd
, const xmlChar
*elem
, const xmlChar
*name
,
3336 const xmlChar
*prefix
) {
3337 xmlAttributeTablePtr table
;
3339 if (dtd
== NULL
) return(NULL
);
3340 if (dtd
->attributes
== NULL
) return(NULL
);
3341 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
3343 return(xmlHashLookup3(table
, name
, prefix
, elem
));
3347 * xmlGetDtdNotationDesc:
3348 * @dtd: a pointer to the DtD to search
3349 * @name: the notation name
3351 * Search the DTD for the description of this notation
3353 * returns the xmlNotationPtr if found or NULL
3357 xmlGetDtdNotationDesc(xmlDtdPtr dtd
, const xmlChar
*name
) {
3358 xmlNotationTablePtr table
;
3360 if (dtd
== NULL
) return(NULL
);
3361 if (dtd
->notations
== NULL
) return(NULL
);
3362 table
= (xmlNotationTablePtr
) dtd
->notations
;
3364 return(xmlHashLookup(table
, name
));
3367 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3369 * xmlValidateNotationUse:
3370 * @ctxt: the validation context
3371 * @doc: the document
3372 * @notationName: the notation name to check
3374 * Validate that the given name match a notation declaration.
3375 * - [ VC: Notation Declared ]
3377 * returns 1 if valid or 0 otherwise
3381 xmlValidateNotationUse(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3382 const xmlChar
*notationName
) {
3383 xmlNotationPtr notaDecl
;
3384 if ((doc
== NULL
) || (doc
->intSubset
== NULL
) ||
3385 (notationName
== NULL
)) return(-1);
3387 notaDecl
= xmlGetDtdNotationDesc(doc
->intSubset
, notationName
);
3388 if ((notaDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3389 notaDecl
= xmlGetDtdNotationDesc(doc
->extSubset
, notationName
);
3391 if ((notaDecl
== NULL
) && (ctxt
!= NULL
)) {
3392 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
, XML_DTD_UNKNOWN_NOTATION
,
3393 "NOTATION %s is not declared\n",
3394 notationName
, NULL
, NULL
);
3399 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3402 * xmlIsMixedElement:
3403 * @doc: the document
3404 * @name: the element name
3406 * Search in the DtDs whether an element accept Mixed content (or ANY)
3407 * basically if it is supposed to accept text childs
3409 * returns 0 if no, 1 if yes, and -1 if no element description is available
3413 xmlIsMixedElement(xmlDocPtr doc
, const xmlChar
*name
) {
3414 xmlElementPtr elemDecl
;
3416 if ((doc
== NULL
) || (doc
->intSubset
== NULL
)) return(-1);
3418 elemDecl
= xmlGetDtdElementDesc(doc
->intSubset
, name
);
3419 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3420 elemDecl
= xmlGetDtdElementDesc(doc
->extSubset
, name
);
3421 if (elemDecl
== NULL
) return(-1);
3422 switch (elemDecl
->etype
) {
3423 case XML_ELEMENT_TYPE_UNDEFINED
:
3425 case XML_ELEMENT_TYPE_ELEMENT
:
3427 case XML_ELEMENT_TYPE_EMPTY
:
3429 * return 1 for EMPTY since we want VC error to pop up
3430 * on <empty> </empty> for example
3432 case XML_ELEMENT_TYPE_ANY
:
3433 case XML_ELEMENT_TYPE_MIXED
:
3439 #ifdef LIBXML_VALID_ENABLED
3442 xmlIsDocNameStartChar(xmlDocPtr doc
, int c
) {
3443 if ((doc
== NULL
) || (doc
->properties
& XML_DOC_OLD10
) == 0) {
3445 * Use the new checks of production [4] [4a] amd [5] of the
3446 * Update 5 of XML-1.0
3448 if (((c
>= 'a') && (c
<= 'z')) ||
3449 ((c
>= 'A') && (c
<= 'Z')) ||
3450 (c
== '_') || (c
== ':') ||
3451 ((c
>= 0xC0) && (c
<= 0xD6)) ||
3452 ((c
>= 0xD8) && (c
<= 0xF6)) ||
3453 ((c
>= 0xF8) && (c
<= 0x2FF)) ||
3454 ((c
>= 0x370) && (c
<= 0x37D)) ||
3455 ((c
>= 0x37F) && (c
<= 0x1FFF)) ||
3456 ((c
>= 0x200C) && (c
<= 0x200D)) ||
3457 ((c
>= 0x2070) && (c
<= 0x218F)) ||
3458 ((c
>= 0x2C00) && (c
<= 0x2FEF)) ||
3459 ((c
>= 0x3001) && (c
<= 0xD7FF)) ||
3460 ((c
>= 0xF900) && (c
<= 0xFDCF)) ||
3461 ((c
>= 0xFDF0) && (c
<= 0xFFFD)) ||
3462 ((c
>= 0x10000) && (c
<= 0xEFFFF)))
3465 if (IS_LETTER(c
) || (c
== '_') || (c
== ':'))
3472 xmlIsDocNameChar(xmlDocPtr doc
, int c
) {
3473 if ((doc
== NULL
) || (doc
->properties
& XML_DOC_OLD10
) == 0) {
3475 * Use the new checks of production [4] [4a] amd [5] of the
3476 * Update 5 of XML-1.0
3478 if (((c
>= 'a') && (c
<= 'z')) ||
3479 ((c
>= 'A') && (c
<= 'Z')) ||
3480 ((c
>= '0') && (c
<= '9')) || /* !start */
3481 (c
== '_') || (c
== ':') ||
3482 (c
== '-') || (c
== '.') || (c
== 0xB7) || /* !start */
3483 ((c
>= 0xC0) && (c
<= 0xD6)) ||
3484 ((c
>= 0xD8) && (c
<= 0xF6)) ||
3485 ((c
>= 0xF8) && (c
<= 0x2FF)) ||
3486 ((c
>= 0x300) && (c
<= 0x36F)) || /* !start */
3487 ((c
>= 0x370) && (c
<= 0x37D)) ||
3488 ((c
>= 0x37F) && (c
<= 0x1FFF)) ||
3489 ((c
>= 0x200C) && (c
<= 0x200D)) ||
3490 ((c
>= 0x203F) && (c
<= 0x2040)) || /* !start */
3491 ((c
>= 0x2070) && (c
<= 0x218F)) ||
3492 ((c
>= 0x2C00) && (c
<= 0x2FEF)) ||
3493 ((c
>= 0x3001) && (c
<= 0xD7FF)) ||
3494 ((c
>= 0xF900) && (c
<= 0xFDCF)) ||
3495 ((c
>= 0xFDF0) && (c
<= 0xFFFD)) ||
3496 ((c
>= 0x10000) && (c
<= 0xEFFFF)))
3499 if ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
3500 (c
== '.') || (c
== '-') ||
3501 (c
== '_') || (c
== ':') ||
3502 (IS_COMBINING(c
)) ||
3510 * xmlValidateNameValue:
3511 * @doc: pointer to the document or NULL
3512 * @value: an Name value
3514 * Validate that the given value match Name production
3516 * returns 1 if valid or 0 otherwise
3520 xmlValidateNameValueInternal(xmlDocPtr doc
, const xmlChar
*value
) {
3524 if (value
== NULL
) return(0);
3526 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3528 if (!xmlIsDocNameStartChar(doc
, val
))
3531 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3533 while (xmlIsDocNameChar(doc
, val
)) {
3534 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3538 if (val
!= 0) return(0);
3544 * xmlValidateNameValue:
3545 * @value: an Name value
3547 * Validate that the given value match Name production
3549 * returns 1 if valid or 0 otherwise
3553 xmlValidateNameValue(const xmlChar
*value
) {
3554 return(xmlValidateNameValueInternal(NULL
, value
));
3558 * xmlValidateNamesValueInternal:
3559 * @doc: pointer to the document or NULL
3560 * @value: an Names value
3562 * Validate that the given value match Names production
3564 * returns 1 if valid or 0 otherwise
3568 xmlValidateNamesValueInternal(xmlDocPtr doc
, const xmlChar
*value
) {
3572 if (value
== NULL
) return(0);
3574 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3577 if (!xmlIsDocNameStartChar(doc
, val
))
3580 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3582 while (xmlIsDocNameChar(doc
, val
)) {
3583 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3587 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3588 while (val
== 0x20) {
3589 while (val
== 0x20) {
3590 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3594 if (!xmlIsDocNameStartChar(doc
, val
))
3597 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3600 while (xmlIsDocNameChar(doc
, val
)) {
3601 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3606 if (val
!= 0) return(0);
3612 * xmlValidateNamesValue:
3613 * @value: an Names value
3615 * Validate that the given value match Names production
3617 * returns 1 if valid or 0 otherwise
3621 xmlValidateNamesValue(const xmlChar
*value
) {
3622 return(xmlValidateNamesValueInternal(NULL
, value
));
3626 * xmlValidateNmtokenValueInternal:
3627 * @doc: pointer to the document or NULL
3628 * @value: an Nmtoken value
3630 * Validate that the given value match Nmtoken production
3632 * [ VC: Name Token ]
3634 * returns 1 if valid or 0 otherwise
3638 xmlValidateNmtokenValueInternal(xmlDocPtr doc
, const xmlChar
*value
) {
3642 if (value
== NULL
) return(0);
3644 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3647 if (!xmlIsDocNameChar(doc
, val
))
3650 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3652 while (xmlIsDocNameChar(doc
, val
)) {
3653 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3657 if (val
!= 0) return(0);
3663 * xmlValidateNmtokenValue:
3664 * @value: an Nmtoken value
3666 * Validate that the given value match Nmtoken production
3668 * [ VC: Name Token ]
3670 * returns 1 if valid or 0 otherwise
3674 xmlValidateNmtokenValue(const xmlChar
*value
) {
3675 return(xmlValidateNmtokenValueInternal(NULL
, value
));
3679 * xmlValidateNmtokensValueInternal:
3680 * @doc: pointer to the document or NULL
3681 * @value: an Nmtokens value
3683 * Validate that the given value match Nmtokens production
3685 * [ VC: Name Token ]
3687 * returns 1 if valid or 0 otherwise
3691 xmlValidateNmtokensValueInternal(xmlDocPtr doc
, const xmlChar
*value
) {
3695 if (value
== NULL
) return(0);
3697 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3700 while (IS_BLANK(val
)) {
3701 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3705 if (!xmlIsDocNameChar(doc
, val
))
3708 while (xmlIsDocNameChar(doc
, val
)) {
3709 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3713 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3714 while (val
== 0x20) {
3715 while (val
== 0x20) {
3716 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3719 if (val
== 0) return(1);
3721 if (!xmlIsDocNameChar(doc
, val
))
3724 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3727 while (xmlIsDocNameChar(doc
, val
)) {
3728 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3733 if (val
!= 0) return(0);
3739 * xmlValidateNmtokensValue:
3740 * @value: an Nmtokens value
3742 * Validate that the given value match Nmtokens production
3744 * [ VC: Name Token ]
3746 * returns 1 if valid or 0 otherwise
3750 xmlValidateNmtokensValue(const xmlChar
*value
) {
3751 return(xmlValidateNmtokensValueInternal(NULL
, value
));
3755 * xmlValidateNotationDecl:
3756 * @ctxt: the validation context
3757 * @doc: a document instance
3758 * @nota: a notation definition
3760 * Try to validate a single notation definition
3761 * basically it does the following checks as described by the
3762 * XML-1.0 recommendation:
3763 * - it seems that no validity constraint exists on notation declarations
3764 * But this function get called anyway ...
3766 * returns 1 if valid or 0 otherwise
3770 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED
, xmlDocPtr doc ATTRIBUTE_UNUSED
,
3771 xmlNotationPtr nota ATTRIBUTE_UNUSED
) {
3778 * xmlValidateAttributeValueInternal:
3779 * @doc: the document
3780 * @type: an attribute type
3781 * @value: an attribute value
3783 * Validate that the given attribute value match the proper production
3785 * returns 1 if valid or 0 otherwise
3789 xmlValidateAttributeValueInternal(xmlDocPtr doc
, xmlAttributeType type
,
3790 const xmlChar
*value
) {
3792 case XML_ATTRIBUTE_ENTITIES
:
3793 case XML_ATTRIBUTE_IDREFS
:
3794 return(xmlValidateNamesValueInternal(doc
, value
));
3795 case XML_ATTRIBUTE_ENTITY
:
3796 case XML_ATTRIBUTE_IDREF
:
3797 case XML_ATTRIBUTE_ID
:
3798 case XML_ATTRIBUTE_NOTATION
:
3799 return(xmlValidateNameValueInternal(doc
, value
));
3800 case XML_ATTRIBUTE_NMTOKENS
:
3801 case XML_ATTRIBUTE_ENUMERATION
:
3802 return(xmlValidateNmtokensValueInternal(doc
, value
));
3803 case XML_ATTRIBUTE_NMTOKEN
:
3804 return(xmlValidateNmtokenValueInternal(doc
, value
));
3805 case XML_ATTRIBUTE_CDATA
:
3812 * xmlValidateAttributeValue:
3813 * @type: an attribute type
3814 * @value: an attribute value
3816 * Validate that the given attribute value match the proper production
3819 * Values of type ID must match the Name production....
3822 * Values of type IDREF must match the Name production, and values
3823 * of type IDREFS must match Names ...
3825 * [ VC: Entity Name ]
3826 * Values of type ENTITY must match the Name production, values
3827 * of type ENTITIES must match Names ...
3829 * [ VC: Name Token ]
3830 * Values of type NMTOKEN must match the Nmtoken production; values
3831 * of type NMTOKENS must match Nmtokens.
3833 * returns 1 if valid or 0 otherwise
3836 xmlValidateAttributeValue(xmlAttributeType type
, const xmlChar
*value
) {
3837 return(xmlValidateAttributeValueInternal(NULL
, type
, value
));
3841 * xmlValidateAttributeValue2:
3842 * @ctxt: the validation context
3843 * @doc: the document
3844 * @name: the attribute name (used for error reporting only)
3845 * @type: the attribute type
3846 * @value: the attribute value
3848 * Validate that the given attribute value match a given type.
3849 * This typically cannot be done before having finished parsing
3853 * Values of type IDREF must match one of the declared IDs
3854 * Values of type IDREFS must match a sequence of the declared IDs
3855 * each Name must match the value of an ID attribute on some element
3856 * in the XML document; i.e. IDREF values must match the value of
3859 * [ VC: Entity Name ]
3860 * Values of type ENTITY must match one declared entity
3861 * Values of type ENTITIES must match a sequence of declared entities
3863 * [ VC: Notation Attributes ]
3864 * all notation names in the declaration must be declared.
3866 * returns 1 if valid or 0 otherwise
3870 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3871 const xmlChar
*name
, xmlAttributeType type
, const xmlChar
*value
) {
3874 case XML_ATTRIBUTE_IDREFS
:
3875 case XML_ATTRIBUTE_IDREF
:
3876 case XML_ATTRIBUTE_ID
:
3877 case XML_ATTRIBUTE_NMTOKENS
:
3878 case XML_ATTRIBUTE_ENUMERATION
:
3879 case XML_ATTRIBUTE_NMTOKEN
:
3880 case XML_ATTRIBUTE_CDATA
:
3882 case XML_ATTRIBUTE_ENTITY
: {
3885 ent
= xmlGetDocEntity(doc
, value
);
3886 /* yeah it's a bit messy... */
3887 if ((ent
== NULL
) && (doc
->standalone
== 1)) {
3888 doc
->standalone
= 0;
3889 ent
= xmlGetDocEntity(doc
, value
);
3892 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
3893 XML_DTD_UNKNOWN_ENTITY
,
3894 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3897 } else if (ent
->etype
!= XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
3898 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
3899 XML_DTD_ENTITY_TYPE
,
3900 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3906 case XML_ATTRIBUTE_ENTITIES
: {
3907 xmlChar
*dup
, *nam
= NULL
, *cur
, save
;
3910 dup
= xmlStrdup(value
);
3916 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
))) cur
++;
3919 ent
= xmlGetDocEntity(doc
, nam
);
3921 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
3922 XML_DTD_UNKNOWN_ENTITY
,
3923 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3926 } else if (ent
->etype
!= XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
3927 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
3928 XML_DTD_ENTITY_TYPE
,
3929 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3936 while (IS_BLANK_CH(*cur
)) cur
++;
3941 case XML_ATTRIBUTE_NOTATION
: {
3942 xmlNotationPtr nota
;
3944 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
3945 if ((nota
== NULL
) && (doc
->extSubset
!= NULL
))
3946 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
3949 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
3950 XML_DTD_UNKNOWN_NOTATION
,
3951 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3962 * xmlValidCtxtNormalizeAttributeValue:
3963 * @ctxt: the validation context
3964 * @doc: the document
3966 * @name: the attribute name
3967 * @value: the attribute value
3968 * @ctxt: the validation context or NULL
3970 * Does the validation related extra step of the normalization of attribute
3973 * If the declared value is not CDATA, then the XML processor must further
3974 * process the normalized attribute value by discarding any leading and
3975 * trailing space (#x20) characters, and by replacing sequences of space
3976 * (#x20) characters by single space (#x20) character.
3978 * Also check VC: Standalone Document Declaration in P32, and update
3979 * ctxt->valid accordingly
3981 * returns a new normalized string if normalization is needed, NULL otherwise
3982 * the caller must free the returned value.
3986 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3987 xmlNodePtr elem
, const xmlChar
*name
, const xmlChar
*value
) {
3990 xmlAttributePtr attrDecl
= NULL
;
3993 if (doc
== NULL
) return(NULL
);
3994 if (elem
== NULL
) return(NULL
);
3995 if (name
== NULL
) return(NULL
);
3996 if (value
== NULL
) return(NULL
);
3998 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
4002 fullname
= xmlBuildQName(elem
->name
, elem
->ns
->prefix
, fn
, 50);
4003 if (fullname
== NULL
)
4005 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullname
, name
);
4006 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
4007 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, fullname
, name
);
4008 if (attrDecl
!= NULL
)
4011 if ((fullname
!= fn
) && (fullname
!= elem
->name
))
4014 if ((attrDecl
== NULL
) && (doc
->intSubset
!= NULL
))
4015 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, name
);
4016 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
4017 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, elem
->name
, name
);
4018 if (attrDecl
!= NULL
)
4022 if (attrDecl
== NULL
)
4024 if (attrDecl
->atype
== XML_ATTRIBUTE_CDATA
)
4027 ret
= xmlStrdup(value
);
4032 while (*src
== 0x20) src
++;
4035 while (*src
== 0x20) src
++;
4043 if ((doc
->standalone
) && (extsubset
== 1) && (!xmlStrEqual(value
, ret
))) {
4044 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOT_STANDALONE
,
4045 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
4046 name
, elem
->name
, NULL
);
4053 * xmlValidNormalizeAttributeValue:
4054 * @doc: the document
4056 * @name: the attribute name
4057 * @value: the attribute value
4059 * Does the validation related extra step of the normalization of attribute
4062 * If the declared value is not CDATA, then the XML processor must further
4063 * process the normalized attribute value by discarding any leading and
4064 * trailing space (#x20) characters, and by replacing sequences of space
4065 * (#x20) characters by single space (#x20) character.
4067 * Returns a new normalized string if normalization is needed, NULL otherwise
4068 * the caller must free the returned value.
4072 xmlValidNormalizeAttributeValue(xmlDocPtr doc
, xmlNodePtr elem
,
4073 const xmlChar
*name
, const xmlChar
*value
) {
4076 xmlAttributePtr attrDecl
= NULL
;
4078 if (doc
== NULL
) return(NULL
);
4079 if (elem
== NULL
) return(NULL
);
4080 if (name
== NULL
) return(NULL
);
4081 if (value
== NULL
) return(NULL
);
4083 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
4087 fullname
= xmlBuildQName(elem
->name
, elem
->ns
->prefix
, fn
, 50);
4088 if (fullname
== NULL
)
4090 if ((fullname
!= fn
) && (fullname
!= elem
->name
))
4093 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, name
);
4094 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4095 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, elem
->name
, name
);
4097 if (attrDecl
== NULL
)
4099 if (attrDecl
->atype
== XML_ATTRIBUTE_CDATA
)
4102 ret
= xmlStrdup(value
);
4107 while (*src
== 0x20) src
++;
4110 while (*src
== 0x20) src
++;
4122 xmlValidateAttributeIdCallback(void *payload
, void *data
,
4123 const xmlChar
*name ATTRIBUTE_UNUSED
) {
4124 xmlAttributePtr attr
= (xmlAttributePtr
) payload
;
4125 int *count
= (int *) data
;
4126 if (attr
->atype
== XML_ATTRIBUTE_ID
) (*count
)++;
4130 * xmlValidateAttributeDecl:
4131 * @ctxt: the validation context
4132 * @doc: a document instance
4133 * @attr: an attribute definition
4135 * Try to validate a single attribute definition
4136 * basically it does the following checks as described by the
4137 * XML-1.0 recommendation:
4138 * - [ VC: Attribute Default Legal ]
4139 * - [ VC: Enumeration ]
4140 * - [ VC: ID Attribute Default ]
4142 * The ID/IDREF uniqueness and matching are done separately
4144 * returns 1 if valid or 0 otherwise
4148 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4149 xmlAttributePtr attr
) {
4153 if(attr
== NULL
) return(1);
4155 /* Attribute Default Legal */
4157 if (attr
->defaultValue
!= NULL
) {
4158 val
= xmlValidateAttributeValueInternal(doc
, attr
->atype
,
4159 attr
->defaultValue
);
4161 xmlErrValidNode(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ATTRIBUTE_DEFAULT
,
4162 "Syntax of default value for attribute %s of %s is not valid\n",
4163 attr
->name
, attr
->elem
, NULL
);
4168 /* ID Attribute Default */
4169 if ((attr
->atype
== XML_ATTRIBUTE_ID
)&&
4170 (attr
->def
!= XML_ATTRIBUTE_IMPLIED
) &&
4171 (attr
->def
!= XML_ATTRIBUTE_REQUIRED
)) {
4172 xmlErrValidNode(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ID_FIXED
,
4173 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4174 attr
->name
, attr
->elem
, NULL
);
4178 /* One ID per Element Type */
4179 if (attr
->atype
== XML_ATTRIBUTE_ID
) {
4182 /* the trick is that we parse DtD as their own internal subset */
4183 xmlElementPtr elem
= xmlGetDtdElementDesc(doc
->intSubset
,
4186 nbId
= xmlScanIDAttributeDecl(NULL
, elem
, 0);
4188 xmlAttributeTablePtr table
;
4191 * The attribute may be declared in the internal subset and the
4192 * element in the external subset.
4195 if (doc
->intSubset
!= NULL
) {
4196 table
= (xmlAttributeTablePtr
) doc
->intSubset
->attributes
;
4197 xmlHashScan3(table
, NULL
, NULL
, attr
->elem
,
4198 xmlValidateAttributeIdCallback
, &nbId
);
4203 xmlErrValidNodeNr(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ID_SUBSET
,
4204 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4205 attr
->elem
, nbId
, attr
->name
);
4206 } else if (doc
->extSubset
!= NULL
) {
4208 elem
= xmlGetDtdElementDesc(doc
->extSubset
, attr
->elem
);
4210 extId
= xmlScanIDAttributeDecl(NULL
, elem
, 0);
4213 xmlErrValidNodeNr(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ID_SUBSET
,
4214 "Element %s has %d ID attribute defined in the external subset : %s\n",
4215 attr
->elem
, extId
, attr
->name
);
4216 } else if (extId
+ nbId
> 1) {
4217 xmlErrValidNode(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ID_SUBSET
,
4218 "Element %s has ID attributes defined in the internal and external subset : %s\n",
4219 attr
->elem
, attr
->name
, NULL
);
4224 /* Validity Constraint: Enumeration */
4225 if ((attr
->defaultValue
!= NULL
) && (attr
->tree
!= NULL
)) {
4226 xmlEnumerationPtr tree
= attr
->tree
;
4227 while (tree
!= NULL
) {
4228 if (xmlStrEqual(tree
->name
, attr
->defaultValue
)) break;
4232 xmlErrValidNode(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ATTRIBUTE_VALUE
,
4233 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4234 attr
->defaultValue
, attr
->name
, attr
->elem
);
4243 * xmlValidateElementDecl:
4244 * @ctxt: the validation context
4245 * @doc: a document instance
4246 * @elem: an element definition
4248 * Try to validate a single element definition
4249 * basically it does the following checks as described by the
4250 * XML-1.0 recommendation:
4251 * - [ VC: One ID per Element Type ]
4252 * - [ VC: No Duplicate Types ]
4253 * - [ VC: Unique Element Type Declaration ]
4255 * returns 1 if valid or 0 otherwise
4259 xmlValidateElementDecl(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4260 xmlElementPtr elem
) {
4266 if (elem
== NULL
) return(1);
4269 #ifdef LIBXML_REGEXP_ENABLED
4270 /* Build the regexp associated to the content model */
4271 ret
= xmlValidBuildContentModel(ctxt
, elem
);
4275 /* No Duplicate Types */
4276 if (elem
->etype
== XML_ELEMENT_TYPE_MIXED
) {
4277 xmlElementContentPtr cur
, next
;
4278 const xmlChar
*name
;
4280 cur
= elem
->content
;
4281 while (cur
!= NULL
) {
4282 if (cur
->type
!= XML_ELEMENT_CONTENT_OR
) break;
4283 if (cur
->c1
== NULL
) break;
4284 if (cur
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
4285 name
= cur
->c1
->name
;
4287 while (next
!= NULL
) {
4288 if (next
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
4289 if ((xmlStrEqual(next
->name
, name
)) &&
4290 (xmlStrEqual(next
->prefix
, cur
->c1
->prefix
))) {
4291 if (cur
->c1
->prefix
== NULL
) {
4292 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_CONTENT_ERROR
,
4293 "Definition of %s has duplicate references of %s\n",
4294 elem
->name
, name
, NULL
);
4296 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_CONTENT_ERROR
,
4297 "Definition of %s has duplicate references of %s:%s\n",
4298 elem
->name
, cur
->c1
->prefix
, name
);
4304 if (next
->c1
== NULL
) break;
4305 if (next
->c1
->type
!= XML_ELEMENT_CONTENT_ELEMENT
) break;
4306 if ((xmlStrEqual(next
->c1
->name
, name
)) &&
4307 (xmlStrEqual(next
->c1
->prefix
, cur
->c1
->prefix
))) {
4308 if (cur
->c1
->prefix
== NULL
) {
4309 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_CONTENT_ERROR
,
4310 "Definition of %s has duplicate references to %s\n",
4311 elem
->name
, name
, NULL
);
4313 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_CONTENT_ERROR
,
4314 "Definition of %s has duplicate references to %s:%s\n",
4315 elem
->name
, cur
->c1
->prefix
, name
);
4326 /* VC: Unique Element Type Declaration */
4327 tst
= xmlGetDtdElementDesc(doc
->intSubset
, elem
->name
);
4328 if ((tst
!= NULL
) && (tst
!= elem
) &&
4329 ((tst
->prefix
== elem
->prefix
) ||
4330 (xmlStrEqual(tst
->prefix
, elem
->prefix
))) &&
4331 (tst
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
)) {
4332 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_ELEM_REDEFINED
,
4333 "Redefinition of element %s\n",
4334 elem
->name
, NULL
, NULL
);
4337 tst
= xmlGetDtdElementDesc(doc
->extSubset
, elem
->name
);
4338 if ((tst
!= NULL
) && (tst
!= elem
) &&
4339 ((tst
->prefix
== elem
->prefix
) ||
4340 (xmlStrEqual(tst
->prefix
, elem
->prefix
))) &&
4341 (tst
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
)) {
4342 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_ELEM_REDEFINED
,
4343 "Redefinition of element %s\n",
4344 elem
->name
, NULL
, NULL
);
4347 /* One ID per Element Type
4348 * already done when registering the attribute
4349 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4356 * xmlValidateOneAttribute:
4357 * @ctxt: the validation context
4358 * @doc: a document instance
4359 * @elem: an element instance
4360 * @attr: an attribute instance
4361 * @value: the attribute value (without entities processing)
4363 * Try to validate a single attribute for an element
4364 * basically it does the following checks as described by the
4365 * XML-1.0 recommendation:
4366 * - [ VC: Attribute Value Type ]
4367 * - [ VC: Fixed Attribute Default ]
4368 * - [ VC: Entity Name ]
4369 * - [ VC: Name Token ]
4372 * - [ VC: Entity Name ]
4373 * - [ VC: Notation Attributes ]
4375 * The ID/IDREF uniqueness and matching are done separately
4377 * returns 1 if valid or 0 otherwise
4381 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4382 xmlNodePtr elem
, xmlAttrPtr attr
, const xmlChar
*value
)
4384 xmlAttributePtr attrDecl
= NULL
;
4389 if ((elem
== NULL
) || (elem
->name
== NULL
)) return(0);
4390 if ((attr
== NULL
) || (attr
->name
== NULL
)) return(0);
4392 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
4396 fullname
= xmlBuildQName(elem
->name
, elem
->ns
->prefix
, fn
, 50);
4397 if (fullname
== NULL
)
4399 if (attr
->ns
!= NULL
) {
4400 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, fullname
,
4401 attr
->name
, attr
->ns
->prefix
);
4402 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4403 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, fullname
,
4404 attr
->name
, attr
->ns
->prefix
);
4406 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullname
, attr
->name
);
4407 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4408 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
4409 fullname
, attr
->name
);
4411 if ((fullname
!= fn
) && (fullname
!= elem
->name
))
4414 if (attrDecl
== NULL
) {
4415 if (attr
->ns
!= NULL
) {
4416 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, elem
->name
,
4417 attr
->name
, attr
->ns
->prefix
);
4418 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4419 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, elem
->name
,
4420 attr
->name
, attr
->ns
->prefix
);
4422 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
,
4423 elem
->name
, attr
->name
);
4424 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4425 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
4426 elem
->name
, attr
->name
);
4431 /* Validity Constraint: Attribute Value Type */
4432 if (attrDecl
== NULL
) {
4433 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_ATTRIBUTE
,
4434 "No declaration for attribute %s of element %s\n",
4435 attr
->name
, elem
->name
, NULL
);
4438 attr
->atype
= attrDecl
->atype
;
4440 val
= xmlValidateAttributeValueInternal(doc
, attrDecl
->atype
, value
);
4442 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4443 "Syntax of value for attribute %s of %s is not valid\n",
4444 attr
->name
, elem
->name
, NULL
);
4448 /* Validity constraint: Fixed Attribute Default */
4449 if (attrDecl
->def
== XML_ATTRIBUTE_FIXED
) {
4450 if (!xmlStrEqual(value
, attrDecl
->defaultValue
)) {
4451 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_DEFAULT
,
4452 "Value for attribute %s of %s is different from default \"%s\"\n",
4453 attr
->name
, elem
->name
, attrDecl
->defaultValue
);
4458 /* Validity Constraint: ID uniqueness */
4459 if (attrDecl
->atype
== XML_ATTRIBUTE_ID
) {
4460 if (xmlAddID(ctxt
, doc
, value
, attr
) == NULL
)
4464 if ((attrDecl
->atype
== XML_ATTRIBUTE_IDREF
) ||
4465 (attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
)) {
4466 if (xmlAddRef(ctxt
, doc
, value
, attr
) == NULL
)
4470 /* Validity Constraint: Notation Attributes */
4471 if (attrDecl
->atype
== XML_ATTRIBUTE_NOTATION
) {
4472 xmlEnumerationPtr tree
= attrDecl
->tree
;
4473 xmlNotationPtr nota
;
4475 /* First check that the given NOTATION was declared */
4476 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
4478 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
4481 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_NOTATION
,
4482 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4483 value
, attr
->name
, elem
->name
);
4487 /* Second, verify that it's among the list */
4488 while (tree
!= NULL
) {
4489 if (xmlStrEqual(tree
->name
, value
)) break;
4493 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOTATION_VALUE
,
4494 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4495 value
, attr
->name
, elem
->name
);
4500 /* Validity Constraint: Enumeration */
4501 if (attrDecl
->atype
== XML_ATTRIBUTE_ENUMERATION
) {
4502 xmlEnumerationPtr tree
= attrDecl
->tree
;
4503 while (tree
!= NULL
) {
4504 if (xmlStrEqual(tree
->name
, value
)) break;
4508 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4509 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4510 value
, attr
->name
, elem
->name
);
4515 /* Fixed Attribute Default */
4516 if ((attrDecl
->def
== XML_ATTRIBUTE_FIXED
) &&
4517 (!xmlStrEqual(attrDecl
->defaultValue
, value
))) {
4518 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4519 "Value for attribute %s of %s must be \"%s\"\n",
4520 attr
->name
, elem
->name
, attrDecl
->defaultValue
);
4524 /* Extra check for the attribute value */
4525 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, attr
->name
,
4526 attrDecl
->atype
, value
);
4532 * xmlValidateOneNamespace:
4533 * @ctxt: the validation context
4534 * @doc: a document instance
4535 * @elem: an element instance
4536 * @prefix: the namespace prefix
4537 * @ns: an namespace declaration instance
4538 * @value: the attribute value (without entities processing)
4540 * Try to validate a single namespace declaration for an element
4541 * basically it does the following checks as described by the
4542 * XML-1.0 recommendation:
4543 * - [ VC: Attribute Value Type ]
4544 * - [ VC: Fixed Attribute Default ]
4545 * - [ VC: Entity Name ]
4546 * - [ VC: Name Token ]
4549 * - [ VC: Entity Name ]
4550 * - [ VC: Notation Attributes ]
4552 * The ID/IDREF uniqueness and matching are done separately
4554 * returns 1 if valid or 0 otherwise
4558 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4559 xmlNodePtr elem
, const xmlChar
*prefix
, xmlNsPtr ns
, const xmlChar
*value
) {
4560 /* xmlElementPtr elemDecl; */
4561 xmlAttributePtr attrDecl
= NULL
;
4566 if ((elem
== NULL
) || (elem
->name
== NULL
)) return(0);
4567 if ((ns
== NULL
) || (ns
->href
== NULL
)) return(0);
4569 if (prefix
!= NULL
) {
4573 fullname
= xmlBuildQName(elem
->name
, prefix
, fn
, 50);
4574 if (fullname
== NULL
) {
4575 xmlVErrMemory(ctxt
, "Validating namespace");
4578 if (ns
->prefix
!= NULL
) {
4579 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, fullname
,
4580 ns
->prefix
, BAD_CAST
"xmlns");
4581 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4582 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, fullname
,
4583 ns
->prefix
, BAD_CAST
"xmlns");
4585 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullname
,
4587 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4588 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, fullname
,
4591 if ((fullname
!= fn
) && (fullname
!= elem
->name
))
4594 if (attrDecl
== NULL
) {
4595 if (ns
->prefix
!= NULL
) {
4596 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, elem
->name
,
4597 ns
->prefix
, BAD_CAST
"xmlns");
4598 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4599 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, elem
->name
,
4600 ns
->prefix
, BAD_CAST
"xmlns");
4602 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
,
4603 elem
->name
, BAD_CAST
"xmlns");
4604 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4605 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
4606 elem
->name
, BAD_CAST
"xmlns");
4611 /* Validity Constraint: Attribute Value Type */
4612 if (attrDecl
== NULL
) {
4613 if (ns
->prefix
!= NULL
) {
4614 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_ATTRIBUTE
,
4615 "No declaration for attribute xmlns:%s of element %s\n",
4616 ns
->prefix
, elem
->name
, NULL
);
4618 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_ATTRIBUTE
,
4619 "No declaration for attribute xmlns of element %s\n",
4620 elem
->name
, NULL
, NULL
);
4625 val
= xmlValidateAttributeValueInternal(doc
, attrDecl
->atype
, value
);
4627 if (ns
->prefix
!= NULL
) {
4628 xmlErrValidNode(ctxt
, elem
, XML_DTD_INVALID_DEFAULT
,
4629 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4630 ns
->prefix
, elem
->name
, NULL
);
4632 xmlErrValidNode(ctxt
, elem
, XML_DTD_INVALID_DEFAULT
,
4633 "Syntax of value for attribute xmlns of %s is not valid\n",
4634 elem
->name
, NULL
, NULL
);
4639 /* Validity constraint: Fixed Attribute Default */
4640 if (attrDecl
->def
== XML_ATTRIBUTE_FIXED
) {
4641 if (!xmlStrEqual(value
, attrDecl
->defaultValue
)) {
4642 if (ns
->prefix
!= NULL
) {
4643 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_DEFAULT
,
4644 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4645 ns
->prefix
, elem
->name
, attrDecl
->defaultValue
);
4647 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_DEFAULT
,
4648 "Value for attribute xmlns of %s is different from default \"%s\"\n",
4649 elem
->name
, attrDecl
->defaultValue
, NULL
);
4656 * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4657 * xmlAddID and xmlAddRef for namespace declarations, but it makes
4658 * no practical sense to use ID types anyway.
4661 /* Validity Constraint: ID uniqueness */
4662 if (attrDecl
->atype
== XML_ATTRIBUTE_ID
) {
4663 if (xmlAddID(ctxt
, doc
, value
, (xmlAttrPtr
) ns
) == NULL
)
4667 if ((attrDecl
->atype
== XML_ATTRIBUTE_IDREF
) ||
4668 (attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
)) {
4669 if (xmlAddRef(ctxt
, doc
, value
, (xmlAttrPtr
) ns
) == NULL
)
4674 /* Validity Constraint: Notation Attributes */
4675 if (attrDecl
->atype
== XML_ATTRIBUTE_NOTATION
) {
4676 xmlEnumerationPtr tree
= attrDecl
->tree
;
4677 xmlNotationPtr nota
;
4679 /* First check that the given NOTATION was declared */
4680 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
4682 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
4685 if (ns
->prefix
!= NULL
) {
4686 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_NOTATION
,
4687 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4688 value
, ns
->prefix
, elem
->name
);
4690 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_NOTATION
,
4691 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4692 value
, elem
->name
, NULL
);
4697 /* Second, verify that it's among the list */
4698 while (tree
!= NULL
) {
4699 if (xmlStrEqual(tree
->name
, value
)) break;
4703 if (ns
->prefix
!= NULL
) {
4704 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOTATION_VALUE
,
4705 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4706 value
, ns
->prefix
, elem
->name
);
4708 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOTATION_VALUE
,
4709 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4710 value
, elem
->name
, NULL
);
4716 /* Validity Constraint: Enumeration */
4717 if (attrDecl
->atype
== XML_ATTRIBUTE_ENUMERATION
) {
4718 xmlEnumerationPtr tree
= attrDecl
->tree
;
4719 while (tree
!= NULL
) {
4720 if (xmlStrEqual(tree
->name
, value
)) break;
4724 if (ns
->prefix
!= NULL
) {
4725 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4726 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4727 value
, ns
->prefix
, elem
->name
);
4729 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4730 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4731 value
, elem
->name
, NULL
);
4737 /* Fixed Attribute Default */
4738 if ((attrDecl
->def
== XML_ATTRIBUTE_FIXED
) &&
4739 (!xmlStrEqual(attrDecl
->defaultValue
, value
))) {
4740 if (ns
->prefix
!= NULL
) {
4741 xmlErrValidNode(ctxt
, elem
, XML_DTD_ELEM_NAMESPACE
,
4742 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4743 ns
->prefix
, elem
->name
, attrDecl
->defaultValue
);
4745 xmlErrValidNode(ctxt
, elem
, XML_DTD_ELEM_NAMESPACE
,
4746 "Value for attribute xmlns of %s must be \"%s\"\n",
4747 elem
->name
, attrDecl
->defaultValue
, NULL
);
4752 /* Extra check for the attribute value */
4753 if (ns
->prefix
!= NULL
) {
4754 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, ns
->prefix
,
4755 attrDecl
->atype
, value
);
4757 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, BAD_CAST
"xmlns",
4758 attrDecl
->atype
, value
);
4764 #ifndef LIBXML_REGEXP_ENABLED
4766 * xmlValidateSkipIgnorable:
4767 * @ctxt: the validation context
4768 * @child: the child list
4770 * Skip ignorable elements w.r.t. the validation process
4772 * returns the first element to consider for validation of the content model
4776 xmlValidateSkipIgnorable(xmlNodePtr child
) {
4777 while (child
!= NULL
) {
4778 switch (child
->type
) {
4779 /* These things are ignored (skipped) during validation. */
4781 case XML_COMMENT_NODE
:
4782 case XML_XINCLUDE_START
:
4783 case XML_XINCLUDE_END
:
4784 child
= child
->next
;
4787 if (xmlIsBlankNode(child
))
4788 child
= child
->next
;
4792 /* keep current node */
4801 * xmlValidateElementType:
4802 * @ctxt: the validation context
4804 * Try to validate the content model of an element internal function
4806 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4807 * reference is found and -3 if the validation succeeded but
4808 * the content model is not determinist.
4812 xmlValidateElementType(xmlValidCtxtPtr ctxt
) {
4814 int determinist
= 1;
4816 NODE
= xmlValidateSkipIgnorable(NODE
);
4817 if ((NODE
== NULL
) && (CONT
== NULL
))
4819 if ((NODE
== NULL
) &&
4820 ((CONT
->ocur
== XML_ELEMENT_CONTENT_MULT
) ||
4821 (CONT
->ocur
== XML_ELEMENT_CONTENT_OPT
))) {
4824 if (CONT
== NULL
) return(-1);
4825 if ((NODE
!= NULL
) && (NODE
->type
== XML_ENTITY_REF_NODE
))
4829 * We arrive here when more states need to be examined
4834 * We just recovered from a rollback generated by a possible
4835 * epsilon transition, go directly to the analysis phase
4837 if (STATE
== ROLLBACK_PARENT
) {
4838 DEBUG_VALID_MSG("restored parent branch");
4839 DEBUG_VALID_STATE(NODE
, CONT
)
4844 DEBUG_VALID_STATE(NODE
, CONT
)
4846 * we may have to save a backup state here. This is the equivalent
4847 * of handling epsilon transition in NFAs.
4849 if ((CONT
!= NULL
) &&
4850 ((CONT
->parent
== NULL
) ||
4851 (CONT
->parent
->type
!= XML_ELEMENT_CONTENT_OR
)) &&
4852 ((CONT
->ocur
== XML_ELEMENT_CONTENT_MULT
) ||
4853 (CONT
->ocur
== XML_ELEMENT_CONTENT_OPT
) ||
4854 ((CONT
->ocur
== XML_ELEMENT_CONTENT_PLUS
) && (OCCURRENCE
)))) {
4855 DEBUG_VALID_MSG("saving parent branch");
4856 if (vstateVPush(ctxt
, CONT
, NODE
, DEPTH
, OCCURS
, ROLLBACK_PARENT
) < 0)
4862 * Check first if the content matches
4864 switch (CONT
->type
) {
4865 case XML_ELEMENT_CONTENT_PCDATA
:
4867 DEBUG_VALID_MSG("pcdata failed no node");
4871 if (NODE
->type
== XML_TEXT_NODE
) {
4872 DEBUG_VALID_MSG("pcdata found, skip to next");
4874 * go to next element in the content model
4875 * skipping ignorable elems
4879 NODE
= xmlValidateSkipIgnorable(NODE
);
4880 if ((NODE
!= NULL
) &&
4881 (NODE
->type
== XML_ENTITY_REF_NODE
))
4883 } while ((NODE
!= NULL
) &&
4884 ((NODE
->type
!= XML_ELEMENT_NODE
) &&
4885 (NODE
->type
!= XML_TEXT_NODE
) &&
4886 (NODE
->type
!= XML_CDATA_SECTION_NODE
)));
4890 DEBUG_VALID_MSG("pcdata failed");
4895 case XML_ELEMENT_CONTENT_ELEMENT
:
4897 DEBUG_VALID_MSG("element failed no node");
4901 ret
= ((NODE
->type
== XML_ELEMENT_NODE
) &&
4902 (xmlStrEqual(NODE
->name
, CONT
->name
)));
4904 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
4905 ret
= (CONT
->prefix
== NULL
);
4906 } else if (CONT
->prefix
== NULL
) {
4909 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->prefix
);
4913 DEBUG_VALID_MSG("element found, skip to next");
4915 * go to next element in the content model
4916 * skipping ignorable elems
4920 NODE
= xmlValidateSkipIgnorable(NODE
);
4921 if ((NODE
!= NULL
) &&
4922 (NODE
->type
== XML_ENTITY_REF_NODE
))
4924 } while ((NODE
!= NULL
) &&
4925 ((NODE
->type
!= XML_ELEMENT_NODE
) &&
4926 (NODE
->type
!= XML_TEXT_NODE
) &&
4927 (NODE
->type
!= XML_CDATA_SECTION_NODE
)));
4929 DEBUG_VALID_MSG("element failed");
4934 case XML_ELEMENT_CONTENT_OR
:
4936 * Small optimization.
4938 if (CONT
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
4939 if ((NODE
== NULL
) ||
4940 (!xmlStrEqual(NODE
->name
, CONT
->c1
->name
))) {
4945 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
4946 ret
= (CONT
->c1
->prefix
== NULL
);
4947 } else if (CONT
->c1
->prefix
== NULL
) {
4950 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->c1
->prefix
);
4960 * save the second branch 'or' branch
4962 DEBUG_VALID_MSG("saving 'or' branch");
4963 if (vstateVPush(ctxt
, CONT
->c2
, NODE
, (unsigned char)(DEPTH
+ 1),
4964 OCCURS
, ROLLBACK_OR
) < 0)
4969 case XML_ELEMENT_CONTENT_SEQ
:
4971 * Small optimization.
4973 if ((CONT
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) &&
4974 ((CONT
->c1
->ocur
== XML_ELEMENT_CONTENT_OPT
) ||
4975 (CONT
->c1
->ocur
== XML_ELEMENT_CONTENT_MULT
))) {
4976 if ((NODE
== NULL
) ||
4977 (!xmlStrEqual(NODE
->name
, CONT
->c1
->name
))) {
4982 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
4983 ret
= (CONT
->c1
->prefix
== NULL
);
4984 } else if (CONT
->c1
->prefix
== NULL
) {
4987 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->c1
->prefix
);
5001 * At this point handle going up in the tree
5004 DEBUG_VALID_MSG("error found returning");
5008 while (CONT
!= NULL
) {
5010 * First do the analysis depending on the occurrence model at
5014 switch (CONT
->ocur
) {
5017 case XML_ELEMENT_CONTENT_ONCE
:
5018 cur
= ctxt
->vstate
->node
;
5019 DEBUG_VALID_MSG("Once branch failed, rollback");
5020 if (vstateVPop(ctxt
) < 0 ) {
5021 DEBUG_VALID_MSG("exhaustion, failed");
5024 if (cur
!= ctxt
->vstate
->node
)
5027 case XML_ELEMENT_CONTENT_PLUS
:
5028 if (OCCURRENCE
== 0) {
5029 cur
= ctxt
->vstate
->node
;
5030 DEBUG_VALID_MSG("Plus branch failed, rollback");
5031 if (vstateVPop(ctxt
) < 0 ) {
5032 DEBUG_VALID_MSG("exhaustion, failed");
5035 if (cur
!= ctxt
->vstate
->node
)
5039 DEBUG_VALID_MSG("Plus branch found");
5042 case XML_ELEMENT_CONTENT_MULT
:
5043 #ifdef DEBUG_VALID_ALGO
5044 if (OCCURRENCE
== 0) {
5045 DEBUG_VALID_MSG("Mult branch failed");
5047 DEBUG_VALID_MSG("Mult branch found");
5052 case XML_ELEMENT_CONTENT_OPT
:
5053 DEBUG_VALID_MSG("Option branch failed");
5058 switch (CONT
->ocur
) {
5059 case XML_ELEMENT_CONTENT_OPT
:
5060 DEBUG_VALID_MSG("Option branch succeeded");
5063 case XML_ELEMENT_CONTENT_ONCE
:
5064 DEBUG_VALID_MSG("Once branch succeeded");
5067 case XML_ELEMENT_CONTENT_PLUS
:
5068 if (STATE
== ROLLBACK_PARENT
) {
5069 DEBUG_VALID_MSG("Plus branch rollback");
5074 DEBUG_VALID_MSG("Plus branch exhausted");
5078 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
5081 case XML_ELEMENT_CONTENT_MULT
:
5082 if (STATE
== ROLLBACK_PARENT
) {
5083 DEBUG_VALID_MSG("Mult branch rollback");
5088 DEBUG_VALID_MSG("Mult branch exhausted");
5092 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
5093 /* SET_OCCURRENCE; */
5100 * Then act accordingly at the parent level
5103 if (CONT
->parent
== NULL
)
5106 switch (CONT
->parent
->type
) {
5107 case XML_ELEMENT_CONTENT_PCDATA
:
5108 DEBUG_VALID_MSG("Error: parent pcdata");
5110 case XML_ELEMENT_CONTENT_ELEMENT
:
5111 DEBUG_VALID_MSG("Error: parent element");
5113 case XML_ELEMENT_CONTENT_OR
:
5115 DEBUG_VALID_MSG("Or succeeded");
5116 CONT
= CONT
->parent
;
5119 DEBUG_VALID_MSG("Or failed");
5120 CONT
= CONT
->parent
;
5124 case XML_ELEMENT_CONTENT_SEQ
:
5126 DEBUG_VALID_MSG("Sequence failed");
5127 CONT
= CONT
->parent
;
5129 } else if (CONT
== CONT
->parent
->c1
) {
5130 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5131 CONT
= CONT
->parent
->c2
;
5134 DEBUG_VALID_MSG("Sequence succeeded");
5135 CONT
= CONT
->parent
;
5143 cur
= ctxt
->vstate
->node
;
5144 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5145 if (vstateVPop(ctxt
) < 0 ) {
5146 DEBUG_VALID_MSG("exhaustion, failed");
5149 if (cur
!= ctxt
->vstate
->node
)
5156 cur
= ctxt
->vstate
->node
;
5157 DEBUG_VALID_MSG("Failure, rollback");
5158 if (vstateVPop(ctxt
) < 0 ) {
5159 DEBUG_VALID_MSG("exhaustion, failed");
5162 if (cur
!= ctxt
->vstate
->node
)
5166 return(determinist
);
5171 * xmlSnprintfElements:
5172 * @buf: an output buffer
5173 * @size: the size of the buffer
5174 * @content: An element
5175 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5177 * This will dump the list of elements to the buffer
5178 * Intended just for the debug routine
5181 xmlSnprintfElements(char *buf
, int size
, xmlNodePtr node
, int glob
) {
5185 if (node
== NULL
) return;
5186 if (glob
) strcat(buf
, "(");
5188 while (cur
!= NULL
) {
5190 if (size
- len
< 50) {
5191 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
5192 strcat(buf
, " ...");
5195 switch (cur
->type
) {
5196 case XML_ELEMENT_NODE
:
5197 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
5198 if (size
- len
< xmlStrlen(cur
->ns
->prefix
) + 10) {
5199 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
5200 strcat(buf
, " ...");
5203 strcat(buf
, (char *) cur
->ns
->prefix
);
5206 if (size
- len
< xmlStrlen(cur
->name
) + 10) {
5207 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
5208 strcat(buf
, " ...");
5211 strcat(buf
, (char *) cur
->name
);
5212 if (cur
->next
!= NULL
)
5216 if (xmlIsBlankNode(cur
))
5218 /* Falls through. */
5219 case XML_CDATA_SECTION_NODE
:
5220 case XML_ENTITY_REF_NODE
:
5221 strcat(buf
, "CDATA");
5222 if (cur
->next
!= NULL
)
5225 case XML_ATTRIBUTE_NODE
:
5226 case XML_DOCUMENT_NODE
:
5227 #ifdef LIBXML_DOCB_ENABLED
5228 case XML_DOCB_DOCUMENT_NODE
:
5230 case XML_HTML_DOCUMENT_NODE
:
5231 case XML_DOCUMENT_TYPE_NODE
:
5232 case XML_DOCUMENT_FRAG_NODE
:
5233 case XML_NOTATION_NODE
:
5234 case XML_NAMESPACE_DECL
:
5236 if (cur
->next
!= NULL
)
5239 case XML_ENTITY_NODE
:
5242 case XML_COMMENT_NODE
:
5243 case XML_ELEMENT_DECL
:
5244 case XML_ATTRIBUTE_DECL
:
5245 case XML_ENTITY_DECL
:
5246 case XML_XINCLUDE_START
:
5247 case XML_XINCLUDE_END
:
5252 if (glob
) strcat(buf
, ")");
5256 * xmlValidateElementContent:
5257 * @ctxt: the validation context
5258 * @child: the child list
5259 * @elemDecl: pointer to the element declaration
5260 * @warn: emit the error message
5261 * @parent: the parent element (for error reporting)
5263 * Try to validate the content model of an element
5265 * returns 1 if valid or 0 if not and -1 in case of error
5269 xmlValidateElementContent(xmlValidCtxtPtr ctxt
, xmlNodePtr child
,
5270 xmlElementPtr elemDecl
, int warn
, xmlNodePtr parent
) {
5272 #ifndef LIBXML_REGEXP_ENABLED
5273 xmlNodePtr repl
= NULL
, last
= NULL
, tmp
;
5276 xmlElementContentPtr cont
;
5277 const xmlChar
*name
;
5279 if ((elemDecl
== NULL
) || (parent
== NULL
) || (ctxt
== NULL
))
5281 cont
= elemDecl
->content
;
5282 name
= elemDecl
->name
;
5284 #ifdef LIBXML_REGEXP_ENABLED
5285 /* Build the regexp associated to the content model */
5286 if (elemDecl
->contModel
== NULL
)
5287 ret
= xmlValidBuildContentModel(ctxt
, elemDecl
);
5288 if (elemDecl
->contModel
== NULL
) {
5291 xmlRegExecCtxtPtr exec
;
5293 if (!xmlRegexpIsDeterminist(elemDecl
->contModel
)) {
5298 ctxt
->nodeTab
= NULL
;
5299 exec
= xmlRegNewExecCtxt(elemDecl
->contModel
, NULL
, NULL
);
5302 while (cur
!= NULL
) {
5303 switch (cur
->type
) {
5304 case XML_ENTITY_REF_NODE
:
5306 * Push the current node to be able to roll back
5307 * and process within the entity
5309 if ((cur
->children
!= NULL
) &&
5310 (cur
->children
->children
!= NULL
)) {
5311 nodeVPush(ctxt
, cur
);
5312 cur
= cur
->children
->children
;
5317 if (xmlIsBlankNode(cur
))
5321 case XML_CDATA_SECTION_NODE
:
5325 case XML_ELEMENT_NODE
:
5326 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
5330 fullname
= xmlBuildQName(cur
->name
,
5331 cur
->ns
->prefix
, fn
, 50);
5332 if (fullname
== NULL
) {
5336 ret
= xmlRegExecPushString(exec
, fullname
, NULL
);
5337 if ((fullname
!= fn
) && (fullname
!= cur
->name
))
5340 ret
= xmlRegExecPushString(exec
, cur
->name
, NULL
);
5347 * Switch to next element
5350 while (cur
== NULL
) {
5351 cur
= nodeVPop(ctxt
);
5357 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
5359 xmlRegFreeExecCtxt(exec
);
5362 #else /* LIBXML_REGEXP_ENABLED */
5364 * Allocate the stack
5366 ctxt
->vstateMax
= 8;
5367 ctxt
->vstateTab
= (xmlValidState
*) xmlMalloc(
5368 ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
5369 if (ctxt
->vstateTab
== NULL
) {
5370 xmlVErrMemory(ctxt
, "malloc failed");
5374 * The first entry in the stack is reserved to the current state
5378 ctxt
->nodeTab
= NULL
;
5379 ctxt
->vstate
= &ctxt
->vstateTab
[0];
5386 ret
= xmlValidateElementType(ctxt
);
5387 if ((ret
== -3) && (warn
)) {
5388 xmlErrValidWarning(ctxt
, child
, XML_DTD_CONTENT_NOT_DETERMINIST
,
5389 "Content model for Element %s is ambiguous\n",
5391 } else if (ret
== -2) {
5393 * An entities reference appeared at this level.
5394 * Buid a minimal representation of this node content
5395 * sufficient to run the validation process on it
5397 DEBUG_VALID_MSG("Found an entity reference, linearizing");
5399 while (cur
!= NULL
) {
5400 switch (cur
->type
) {
5401 case XML_ENTITY_REF_NODE
:
5403 * Push the current node to be able to roll back
5404 * and process within the entity
5406 if ((cur
->children
!= NULL
) &&
5407 (cur
->children
->children
!= NULL
)) {
5408 nodeVPush(ctxt
, cur
);
5409 cur
= cur
->children
->children
;
5414 if (xmlIsBlankNode(cur
))
5416 /* no break on purpose */
5417 case XML_CDATA_SECTION_NODE
:
5418 /* no break on purpose */
5419 case XML_ELEMENT_NODE
:
5421 * Allocate a new node and minimally fills in
5424 tmp
= (xmlNodePtr
) xmlMalloc(sizeof(xmlNode
));
5426 xmlVErrMemory(ctxt
, "malloc failed");
5427 xmlFreeNodeList(repl
);
5431 tmp
->type
= cur
->type
;
5432 tmp
->name
= cur
->name
;
5435 tmp
->content
= NULL
;
5442 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
5444 * E59 spaces in CDATA does not match the
5447 tmp
->content
= xmlStrdup(BAD_CAST
"CDATA");
5454 * Switch to next element
5457 while (cur
== NULL
) {
5458 cur
= nodeVPop(ctxt
);
5466 * Relaunch the validation
5468 ctxt
->vstate
= &ctxt
->vstateTab
[0];
5475 ret
= xmlValidateElementType(ctxt
);
5477 #endif /* LIBXML_REGEXP_ENABLED */
5478 if ((warn
) && ((ret
!= 1) && (ret
!= -3))) {
5484 xmlSnprintfElementContent(&expr
[0], 5000, cont
, 1);
5486 #ifndef LIBXML_REGEXP_ENABLED
5488 xmlSnprintfElements(&list
[0], 5000, repl
, 1);
5490 #endif /* LIBXML_REGEXP_ENABLED */
5491 xmlSnprintfElements(&list
[0], 5000, child
, 1);
5494 xmlErrValidNode(ctxt
, parent
, XML_DTD_CONTENT_MODEL
,
5495 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5496 name
, BAD_CAST expr
, BAD_CAST list
);
5498 xmlErrValidNode(ctxt
, parent
, XML_DTD_CONTENT_MODEL
,
5499 "Element content does not follow the DTD, expecting %s, got %s\n",
5500 BAD_CAST expr
, BAD_CAST list
, NULL
);
5504 xmlErrValidNode(ctxt
, parent
, XML_DTD_CONTENT_MODEL
,
5505 "Element %s content does not follow the DTD\n",
5508 xmlErrValidNode(ctxt
, parent
, XML_DTD_CONTENT_MODEL
,
5509 "Element content does not follow the DTD\n",
5518 #ifndef LIBXML_REGEXP_ENABLED
5521 * Deallocate the copy if done, and free up the validation stack
5523 while (repl
!= NULL
) {
5528 ctxt
->vstateMax
= 0;
5529 if (ctxt
->vstateTab
!= NULL
) {
5530 xmlFree(ctxt
->vstateTab
);
5531 ctxt
->vstateTab
= NULL
;
5536 if (ctxt
->nodeTab
!= NULL
) {
5537 xmlFree(ctxt
->nodeTab
);
5538 ctxt
->nodeTab
= NULL
;
5545 * xmlValidateCdataElement:
5546 * @ctxt: the validation context
5547 * @doc: a document instance
5548 * @elem: an element instance
5550 * Check that an element follows #CDATA
5552 * returns 1 if valid or 0 otherwise
5555 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
5558 xmlNodePtr cur
, child
;
5560 if ((ctxt
== NULL
) || (doc
== NULL
) || (elem
== NULL
) ||
5561 (elem
->type
!= XML_ELEMENT_NODE
))
5564 child
= elem
->children
;
5567 while (cur
!= NULL
) {
5568 switch (cur
->type
) {
5569 case XML_ENTITY_REF_NODE
:
5571 * Push the current node to be able to roll back
5572 * and process within the entity
5574 if ((cur
->children
!= NULL
) &&
5575 (cur
->children
->children
!= NULL
)) {
5576 nodeVPush(ctxt
, cur
);
5577 cur
= cur
->children
->children
;
5581 case XML_COMMENT_NODE
:
5584 case XML_CDATA_SECTION_NODE
:
5591 * Switch to next element
5594 while (cur
== NULL
) {
5595 cur
= nodeVPop(ctxt
);
5604 if (ctxt
->nodeTab
!= NULL
) {
5605 xmlFree(ctxt
->nodeTab
);
5606 ctxt
->nodeTab
= NULL
;
5612 * xmlValidateCheckMixed:
5613 * @ctxt: the validation context
5614 * @cont: the mixed content model
5615 * @qname: the qualified name as appearing in the serialization
5617 * Check if the given node is part of the content model.
5619 * Returns 1 if yes, 0 if no, -1 in case of error
5622 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt
,
5623 xmlElementContentPtr cont
, const xmlChar
*qname
) {
5624 const xmlChar
*name
;
5626 name
= xmlSplitQName3(qname
, &plen
);
5629 while (cont
!= NULL
) {
5630 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
5631 if ((cont
->prefix
== NULL
) && (xmlStrEqual(cont
->name
, qname
)))
5633 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
5634 (cont
->c1
!= NULL
) &&
5635 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)){
5636 if ((cont
->c1
->prefix
== NULL
) &&
5637 (xmlStrEqual(cont
->c1
->name
, qname
)))
5639 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
5640 (cont
->c1
== NULL
) ||
5641 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)){
5642 xmlErrValid(NULL
, XML_DTD_MIXED_CORRUPT
,
5643 "Internal: MIXED struct corrupted\n",
5650 while (cont
!= NULL
) {
5651 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
5652 if ((cont
->prefix
!= NULL
) &&
5653 (xmlStrncmp(cont
->prefix
, qname
, plen
) == 0) &&
5654 (xmlStrEqual(cont
->name
, name
)))
5656 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
5657 (cont
->c1
!= NULL
) &&
5658 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)){
5659 if ((cont
->c1
->prefix
!= NULL
) &&
5660 (xmlStrncmp(cont
->c1
->prefix
, qname
, plen
) == 0) &&
5661 (xmlStrEqual(cont
->c1
->name
, name
)))
5663 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
5664 (cont
->c1
== NULL
) ||
5665 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)){
5666 xmlErrValid(ctxt
, XML_DTD_MIXED_CORRUPT
,
5667 "Internal: MIXED struct corrupted\n",
5678 * xmlValidGetElemDecl:
5679 * @ctxt: the validation context
5680 * @doc: a document instance
5681 * @elem: an element instance
5682 * @extsubset: pointer, (out) indicate if the declaration was found
5683 * in the external subset.
5685 * Finds a declaration associated to an element in the document.
5687 * returns the pointer to the declaration or NULL if not found.
5689 static xmlElementPtr
5690 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
5691 xmlNodePtr elem
, int *extsubset
) {
5692 xmlElementPtr elemDecl
= NULL
;
5693 const xmlChar
*prefix
= NULL
;
5695 if ((ctxt
== NULL
) || (doc
== NULL
) ||
5696 (elem
== NULL
) || (elem
->name
== NULL
))
5698 if (extsubset
!= NULL
)
5702 * Fetch the declaration for the qualified name
5704 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
))
5705 prefix
= elem
->ns
->prefix
;
5707 if (prefix
!= NULL
) {
5708 elemDecl
= xmlGetDtdQElementDesc(doc
->intSubset
,
5709 elem
->name
, prefix
);
5710 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
5711 elemDecl
= xmlGetDtdQElementDesc(doc
->extSubset
,
5712 elem
->name
, prefix
);
5713 if ((elemDecl
!= NULL
) && (extsubset
!= NULL
))
5719 * Fetch the declaration for the non qualified name
5720 * This is "non-strict" validation should be done on the
5721 * full QName but in that case being flexible makes sense.
5723 if (elemDecl
== NULL
) {
5724 elemDecl
= xmlGetDtdElementDesc(doc
->intSubset
, elem
->name
);
5725 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
5726 elemDecl
= xmlGetDtdElementDesc(doc
->extSubset
, elem
->name
);
5727 if ((elemDecl
!= NULL
) && (extsubset
!= NULL
))
5731 if (elemDecl
== NULL
) {
5732 xmlErrValidNode(ctxt
, elem
,
5733 XML_DTD_UNKNOWN_ELEM
,
5734 "No declaration for element %s\n",
5735 elem
->name
, NULL
, NULL
);
5740 #ifdef LIBXML_REGEXP_ENABLED
5742 * xmlValidatePushElement:
5743 * @ctxt: the validation context
5744 * @doc: a document instance
5745 * @elem: an element instance
5746 * @qname: the qualified name as appearing in the serialization
5748 * Push a new element start on the validation stack.
5750 * returns 1 if no validation problem was found or 0 otherwise
5753 xmlValidatePushElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
5754 xmlNodePtr elem
, const xmlChar
*qname
) {
5756 xmlElementPtr eDecl
;
5761 /* printf("PushElem %s\n", qname); */
5762 if ((ctxt
->vstateNr
> 0) && (ctxt
->vstate
!= NULL
)) {
5763 xmlValidStatePtr state
= ctxt
->vstate
;
5764 xmlElementPtr elemDecl
;
5767 * Check the new element against the content model of the new elem.
5769 if (state
->elemDecl
!= NULL
) {
5770 elemDecl
= state
->elemDecl
;
5772 switch(elemDecl
->etype
) {
5773 case XML_ELEMENT_TYPE_UNDEFINED
:
5776 case XML_ELEMENT_TYPE_EMPTY
:
5777 xmlErrValidNode(ctxt
, state
->node
,
5779 "Element %s was declared EMPTY this one has content\n",
5780 state
->node
->name
, NULL
, NULL
);
5783 case XML_ELEMENT_TYPE_ANY
:
5784 /* I don't think anything is required then */
5786 case XML_ELEMENT_TYPE_MIXED
:
5787 /* simple case of declared as #PCDATA */
5788 if ((elemDecl
->content
!= NULL
) &&
5789 (elemDecl
->content
->type
==
5790 XML_ELEMENT_CONTENT_PCDATA
)) {
5791 xmlErrValidNode(ctxt
, state
->node
,
5793 "Element %s was declared #PCDATA but contains non text nodes\n",
5794 state
->node
->name
, NULL
, NULL
);
5797 ret
= xmlValidateCheckMixed(ctxt
, elemDecl
->content
,
5800 xmlErrValidNode(ctxt
, state
->node
,
5801 XML_DTD_INVALID_CHILD
,
5802 "Element %s is not declared in %s list of possible children\n",
5803 qname
, state
->node
->name
, NULL
);
5807 case XML_ELEMENT_TYPE_ELEMENT
:
5810 * VC: Standalone Document Declaration
5811 * - element types with element content, if white space
5812 * occurs directly within any instance of those types.
5814 if (state
->exec
!= NULL
) {
5815 ret
= xmlRegExecPushString(state
->exec
, qname
, NULL
);
5817 xmlErrValidNode(ctxt
, state
->node
,
5818 XML_DTD_CONTENT_MODEL
,
5819 "Element %s content does not follow the DTD, Misplaced %s\n",
5820 state
->node
->name
, qname
, NULL
);
5830 eDecl
= xmlValidGetElemDecl(ctxt
, doc
, elem
, &extsubset
);
5831 vstateVPush(ctxt
, eDecl
, elem
);
5836 * xmlValidatePushCData:
5837 * @ctxt: the validation context
5838 * @data: some character data read
5839 * @len: the length of the data
5841 * check the CData parsed for validation in the current stack
5843 * returns 1 if no validation problem was found or 0 otherwise
5846 xmlValidatePushCData(xmlValidCtxtPtr ctxt
, const xmlChar
*data
, int len
) {
5849 /* printf("CDATA %s %d\n", data, len); */
5854 if ((ctxt
->vstateNr
> 0) && (ctxt
->vstate
!= NULL
)) {
5855 xmlValidStatePtr state
= ctxt
->vstate
;
5856 xmlElementPtr elemDecl
;
5859 * Check the new element against the content model of the new elem.
5861 if (state
->elemDecl
!= NULL
) {
5862 elemDecl
= state
->elemDecl
;
5864 switch(elemDecl
->etype
) {
5865 case XML_ELEMENT_TYPE_UNDEFINED
:
5868 case XML_ELEMENT_TYPE_EMPTY
:
5869 xmlErrValidNode(ctxt
, state
->node
,
5871 "Element %s was declared EMPTY this one has content\n",
5872 state
->node
->name
, NULL
, NULL
);
5875 case XML_ELEMENT_TYPE_ANY
:
5877 case XML_ELEMENT_TYPE_MIXED
:
5879 case XML_ELEMENT_TYPE_ELEMENT
:
5883 for (i
= 0;i
< len
;i
++) {
5884 if (!IS_BLANK_CH(data
[i
])) {
5885 xmlErrValidNode(ctxt
, state
->node
,
5886 XML_DTD_CONTENT_MODEL
,
5887 "Element %s content does not follow the DTD, Text not allowed\n",
5888 state
->node
->name
, NULL
, NULL
);
5895 * VC: Standalone Document Declaration
5896 * element types with element content, if white space
5897 * occurs directly within any instance of those types.
5909 * xmlValidatePopElement:
5910 * @ctxt: the validation context
5911 * @doc: a document instance
5912 * @elem: an element instance
5913 * @qname: the qualified name as appearing in the serialization
5915 * Pop the element end from the validation stack.
5917 * returns 1 if no validation problem was found or 0 otherwise
5920 xmlValidatePopElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc ATTRIBUTE_UNUSED
,
5921 xmlNodePtr elem ATTRIBUTE_UNUSED
,
5922 const xmlChar
*qname ATTRIBUTE_UNUSED
) {
5927 /* printf("PopElem %s\n", qname); */
5928 if ((ctxt
->vstateNr
> 0) && (ctxt
->vstate
!= NULL
)) {
5929 xmlValidStatePtr state
= ctxt
->vstate
;
5930 xmlElementPtr elemDecl
;
5933 * Check the new element against the content model of the new elem.
5935 if (state
->elemDecl
!= NULL
) {
5936 elemDecl
= state
->elemDecl
;
5938 if (elemDecl
->etype
== XML_ELEMENT_TYPE_ELEMENT
) {
5939 if (state
->exec
!= NULL
) {
5940 ret
= xmlRegExecPushString(state
->exec
, NULL
, NULL
);
5942 xmlErrValidNode(ctxt
, state
->node
,
5943 XML_DTD_CONTENT_MODEL
,
5944 "Element %s content does not follow the DTD, Expecting more child\n",
5945 state
->node
->name
, NULL
,NULL
);
5948 * previous validation errors should not generate
5960 #endif /* LIBXML_REGEXP_ENABLED */
5963 * xmlValidateOneElement:
5964 * @ctxt: the validation context
5965 * @doc: a document instance
5966 * @elem: an element instance
5968 * Try to validate a single element and it's attributes,
5969 * basically it does the following checks as described by the
5970 * XML-1.0 recommendation:
5971 * - [ VC: Element Valid ]
5972 * - [ VC: Required Attribute ]
5973 * Then call xmlValidateOneAttribute() for each attribute present.
5975 * The ID/IDREF checkings are done separately
5977 * returns 1 if valid or 0 otherwise
5981 xmlValidateOneElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
5983 xmlElementPtr elemDecl
= NULL
;
5984 xmlElementContentPtr cont
;
5985 xmlAttributePtr attr
;
5988 const xmlChar
*name
;
5993 if (elem
== NULL
) return(0);
5994 switch (elem
->type
) {
5995 case XML_ATTRIBUTE_NODE
:
5996 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
5997 "Attribute element not expected\n", NULL
, NULL
,NULL
);
6000 if (elem
->children
!= NULL
) {
6001 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6002 "Text element has children !\n",
6006 if (elem
->ns
!= NULL
) {
6007 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6008 "Text element has namespace !\n",
6012 if (elem
->content
== NULL
) {
6013 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6014 "Text element has no content !\n",
6019 case XML_XINCLUDE_START
:
6020 case XML_XINCLUDE_END
:
6022 case XML_CDATA_SECTION_NODE
:
6023 case XML_ENTITY_REF_NODE
:
6025 case XML_COMMENT_NODE
:
6027 case XML_ENTITY_NODE
:
6028 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6029 "Entity element not expected\n", NULL
, NULL
,NULL
);
6031 case XML_NOTATION_NODE
:
6032 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6033 "Notation element not expected\n", NULL
, NULL
,NULL
);
6035 case XML_DOCUMENT_NODE
:
6036 case XML_DOCUMENT_TYPE_NODE
:
6037 case XML_DOCUMENT_FRAG_NODE
:
6038 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6039 "Document element not expected\n", NULL
, NULL
,NULL
);
6041 case XML_HTML_DOCUMENT_NODE
:
6042 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6043 "HTML Document not expected\n", NULL
, NULL
,NULL
);
6045 case XML_ELEMENT_NODE
:
6048 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6049 "unknown element type\n", NULL
, NULL
,NULL
);
6054 * Fetch the declaration
6056 elemDecl
= xmlValidGetElemDecl(ctxt
, doc
, elem
, &extsubset
);
6057 if (elemDecl
== NULL
)
6061 * If vstateNr is not zero that means continuous validation is
6062 * activated, do not try to check the content model at that level.
6064 if (ctxt
->vstateNr
== 0) {
6065 /* Check that the element content matches the definition */
6066 switch (elemDecl
->etype
) {
6067 case XML_ELEMENT_TYPE_UNDEFINED
:
6068 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_ELEM
,
6069 "No declaration for element %s\n",
6070 elem
->name
, NULL
, NULL
);
6072 case XML_ELEMENT_TYPE_EMPTY
:
6073 if (elem
->children
!= NULL
) {
6074 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOT_EMPTY
,
6075 "Element %s was declared EMPTY this one has content\n",
6076 elem
->name
, NULL
, NULL
);
6080 case XML_ELEMENT_TYPE_ANY
:
6081 /* I don't think anything is required then */
6083 case XML_ELEMENT_TYPE_MIXED
:
6085 /* simple case of declared as #PCDATA */
6086 if ((elemDecl
->content
!= NULL
) &&
6087 (elemDecl
->content
->type
== XML_ELEMENT_CONTENT_PCDATA
)) {
6088 ret
= xmlValidateOneCdataElement(ctxt
, doc
, elem
);
6090 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOT_PCDATA
,
6091 "Element %s was declared #PCDATA but contains non text nodes\n",
6092 elem
->name
, NULL
, NULL
);
6096 child
= elem
->children
;
6097 /* Hum, this start to get messy */
6098 while (child
!= NULL
) {
6099 if (child
->type
== XML_ELEMENT_NODE
) {
6101 if ((child
->ns
!= NULL
) && (child
->ns
->prefix
!= NULL
)) {
6105 fullname
= xmlBuildQName(child
->name
, child
->ns
->prefix
,
6107 if (fullname
== NULL
)
6109 cont
= elemDecl
->content
;
6110 while (cont
!= NULL
) {
6111 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
6112 if (xmlStrEqual(cont
->name
, fullname
))
6114 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
6115 (cont
->c1
!= NULL
) &&
6116 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)){
6117 if (xmlStrEqual(cont
->c1
->name
, fullname
))
6119 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
6120 (cont
->c1
== NULL
) ||
6121 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)){
6122 xmlErrValid(NULL
, XML_DTD_MIXED_CORRUPT
,
6123 "Internal: MIXED struct corrupted\n",
6129 if ((fullname
!= fn
) && (fullname
!= child
->name
))
6134 cont
= elemDecl
->content
;
6135 while (cont
!= NULL
) {
6136 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
6137 if (xmlStrEqual(cont
->name
, name
)) break;
6138 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
6139 (cont
->c1
!= NULL
) &&
6140 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)) {
6141 if (xmlStrEqual(cont
->c1
->name
, name
)) break;
6142 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
6143 (cont
->c1
== NULL
) ||
6144 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)) {
6145 xmlErrValid(ctxt
, XML_DTD_MIXED_CORRUPT
,
6146 "Internal: MIXED struct corrupted\n",
6153 xmlErrValidNode(ctxt
, elem
, XML_DTD_INVALID_CHILD
,
6154 "Element %s is not declared in %s list of possible children\n",
6155 name
, elem
->name
, NULL
);
6160 child
= child
->next
;
6163 case XML_ELEMENT_TYPE_ELEMENT
:
6164 if ((doc
->standalone
== 1) && (extsubset
== 1)) {
6166 * VC: Standalone Document Declaration
6167 * - element types with element content, if white space
6168 * occurs directly within any instance of those types.
6170 child
= elem
->children
;
6171 while (child
!= NULL
) {
6172 if (child
->type
== XML_TEXT_NODE
) {
6173 const xmlChar
*content
= child
->content
;
6175 while (IS_BLANK_CH(*content
))
6177 if (*content
== 0) {
6178 xmlErrValidNode(ctxt
, elem
,
6179 XML_DTD_STANDALONE_WHITE_SPACE
,
6180 "standalone: %s declared in the external subset contains white spaces nodes\n",
6181 elem
->name
, NULL
, NULL
);
6189 child
= elem
->children
;
6190 cont
= elemDecl
->content
;
6191 tmp
= xmlValidateElementContent(ctxt
, child
, elemDecl
, 1, elem
);
6196 } /* not continuous */
6198 /* [ VC: Required Attribute ] */
6199 attr
= elemDecl
->attributes
;
6200 while (attr
!= NULL
) {
6201 if (attr
->def
== XML_ATTRIBUTE_REQUIRED
) {
6204 if ((attr
->prefix
== NULL
) &&
6205 (xmlStrEqual(attr
->name
, BAD_CAST
"xmlns"))) {
6209 while (ns
!= NULL
) {
6210 if (ns
->prefix
== NULL
)
6214 } else if (xmlStrEqual(attr
->prefix
, BAD_CAST
"xmlns")) {
6218 while (ns
!= NULL
) {
6219 if (xmlStrEqual(attr
->name
, ns
->prefix
))
6226 attrib
= elem
->properties
;
6227 while (attrib
!= NULL
) {
6228 if (xmlStrEqual(attrib
->name
, attr
->name
)) {
6229 if (attr
->prefix
!= NULL
) {
6230 xmlNsPtr nameSpace
= attrib
->ns
;
6232 if (nameSpace
== NULL
)
6233 nameSpace
= elem
->ns
;
6235 * qualified names handling is problematic, having a
6236 * different prefix should be possible but DTDs don't
6237 * allow to define the URI instead of the prefix :-(
6239 if (nameSpace
== NULL
) {
6242 } else if (!xmlStrEqual(nameSpace
->prefix
,
6250 * We should allow applications to define namespaces
6251 * for their application even if the DTD doesn't
6252 * carry one, otherwise, basically we would always
6258 attrib
= attrib
->next
;
6261 if (qualified
== -1) {
6262 if (attr
->prefix
== NULL
) {
6263 xmlErrValidNode(ctxt
, elem
, XML_DTD_MISSING_ATTRIBUTE
,
6264 "Element %s does not carry attribute %s\n",
6265 elem
->name
, attr
->name
, NULL
);
6268 xmlErrValidNode(ctxt
, elem
, XML_DTD_MISSING_ATTRIBUTE
,
6269 "Element %s does not carry attribute %s:%s\n",
6270 elem
->name
, attr
->prefix
,attr
->name
);
6273 } else if (qualified
== 0) {
6274 xmlErrValidWarning(ctxt
, elem
, XML_DTD_NO_PREFIX
,
6275 "Element %s required attribute %s:%s has no prefix\n",
6276 elem
->name
, attr
->prefix
, attr
->name
);
6277 } else if (qualified
== 1) {
6278 xmlErrValidWarning(ctxt
, elem
, XML_DTD_DIFFERENT_PREFIX
,
6279 "Element %s required attribute %s:%s has different prefix\n",
6280 elem
->name
, attr
->prefix
, attr
->name
);
6282 } else if (attr
->def
== XML_ATTRIBUTE_FIXED
) {
6284 * Special tests checking #FIXED namespace declarations
6285 * have the right value since this is not done as an
6286 * attribute checking
6288 if ((attr
->prefix
== NULL
) &&
6289 (xmlStrEqual(attr
->name
, BAD_CAST
"xmlns"))) {
6293 while (ns
!= NULL
) {
6294 if (ns
->prefix
== NULL
) {
6295 if (!xmlStrEqual(attr
->defaultValue
, ns
->href
)) {
6296 xmlErrValidNode(ctxt
, elem
,
6297 XML_DTD_ELEM_DEFAULT_NAMESPACE
,
6298 "Element %s namespace name for default namespace does not match the DTD\n",
6299 elem
->name
, NULL
, NULL
);
6306 } else if (xmlStrEqual(attr
->prefix
, BAD_CAST
"xmlns")) {
6310 while (ns
!= NULL
) {
6311 if (xmlStrEqual(attr
->name
, ns
->prefix
)) {
6312 if (!xmlStrEqual(attr
->defaultValue
, ns
->href
)) {
6313 xmlErrValidNode(ctxt
, elem
, XML_DTD_ELEM_NAMESPACE
,
6314 "Element %s namespace name for %s does not match the DTD\n",
6315 elem
->name
, ns
->prefix
, NULL
);
6332 * @ctxt: the validation context
6333 * @doc: a document instance
6335 * Try to validate a the root element
6336 * basically it does the following check as described by the
6337 * XML-1.0 recommendation:
6338 * - [ VC: Root Element Type ]
6339 * it doesn't try to recurse or apply other check to the element
6341 * returns 1 if valid or 0 otherwise
6345 xmlValidateRoot(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
6349 if (doc
== NULL
) return(0);
6351 root
= xmlDocGetRootElement(doc
);
6352 if ((root
== NULL
) || (root
->name
== NULL
)) {
6353 xmlErrValid(ctxt
, XML_DTD_NO_ROOT
,
6354 "no root element\n", NULL
);
6359 * When doing post validation against a separate DTD, those may
6360 * no internal subset has been generated
6362 if ((doc
->intSubset
!= NULL
) &&
6363 (doc
->intSubset
->name
!= NULL
)) {
6365 * Check first the document root against the NQName
6367 if (!xmlStrEqual(doc
->intSubset
->name
, root
->name
)) {
6368 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
)) {
6372 fullname
= xmlBuildQName(root
->name
, root
->ns
->prefix
, fn
, 50);
6373 if (fullname
== NULL
) {
6374 xmlVErrMemory(ctxt
, NULL
);
6377 ret
= xmlStrEqual(doc
->intSubset
->name
, fullname
);
6378 if ((fullname
!= fn
) && (fullname
!= root
->name
))
6383 if ((xmlStrEqual(doc
->intSubset
->name
, BAD_CAST
"HTML")) &&
6384 (xmlStrEqual(root
->name
, BAD_CAST
"html")))
6386 xmlErrValidNode(ctxt
, root
, XML_DTD_ROOT_NAME
,
6387 "root and DTD name do not match '%s' and '%s'\n",
6388 root
->name
, doc
->intSubset
->name
, NULL
);
6398 * xmlValidateElement:
6399 * @ctxt: the validation context
6400 * @doc: a document instance
6401 * @elem: an element instance
6403 * Try to validate the subtree under an element
6405 * returns 1 if valid or 0 otherwise
6409 xmlValidateElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, xmlNodePtr elem
) {
6413 const xmlChar
*value
;
6416 if (elem
== NULL
) return(0);
6419 * XInclude elements were added after parsing in the infoset,
6420 * they don't really mean anything validation wise.
6422 if ((elem
->type
== XML_XINCLUDE_START
) ||
6423 (elem
->type
== XML_XINCLUDE_END
) ||
6424 (elem
->type
== XML_NAMESPACE_DECL
))
6430 * Entities references have to be handled separately
6432 if (elem
->type
== XML_ENTITY_REF_NODE
) {
6436 ret
&= xmlValidateOneElement(ctxt
, doc
, elem
);
6437 if (elem
->type
== XML_ELEMENT_NODE
) {
6438 attr
= elem
->properties
;
6439 while (attr
!= NULL
) {
6440 value
= xmlNodeListGetString(doc
, attr
->children
, 0);
6441 ret
&= xmlValidateOneAttribute(ctxt
, doc
, elem
, attr
, value
);
6443 xmlFree((char *)value
);
6447 while (ns
!= NULL
) {
6448 if (elem
->ns
== NULL
)
6449 ret
&= xmlValidateOneNamespace(ctxt
, doc
, elem
, NULL
,
6452 ret
&= xmlValidateOneNamespace(ctxt
, doc
, elem
,
6453 elem
->ns
->prefix
, ns
, ns
->href
);
6457 child
= elem
->children
;
6458 while (child
!= NULL
) {
6459 ret
&= xmlValidateElement(ctxt
, doc
, child
);
6460 child
= child
->next
;
6468 * @ref: A reference to be validated
6469 * @ctxt: Validation context
6470 * @name: Name of ID we are searching for
6474 xmlValidateRef(xmlRefPtr ref
, xmlValidCtxtPtr ctxt
,
6475 const xmlChar
*name
) {
6481 if ((ref
->attr
== NULL
) && (ref
->name
== NULL
))
6485 xmlChar
*dup
, *str
= NULL
, *cur
, save
;
6487 dup
= xmlStrdup(name
);
6495 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
))) cur
++;
6498 id
= xmlGetID(ctxt
->doc
, str
);
6500 xmlErrValidNodeNr(ctxt
, NULL
, XML_DTD_UNKNOWN_ID
,
6501 "attribute %s line %d references an unknown ID \"%s\"\n",
6502 ref
->name
, ref
->lineno
, str
);
6508 while (IS_BLANK_CH(*cur
)) cur
++;
6511 } else if (attr
->atype
== XML_ATTRIBUTE_IDREF
) {
6512 id
= xmlGetID(ctxt
->doc
, name
);
6514 xmlErrValidNode(ctxt
, attr
->parent
, XML_DTD_UNKNOWN_ID
,
6515 "IDREF attribute %s references an unknown ID \"%s\"\n",
6516 attr
->name
, name
, NULL
);
6519 } else if (attr
->atype
== XML_ATTRIBUTE_IDREFS
) {
6520 xmlChar
*dup
, *str
= NULL
, *cur
, save
;
6522 dup
= xmlStrdup(name
);
6524 xmlVErrMemory(ctxt
, "IDREFS split");
6531 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
))) cur
++;
6534 id
= xmlGetID(ctxt
->doc
, str
);
6536 xmlErrValidNode(ctxt
, attr
->parent
, XML_DTD_UNKNOWN_ID
,
6537 "IDREFS attribute %s references an unknown ID \"%s\"\n",
6538 attr
->name
, str
, NULL
);
6544 while (IS_BLANK_CH(*cur
)) cur
++;
6551 * xmlWalkValidateList:
6552 * @data: Contents of current link
6553 * @user: Value supplied by the user
6555 * Returns 0 to abort the walk or 1 to continue
6558 xmlWalkValidateList(const void *data
, void *user
)
6560 xmlValidateMemoPtr memo
= (xmlValidateMemoPtr
)user
;
6561 xmlValidateRef((xmlRefPtr
)data
, memo
->ctxt
, memo
->name
);
6566 * xmlValidateCheckRefCallback:
6567 * @ref_list: List of references
6568 * @ctxt: Validation context
6569 * @name: Name of ID we are searching for
6573 xmlValidateCheckRefCallback(void *payload
, void *data
, const xmlChar
*name
) {
6574 xmlListPtr ref_list
= (xmlListPtr
) payload
;
6575 xmlValidCtxtPtr ctxt
= (xmlValidCtxtPtr
) data
;
6576 xmlValidateMemo memo
;
6578 if (ref_list
== NULL
)
6583 xmlListWalk(ref_list
, xmlWalkValidateList
, &memo
);
6588 * xmlValidateDocumentFinal:
6589 * @ctxt: the validation context
6590 * @doc: a document instance
6592 * Does the final step for the document validation once all the
6593 * incremental validation steps have been completed
6595 * basically it does the following checks described by the XML Rec
6597 * Check all the IDREF/IDREFS attributes definition for validity
6599 * returns 1 if valid or 0 otherwise
6603 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
6604 xmlRefTablePtr table
;
6610 xmlErrValid(ctxt
, XML_DTD_NO_DOC
,
6611 "xmlValidateDocumentFinal: doc == NULL\n", NULL
);
6615 /* trick to get correct line id report */
6616 save
= ctxt
->finishDtd
;
6617 ctxt
->finishDtd
= 0;
6620 * Check all the NOTATION/NOTATIONS attributes
6623 * Check all the ENTITY/ENTITIES attributes definition for validity
6626 * Check all the IDREF/IDREFS attributes definition for validity
6628 table
= (xmlRefTablePtr
) doc
->refs
;
6631 xmlHashScan(table
, xmlValidateCheckRefCallback
, ctxt
);
6633 ctxt
->finishDtd
= save
;
6634 return(ctxt
->valid
);
6639 * @ctxt: the validation context
6640 * @doc: a document instance
6641 * @dtd: a dtd instance
6643 * Try to validate the document against the dtd instance
6645 * Basically it does check all the definitions in the DtD.
6646 * Note the the internal subset (if present) is de-coupled
6647 * (i.e. not used), which could give problems if ID or IDREF
6650 * returns 1 if valid or 0 otherwise
6654 xmlValidateDtd(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, xmlDtdPtr dtd
) {
6656 xmlDtdPtr oldExt
, oldInt
;
6659 if (dtd
== NULL
) return(0);
6660 if (doc
== NULL
) return(0);
6661 oldExt
= doc
->extSubset
;
6662 oldInt
= doc
->intSubset
;
6663 doc
->extSubset
= dtd
;
6664 doc
->intSubset
= NULL
;
6665 ret
= xmlValidateRoot(ctxt
, doc
);
6667 doc
->extSubset
= oldExt
;
6668 doc
->intSubset
= oldInt
;
6671 if (doc
->ids
!= NULL
) {
6672 xmlFreeIDTable(doc
->ids
);
6675 if (doc
->refs
!= NULL
) {
6676 xmlFreeRefTable(doc
->refs
);
6679 root
= xmlDocGetRootElement(doc
);
6680 ret
= xmlValidateElement(ctxt
, doc
, root
);
6681 ret
&= xmlValidateDocumentFinal(ctxt
, doc
);
6682 doc
->extSubset
= oldExt
;
6683 doc
->intSubset
= oldInt
;
6688 xmlValidateNotationCallback(void *payload
, void *data
,
6689 const xmlChar
*name ATTRIBUTE_UNUSED
) {
6690 xmlEntityPtr cur
= (xmlEntityPtr
) payload
;
6691 xmlValidCtxtPtr ctxt
= (xmlValidCtxtPtr
) data
;
6694 if (cur
->etype
== XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
6695 xmlChar
*notation
= cur
->content
;
6697 if (notation
!= NULL
) {
6700 ret
= xmlValidateNotationUse(ctxt
, cur
->doc
, notation
);
6709 xmlValidateAttributeCallback(void *payload
, void *data
,
6710 const xmlChar
*name ATTRIBUTE_UNUSED
) {
6711 xmlAttributePtr cur
= (xmlAttributePtr
) payload
;
6712 xmlValidCtxtPtr ctxt
= (xmlValidCtxtPtr
) data
;
6715 xmlElementPtr elem
= NULL
;
6719 switch (cur
->atype
) {
6720 case XML_ATTRIBUTE_CDATA
:
6721 case XML_ATTRIBUTE_ID
:
6722 case XML_ATTRIBUTE_IDREF
:
6723 case XML_ATTRIBUTE_IDREFS
:
6724 case XML_ATTRIBUTE_NMTOKEN
:
6725 case XML_ATTRIBUTE_NMTOKENS
:
6726 case XML_ATTRIBUTE_ENUMERATION
:
6728 case XML_ATTRIBUTE_ENTITY
:
6729 case XML_ATTRIBUTE_ENTITIES
:
6730 case XML_ATTRIBUTE_NOTATION
:
6731 if (cur
->defaultValue
!= NULL
) {
6733 ret
= xmlValidateAttributeValue2(ctxt
, ctxt
->doc
, cur
->name
,
6734 cur
->atype
, cur
->defaultValue
);
6735 if ((ret
== 0) && (ctxt
->valid
== 1))
6738 if (cur
->tree
!= NULL
) {
6739 xmlEnumerationPtr tree
= cur
->tree
;
6740 while (tree
!= NULL
) {
6741 ret
= xmlValidateAttributeValue2(ctxt
, ctxt
->doc
,
6742 cur
->name
, cur
->atype
, tree
->name
);
6743 if ((ret
== 0) && (ctxt
->valid
== 1))
6749 if (cur
->atype
== XML_ATTRIBUTE_NOTATION
) {
6751 if (cur
->elem
== NULL
) {
6752 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
6753 "xmlValidateAttributeCallback(%s): internal error\n",
6754 (const char *) cur
->name
);
6759 elem
= xmlGetDtdElementDesc(doc
->intSubset
, cur
->elem
);
6760 if ((elem
== NULL
) && (doc
!= NULL
))
6761 elem
= xmlGetDtdElementDesc(doc
->extSubset
, cur
->elem
);
6762 if ((elem
== NULL
) && (cur
->parent
!= NULL
) &&
6763 (cur
->parent
->type
== XML_DTD_NODE
))
6764 elem
= xmlGetDtdElementDesc((xmlDtdPtr
) cur
->parent
, cur
->elem
);
6766 xmlErrValidNode(ctxt
, NULL
, XML_DTD_UNKNOWN_ELEM
,
6767 "attribute %s: could not find decl for element %s\n",
6768 cur
->name
, cur
->elem
, NULL
);
6771 if (elem
->etype
== XML_ELEMENT_TYPE_EMPTY
) {
6772 xmlErrValidNode(ctxt
, NULL
, XML_DTD_EMPTY_NOTATION
,
6773 "NOTATION attribute %s declared for EMPTY element %s\n",
6774 cur
->name
, cur
->elem
, NULL
);
6781 * xmlValidateDtdFinal:
6782 * @ctxt: the validation context
6783 * @doc: a document instance
6785 * Does the final step for the dtds validation once all the
6786 * subsets have been parsed
6788 * basically it does the following checks described by the XML Rec
6789 * - check that ENTITY and ENTITIES type attributes default or
6790 * possible values matches one of the defined entities.
6791 * - check that NOTATION type attributes default or
6792 * possible values matches one of the defined notations.
6794 * returns 1 if valid or 0 if invalid and -1 if not well-formed
6798 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
6800 xmlAttributeTablePtr table
;
6801 xmlEntitiesTablePtr entities
;
6803 if ((doc
== NULL
) || (ctxt
== NULL
)) return(0);
6804 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
))
6808 dtd
= doc
->intSubset
;
6809 if ((dtd
!= NULL
) && (dtd
->attributes
!= NULL
)) {
6810 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
6811 xmlHashScan(table
, xmlValidateAttributeCallback
, ctxt
);
6813 if ((dtd
!= NULL
) && (dtd
->entities
!= NULL
)) {
6814 entities
= (xmlEntitiesTablePtr
) dtd
->entities
;
6815 xmlHashScan(entities
, xmlValidateNotationCallback
, ctxt
);
6817 dtd
= doc
->extSubset
;
6818 if ((dtd
!= NULL
) && (dtd
->attributes
!= NULL
)) {
6819 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
6820 xmlHashScan(table
, xmlValidateAttributeCallback
, ctxt
);
6822 if ((dtd
!= NULL
) && (dtd
->entities
!= NULL
)) {
6823 entities
= (xmlEntitiesTablePtr
) dtd
->entities
;
6824 xmlHashScan(entities
, xmlValidateNotationCallback
, ctxt
);
6826 return(ctxt
->valid
);
6830 * xmlValidateDocument:
6831 * @ctxt: the validation context
6832 * @doc: a document instance
6834 * Try to validate the document instance
6836 * basically it does the all the checks described by the XML Rec
6837 * i.e. validates the internal and external subset (if present)
6838 * and validate the document tree.
6840 * returns 1 if valid or 0 otherwise
6844 xmlValidateDocument(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
6850 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
)) {
6851 xmlErrValid(ctxt
, XML_DTD_NO_DTD
,
6852 "no DTD found!\n", NULL
);
6855 if ((doc
->intSubset
!= NULL
) && ((doc
->intSubset
->SystemID
!= NULL
) ||
6856 (doc
->intSubset
->ExternalID
!= NULL
)) && (doc
->extSubset
== NULL
)) {
6858 if (doc
->intSubset
->SystemID
!= NULL
) {
6859 sysID
= xmlBuildURI(doc
->intSubset
->SystemID
,
6861 if (sysID
== NULL
) {
6862 xmlErrValid(ctxt
, XML_DTD_LOAD_ERROR
,
6863 "Could not build URI for external subset \"%s\"\n",
6864 (const char *) doc
->intSubset
->SystemID
);
6869 doc
->extSubset
= xmlParseDTD(doc
->intSubset
->ExternalID
,
6870 (const xmlChar
*)sysID
);
6873 if (doc
->extSubset
== NULL
) {
6874 if (doc
->intSubset
->SystemID
!= NULL
) {
6875 xmlErrValid(ctxt
, XML_DTD_LOAD_ERROR
,
6876 "Could not load the external subset \"%s\"\n",
6877 (const char *) doc
->intSubset
->SystemID
);
6879 xmlErrValid(ctxt
, XML_DTD_LOAD_ERROR
,
6880 "Could not load the external subset \"%s\"\n",
6881 (const char *) doc
->intSubset
->ExternalID
);
6887 if (doc
->ids
!= NULL
) {
6888 xmlFreeIDTable(doc
->ids
);
6891 if (doc
->refs
!= NULL
) {
6892 xmlFreeRefTable(doc
->refs
);
6895 ret
= xmlValidateDtdFinal(ctxt
, doc
);
6896 if (!xmlValidateRoot(ctxt
, doc
)) return(0);
6898 root
= xmlDocGetRootElement(doc
);
6899 ret
&= xmlValidateElement(ctxt
, doc
, root
);
6900 ret
&= xmlValidateDocumentFinal(ctxt
, doc
);
6904 /************************************************************************
6906 * Routines for dynamic validation editing *
6908 ************************************************************************/
6911 * xmlValidGetPotentialChildren:
6912 * @ctree: an element content tree
6913 * @names: an array to store the list of child names
6914 * @len: a pointer to the number of element in the list
6915 * @max: the size of the array
6917 * Build/extend a list of potential children allowed by the content tree
6919 * returns the number of element in the list, or -1 in case of error.
6923 xmlValidGetPotentialChildren(xmlElementContent
*ctree
,
6924 const xmlChar
**names
,
6925 int *len
, int max
) {
6928 if ((ctree
== NULL
) || (names
== NULL
) || (len
== NULL
))
6930 if (*len
>= max
) return(*len
);
6932 switch (ctree
->type
) {
6933 case XML_ELEMENT_CONTENT_PCDATA
:
6934 for (i
= 0; i
< *len
;i
++)
6935 if (xmlStrEqual(BAD_CAST
"#PCDATA", names
[i
])) return(*len
);
6936 names
[(*len
)++] = BAD_CAST
"#PCDATA";
6938 case XML_ELEMENT_CONTENT_ELEMENT
:
6939 for (i
= 0; i
< *len
;i
++)
6940 if (xmlStrEqual(ctree
->name
, names
[i
])) return(*len
);
6941 names
[(*len
)++] = ctree
->name
;
6943 case XML_ELEMENT_CONTENT_SEQ
:
6944 xmlValidGetPotentialChildren(ctree
->c1
, names
, len
, max
);
6945 xmlValidGetPotentialChildren(ctree
->c2
, names
, len
, max
);
6947 case XML_ELEMENT_CONTENT_OR
:
6948 xmlValidGetPotentialChildren(ctree
->c1
, names
, len
, max
);
6949 xmlValidGetPotentialChildren(ctree
->c2
, names
, len
, max
);
6957 * Dummy function to suppress messages while we try out valid elements
6959 static void XMLCDECL
xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED
,
6960 const char *msg ATTRIBUTE_UNUSED
, ...) {
6965 * xmlValidGetValidElements:
6966 * @prev: an element to insert after
6967 * @next: an element to insert next
6968 * @names: an array to store the list of child names
6969 * @max: the size of the array
6971 * This function returns the list of authorized children to insert
6972 * within an existing tree while respecting the validity constraints
6973 * forced by the Dtd. The insertion point is defined using @prev and
6974 * @next in the following ways:
6975 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6976 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6977 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6978 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6979 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6981 * pointers to the element names are inserted at the beginning of the array
6982 * and do not need to be freed.
6984 * returns the number of element in the list, or -1 in case of error. If
6985 * the function returns the value @max the caller is invited to grow the
6986 * receiving array and retry.
6990 xmlValidGetValidElements(xmlNode
*prev
, xmlNode
*next
, const xmlChar
**names
,
6993 int nb_valid_elements
= 0;
6994 const xmlChar
*elements
[256]={0};
6995 int nb_elements
= 0, i
;
6996 const xmlChar
*name
;
7004 xmlNode
*parent_childs
;
7005 xmlNode
*parent_last
;
7007 xmlElement
*element_desc
;
7009 if (prev
== NULL
&& next
== NULL
)
7012 if (names
== NULL
) return(-1);
7013 if (max
<= 0) return(-1);
7015 memset(&vctxt
, 0, sizeof (xmlValidCtxt
));
7016 vctxt
.error
= xmlNoValidityErr
; /* this suppresses err/warn output */
7018 nb_valid_elements
= 0;
7019 ref_node
= prev
? prev
: next
;
7020 parent
= ref_node
->parent
;
7023 * Retrieves the parent element declaration
7025 element_desc
= xmlGetDtdElementDesc(parent
->doc
->intSubset
,
7027 if ((element_desc
== NULL
) && (parent
->doc
->extSubset
!= NULL
))
7028 element_desc
= xmlGetDtdElementDesc(parent
->doc
->extSubset
,
7030 if (element_desc
== NULL
) return(-1);
7033 * Do a backup of the current tree structure
7035 prev_next
= prev
? prev
->next
: NULL
;
7036 next_prev
= next
? next
->prev
: NULL
;
7037 parent_childs
= parent
->children
;
7038 parent_last
= parent
->last
;
7041 * Creates a dummy node and insert it into the tree
7043 test_node
= xmlNewDocNode (ref_node
->doc
, NULL
, BAD_CAST
"<!dummy?>", NULL
);
7044 if (test_node
== NULL
)
7047 test_node
->parent
= parent
;
7048 test_node
->prev
= prev
;
7049 test_node
->next
= next
;
7050 name
= test_node
->name
;
7052 if (prev
) prev
->next
= test_node
;
7053 else parent
->children
= test_node
;
7055 if (next
) next
->prev
= test_node
;
7056 else parent
->last
= test_node
;
7059 * Insert each potential child node and check if the parent is
7062 nb_elements
= xmlValidGetPotentialChildren(element_desc
->content
,
7063 elements
, &nb_elements
, 256);
7065 for (i
= 0;i
< nb_elements
;i
++) {
7066 test_node
->name
= elements
[i
];
7067 if (xmlValidateOneElement(&vctxt
, parent
->doc
, parent
)) {
7070 for (j
= 0; j
< nb_valid_elements
;j
++)
7071 if (xmlStrEqual(elements
[i
], names
[j
])) break;
7072 names
[nb_valid_elements
++] = elements
[i
];
7073 if (nb_valid_elements
>= max
) break;
7078 * Restore the tree structure
7080 if (prev
) prev
->next
= prev_next
;
7081 if (next
) next
->prev
= next_prev
;
7082 parent
->children
= parent_childs
;
7083 parent
->last
= parent_last
;
7086 * Free up the dummy node
7088 test_node
->name
= name
;
7089 xmlFreeNode(test_node
);
7091 return(nb_valid_elements
);
7093 #endif /* LIBXML_VALID_ENABLED */
7095 #define bottom_valid
7096 #include "elfgcchack.h"