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.
16 #include <libxml/xmlmemory.h>
17 #include <libxml/hash.h>
18 #include <libxml/uri.h>
19 #include <libxml/valid.h>
20 #include <libxml/parser.h>
21 #include <libxml/parserInternals.h>
22 #include <libxml/xmlerror.h>
23 #include <libxml/list.h>
24 #include <libxml/globals.h>
26 #include "private/error.h"
27 #include "private/parser.h"
30 xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt
, xmlDtdPtr dtd
, const xmlChar
*name
,
32 /* #define DEBUG_VALID_ALGO */
33 /* #define DEBUG_REGEXP_ALGO */
36 xmlGenericError(xmlGenericErrorContext, \
37 "Unimplemented block at %s:%d\n", \
40 #ifdef LIBXML_VALID_ENABLED
42 xmlValidateAttributeValueInternal(xmlDocPtr doc
, xmlAttributeType type
,
43 const xmlChar
*value
);
45 /************************************************************************
47 * Error handling routines *
49 ************************************************************************/
53 * @ctxt: an XML validation parser context
54 * @extra: extra information
56 * Handle an out of memory error
59 xmlVErrMemory(xmlValidCtxtPtr ctxt
, const char *extra
)
61 xmlGenericErrorFunc channel
= NULL
;
62 xmlParserCtxtPtr pctxt
= NULL
;
66 channel
= ctxt
->error
;
67 data
= ctxt
->userData
;
68 /* Look up flag to detect if it is part of a parsing
70 if (ctxt
->flags
& XML_VCTXT_USE_PCTXT
) {
71 pctxt
= ctxt
->userData
;
75 __xmlRaiseError(NULL
, channel
, data
,
76 pctxt
, NULL
, XML_FROM_VALID
, XML_ERR_NO_MEMORY
,
77 XML_ERR_FATAL
, NULL
, 0, extra
, NULL
, NULL
, 0, 0,
78 "Memory allocation failed : %s\n", extra
);
80 __xmlRaiseError(NULL
, channel
, data
,
81 pctxt
, NULL
, XML_FROM_VALID
, XML_ERR_NO_MEMORY
,
82 XML_ERR_FATAL
, NULL
, 0, NULL
, NULL
, NULL
, 0, 0,
83 "Memory allocation failed\n");
88 * @ctxt: an XML validation parser context
89 * @error: the error number
90 * @extra: extra information
92 * Handle a validation error
94 static void LIBXML_ATTR_FORMAT(3,0)
95 xmlErrValid(xmlValidCtxtPtr ctxt
, xmlParserErrors error
,
96 const char *msg
, const char *extra
)
98 xmlGenericErrorFunc channel
= NULL
;
99 xmlParserCtxtPtr pctxt
= NULL
;
103 channel
= ctxt
->error
;
104 data
= ctxt
->userData
;
105 /* Look up flag to detect if it is part of a parsing
107 if (ctxt
->flags
& XML_VCTXT_USE_PCTXT
) {
108 pctxt
= ctxt
->userData
;
112 __xmlRaiseError(NULL
, channel
, data
,
113 pctxt
, NULL
, XML_FROM_VALID
, error
,
114 XML_ERR_ERROR
, NULL
, 0, extra
, NULL
, NULL
, 0, 0,
117 __xmlRaiseError(NULL
, channel
, data
,
118 pctxt
, NULL
, XML_FROM_VALID
, error
,
119 XML_ERR_ERROR
, NULL
, 0, NULL
, NULL
, NULL
, 0, 0,
123 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
126 * @ctxt: an XML validation parser context
127 * @node: the node raising the error
128 * @error: the error number
129 * @str1: extra information
130 * @str2: extra information
131 * @str3: extra information
133 * Handle a validation error, provide contextual information
135 static void LIBXML_ATTR_FORMAT(4,0)
136 xmlErrValidNode(xmlValidCtxtPtr ctxt
,
137 xmlNodePtr node
, xmlParserErrors error
,
138 const char *msg
, const xmlChar
* str1
,
139 const xmlChar
* str2
, const xmlChar
* str3
)
141 xmlStructuredErrorFunc schannel
= NULL
;
142 xmlGenericErrorFunc channel
= NULL
;
143 xmlParserCtxtPtr pctxt
= NULL
;
147 channel
= ctxt
->error
;
148 data
= ctxt
->userData
;
149 /* Look up flag to detect if it is part of a parsing
151 if (ctxt
->flags
& XML_VCTXT_USE_PCTXT
) {
152 pctxt
= ctxt
->userData
;
155 __xmlRaiseError(schannel
, channel
, data
, pctxt
, node
, XML_FROM_VALID
, error
,
156 XML_ERR_ERROR
, NULL
, 0,
159 (const char *) str3
, 0, 0, msg
, str1
, str2
, str3
);
161 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
163 #ifdef LIBXML_VALID_ENABLED
166 * @ctxt: an XML validation parser context
167 * @node: the node raising the error
168 * @error: the error number
169 * @str1: extra information
170 * @int2: extra information
171 * @str3: extra information
173 * Handle a validation error, provide contextual information
175 static void LIBXML_ATTR_FORMAT(4,0)
176 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt
,
177 xmlNodePtr node
, xmlParserErrors error
,
178 const char *msg
, const xmlChar
* str1
,
179 int int2
, const xmlChar
* str3
)
181 xmlStructuredErrorFunc schannel
= NULL
;
182 xmlGenericErrorFunc channel
= NULL
;
183 xmlParserCtxtPtr pctxt
= NULL
;
187 channel
= ctxt
->error
;
188 data
= ctxt
->userData
;
189 /* Look up flag to detect if it is part of a parsing
191 if (ctxt
->flags
& XML_VCTXT_USE_PCTXT
) {
192 pctxt
= ctxt
->userData
;
195 __xmlRaiseError(schannel
, channel
, data
, pctxt
, node
, XML_FROM_VALID
, error
,
196 XML_ERR_ERROR
, NULL
, 0,
199 NULL
, int2
, 0, msg
, str1
, int2
, str3
);
203 * xmlErrValidWarning:
204 * @ctxt: an XML validation parser context
205 * @node: the node raising the error
206 * @error: the error number
207 * @str1: extra information
208 * @str2: extra information
209 * @str3: extra information
211 * Handle a validation error, provide contextual information
213 static void LIBXML_ATTR_FORMAT(4,0)
214 xmlErrValidWarning(xmlValidCtxtPtr ctxt
,
215 xmlNodePtr node
, xmlParserErrors error
,
216 const char *msg
, const xmlChar
* str1
,
217 const xmlChar
* str2
, const xmlChar
* str3
)
219 xmlStructuredErrorFunc schannel
= NULL
;
220 xmlGenericErrorFunc channel
= NULL
;
221 xmlParserCtxtPtr pctxt
= NULL
;
225 channel
= ctxt
->warning
;
226 data
= ctxt
->userData
;
227 /* Look up flag to detect if it is part of a parsing
229 if (ctxt
->flags
& XML_VCTXT_USE_PCTXT
) {
230 pctxt
= ctxt
->userData
;
233 __xmlRaiseError(schannel
, channel
, data
, pctxt
, node
, XML_FROM_VALID
, error
,
234 XML_ERR_WARNING
, NULL
, 0,
237 (const char *) str3
, 0, 0, msg
, str1
, str2
, str3
);
242 #ifdef LIBXML_REGEXP_ENABLED
244 * If regexp are enabled we can do continuous validation without the
245 * need of a tree to validate the content model. this is done in each
247 * Each xmlValidState represent the validation state associated to the
248 * set of nodes currently open from the document root to the current element.
252 typedef struct _xmlValidState
{
253 xmlElementPtr elemDecl
; /* pointer to the content model */
254 xmlNodePtr node
; /* pointer to the current node */
255 xmlRegExecCtxtPtr exec
; /* regexp runtime */
260 vstateVPush(xmlValidCtxtPtr ctxt
, xmlElementPtr elemDecl
, xmlNodePtr node
) {
261 if ((ctxt
->vstateMax
== 0) || (ctxt
->vstateTab
== NULL
)) {
262 ctxt
->vstateMax
= 10;
263 ctxt
->vstateTab
= (xmlValidState
*) xmlMalloc(ctxt
->vstateMax
*
264 sizeof(ctxt
->vstateTab
[0]));
265 if (ctxt
->vstateTab
== NULL
) {
266 xmlVErrMemory(ctxt
, "malloc failed");
271 if (ctxt
->vstateNr
>= ctxt
->vstateMax
) {
274 tmp
= (xmlValidState
*) xmlRealloc(ctxt
->vstateTab
,
275 2 * ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
277 xmlVErrMemory(ctxt
, "realloc failed");
280 ctxt
->vstateMax
*= 2;
281 ctxt
->vstateTab
= tmp
;
283 ctxt
->vstate
= &ctxt
->vstateTab
[ctxt
->vstateNr
];
284 ctxt
->vstateTab
[ctxt
->vstateNr
].elemDecl
= elemDecl
;
285 ctxt
->vstateTab
[ctxt
->vstateNr
].node
= node
;
286 if ((elemDecl
!= NULL
) && (elemDecl
->etype
== XML_ELEMENT_TYPE_ELEMENT
)) {
287 if (elemDecl
->contModel
== NULL
)
288 xmlValidBuildContentModel(ctxt
, elemDecl
);
289 if (elemDecl
->contModel
!= NULL
) {
290 ctxt
->vstateTab
[ctxt
->vstateNr
].exec
=
291 xmlRegNewExecCtxt(elemDecl
->contModel
, NULL
, NULL
);
293 ctxt
->vstateTab
[ctxt
->vstateNr
].exec
= NULL
;
294 xmlErrValidNode(ctxt
, (xmlNodePtr
) elemDecl
,
295 XML_ERR_INTERNAL_ERROR
,
296 "Failed to build content model regexp for %s\n",
297 node
->name
, NULL
, NULL
);
300 return(ctxt
->vstateNr
++);
304 vstateVPop(xmlValidCtxtPtr ctxt
) {
305 xmlElementPtr elemDecl
;
307 if (ctxt
->vstateNr
< 1) return(-1);
309 elemDecl
= ctxt
->vstateTab
[ctxt
->vstateNr
].elemDecl
;
310 ctxt
->vstateTab
[ctxt
->vstateNr
].elemDecl
= NULL
;
311 ctxt
->vstateTab
[ctxt
->vstateNr
].node
= NULL
;
312 if ((elemDecl
!= NULL
) && (elemDecl
->etype
== XML_ELEMENT_TYPE_ELEMENT
)) {
313 xmlRegFreeExecCtxt(ctxt
->vstateTab
[ctxt
->vstateNr
].exec
);
315 ctxt
->vstateTab
[ctxt
->vstateNr
].exec
= NULL
;
316 if (ctxt
->vstateNr
>= 1)
317 ctxt
->vstate
= &ctxt
->vstateTab
[ctxt
->vstateNr
- 1];
320 return(ctxt
->vstateNr
);
323 #else /* not LIBXML_REGEXP_ENABLED */
325 * If regexp are not enabled, it uses a home made algorithm less
326 * complex and easier to
327 * debug/maintain than a generic NFA -> DFA state based algo. The
328 * only restriction is on the deepness of the tree limited by the
329 * size of the occurs bitfield
331 * this is the content of a saved state for rollbacks
334 #define ROLLBACK_OR 0
335 #define ROLLBACK_PARENT 1
337 typedef struct _xmlValidState
{
338 xmlElementContentPtr cont
; /* pointer to the content model subtree */
339 xmlNodePtr node
; /* pointer to the current node in the list */
340 long occurs
;/* bitfield for multiple occurrences */
341 unsigned char depth
; /* current depth in the overall tree */
342 unsigned char state
; /* ROLLBACK_XXX */
345 #define MAX_RECURSE 25000
346 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
347 #define CONT ctxt->vstate->cont
348 #define NODE ctxt->vstate->node
349 #define DEPTH ctxt->vstate->depth
350 #define OCCURS ctxt->vstate->occurs
351 #define STATE ctxt->vstate->state
353 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
354 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
356 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
357 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
360 vstateVPush(xmlValidCtxtPtr ctxt
, xmlElementContentPtr cont
,
361 xmlNodePtr node
, unsigned char depth
, long occurs
,
362 unsigned char state
) {
363 int i
= ctxt
->vstateNr
- 1;
365 if (ctxt
->vstateNr
> MAX_RECURSE
) {
368 if (ctxt
->vstateTab
== NULL
) {
370 ctxt
->vstateTab
= (xmlValidState
*) xmlMalloc(
371 ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
372 if (ctxt
->vstateTab
== NULL
) {
373 xmlVErrMemory(ctxt
, "malloc failed");
377 if (ctxt
->vstateNr
>= ctxt
->vstateMax
) {
380 tmp
= (xmlValidState
*) xmlRealloc(ctxt
->vstateTab
,
381 2 * ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
383 xmlVErrMemory(ctxt
, "malloc failed");
386 ctxt
->vstateMax
*= 2;
387 ctxt
->vstateTab
= tmp
;
388 ctxt
->vstate
= &ctxt
->vstateTab
[0];
391 * Don't push on the stack a state already here
393 if ((i
>= 0) && (ctxt
->vstateTab
[i
].cont
== cont
) &&
394 (ctxt
->vstateTab
[i
].node
== node
) &&
395 (ctxt
->vstateTab
[i
].depth
== depth
) &&
396 (ctxt
->vstateTab
[i
].occurs
== occurs
) &&
397 (ctxt
->vstateTab
[i
].state
== state
))
398 return(ctxt
->vstateNr
);
399 ctxt
->vstateTab
[ctxt
->vstateNr
].cont
= cont
;
400 ctxt
->vstateTab
[ctxt
->vstateNr
].node
= node
;
401 ctxt
->vstateTab
[ctxt
->vstateNr
].depth
= depth
;
402 ctxt
->vstateTab
[ctxt
->vstateNr
].occurs
= occurs
;
403 ctxt
->vstateTab
[ctxt
->vstateNr
].state
= state
;
404 return(ctxt
->vstateNr
++);
408 vstateVPop(xmlValidCtxtPtr ctxt
) {
409 if (ctxt
->vstateNr
<= 1) return(-1);
411 ctxt
->vstate
= &ctxt
->vstateTab
[0];
412 ctxt
->vstate
->cont
= ctxt
->vstateTab
[ctxt
->vstateNr
].cont
;
413 ctxt
->vstate
->node
= ctxt
->vstateTab
[ctxt
->vstateNr
].node
;
414 ctxt
->vstate
->depth
= ctxt
->vstateTab
[ctxt
->vstateNr
].depth
;
415 ctxt
->vstate
->occurs
= ctxt
->vstateTab
[ctxt
->vstateNr
].occurs
;
416 ctxt
->vstate
->state
= ctxt
->vstateTab
[ctxt
->vstateNr
].state
;
417 return(ctxt
->vstateNr
);
420 #endif /* LIBXML_REGEXP_ENABLED */
423 nodeVPush(xmlValidCtxtPtr ctxt
, xmlNodePtr value
)
425 if (ctxt
->nodeMax
<= 0) {
428 (xmlNodePtr
*) xmlMalloc(ctxt
->nodeMax
*
429 sizeof(ctxt
->nodeTab
[0]));
430 if (ctxt
->nodeTab
== NULL
) {
431 xmlVErrMemory(ctxt
, "malloc failed");
436 if (ctxt
->nodeNr
>= ctxt
->nodeMax
) {
438 tmp
= (xmlNodePtr
*) xmlRealloc(ctxt
->nodeTab
,
439 ctxt
->nodeMax
* 2 * sizeof(ctxt
->nodeTab
[0]));
441 xmlVErrMemory(ctxt
, "realloc failed");
447 ctxt
->nodeTab
[ctxt
->nodeNr
] = value
;
449 return (ctxt
->nodeNr
++);
452 nodeVPop(xmlValidCtxtPtr ctxt
)
456 if (ctxt
->nodeNr
<= 0)
459 if (ctxt
->nodeNr
> 0)
460 ctxt
->node
= ctxt
->nodeTab
[ctxt
->nodeNr
- 1];
463 ret
= ctxt
->nodeTab
[ctxt
->nodeNr
];
464 ctxt
->nodeTab
[ctxt
->nodeNr
] = NULL
;
468 #ifdef DEBUG_VALID_ALGO
470 xmlValidPrintNode(xmlNodePtr cur
) {
472 xmlGenericError(xmlGenericErrorContext
, "null");
476 case XML_ELEMENT_NODE
:
477 xmlGenericError(xmlGenericErrorContext
, "%s ", cur
->name
);
480 xmlGenericError(xmlGenericErrorContext
, "text ");
482 case XML_CDATA_SECTION_NODE
:
483 xmlGenericError(xmlGenericErrorContext
, "cdata ");
485 case XML_ENTITY_REF_NODE
:
486 xmlGenericError(xmlGenericErrorContext
, "&%s; ", cur
->name
);
489 xmlGenericError(xmlGenericErrorContext
, "pi(%s) ", cur
->name
);
491 case XML_COMMENT_NODE
:
492 xmlGenericError(xmlGenericErrorContext
, "comment ");
494 case XML_ATTRIBUTE_NODE
:
495 xmlGenericError(xmlGenericErrorContext
, "?attr? ");
497 case XML_ENTITY_NODE
:
498 xmlGenericError(xmlGenericErrorContext
, "?ent? ");
500 case XML_DOCUMENT_NODE
:
501 xmlGenericError(xmlGenericErrorContext
, "?doc? ");
503 case XML_DOCUMENT_TYPE_NODE
:
504 xmlGenericError(xmlGenericErrorContext
, "?doctype? ");
506 case XML_DOCUMENT_FRAG_NODE
:
507 xmlGenericError(xmlGenericErrorContext
, "?frag? ");
509 case XML_NOTATION_NODE
:
510 xmlGenericError(xmlGenericErrorContext
, "?nota? ");
512 case XML_HTML_DOCUMENT_NODE
:
513 xmlGenericError(xmlGenericErrorContext
, "?html? ");
516 xmlGenericError(xmlGenericErrorContext
, "?dtd? ");
518 case XML_ELEMENT_DECL
:
519 xmlGenericError(xmlGenericErrorContext
, "?edecl? ");
521 case XML_ATTRIBUTE_DECL
:
522 xmlGenericError(xmlGenericErrorContext
, "?adecl? ");
524 case XML_ENTITY_DECL
:
525 xmlGenericError(xmlGenericErrorContext
, "?entdecl? ");
527 case XML_NAMESPACE_DECL
:
528 xmlGenericError(xmlGenericErrorContext
, "?nsdecl? ");
530 case XML_XINCLUDE_START
:
531 xmlGenericError(xmlGenericErrorContext
, "incstart ");
533 case XML_XINCLUDE_END
:
534 xmlGenericError(xmlGenericErrorContext
, "incend ");
540 xmlValidPrintNodeList(xmlNodePtr cur
) {
542 xmlGenericError(xmlGenericErrorContext
, "null ");
543 while (cur
!= NULL
) {
544 xmlValidPrintNode(cur
);
550 xmlValidDebug(xmlNodePtr cur
, xmlElementContentPtr cont
) {
554 xmlGenericError(xmlGenericErrorContext
, "valid: ");
555 xmlValidPrintNodeList(cur
);
556 xmlGenericError(xmlGenericErrorContext
, "against ");
557 xmlSnprintfElementContent(expr
, 5000, cont
, 1);
558 xmlGenericError(xmlGenericErrorContext
, "%s\n", expr
);
562 xmlValidDebugState(xmlValidStatePtr state
) {
563 xmlGenericError(xmlGenericErrorContext
, "(");
564 if (state
->cont
== NULL
)
565 xmlGenericError(xmlGenericErrorContext
, "null,");
567 switch (state
->cont
->type
) {
568 case XML_ELEMENT_CONTENT_PCDATA
:
569 xmlGenericError(xmlGenericErrorContext
, "pcdata,");
571 case XML_ELEMENT_CONTENT_ELEMENT
:
572 xmlGenericError(xmlGenericErrorContext
, "%s,",
575 case XML_ELEMENT_CONTENT_SEQ
:
576 xmlGenericError(xmlGenericErrorContext
, "seq,");
578 case XML_ELEMENT_CONTENT_OR
:
579 xmlGenericError(xmlGenericErrorContext
, "or,");
582 xmlValidPrintNode(state
->node
);
583 xmlGenericError(xmlGenericErrorContext
, ",%d,%X,%d)",
584 state
->depth
, state
->occurs
, state
->state
);
588 xmlValidStateDebug(xmlValidCtxtPtr ctxt
) {
591 xmlGenericError(xmlGenericErrorContext
, "state: ");
592 xmlValidDebugState(ctxt
->vstate
);
593 xmlGenericError(xmlGenericErrorContext
, " stack: %d ",
595 for (i
= 0, j
= ctxt
->vstateNr
- 1;(i
< 3) && (j
> 0);i
++,j
--)
596 xmlValidDebugState(&ctxt
->vstateTab
[j
]);
597 xmlGenericError(xmlGenericErrorContext
, "\n");
601 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
604 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
605 #define DEBUG_VALID_MSG(m) \
606 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
609 #define DEBUG_VALID_STATE(n,c)
610 #define DEBUG_VALID_MSG(m)
613 /* TODO: use hash table for accesses to elem and attribute definitions */
617 if (doc == NULL) return(0); \
618 else if ((doc->intSubset == NULL) && \
619 (doc->extSubset == NULL)) return(0)
621 #ifdef LIBXML_REGEXP_ENABLED
623 /************************************************************************
625 * Content model validation based on the regexps *
627 ************************************************************************/
630 * xmlValidBuildAContentModel:
631 * @content: the content model
632 * @ctxt: the schema parser context
633 * @name: the element name whose content is being built
635 * Generate the automata sequence needed for that type
637 * Returns 1 if successful or 0 in case of error.
640 xmlValidBuildAContentModel(xmlElementContentPtr content
,
641 xmlValidCtxtPtr ctxt
,
642 const xmlChar
*name
) {
643 if (content
== NULL
) {
644 xmlErrValidNode(ctxt
, NULL
, XML_ERR_INTERNAL_ERROR
,
645 "Found NULL content in content model of %s\n",
649 switch (content
->type
) {
650 case XML_ELEMENT_CONTENT_PCDATA
:
651 xmlErrValidNode(ctxt
, NULL
, XML_ERR_INTERNAL_ERROR
,
652 "Found PCDATA in content model of %s\n",
656 case XML_ELEMENT_CONTENT_ELEMENT
: {
657 xmlAutomataStatePtr oldstate
= ctxt
->state
;
661 fullname
= xmlBuildQName(content
->name
, content
->prefix
, fn
, 50);
662 if (fullname
== NULL
) {
663 xmlVErrMemory(ctxt
, "Building content model");
667 switch (content
->ocur
) {
668 case XML_ELEMENT_CONTENT_ONCE
:
669 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
670 ctxt
->state
, NULL
, fullname
, NULL
);
672 case XML_ELEMENT_CONTENT_OPT
:
673 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
674 ctxt
->state
, NULL
, fullname
, NULL
);
675 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
677 case XML_ELEMENT_CONTENT_PLUS
:
678 ctxt
->state
= xmlAutomataNewTransition(ctxt
->am
,
679 ctxt
->state
, NULL
, fullname
, NULL
);
680 xmlAutomataNewTransition(ctxt
->am
, ctxt
->state
,
681 ctxt
->state
, fullname
, NULL
);
683 case XML_ELEMENT_CONTENT_MULT
:
684 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
,
686 xmlAutomataNewTransition(ctxt
->am
,
687 ctxt
->state
, ctxt
->state
, fullname
, NULL
);
690 if ((fullname
!= fn
) && (fullname
!= content
->name
))
694 case XML_ELEMENT_CONTENT_SEQ
: {
695 xmlAutomataStatePtr oldstate
, oldend
;
696 xmlElementContentOccur ocur
;
699 * Simply iterate over the content
701 oldstate
= ctxt
->state
;
702 ocur
= content
->ocur
;
703 if (ocur
!= XML_ELEMENT_CONTENT_ONCE
) {
704 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
705 oldstate
= ctxt
->state
;
708 xmlValidBuildAContentModel(content
->c1
, ctxt
, name
);
709 content
= content
->c2
;
710 } while ((content
->type
== XML_ELEMENT_CONTENT_SEQ
) &&
711 (content
->ocur
== XML_ELEMENT_CONTENT_ONCE
));
712 xmlValidBuildAContentModel(content
, ctxt
, name
);
713 oldend
= ctxt
->state
;
714 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
, oldend
, NULL
);
716 case XML_ELEMENT_CONTENT_ONCE
:
718 case XML_ELEMENT_CONTENT_OPT
:
719 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
721 case XML_ELEMENT_CONTENT_MULT
:
722 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
723 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
725 case XML_ELEMENT_CONTENT_PLUS
:
726 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
731 case XML_ELEMENT_CONTENT_OR
: {
732 xmlAutomataStatePtr oldstate
, oldend
;
733 xmlElementContentOccur ocur
;
735 ocur
= content
->ocur
;
736 if ((ocur
== XML_ELEMENT_CONTENT_PLUS
) ||
737 (ocur
== XML_ELEMENT_CONTENT_MULT
)) {
738 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
,
741 oldstate
= ctxt
->state
;
742 oldend
= xmlAutomataNewState(ctxt
->am
);
745 * iterate over the subtypes and remerge the end with an
749 ctxt
->state
= oldstate
;
750 xmlValidBuildAContentModel(content
->c1
, ctxt
, name
);
751 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldend
);
752 content
= content
->c2
;
753 } while ((content
->type
== XML_ELEMENT_CONTENT_OR
) &&
754 (content
->ocur
== XML_ELEMENT_CONTENT_ONCE
));
755 ctxt
->state
= oldstate
;
756 xmlValidBuildAContentModel(content
, ctxt
, name
);
757 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldend
);
758 ctxt
->state
= xmlAutomataNewEpsilon(ctxt
->am
, oldend
, NULL
);
760 case XML_ELEMENT_CONTENT_ONCE
:
762 case XML_ELEMENT_CONTENT_OPT
:
763 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
765 case XML_ELEMENT_CONTENT_MULT
:
766 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
767 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
769 case XML_ELEMENT_CONTENT_PLUS
:
770 xmlAutomataNewEpsilon(ctxt
->am
, oldend
, oldstate
);
776 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
777 "ContentModel broken for element %s\n",
778 (const char *) name
);
784 * xmlValidBuildContentModel:
785 * @ctxt: a validation context
786 * @elem: an element declaration node
788 * (Re)Build the automata associated to the content model of this
791 * Returns 1 in case of success, 0 in case of error
794 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt
, xmlElementPtr elem
) {
796 if ((ctxt
== NULL
) || (elem
== NULL
))
798 if (elem
->type
!= XML_ELEMENT_DECL
)
800 if (elem
->etype
!= XML_ELEMENT_TYPE_ELEMENT
)
802 /* TODO: should we rebuild in this case ? */
803 if (elem
->contModel
!= NULL
) {
804 if (!xmlRegexpIsDeterminist(elem
->contModel
)) {
811 ctxt
->am
= xmlNewAutomata();
812 if (ctxt
->am
== NULL
) {
813 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
,
814 XML_ERR_INTERNAL_ERROR
,
815 "Cannot create automata for element %s\n",
816 elem
->name
, NULL
, NULL
);
819 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
820 xmlValidBuildAContentModel(elem
->content
, ctxt
, elem
->name
);
821 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
822 elem
->contModel
= xmlAutomataCompile(ctxt
->am
);
823 if (xmlRegexpIsDeterminist(elem
->contModel
) != 1) {
826 xmlSnprintfElementContent(expr
, 5000, elem
->content
, 1);
827 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
,
828 XML_DTD_CONTENT_NOT_DETERMINIST
,
829 "Content model of %s is not deterministic: %s\n",
830 elem
->name
, BAD_CAST expr
, NULL
);
831 #ifdef DEBUG_REGEXP_ALGO
832 xmlRegexpPrint(stderr
, elem
->contModel
);
836 xmlFreeAutomata(ctxt
->am
);
841 xmlFreeAutomata(ctxt
->am
);
846 #endif /* LIBXML_REGEXP_ENABLED */
848 /****************************************************************
850 * Util functions for data allocation/deallocation *
852 ****************************************************************/
857 * Allocate a validation context structure.
859 * Returns NULL if not, otherwise the new validation context structure
861 xmlValidCtxtPtr
xmlNewValidCtxt(void) {
864 if ((ret
= xmlMalloc(sizeof (xmlValidCtxt
))) == NULL
) {
865 xmlVErrMemory(NULL
, "malloc failed");
869 (void) memset(ret
, 0, sizeof (xmlValidCtxt
));
876 * @cur: the validation context to free
878 * Free a validation context structure.
881 xmlFreeValidCtxt(xmlValidCtxtPtr cur
) {
884 if (cur
->vstateTab
!= NULL
)
885 xmlFree(cur
->vstateTab
);
886 if (cur
->nodeTab
!= NULL
)
887 xmlFree(cur
->nodeTab
);
891 #endif /* LIBXML_VALID_ENABLED */
894 * xmlNewDocElementContent:
896 * @name: the subelement name or NULL
897 * @type: the type of element content decl
899 * Allocate an element content structure for the document.
901 * Returns NULL if not, otherwise the new element content structure
904 xmlNewDocElementContent(xmlDocPtr doc
, const xmlChar
*name
,
905 xmlElementContentType type
) {
906 xmlElementContentPtr ret
;
907 xmlDictPtr dict
= NULL
;
913 case XML_ELEMENT_CONTENT_ELEMENT
:
915 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
916 "xmlNewElementContent : name == NULL !\n",
920 case XML_ELEMENT_CONTENT_PCDATA
:
921 case XML_ELEMENT_CONTENT_SEQ
:
922 case XML_ELEMENT_CONTENT_OR
:
924 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
925 "xmlNewElementContent : name != NULL !\n",
930 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
931 "Internal: ELEMENT content corrupted invalid type\n",
935 ret
= (xmlElementContentPtr
) xmlMalloc(sizeof(xmlElementContent
));
937 xmlVErrMemory(NULL
, "malloc failed");
940 memset(ret
, 0, sizeof(xmlElementContent
));
942 ret
->ocur
= XML_ELEMENT_CONTENT_ONCE
;
947 tmp
= xmlSplitQName3(name
, &l
);
950 ret
->name
= xmlStrdup(name
);
952 ret
->name
= xmlDictLookup(dict
, name
, -1);
955 ret
->prefix
= xmlStrndup(name
, l
);
956 ret
->name
= xmlStrdup(tmp
);
958 ret
->prefix
= xmlDictLookup(dict
, name
, l
);
959 ret
->name
= xmlDictLookup(dict
, tmp
, -1);
967 * xmlNewElementContent:
968 * @name: the subelement name or NULL
969 * @type: the type of element content decl
971 * Allocate an element content structure.
972 * Deprecated in favor of xmlNewDocElementContent
974 * Returns NULL if not, otherwise the new element content structure
977 xmlNewElementContent(const xmlChar
*name
, xmlElementContentType type
) {
978 return(xmlNewDocElementContent(NULL
, name
, type
));
982 * xmlCopyDocElementContent:
983 * @doc: the document owning the element declaration
984 * @cur: An element content pointer.
986 * Build a copy of an element content description.
988 * Returns the new xmlElementContentPtr or NULL in case of error.
991 xmlCopyDocElementContent(xmlDocPtr doc
, xmlElementContentPtr cur
) {
992 xmlElementContentPtr ret
= NULL
, prev
= NULL
, tmp
;
993 xmlDictPtr dict
= NULL
;
995 if (cur
== NULL
) return(NULL
);
1000 ret
= (xmlElementContentPtr
) xmlMalloc(sizeof(xmlElementContent
));
1002 xmlVErrMemory(NULL
, "malloc failed");
1005 memset(ret
, 0, sizeof(xmlElementContent
));
1006 ret
->type
= cur
->type
;
1007 ret
->ocur
= cur
->ocur
;
1008 if (cur
->name
!= NULL
) {
1010 ret
->name
= xmlDictLookup(dict
, cur
->name
, -1);
1012 ret
->name
= xmlStrdup(cur
->name
);
1015 if (cur
->prefix
!= NULL
) {
1017 ret
->prefix
= xmlDictLookup(dict
, cur
->prefix
, -1);
1019 ret
->prefix
= xmlStrdup(cur
->prefix
);
1021 if (cur
->c1
!= NULL
)
1022 ret
->c1
= xmlCopyDocElementContent(doc
, cur
->c1
);
1023 if (ret
->c1
!= NULL
)
1024 ret
->c1
->parent
= ret
;
1025 if (cur
->c2
!= NULL
) {
1028 while (cur
!= NULL
) {
1029 tmp
= (xmlElementContentPtr
) xmlMalloc(sizeof(xmlElementContent
));
1031 xmlVErrMemory(NULL
, "malloc failed");
1034 memset(tmp
, 0, sizeof(xmlElementContent
));
1035 tmp
->type
= cur
->type
;
1036 tmp
->ocur
= cur
->ocur
;
1039 if (cur
->name
!= NULL
) {
1041 tmp
->name
= xmlDictLookup(dict
, cur
->name
, -1);
1043 tmp
->name
= xmlStrdup(cur
->name
);
1046 if (cur
->prefix
!= NULL
) {
1048 tmp
->prefix
= xmlDictLookup(dict
, cur
->prefix
, -1);
1050 tmp
->prefix
= xmlStrdup(cur
->prefix
);
1052 if (cur
->c1
!= NULL
)
1053 tmp
->c1
= xmlCopyDocElementContent(doc
,cur
->c1
);
1054 if (tmp
->c1
!= NULL
)
1055 tmp
->c1
->parent
= ret
;
1064 * xmlCopyElementContent:
1065 * @cur: An element content pointer.
1067 * Build a copy of an element content description.
1068 * Deprecated, use xmlCopyDocElementContent instead
1070 * Returns the new xmlElementContentPtr or NULL in case of error.
1072 xmlElementContentPtr
1073 xmlCopyElementContent(xmlElementContentPtr cur
) {
1074 return(xmlCopyDocElementContent(NULL
, cur
));
1078 * xmlFreeDocElementContent:
1079 * @doc: the document owning the element declaration
1080 * @cur: the element content tree to free
1082 * Free an element content structure. The whole subtree is removed.
1085 xmlFreeDocElementContent(xmlDocPtr doc
, xmlElementContentPtr cur
) {
1086 xmlDictPtr dict
= NULL
;
1095 xmlElementContentPtr parent
;
1097 while ((cur
->c1
!= NULL
) || (cur
->c2
!= NULL
)) {
1098 cur
= (cur
->c1
!= NULL
) ? cur
->c1
: cur
->c2
;
1102 switch (cur
->type
) {
1103 case XML_ELEMENT_CONTENT_PCDATA
:
1104 case XML_ELEMENT_CONTENT_ELEMENT
:
1105 case XML_ELEMENT_CONTENT_SEQ
:
1106 case XML_ELEMENT_CONTENT_OR
:
1109 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
1110 "Internal: ELEMENT content corrupted invalid type\n",
1115 if ((cur
->name
!= NULL
) && (!xmlDictOwns(dict
, cur
->name
)))
1116 xmlFree((xmlChar
*) cur
->name
);
1117 if ((cur
->prefix
!= NULL
) && (!xmlDictOwns(dict
, cur
->prefix
)))
1118 xmlFree((xmlChar
*) cur
->prefix
);
1120 if (cur
->name
!= NULL
) xmlFree((xmlChar
*) cur
->name
);
1121 if (cur
->prefix
!= NULL
) xmlFree((xmlChar
*) cur
->prefix
);
1123 parent
= cur
->parent
;
1124 if ((depth
== 0) || (parent
== NULL
)) {
1128 if (cur
== parent
->c1
)
1134 if (parent
->c2
!= NULL
) {
1144 * xmlFreeElementContent:
1145 * @cur: the element content tree to free
1147 * Free an element content structure. The whole subtree is removed.
1148 * Deprecated, use xmlFreeDocElementContent instead
1151 xmlFreeElementContent(xmlElementContentPtr cur
) {
1152 xmlFreeDocElementContent(NULL
, cur
);
1155 #ifdef LIBXML_OUTPUT_ENABLED
1157 * xmlDumpElementOccur:
1158 * @buf: An XML buffer
1159 * @cur: An element table
1161 * Dump the occurrence operator of an element.
1164 xmlDumpElementOccur(xmlBufferPtr buf
, xmlElementContentPtr cur
) {
1165 switch (cur
->ocur
) {
1166 case XML_ELEMENT_CONTENT_ONCE
:
1168 case XML_ELEMENT_CONTENT_OPT
:
1169 xmlBufferWriteChar(buf
, "?");
1171 case XML_ELEMENT_CONTENT_MULT
:
1172 xmlBufferWriteChar(buf
, "*");
1174 case XML_ELEMENT_CONTENT_PLUS
:
1175 xmlBufferWriteChar(buf
, "+");
1181 * xmlDumpElementContent:
1182 * @buf: An XML buffer
1183 * @content: An element table
1185 * This will dump the content of the element table as an XML DTD definition
1188 xmlDumpElementContent(xmlBufferPtr buf
, xmlElementContentPtr content
) {
1189 xmlElementContentPtr cur
;
1191 if (content
== NULL
) return;
1193 xmlBufferWriteChar(buf
, "(");
1197 if (cur
== NULL
) return;
1199 switch (cur
->type
) {
1200 case XML_ELEMENT_CONTENT_PCDATA
:
1201 xmlBufferWriteChar(buf
, "#PCDATA");
1203 case XML_ELEMENT_CONTENT_ELEMENT
:
1204 if (cur
->prefix
!= NULL
) {
1205 xmlBufferWriteCHAR(buf
, cur
->prefix
);
1206 xmlBufferWriteChar(buf
, ":");
1208 xmlBufferWriteCHAR(buf
, cur
->name
);
1210 case XML_ELEMENT_CONTENT_SEQ
:
1211 case XML_ELEMENT_CONTENT_OR
:
1212 if ((cur
!= content
) &&
1213 (cur
->parent
!= NULL
) &&
1214 ((cur
->type
!= cur
->parent
->type
) ||
1215 (cur
->ocur
!= XML_ELEMENT_CONTENT_ONCE
)))
1216 xmlBufferWriteChar(buf
, "(");
1220 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
1221 "Internal: ELEMENT cur corrupted invalid type\n",
1225 while (cur
!= content
) {
1226 xmlElementContentPtr parent
= cur
->parent
;
1228 if (parent
== NULL
) return;
1230 if (((cur
->type
== XML_ELEMENT_CONTENT_OR
) ||
1231 (cur
->type
== XML_ELEMENT_CONTENT_SEQ
)) &&
1232 ((cur
->type
!= parent
->type
) ||
1233 (cur
->ocur
!= XML_ELEMENT_CONTENT_ONCE
)))
1234 xmlBufferWriteChar(buf
, ")");
1235 xmlDumpElementOccur(buf
, cur
);
1237 if (cur
== parent
->c1
) {
1238 if (parent
->type
== XML_ELEMENT_CONTENT_SEQ
)
1239 xmlBufferWriteChar(buf
, " , ");
1240 else if (parent
->type
== XML_ELEMENT_CONTENT_OR
)
1241 xmlBufferWriteChar(buf
, " | ");
1249 } while (cur
!= content
);
1251 xmlBufferWriteChar(buf
, ")");
1252 xmlDumpElementOccur(buf
, content
);
1256 * xmlSprintfElementContent:
1257 * @buf: an output buffer
1258 * @content: An element table
1259 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1261 * Deprecated, unsafe, use xmlSnprintfElementContent
1264 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED
,
1265 xmlElementContentPtr content ATTRIBUTE_UNUSED
,
1266 int englob ATTRIBUTE_UNUSED
) {
1268 #endif /* LIBXML_OUTPUT_ENABLED */
1271 * xmlSnprintfElementContent:
1272 * @buf: an output buffer
1273 * @size: the buffer size
1274 * @content: An element table
1275 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1277 * This will dump the content of the element content definition
1278 * Intended just for the debug routine
1281 xmlSnprintfElementContent(char *buf
, int size
, xmlElementContentPtr content
, int englob
) {
1284 if (content
== NULL
) return;
1286 if (size
- len
< 50) {
1287 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
1288 strcat(buf
, " ...");
1291 if (englob
) strcat(buf
, "(");
1292 switch (content
->type
) {
1293 case XML_ELEMENT_CONTENT_PCDATA
:
1294 strcat(buf
, "#PCDATA");
1296 case XML_ELEMENT_CONTENT_ELEMENT
: {
1297 int qnameLen
= xmlStrlen(content
->name
);
1299 if (content
->prefix
!= NULL
)
1300 qnameLen
+= xmlStrlen(content
->prefix
) + 1;
1301 if (size
- len
< qnameLen
+ 10) {
1302 strcat(buf
, " ...");
1305 if (content
->prefix
!= NULL
) {
1306 strcat(buf
, (char *) content
->prefix
);
1309 if (content
->name
!= NULL
)
1310 strcat(buf
, (char *) content
->name
);
1313 case XML_ELEMENT_CONTENT_SEQ
:
1314 if ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
1315 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
))
1316 xmlSnprintfElementContent(buf
, size
, content
->c1
, 1);
1318 xmlSnprintfElementContent(buf
, size
, content
->c1
, 0);
1320 if (size
- len
< 50) {
1321 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
1322 strcat(buf
, " ...");
1326 if (((content
->c2
->type
== XML_ELEMENT_CONTENT_OR
) ||
1327 (content
->c2
->ocur
!= XML_ELEMENT_CONTENT_ONCE
)) &&
1328 (content
->c2
->type
!= XML_ELEMENT_CONTENT_ELEMENT
))
1329 xmlSnprintfElementContent(buf
, size
, content
->c2
, 1);
1331 xmlSnprintfElementContent(buf
, size
, content
->c2
, 0);
1333 case XML_ELEMENT_CONTENT_OR
:
1334 if ((content
->c1
->type
== XML_ELEMENT_CONTENT_OR
) ||
1335 (content
->c1
->type
== XML_ELEMENT_CONTENT_SEQ
))
1336 xmlSnprintfElementContent(buf
, size
, content
->c1
, 1);
1338 xmlSnprintfElementContent(buf
, size
, content
->c1
, 0);
1340 if (size
- len
< 50) {
1341 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
1342 strcat(buf
, " ...");
1346 if (((content
->c2
->type
== XML_ELEMENT_CONTENT_SEQ
) ||
1347 (content
->c2
->ocur
!= XML_ELEMENT_CONTENT_ONCE
)) &&
1348 (content
->c2
->type
!= XML_ELEMENT_CONTENT_ELEMENT
))
1349 xmlSnprintfElementContent(buf
, size
, content
->c2
, 1);
1351 xmlSnprintfElementContent(buf
, size
, content
->c2
, 0);
1354 if (size
- strlen(buf
) <= 2) return;
1357 switch (content
->ocur
) {
1358 case XML_ELEMENT_CONTENT_ONCE
:
1360 case XML_ELEMENT_CONTENT_OPT
:
1363 case XML_ELEMENT_CONTENT_MULT
:
1366 case XML_ELEMENT_CONTENT_PLUS
:
1372 /****************************************************************
1374 * Registration of DTD declarations *
1376 ****************************************************************/
1382 * Deallocate the memory used by an element definition
1385 xmlFreeElement(xmlElementPtr elem
) {
1386 if (elem
== NULL
) return;
1387 xmlUnlinkNode((xmlNodePtr
) elem
);
1388 xmlFreeDocElementContent(elem
->doc
, elem
->content
);
1389 if (elem
->name
!= NULL
)
1390 xmlFree((xmlChar
*) elem
->name
);
1391 if (elem
->prefix
!= NULL
)
1392 xmlFree((xmlChar
*) elem
->prefix
);
1393 #ifdef LIBXML_REGEXP_ENABLED
1394 if (elem
->contModel
!= NULL
)
1395 xmlRegFreeRegexp(elem
->contModel
);
1402 * xmlAddElementDecl:
1403 * @ctxt: the validation context
1404 * @dtd: pointer to the DTD
1405 * @name: the entity name
1406 * @type: the element type
1407 * @content: the element content tree or NULL
1409 * Register a new element declaration
1411 * Returns NULL if not, otherwise the entity
1414 xmlAddElementDecl(xmlValidCtxtPtr ctxt
,
1415 xmlDtdPtr dtd
, const xmlChar
*name
,
1416 xmlElementTypeVal type
,
1417 xmlElementContentPtr content
) {
1419 xmlElementTablePtr table
;
1420 xmlAttributePtr oldAttributes
= NULL
;
1421 xmlChar
*ns
, *uqname
;
1431 case XML_ELEMENT_TYPE_EMPTY
:
1432 if (content
!= NULL
) {
1433 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1434 "xmlAddElementDecl: content != NULL for EMPTY\n",
1439 case XML_ELEMENT_TYPE_ANY
:
1440 if (content
!= NULL
) {
1441 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1442 "xmlAddElementDecl: content != NULL for ANY\n",
1447 case XML_ELEMENT_TYPE_MIXED
:
1448 if (content
== NULL
) {
1449 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1450 "xmlAddElementDecl: content == NULL for MIXED\n",
1455 case XML_ELEMENT_TYPE_ELEMENT
:
1456 if (content
== NULL
) {
1457 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1458 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1464 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
1465 "Internal: ELEMENT decl corrupted invalid type\n",
1471 * check if name is a QName
1473 uqname
= xmlSplitQName2(name
, &ns
);
1478 * Create the Element table if needed.
1480 table
= (xmlElementTablePtr
) dtd
->elements
;
1481 if (table
== NULL
) {
1482 xmlDictPtr dict
= NULL
;
1484 if (dtd
->doc
!= NULL
)
1485 dict
= dtd
->doc
->dict
;
1486 table
= xmlHashCreateDict(0, dict
);
1487 dtd
->elements
= (void *) table
;
1489 if (table
== NULL
) {
1491 "xmlAddElementDecl: Table creation failed!\n");
1500 * lookup old attributes inserted on an undefined element in the
1503 if ((dtd
->doc
!= NULL
) && (dtd
->doc
->intSubset
!= NULL
)) {
1504 ret
= xmlHashLookup2(dtd
->doc
->intSubset
->elements
, name
, ns
);
1505 if ((ret
!= NULL
) && (ret
->etype
== XML_ELEMENT_TYPE_UNDEFINED
)) {
1506 oldAttributes
= ret
->attributes
;
1507 ret
->attributes
= NULL
;
1508 xmlHashRemoveEntry2(dtd
->doc
->intSubset
->elements
, name
, ns
, NULL
);
1509 xmlFreeElement(ret
);
1514 * The element may already be present if one of its attribute
1515 * was registered first
1517 ret
= xmlHashLookup2(table
, name
, ns
);
1519 if (ret
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
) {
1520 #ifdef LIBXML_VALID_ENABLED
1522 * The element is already defined in this DTD.
1524 xmlErrValidNode(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_ELEM_REDEFINED
,
1525 "Redefinition of element %s\n",
1527 #endif /* LIBXML_VALID_ENABLED */
1539 ret
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
1541 xmlVErrMemory(ctxt
, "malloc failed");
1548 memset(ret
, 0, sizeof(xmlElement
));
1549 ret
->type
= XML_ELEMENT_DECL
;
1552 * fill the structure.
1554 ret
->name
= xmlStrdup(name
);
1555 if (ret
->name
== NULL
) {
1556 xmlVErrMemory(ctxt
, "malloc failed");
1568 * Insertion must not fail
1570 if (xmlHashAddEntry2(table
, name
, ns
, ret
)) {
1571 #ifdef LIBXML_VALID_ENABLED
1573 * The element is already defined in this DTD.
1575 xmlErrValidNode(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_ELEM_REDEFINED
,
1576 "Redefinition of element %s\n",
1578 #endif /* LIBXML_VALID_ENABLED */
1579 xmlFreeElement(ret
);
1585 * For new element, may have attributes from earlier
1586 * definition in internal subset
1588 ret
->attributes
= oldAttributes
;
1592 * Finish to fill the structure.
1596 * Avoid a stupid copy when called by the parser
1597 * and flag it by setting a special parent value
1598 * so the parser doesn't unallocate it.
1600 if ((ctxt
!= NULL
) && (ctxt
->flags
& XML_VCTXT_USE_PCTXT
)) {
1601 ret
->content
= content
;
1602 if (content
!= NULL
)
1603 content
->parent
= (xmlElementContentPtr
) 1;
1605 ret
->content
= xmlCopyDocElementContent(dtd
->doc
, content
);
1609 * Link it to the DTD
1612 ret
->doc
= dtd
->doc
;
1613 if (dtd
->last
== NULL
) {
1614 dtd
->children
= dtd
->last
= (xmlNodePtr
) ret
;
1616 dtd
->last
->next
= (xmlNodePtr
) ret
;
1617 ret
->prev
= dtd
->last
;
1618 dtd
->last
= (xmlNodePtr
) ret
;
1626 xmlFreeElementTableEntry(void *elem
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
1627 xmlFreeElement((xmlElementPtr
) elem
);
1631 * xmlFreeElementTable:
1632 * @table: An element table
1634 * Deallocate the memory used by an element hash table.
1637 xmlFreeElementTable(xmlElementTablePtr table
) {
1638 xmlHashFree(table
, xmlFreeElementTableEntry
);
1641 #ifdef LIBXML_TREE_ENABLED
1646 * Build a copy of an element.
1648 * Returns the new xmlElementPtr or NULL in case of error.
1651 xmlCopyElement(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
1652 xmlElementPtr elem
= (xmlElementPtr
) payload
;
1655 cur
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
1657 xmlVErrMemory(NULL
, "malloc failed");
1660 memset(cur
, 0, sizeof(xmlElement
));
1661 cur
->type
= XML_ELEMENT_DECL
;
1662 cur
->etype
= elem
->etype
;
1663 if (elem
->name
!= NULL
)
1664 cur
->name
= xmlStrdup(elem
->name
);
1667 if (elem
->prefix
!= NULL
)
1668 cur
->prefix
= xmlStrdup(elem
->prefix
);
1671 cur
->content
= xmlCopyElementContent(elem
->content
);
1672 /* TODO : rebuild the attribute list on the copy */
1673 cur
->attributes
= NULL
;
1678 * xmlCopyElementTable:
1679 * @table: An element table
1681 * Build a copy of an element table.
1683 * Returns the new xmlElementTablePtr or NULL in case of error.
1686 xmlCopyElementTable(xmlElementTablePtr table
) {
1687 return((xmlElementTablePtr
) xmlHashCopy(table
, xmlCopyElement
));
1689 #endif /* LIBXML_TREE_ENABLED */
1691 #ifdef LIBXML_OUTPUT_ENABLED
1693 * xmlDumpElementDecl:
1694 * @buf: the XML buffer output
1695 * @elem: An element table
1697 * This will dump the content of the element declaration as an XML
1701 xmlDumpElementDecl(xmlBufferPtr buf
, xmlElementPtr elem
) {
1702 if ((buf
== NULL
) || (elem
== NULL
))
1704 switch (elem
->etype
) {
1705 case XML_ELEMENT_TYPE_EMPTY
:
1706 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1707 if (elem
->prefix
!= NULL
) {
1708 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1709 xmlBufferWriteChar(buf
, ":");
1711 xmlBufferWriteCHAR(buf
, elem
->name
);
1712 xmlBufferWriteChar(buf
, " EMPTY>\n");
1714 case XML_ELEMENT_TYPE_ANY
:
1715 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1716 if (elem
->prefix
!= NULL
) {
1717 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1718 xmlBufferWriteChar(buf
, ":");
1720 xmlBufferWriteCHAR(buf
, elem
->name
);
1721 xmlBufferWriteChar(buf
, " ANY>\n");
1723 case XML_ELEMENT_TYPE_MIXED
:
1724 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1725 if (elem
->prefix
!= NULL
) {
1726 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1727 xmlBufferWriteChar(buf
, ":");
1729 xmlBufferWriteCHAR(buf
, elem
->name
);
1730 xmlBufferWriteChar(buf
, " ");
1731 xmlDumpElementContent(buf
, elem
->content
);
1732 xmlBufferWriteChar(buf
, ">\n");
1734 case XML_ELEMENT_TYPE_ELEMENT
:
1735 xmlBufferWriteChar(buf
, "<!ELEMENT ");
1736 if (elem
->prefix
!= NULL
) {
1737 xmlBufferWriteCHAR(buf
, elem
->prefix
);
1738 xmlBufferWriteChar(buf
, ":");
1740 xmlBufferWriteCHAR(buf
, elem
->name
);
1741 xmlBufferWriteChar(buf
, " ");
1742 xmlDumpElementContent(buf
, elem
->content
);
1743 xmlBufferWriteChar(buf
, ">\n");
1746 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
1747 "Internal: ELEMENT struct corrupted invalid type\n",
1753 * xmlDumpElementDeclScan:
1754 * @elem: An element table
1755 * @buf: the XML buffer output
1757 * This routine is used by the hash scan function. It just reverses
1761 xmlDumpElementDeclScan(void *elem
, void *buf
,
1762 const xmlChar
*name ATTRIBUTE_UNUSED
) {
1763 xmlDumpElementDecl((xmlBufferPtr
) buf
, (xmlElementPtr
) elem
);
1767 * xmlDumpElementTable:
1768 * @buf: the XML buffer output
1769 * @table: An element table
1771 * This will dump the content of the element table as an XML DTD definition
1774 xmlDumpElementTable(xmlBufferPtr buf
, xmlElementTablePtr table
) {
1775 if ((buf
== NULL
) || (table
== NULL
))
1777 xmlHashScan(table
, xmlDumpElementDeclScan
, buf
);
1779 #endif /* LIBXML_OUTPUT_ENABLED */
1782 * xmlCreateEnumeration:
1783 * @name: the enumeration name or NULL
1785 * create and initialize an enumeration attribute node.
1787 * Returns the xmlEnumerationPtr just created or NULL in case
1791 xmlCreateEnumeration(const xmlChar
*name
) {
1792 xmlEnumerationPtr ret
;
1794 ret
= (xmlEnumerationPtr
) xmlMalloc(sizeof(xmlEnumeration
));
1796 xmlVErrMemory(NULL
, "malloc failed");
1799 memset(ret
, 0, sizeof(xmlEnumeration
));
1802 ret
->name
= xmlStrdup(name
);
1807 * xmlFreeEnumeration:
1808 * @cur: the tree to free.
1810 * free an enumeration attribute node (recursive).
1813 xmlFreeEnumeration(xmlEnumerationPtr cur
) {
1814 if (cur
== NULL
) return;
1816 if (cur
->next
!= NULL
) xmlFreeEnumeration(cur
->next
);
1818 if (cur
->name
!= NULL
) xmlFree((xmlChar
*) cur
->name
);
1822 #ifdef LIBXML_TREE_ENABLED
1824 * xmlCopyEnumeration:
1825 * @cur: the tree to copy.
1827 * Copy an enumeration attribute node (recursive).
1829 * Returns the xmlEnumerationPtr just created or NULL in case
1833 xmlCopyEnumeration(xmlEnumerationPtr cur
) {
1834 xmlEnumerationPtr ret
;
1836 if (cur
== NULL
) return(NULL
);
1837 ret
= xmlCreateEnumeration((xmlChar
*) cur
->name
);
1838 if (ret
== NULL
) return(NULL
);
1840 if (cur
->next
!= NULL
) ret
->next
= xmlCopyEnumeration(cur
->next
);
1841 else ret
->next
= NULL
;
1845 #endif /* LIBXML_TREE_ENABLED */
1847 #ifdef LIBXML_OUTPUT_ENABLED
1849 * xmlDumpEnumeration:
1850 * @buf: the XML buffer output
1851 * @enum: An enumeration
1853 * This will dump the content of the enumeration
1856 xmlDumpEnumeration(xmlBufferPtr buf
, xmlEnumerationPtr cur
) {
1857 if ((buf
== NULL
) || (cur
== NULL
))
1860 xmlBufferWriteCHAR(buf
, cur
->name
);
1861 if (cur
->next
== NULL
)
1862 xmlBufferWriteChar(buf
, ")");
1864 xmlBufferWriteChar(buf
, " | ");
1865 xmlDumpEnumeration(buf
, cur
->next
);
1868 #endif /* LIBXML_OUTPUT_ENABLED */
1870 #ifdef LIBXML_VALID_ENABLED
1872 * xmlScanIDAttributeDecl:
1873 * @ctxt: the validation context
1874 * @elem: the element name
1875 * @err: whether to raise errors here
1877 * Verify that the element don't have too many ID attributes
1880 * Returns the number of ID attributes found.
1883 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt
, xmlElementPtr elem
, int err
) {
1884 xmlAttributePtr cur
;
1887 if (elem
== NULL
) return(0);
1888 cur
= elem
->attributes
;
1889 while (cur
!= NULL
) {
1890 if (cur
->atype
== XML_ATTRIBUTE_ID
) {
1892 if ((ret
> 1) && (err
))
1893 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_MULTIPLE_ID
,
1894 "Element %s has too many ID attributes defined : %s\n",
1895 elem
->name
, cur
->name
, NULL
);
1901 #endif /* LIBXML_VALID_ENABLED */
1905 * @elem: An attribute
1907 * Deallocate the memory used by an attribute definition
1910 xmlFreeAttribute(xmlAttributePtr attr
) {
1913 if (attr
== NULL
) return;
1914 if (attr
->doc
!= NULL
)
1915 dict
= attr
->doc
->dict
;
1918 xmlUnlinkNode((xmlNodePtr
) attr
);
1919 if (attr
->tree
!= NULL
)
1920 xmlFreeEnumeration(attr
->tree
);
1922 if ((attr
->elem
!= NULL
) && (!xmlDictOwns(dict
, attr
->elem
)))
1923 xmlFree((xmlChar
*) attr
->elem
);
1924 if ((attr
->name
!= NULL
) && (!xmlDictOwns(dict
, attr
->name
)))
1925 xmlFree((xmlChar
*) attr
->name
);
1926 if ((attr
->prefix
!= NULL
) && (!xmlDictOwns(dict
, attr
->prefix
)))
1927 xmlFree((xmlChar
*) attr
->prefix
);
1928 if ((attr
->defaultValue
!= NULL
) &&
1929 (!xmlDictOwns(dict
, attr
->defaultValue
)))
1930 xmlFree((xmlChar
*) attr
->defaultValue
);
1932 if (attr
->elem
!= NULL
)
1933 xmlFree((xmlChar
*) attr
->elem
);
1934 if (attr
->name
!= NULL
)
1935 xmlFree((xmlChar
*) attr
->name
);
1936 if (attr
->defaultValue
!= NULL
)
1937 xmlFree((xmlChar
*) attr
->defaultValue
);
1938 if (attr
->prefix
!= NULL
)
1939 xmlFree((xmlChar
*) attr
->prefix
);
1946 * xmlAddAttributeDecl:
1947 * @ctxt: the validation context
1948 * @dtd: pointer to the DTD
1949 * @elem: the element name
1950 * @name: the attribute name
1951 * @ns: the attribute namespace prefix
1952 * @type: the attribute type
1953 * @def: the attribute default type
1954 * @defaultValue: the attribute default value
1955 * @tree: if it's an enumeration, the associated list
1957 * Register a new attribute declaration
1958 * Note that @tree becomes the ownership of the DTD
1960 * Returns NULL if not new, otherwise the attribute decl
1963 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt
,
1964 xmlDtdPtr dtd
, const xmlChar
*elem
,
1965 const xmlChar
*name
, const xmlChar
*ns
,
1966 xmlAttributeType type
, xmlAttributeDefault def
,
1967 const xmlChar
*defaultValue
, xmlEnumerationPtr tree
) {
1968 xmlAttributePtr ret
;
1969 xmlAttributeTablePtr table
;
1970 xmlElementPtr elemDef
;
1971 xmlDictPtr dict
= NULL
;
1974 xmlFreeEnumeration(tree
);
1978 xmlFreeEnumeration(tree
);
1982 xmlFreeEnumeration(tree
);
1985 if (dtd
->doc
!= NULL
)
1986 dict
= dtd
->doc
->dict
;
1988 #ifdef LIBXML_VALID_ENABLED
1990 * Check the type and possibly the default value.
1993 case XML_ATTRIBUTE_CDATA
:
1995 case XML_ATTRIBUTE_ID
:
1997 case XML_ATTRIBUTE_IDREF
:
1999 case XML_ATTRIBUTE_IDREFS
:
2001 case XML_ATTRIBUTE_ENTITY
:
2003 case XML_ATTRIBUTE_ENTITIES
:
2005 case XML_ATTRIBUTE_NMTOKEN
:
2007 case XML_ATTRIBUTE_NMTOKENS
:
2009 case XML_ATTRIBUTE_ENUMERATION
:
2011 case XML_ATTRIBUTE_NOTATION
:
2014 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
2015 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2017 xmlFreeEnumeration(tree
);
2020 if ((defaultValue
!= NULL
) &&
2021 (!xmlValidateAttributeValueInternal(dtd
->doc
, type
, defaultValue
))) {
2022 xmlErrValidNode(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_ATTRIBUTE_DEFAULT
,
2023 "Attribute %s of %s: invalid default value\n",
2024 elem
, name
, defaultValue
);
2025 defaultValue
= NULL
;
2029 #endif /* LIBXML_VALID_ENABLED */
2032 * Check first that an attribute defined in the external subset wasn't
2033 * already defined in the internal subset
2035 if ((dtd
->doc
!= NULL
) && (dtd
->doc
->extSubset
== dtd
) &&
2036 (dtd
->doc
->intSubset
!= NULL
) &&
2037 (dtd
->doc
->intSubset
->attributes
!= NULL
)) {
2038 ret
= xmlHashLookup3(dtd
->doc
->intSubset
->attributes
, name
, ns
, elem
);
2040 xmlFreeEnumeration(tree
);
2046 * Create the Attribute table if needed.
2048 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
2049 if (table
== NULL
) {
2050 table
= xmlHashCreateDict(0, dict
);
2051 dtd
->attributes
= (void *) table
;
2053 if (table
== NULL
) {
2055 "xmlAddAttributeDecl: Table creation failed!\n");
2056 xmlFreeEnumeration(tree
);
2061 ret
= (xmlAttributePtr
) xmlMalloc(sizeof(xmlAttribute
));
2063 xmlVErrMemory(ctxt
, "malloc failed");
2064 xmlFreeEnumeration(tree
);
2067 memset(ret
, 0, sizeof(xmlAttribute
));
2068 ret
->type
= XML_ATTRIBUTE_DECL
;
2071 * fill the structure.
2075 * doc must be set before possible error causes call
2076 * to xmlFreeAttribute (because it's used to check on
2079 ret
->doc
= dtd
->doc
;
2081 ret
->name
= xmlDictLookup(dict
, name
, -1);
2082 ret
->prefix
= xmlDictLookup(dict
, ns
, -1);
2083 ret
->elem
= xmlDictLookup(dict
, elem
, -1);
2085 ret
->name
= xmlStrdup(name
);
2086 ret
->prefix
= xmlStrdup(ns
);
2087 ret
->elem
= xmlStrdup(elem
);
2091 if (defaultValue
!= NULL
) {
2093 ret
->defaultValue
= xmlDictLookup(dict
, defaultValue
, -1);
2095 ret
->defaultValue
= xmlStrdup(defaultValue
);
2100 * Search the DTD for previous declarations of the ATTLIST
2102 if (xmlHashAddEntry3(table
, ret
->name
, ret
->prefix
, ret
->elem
, ret
) < 0) {
2103 #ifdef LIBXML_VALID_ENABLED
2105 * The attribute is already defined in this DTD.
2107 xmlErrValidWarning(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_ATTRIBUTE_REDEFINED
,
2108 "Attribute %s of element %s: already defined\n",
2110 #endif /* LIBXML_VALID_ENABLED */
2111 xmlFreeAttribute(ret
);
2117 * Multiple ID per element
2119 elemDef
= xmlGetDtdElementDesc2(ctxt
, dtd
, elem
, 1);
2120 if (elemDef
!= NULL
) {
2122 #ifdef LIBXML_VALID_ENABLED
2123 if ((type
== XML_ATTRIBUTE_ID
) &&
2124 (xmlScanIDAttributeDecl(NULL
, elemDef
, 1) != 0)) {
2125 xmlErrValidNode(ctxt
, (xmlNodePtr
) dtd
, XML_DTD_MULTIPLE_ID
,
2126 "Element %s has too may ID attributes defined : %s\n",
2131 #endif /* LIBXML_VALID_ENABLED */
2134 * Insert namespace default def first they need to be
2137 if ((xmlStrEqual(ret
->name
, BAD_CAST
"xmlns")) ||
2138 ((ret
->prefix
!= NULL
&&
2139 (xmlStrEqual(ret
->prefix
, BAD_CAST
"xmlns"))))) {
2140 ret
->nexth
= elemDef
->attributes
;
2141 elemDef
->attributes
= ret
;
2143 xmlAttributePtr tmp
= elemDef
->attributes
;
2145 while ((tmp
!= NULL
) &&
2146 ((xmlStrEqual(tmp
->name
, BAD_CAST
"xmlns")) ||
2147 ((ret
->prefix
!= NULL
&&
2148 (xmlStrEqual(ret
->prefix
, BAD_CAST
"xmlns")))))) {
2149 if (tmp
->nexth
== NULL
)
2154 ret
->nexth
= tmp
->nexth
;
2157 ret
->nexth
= elemDef
->attributes
;
2158 elemDef
->attributes
= ret
;
2164 * Link it to the DTD
2167 if (dtd
->last
== NULL
) {
2168 dtd
->children
= dtd
->last
= (xmlNodePtr
) ret
;
2170 dtd
->last
->next
= (xmlNodePtr
) ret
;
2171 ret
->prev
= dtd
->last
;
2172 dtd
->last
= (xmlNodePtr
) ret
;
2178 xmlFreeAttributeTableEntry(void *attr
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2179 xmlFreeAttribute((xmlAttributePtr
) attr
);
2183 * xmlFreeAttributeTable:
2184 * @table: An attribute table
2186 * Deallocate the memory used by an entities hash table.
2189 xmlFreeAttributeTable(xmlAttributeTablePtr table
) {
2190 xmlHashFree(table
, xmlFreeAttributeTableEntry
);
2193 #ifdef LIBXML_TREE_ENABLED
2196 * @attr: An attribute
2198 * Build a copy of an attribute.
2200 * Returns the new xmlAttributePtr or NULL in case of error.
2203 xmlCopyAttribute(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2204 xmlAttributePtr attr
= (xmlAttributePtr
) payload
;
2205 xmlAttributePtr cur
;
2207 cur
= (xmlAttributePtr
) xmlMalloc(sizeof(xmlAttribute
));
2209 xmlVErrMemory(NULL
, "malloc failed");
2212 memset(cur
, 0, sizeof(xmlAttribute
));
2213 cur
->type
= XML_ATTRIBUTE_DECL
;
2214 cur
->atype
= attr
->atype
;
2215 cur
->def
= attr
->def
;
2216 cur
->tree
= xmlCopyEnumeration(attr
->tree
);
2217 if (attr
->elem
!= NULL
)
2218 cur
->elem
= xmlStrdup(attr
->elem
);
2219 if (attr
->name
!= NULL
)
2220 cur
->name
= xmlStrdup(attr
->name
);
2221 if (attr
->prefix
!= NULL
)
2222 cur
->prefix
= xmlStrdup(attr
->prefix
);
2223 if (attr
->defaultValue
!= NULL
)
2224 cur
->defaultValue
= xmlStrdup(attr
->defaultValue
);
2229 * xmlCopyAttributeTable:
2230 * @table: An attribute table
2232 * Build a copy of an attribute table.
2234 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2236 xmlAttributeTablePtr
2237 xmlCopyAttributeTable(xmlAttributeTablePtr table
) {
2238 return((xmlAttributeTablePtr
) xmlHashCopy(table
, xmlCopyAttribute
));
2240 #endif /* LIBXML_TREE_ENABLED */
2242 #ifdef LIBXML_OUTPUT_ENABLED
2244 * xmlDumpAttributeDecl:
2245 * @buf: the XML buffer output
2246 * @attr: An attribute declaration
2248 * This will dump the content of the attribute declaration as an XML
2252 xmlDumpAttributeDecl(xmlBufferPtr buf
, xmlAttributePtr attr
) {
2253 if ((buf
== NULL
) || (attr
== NULL
))
2255 xmlBufferWriteChar(buf
, "<!ATTLIST ");
2256 xmlBufferWriteCHAR(buf
, attr
->elem
);
2257 xmlBufferWriteChar(buf
, " ");
2258 if (attr
->prefix
!= NULL
) {
2259 xmlBufferWriteCHAR(buf
, attr
->prefix
);
2260 xmlBufferWriteChar(buf
, ":");
2262 xmlBufferWriteCHAR(buf
, attr
->name
);
2263 switch (attr
->atype
) {
2264 case XML_ATTRIBUTE_CDATA
:
2265 xmlBufferWriteChar(buf
, " CDATA");
2267 case XML_ATTRIBUTE_ID
:
2268 xmlBufferWriteChar(buf
, " ID");
2270 case XML_ATTRIBUTE_IDREF
:
2271 xmlBufferWriteChar(buf
, " IDREF");
2273 case XML_ATTRIBUTE_IDREFS
:
2274 xmlBufferWriteChar(buf
, " IDREFS");
2276 case XML_ATTRIBUTE_ENTITY
:
2277 xmlBufferWriteChar(buf
, " ENTITY");
2279 case XML_ATTRIBUTE_ENTITIES
:
2280 xmlBufferWriteChar(buf
, " ENTITIES");
2282 case XML_ATTRIBUTE_NMTOKEN
:
2283 xmlBufferWriteChar(buf
, " NMTOKEN");
2285 case XML_ATTRIBUTE_NMTOKENS
:
2286 xmlBufferWriteChar(buf
, " NMTOKENS");
2288 case XML_ATTRIBUTE_ENUMERATION
:
2289 xmlBufferWriteChar(buf
, " (");
2290 xmlDumpEnumeration(buf
, attr
->tree
);
2292 case XML_ATTRIBUTE_NOTATION
:
2293 xmlBufferWriteChar(buf
, " NOTATION (");
2294 xmlDumpEnumeration(buf
, attr
->tree
);
2297 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
2298 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2301 switch (attr
->def
) {
2302 case XML_ATTRIBUTE_NONE
:
2304 case XML_ATTRIBUTE_REQUIRED
:
2305 xmlBufferWriteChar(buf
, " #REQUIRED");
2307 case XML_ATTRIBUTE_IMPLIED
:
2308 xmlBufferWriteChar(buf
, " #IMPLIED");
2310 case XML_ATTRIBUTE_FIXED
:
2311 xmlBufferWriteChar(buf
, " #FIXED");
2314 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
2315 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2318 if (attr
->defaultValue
!= NULL
) {
2319 xmlBufferWriteChar(buf
, " ");
2320 xmlBufferWriteQuotedString(buf
, attr
->defaultValue
);
2322 xmlBufferWriteChar(buf
, ">\n");
2326 * xmlDumpAttributeDeclScan:
2327 * @attr: An attribute declaration
2328 * @buf: the XML buffer output
2330 * This is used with the hash scan function - just reverses arguments
2333 xmlDumpAttributeDeclScan(void *attr
, void *buf
,
2334 const xmlChar
*name ATTRIBUTE_UNUSED
) {
2335 xmlDumpAttributeDecl((xmlBufferPtr
) buf
, (xmlAttributePtr
) attr
);
2339 * xmlDumpAttributeTable:
2340 * @buf: the XML buffer output
2341 * @table: An attribute table
2343 * This will dump the content of the attribute table as an XML DTD definition
2346 xmlDumpAttributeTable(xmlBufferPtr buf
, xmlAttributeTablePtr table
) {
2347 if ((buf
== NULL
) || (table
== NULL
))
2349 xmlHashScan(table
, xmlDumpAttributeDeclScan
, buf
);
2351 #endif /* LIBXML_OUTPUT_ENABLED */
2353 /************************************************************************
2357 ************************************************************************/
2362 * Deallocate the memory used by an notation definition
2365 xmlFreeNotation(xmlNotationPtr nota
) {
2366 if (nota
== NULL
) return;
2367 if (nota
->name
!= NULL
)
2368 xmlFree((xmlChar
*) nota
->name
);
2369 if (nota
->PublicID
!= NULL
)
2370 xmlFree((xmlChar
*) nota
->PublicID
);
2371 if (nota
->SystemID
!= NULL
)
2372 xmlFree((xmlChar
*) nota
->SystemID
);
2378 * xmlAddNotationDecl:
2379 * @dtd: pointer to the DTD
2380 * @ctxt: the validation context
2381 * @name: the entity name
2382 * @PublicID: the public identifier or NULL
2383 * @SystemID: the system identifier or NULL
2385 * Register a new notation declaration
2387 * Returns NULL if not, otherwise the entity
2390 xmlAddNotationDecl(xmlValidCtxtPtr ctxt
, xmlDtdPtr dtd
,
2391 const xmlChar
*name
,
2392 const xmlChar
*PublicID
, const xmlChar
*SystemID
) {
2394 xmlNotationTablePtr table
;
2402 if ((PublicID
== NULL
) && (SystemID
== NULL
)) {
2407 * Create the Notation table if needed.
2409 table
= (xmlNotationTablePtr
) dtd
->notations
;
2410 if (table
== NULL
) {
2411 xmlDictPtr dict
= NULL
;
2412 if (dtd
->doc
!= NULL
)
2413 dict
= dtd
->doc
->dict
;
2415 dtd
->notations
= table
= xmlHashCreateDict(0, dict
);
2417 if (table
== NULL
) {
2419 "xmlAddNotationDecl: Table creation failed!\n");
2423 ret
= (xmlNotationPtr
) xmlMalloc(sizeof(xmlNotation
));
2425 xmlVErrMemory(ctxt
, "malloc failed");
2428 memset(ret
, 0, sizeof(xmlNotation
));
2431 * fill the structure.
2433 ret
->name
= xmlStrdup(name
);
2434 if (SystemID
!= NULL
)
2435 ret
->SystemID
= xmlStrdup(SystemID
);
2436 if (PublicID
!= NULL
)
2437 ret
->PublicID
= xmlStrdup(PublicID
);
2441 * Check the DTD for previous declarations of the ATTLIST
2443 if (xmlHashAddEntry(table
, name
, ret
)) {
2444 #ifdef LIBXML_VALID_ENABLED
2445 xmlErrValid(NULL
, XML_DTD_NOTATION_REDEFINED
,
2446 "xmlAddNotationDecl: %s already defined\n",
2447 (const char *) name
);
2448 #endif /* LIBXML_VALID_ENABLED */
2449 xmlFreeNotation(ret
);
2456 xmlFreeNotationTableEntry(void *nota
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2457 xmlFreeNotation((xmlNotationPtr
) nota
);
2461 * xmlFreeNotationTable:
2462 * @table: An notation table
2464 * Deallocate the memory used by an entities hash table.
2467 xmlFreeNotationTable(xmlNotationTablePtr table
) {
2468 xmlHashFree(table
, xmlFreeNotationTableEntry
);
2471 #ifdef LIBXML_TREE_ENABLED
2476 * Build a copy of a notation.
2478 * Returns the new xmlNotationPtr or NULL in case of error.
2481 xmlCopyNotation(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2482 xmlNotationPtr nota
= (xmlNotationPtr
) payload
;
2485 cur
= (xmlNotationPtr
) xmlMalloc(sizeof(xmlNotation
));
2487 xmlVErrMemory(NULL
, "malloc failed");
2490 if (nota
->name
!= NULL
)
2491 cur
->name
= xmlStrdup(nota
->name
);
2494 if (nota
->PublicID
!= NULL
)
2495 cur
->PublicID
= xmlStrdup(nota
->PublicID
);
2497 cur
->PublicID
= NULL
;
2498 if (nota
->SystemID
!= NULL
)
2499 cur
->SystemID
= xmlStrdup(nota
->SystemID
);
2501 cur
->SystemID
= NULL
;
2506 * xmlCopyNotationTable:
2507 * @table: A notation table
2509 * Build a copy of a notation table.
2511 * Returns the new xmlNotationTablePtr or NULL in case of error.
2514 xmlCopyNotationTable(xmlNotationTablePtr table
) {
2515 return((xmlNotationTablePtr
) xmlHashCopy(table
, xmlCopyNotation
));
2517 #endif /* LIBXML_TREE_ENABLED */
2519 #ifdef LIBXML_OUTPUT_ENABLED
2521 * xmlDumpNotationDecl:
2522 * @buf: the XML buffer output
2523 * @nota: A notation declaration
2525 * This will dump the content the notation declaration as an XML DTD definition
2528 xmlDumpNotationDecl(xmlBufferPtr buf
, xmlNotationPtr nota
) {
2529 if ((buf
== NULL
) || (nota
== NULL
))
2531 xmlBufferWriteChar(buf
, "<!NOTATION ");
2532 xmlBufferWriteCHAR(buf
, nota
->name
);
2533 if (nota
->PublicID
!= NULL
) {
2534 xmlBufferWriteChar(buf
, " PUBLIC ");
2535 xmlBufferWriteQuotedString(buf
, nota
->PublicID
);
2536 if (nota
->SystemID
!= NULL
) {
2537 xmlBufferWriteChar(buf
, " ");
2538 xmlBufferWriteQuotedString(buf
, nota
->SystemID
);
2541 xmlBufferWriteChar(buf
, " SYSTEM ");
2542 xmlBufferWriteQuotedString(buf
, nota
->SystemID
);
2544 xmlBufferWriteChar(buf
, " >\n");
2548 * xmlDumpNotationDeclScan:
2549 * @nota: A notation declaration
2550 * @buf: the XML buffer output
2552 * This is called with the hash scan function, and just reverses args
2555 xmlDumpNotationDeclScan(void *nota
, void *buf
,
2556 const xmlChar
*name ATTRIBUTE_UNUSED
) {
2557 xmlDumpNotationDecl((xmlBufferPtr
) buf
, (xmlNotationPtr
) nota
);
2561 * xmlDumpNotationTable:
2562 * @buf: the XML buffer output
2563 * @table: A notation table
2565 * This will dump the content of the notation table as an XML DTD definition
2568 xmlDumpNotationTable(xmlBufferPtr buf
, xmlNotationTablePtr table
) {
2569 if ((buf
== NULL
) || (table
== NULL
))
2571 xmlHashScan(table
, xmlDumpNotationDeclScan
, buf
);
2573 #endif /* LIBXML_OUTPUT_ENABLED */
2575 /************************************************************************
2579 ************************************************************************/
2584 * Free a string if it is not owned by the "dict" dictionary in the
2587 #define DICT_FREE(str) \
2588 if ((str) && ((!dict) || \
2589 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2590 xmlFree((char *)(str));
2593 * xmlValidNormalizeString:
2596 * Normalize a string in-place.
2599 xmlValidNormalizeString(xmlChar
*str
) {
2608 while (*src
== 0x20) src
++;
2611 while (*src
== 0x20) src
++;
2622 xmlIsStreaming(xmlValidCtxtPtr ctxt
) {
2623 xmlParserCtxtPtr pctxt
;
2627 if ((ctxt
->flags
& XML_VCTXT_USE_PCTXT
) == 0)
2629 pctxt
= ctxt
->userData
;
2630 return(pctxt
->parseMode
== XML_PARSE_READER
);
2637 * Deallocate the memory used by an id definition
2640 xmlFreeID(xmlIDPtr id
) {
2641 xmlDictPtr dict
= NULL
;
2643 if (id
== NULL
) return;
2645 if (id
->doc
!= NULL
)
2646 dict
= id
->doc
->dict
;
2648 if (id
->value
!= NULL
)
2649 DICT_FREE(id
->value
)
2650 if (id
->name
!= NULL
)
2658 * @ctxt: the validation context
2659 * @doc: pointer to the document
2660 * @value: the value name
2661 * @attr: the attribute holding the ID
2663 * Register a new id declaration
2665 * Returns NULL if not, otherwise the new xmlIDPtr
2668 xmlAddID(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, const xmlChar
*value
,
2671 xmlIDTablePtr table
;
2676 if ((value
== NULL
) || (value
[0] == 0)) {
2684 * Create the ID table if needed.
2686 table
= (xmlIDTablePtr
) doc
->ids
;
2687 if (table
== NULL
) {
2688 doc
->ids
= table
= xmlHashCreateDict(0, doc
->dict
);
2690 if (table
== NULL
) {
2692 "xmlAddID: Table creation failed!\n");
2696 ret
= (xmlIDPtr
) xmlMalloc(sizeof(xmlID
));
2698 xmlVErrMemory(ctxt
, "malloc failed");
2703 * fill the structure.
2705 ret
->value
= xmlStrdup(value
);
2707 if (xmlIsStreaming(ctxt
)) {
2709 * Operating in streaming mode, attr is gonna disappear
2711 if (doc
->dict
!= NULL
)
2712 ret
->name
= xmlDictLookup(doc
->dict
, attr
->name
, -1);
2714 ret
->name
= xmlStrdup(attr
->name
);
2720 ret
->lineno
= xmlGetLineNo(attr
->parent
);
2722 if (xmlHashAddEntry(table
, value
, ret
) < 0) {
2723 #ifdef LIBXML_VALID_ENABLED
2725 * The id is already defined in this DTD.
2728 xmlErrValidNode(ctxt
, attr
->parent
, XML_DTD_ID_REDEFINED
,
2729 "ID %s already defined\n", value
, NULL
, NULL
);
2731 #endif /* LIBXML_VALID_ENABLED */
2736 attr
->atype
= XML_ATTRIBUTE_ID
;
2741 xmlFreeIDTableEntry(void *id
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2742 xmlFreeID((xmlIDPtr
) id
);
2747 * @table: An id table
2749 * Deallocate the memory used by an ID hash table.
2752 xmlFreeIDTable(xmlIDTablePtr table
) {
2753 xmlHashFree(table
, xmlFreeIDTableEntry
);
2758 * @doc: the document
2759 * @elem: the element carrying the attribute
2760 * @attr: the attribute
2762 * Determine whether an attribute is of type ID. In case we have DTD(s)
2763 * then this is done if DTD loading has been requested. In the case
2764 * of HTML documents parsed with the HTML parser, then ID detection is
2765 * done systematically.
2767 * Returns 0 or 1 depending on the lookup result
2770 xmlIsID(xmlDocPtr doc
, xmlNodePtr elem
, xmlAttrPtr attr
) {
2771 if ((attr
== NULL
) || (attr
->name
== NULL
)) return(0);
2772 if ((attr
->ns
!= NULL
) && (attr
->ns
->prefix
!= NULL
) &&
2773 (!strcmp((char *) attr
->name
, "id")) &&
2774 (!strcmp((char *) attr
->ns
->prefix
, "xml")))
2776 if (doc
== NULL
) return(0);
2777 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
) &&
2778 (doc
->type
!= XML_HTML_DOCUMENT_NODE
)) {
2780 } else if (doc
->type
== XML_HTML_DOCUMENT_NODE
) {
2781 if ((xmlStrEqual(BAD_CAST
"id", attr
->name
)) ||
2782 ((xmlStrEqual(BAD_CAST
"name", attr
->name
)) &&
2783 ((elem
== NULL
) || (xmlStrEqual(elem
->name
, BAD_CAST
"a")))))
2786 } else if (elem
== NULL
) {
2789 xmlAttributePtr attrDecl
= NULL
;
2791 xmlChar felem
[50], fattr
[50];
2792 xmlChar
*fullelemname
, *fullattrname
;
2794 fullelemname
= (elem
->ns
!= NULL
&& elem
->ns
->prefix
!= NULL
) ?
2795 xmlBuildQName(elem
->name
, elem
->ns
->prefix
, felem
, 50) :
2796 (xmlChar
*)elem
->name
;
2798 fullattrname
= (attr
->ns
!= NULL
&& attr
->ns
->prefix
!= NULL
) ?
2799 xmlBuildQName(attr
->name
, attr
->ns
->prefix
, fattr
, 50) :
2800 (xmlChar
*)attr
->name
;
2802 if (fullelemname
!= NULL
&& fullattrname
!= NULL
) {
2803 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullelemname
,
2805 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
2806 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, fullelemname
,
2810 if ((fullattrname
!= fattr
) && (fullattrname
!= attr
->name
))
2811 xmlFree(fullattrname
);
2812 if ((fullelemname
!= felem
) && (fullelemname
!= elem
->name
))
2813 xmlFree(fullelemname
);
2815 if ((attrDecl
!= NULL
) && (attrDecl
->atype
== XML_ATTRIBUTE_ID
))
2823 * @doc: the document
2824 * @attr: the attribute
2826 * Remove the given attribute from the ID table maintained internally.
2828 * Returns -1 if the lookup failed and 0 otherwise
2831 xmlRemoveID(xmlDocPtr doc
, xmlAttrPtr attr
) {
2832 xmlIDTablePtr table
;
2836 if (doc
== NULL
) return(-1);
2837 if (attr
== NULL
) return(-1);
2839 table
= (xmlIDTablePtr
) doc
->ids
;
2843 ID
= xmlNodeListGetString(doc
, attr
->children
, 1);
2846 xmlValidNormalizeString(ID
);
2848 id
= xmlHashLookup(table
, ID
);
2849 if (id
== NULL
|| id
->attr
!= attr
) {
2854 xmlHashRemoveEntry(table
, ID
, xmlFreeIDTableEntry
);
2862 * @doc: pointer to the document
2865 * Search the attribute declaring the given ID
2867 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2870 xmlGetID(xmlDocPtr doc
, const xmlChar
*ID
) {
2871 xmlIDTablePtr table
;
2882 table
= (xmlIDTablePtr
) doc
->ids
;
2886 id
= xmlHashLookup(table
, ID
);
2889 if (id
->attr
== NULL
) {
2891 * We are operating on a stream, return a well known reference
2892 * since the attribute node doesn't exist anymore
2894 return((xmlAttrPtr
) doc
);
2899 /************************************************************************
2903 ************************************************************************/
2904 typedef struct xmlRemoveMemo_t
2910 typedef xmlRemoveMemo
*xmlRemoveMemoPtr
;
2912 typedef struct xmlValidateMemo_t
2914 xmlValidCtxtPtr ctxt
;
2915 const xmlChar
*name
;
2918 typedef xmlValidateMemo
*xmlValidateMemoPtr
;
2924 * Deallocate the memory used by a ref definition
2927 xmlFreeRef(xmlLinkPtr lk
) {
2928 xmlRefPtr ref
= (xmlRefPtr
)xmlLinkGetData(lk
);
2929 if (ref
== NULL
) return;
2930 if (ref
->value
!= NULL
)
2931 xmlFree((xmlChar
*)ref
->value
);
2932 if (ref
->name
!= NULL
)
2933 xmlFree((xmlChar
*)ref
->name
);
2938 * xmlFreeRefTableEntry:
2939 * @list_ref: A list of references.
2941 * Deallocate the memory used by a list of references
2944 xmlFreeRefTableEntry(void *payload
, const xmlChar
*name ATTRIBUTE_UNUSED
) {
2945 xmlListPtr list_ref
= (xmlListPtr
) payload
;
2946 if (list_ref
== NULL
) return;
2947 xmlListDelete(list_ref
);
2952 * @data: Contents of current link
2953 * @user: Value supplied by the user
2955 * Returns 0 to abort the walk or 1 to continue
2958 xmlWalkRemoveRef(const void *data
, void *user
)
2960 xmlAttrPtr attr0
= ((xmlRefPtr
)data
)->attr
;
2961 xmlAttrPtr attr1
= ((xmlRemoveMemoPtr
)user
)->ap
;
2962 xmlListPtr ref_list
= ((xmlRemoveMemoPtr
)user
)->l
;
2964 if (attr0
== attr1
) { /* Matched: remove and terminate walk */
2965 xmlListRemoveFirst(ref_list
, (void *)data
);
2973 * @data0: Value supplied by the user
2974 * @data1: Value supplied by the user
2976 * Do nothing, return 0. Used to create unordered lists.
2979 xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED
,
2980 const void *data1 ATTRIBUTE_UNUSED
)
2987 * @ctxt: the validation context
2988 * @doc: pointer to the document
2989 * @value: the value name
2990 * @attr: the attribute holding the Ref
2992 * DEPRECATED, do not use. This function will be removed from the public API.
2994 * Register a new ref declaration
2996 * Returns NULL if not, otherwise the new xmlRefPtr
2999 xmlAddRef(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, const xmlChar
*value
,
3002 xmlRefTablePtr table
;
3003 xmlListPtr ref_list
;
3008 if (value
== NULL
) {
3016 * Create the Ref table if needed.
3018 table
= (xmlRefTablePtr
) doc
->refs
;
3019 if (table
== NULL
) {
3020 doc
->refs
= table
= xmlHashCreateDict(0, doc
->dict
);
3022 if (table
== NULL
) {
3024 "xmlAddRef: Table creation failed!\n");
3028 ret
= (xmlRefPtr
) xmlMalloc(sizeof(xmlRef
));
3030 xmlVErrMemory(ctxt
, "malloc failed");
3035 * fill the structure.
3037 ret
->value
= xmlStrdup(value
);
3038 if (xmlIsStreaming(ctxt
)) {
3040 * Operating in streaming mode, attr is gonna disappear
3042 ret
->name
= xmlStrdup(attr
->name
);
3048 ret
->lineno
= xmlGetLineNo(attr
->parent
);
3050 /* To add a reference :-
3051 * References are maintained as a list of references,
3052 * Lookup the entry, if no entry create new nodelist
3053 * Add the owning node to the NodeList
3057 if (NULL
== (ref_list
= xmlHashLookup(table
, value
))) {
3058 if (NULL
== (ref_list
= xmlListCreate(xmlFreeRef
, xmlDummyCompare
))) {
3059 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
3060 "xmlAddRef: Reference list creation failed!\n",
3064 if (xmlHashAddEntry(table
, value
, ref_list
) < 0) {
3065 xmlListDelete(ref_list
);
3066 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
3067 "xmlAddRef: Reference list insertion failed!\n",
3072 if (xmlListAppend(ref_list
, ret
) != 0) {
3073 xmlErrValid(NULL
, XML_ERR_INTERNAL_ERROR
,
3074 "xmlAddRef: Reference list insertion failed!\n",
3081 if (ret
->value
!= NULL
)
3082 xmlFree((char *)ret
->value
);
3083 if (ret
->name
!= NULL
)
3084 xmlFree((char *)ret
->name
);
3092 * @table: An ref table
3094 * DEPRECATED, do not use. This function will be removed from the public API.
3096 * Deallocate the memory used by an Ref hash table.
3099 xmlFreeRefTable(xmlRefTablePtr table
) {
3100 xmlHashFree(table
, xmlFreeRefTableEntry
);
3105 * @doc: the document
3106 * @elem: the element carrying the attribute
3107 * @attr: the attribute
3109 * DEPRECATED, do not use. This function will be removed from the public API.
3111 * Determine whether an attribute is of type Ref. In case we have DTD(s)
3112 * then this is simple, otherwise we use an heuristic: name Ref (upper
3115 * Returns 0 or 1 depending on the lookup result
3118 xmlIsRef(xmlDocPtr doc
, xmlNodePtr elem
, xmlAttrPtr attr
) {
3123 if (doc
== NULL
) return(0);
3126 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
)) {
3128 } else if (doc
->type
== XML_HTML_DOCUMENT_NODE
) {
3132 xmlAttributePtr attrDecl
;
3134 if (elem
== NULL
) return(0);
3135 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, attr
->name
);
3136 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3137 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
3138 elem
->name
, attr
->name
);
3140 if ((attrDecl
!= NULL
) &&
3141 (attrDecl
->atype
== XML_ATTRIBUTE_IDREF
||
3142 attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
))
3150 * @doc: the document
3151 * @attr: the attribute
3153 * DEPRECATED, do not use. This function will be removed from the public API.
3155 * Remove the given attribute from the Ref table maintained internally.
3157 * Returns -1 if the lookup failed and 0 otherwise
3160 xmlRemoveRef(xmlDocPtr doc
, xmlAttrPtr attr
) {
3161 xmlListPtr ref_list
;
3162 xmlRefTablePtr table
;
3164 xmlRemoveMemo target
;
3166 if (doc
== NULL
) return(-1);
3167 if (attr
== NULL
) return(-1);
3169 table
= (xmlRefTablePtr
) doc
->refs
;
3173 ID
= xmlNodeListGetString(doc
, attr
->children
, 1);
3177 ref_list
= xmlHashLookup(table
, ID
);
3178 if(ref_list
== NULL
) {
3183 /* At this point, ref_list refers to a list of references which
3184 * have the same key as the supplied attr. Our list of references
3185 * is ordered by reference address and we don't have that information
3186 * here to use when removing. We'll have to walk the list and
3187 * check for a matching attribute, when we find one stop the walk
3188 * and remove the entry.
3189 * The list is ordered by reference, so that means we don't have the
3190 * key. Passing the list and the reference to the walker means we
3191 * will have enough data to be able to remove the entry.
3193 target
.l
= ref_list
;
3196 /* Remove the supplied attr from our list */
3197 xmlListWalk(ref_list
, xmlWalkRemoveRef
, &target
);
3199 /*If the list is empty then remove the list entry in the hash */
3200 if (xmlListEmpty(ref_list
))
3201 xmlHashUpdateEntry(table
, ID
, NULL
, xmlFreeRefTableEntry
);
3208 * @doc: pointer to the document
3211 * DEPRECATED, do not use. This function will be removed from the public API.
3213 * Find the set of references for the supplied ID.
3215 * Returns NULL if not found, otherwise node set for the ID.
3218 xmlGetRefs(xmlDocPtr doc
, const xmlChar
*ID
) {
3219 xmlRefTablePtr table
;
3229 table
= (xmlRefTablePtr
) doc
->refs
;
3233 return (xmlHashLookup(table
, ID
));
3236 /************************************************************************
3238 * Routines for validity checking *
3240 ************************************************************************/
3243 * xmlGetDtdElementDesc:
3244 * @dtd: a pointer to the DtD to search
3245 * @name: the element name
3247 * Search the DTD for the description of this element
3249 * returns the xmlElementPtr if found or NULL
3253 xmlGetDtdElementDesc(xmlDtdPtr dtd
, const xmlChar
*name
) {
3254 xmlElementTablePtr table
;
3256 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
3258 if ((dtd
== NULL
) || (name
== NULL
)) return(NULL
);
3259 if (dtd
->elements
== NULL
)
3261 table
= (xmlElementTablePtr
) dtd
->elements
;
3263 uqname
= xmlSplitQName2(name
, &prefix
);
3266 cur
= xmlHashLookup2(table
, name
, prefix
);
3267 if (prefix
!= NULL
) xmlFree(prefix
);
3268 if (uqname
!= NULL
) xmlFree(uqname
);
3272 * xmlGetDtdElementDesc2:
3273 * @dtd: a pointer to the DtD to search
3274 * @name: the element name
3275 * @create: create an empty description if not found
3277 * Search the DTD for the description of this element
3279 * returns the xmlElementPtr if found or NULL
3282 static xmlElementPtr
3283 xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt
, xmlDtdPtr dtd
, const xmlChar
*name
,
3285 xmlElementTablePtr table
;
3287 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
3289 if (dtd
== NULL
) return(NULL
);
3290 if (dtd
->elements
== NULL
) {
3291 xmlDictPtr dict
= NULL
;
3293 if (dtd
->doc
!= NULL
)
3294 dict
= dtd
->doc
->dict
;
3299 * Create the Element table if needed.
3301 table
= (xmlElementTablePtr
) dtd
->elements
;
3302 if (table
== NULL
) {
3303 table
= xmlHashCreateDict(0, dict
);
3304 dtd
->elements
= (void *) table
;
3306 if (table
== NULL
) {
3307 xmlVErrMemory(ctxt
, "element table allocation failed");
3311 table
= (xmlElementTablePtr
) dtd
->elements
;
3313 uqname
= xmlSplitQName2(name
, &prefix
);
3316 cur
= xmlHashLookup2(table
, name
, prefix
);
3317 if ((cur
== NULL
) && (create
)) {
3318 cur
= (xmlElementPtr
) xmlMalloc(sizeof(xmlElement
));
3320 xmlVErrMemory(ctxt
, "malloc failed");
3323 memset(cur
, 0, sizeof(xmlElement
));
3324 cur
->type
= XML_ELEMENT_DECL
;
3327 * fill the structure.
3329 cur
->name
= xmlStrdup(name
);
3330 cur
->prefix
= xmlStrdup(prefix
);
3331 cur
->etype
= XML_ELEMENT_TYPE_UNDEFINED
;
3333 if (xmlHashAddEntry2(table
, name
, prefix
, cur
) < 0) {
3334 xmlVErrMemory(ctxt
, "adding entry failed");
3335 xmlFreeElement(cur
);
3340 if (prefix
!= NULL
) xmlFree(prefix
);
3341 if (uqname
!= NULL
) xmlFree(uqname
);
3346 * xmlGetDtdQElementDesc:
3347 * @dtd: a pointer to the DtD to search
3348 * @name: the element name
3349 * @prefix: the element namespace prefix
3351 * Search the DTD for the description of this element
3353 * returns the xmlElementPtr if found or NULL
3357 xmlGetDtdQElementDesc(xmlDtdPtr dtd
, const xmlChar
*name
,
3358 const xmlChar
*prefix
) {
3359 xmlElementTablePtr table
;
3361 if (dtd
== NULL
) return(NULL
);
3362 if (dtd
->elements
== NULL
) return(NULL
);
3363 table
= (xmlElementTablePtr
) dtd
->elements
;
3365 return(xmlHashLookup2(table
, name
, prefix
));
3369 * xmlGetDtdAttrDesc:
3370 * @dtd: a pointer to the DtD to search
3371 * @elem: the element name
3372 * @name: the attribute name
3374 * Search the DTD for the description of this attribute on
3377 * returns the xmlAttributePtr if found or NULL
3381 xmlGetDtdAttrDesc(xmlDtdPtr dtd
, const xmlChar
*elem
, const xmlChar
*name
) {
3382 xmlAttributeTablePtr table
;
3383 xmlAttributePtr cur
;
3384 xmlChar
*uqname
= NULL
, *prefix
= NULL
;
3386 if (dtd
== NULL
) return(NULL
);
3387 if (dtd
->attributes
== NULL
) return(NULL
);
3389 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
3393 uqname
= xmlSplitQName2(name
, &prefix
);
3395 if (uqname
!= NULL
) {
3396 cur
= xmlHashLookup3(table
, uqname
, prefix
, elem
);
3397 if (prefix
!= NULL
) xmlFree(prefix
);
3398 if (uqname
!= NULL
) xmlFree(uqname
);
3400 cur
= xmlHashLookup3(table
, name
, NULL
, elem
);
3405 * xmlGetDtdQAttrDesc:
3406 * @dtd: a pointer to the DtD to search
3407 * @elem: the element name
3408 * @name: the attribute name
3409 * @prefix: the attribute namespace prefix
3411 * Search the DTD for the description of this qualified attribute on
3414 * returns the xmlAttributePtr if found or NULL
3418 xmlGetDtdQAttrDesc(xmlDtdPtr dtd
, const xmlChar
*elem
, const xmlChar
*name
,
3419 const xmlChar
*prefix
) {
3420 xmlAttributeTablePtr table
;
3422 if (dtd
== NULL
) return(NULL
);
3423 if (dtd
->attributes
== NULL
) return(NULL
);
3424 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
3426 return(xmlHashLookup3(table
, name
, prefix
, elem
));
3430 * xmlGetDtdNotationDesc:
3431 * @dtd: a pointer to the DtD to search
3432 * @name: the notation name
3434 * Search the DTD for the description of this notation
3436 * returns the xmlNotationPtr if found or NULL
3440 xmlGetDtdNotationDesc(xmlDtdPtr dtd
, const xmlChar
*name
) {
3441 xmlNotationTablePtr table
;
3443 if (dtd
== NULL
) return(NULL
);
3444 if (dtd
->notations
== NULL
) return(NULL
);
3445 table
= (xmlNotationTablePtr
) dtd
->notations
;
3447 return(xmlHashLookup(table
, name
));
3450 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3452 * xmlValidateNotationUse:
3453 * @ctxt: the validation context
3454 * @doc: the document
3455 * @notationName: the notation name to check
3457 * Validate that the given name match a notation declaration.
3458 * - [ VC: Notation Declared ]
3460 * returns 1 if valid or 0 otherwise
3464 xmlValidateNotationUse(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3465 const xmlChar
*notationName
) {
3466 xmlNotationPtr notaDecl
;
3467 if ((doc
== NULL
) || (doc
->intSubset
== NULL
) ||
3468 (notationName
== NULL
)) return(-1);
3470 notaDecl
= xmlGetDtdNotationDesc(doc
->intSubset
, notationName
);
3471 if ((notaDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3472 notaDecl
= xmlGetDtdNotationDesc(doc
->extSubset
, notationName
);
3474 if ((notaDecl
== NULL
) && (ctxt
!= NULL
)) {
3475 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
, XML_DTD_UNKNOWN_NOTATION
,
3476 "NOTATION %s is not declared\n",
3477 notationName
, NULL
, NULL
);
3482 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3485 * xmlIsMixedElement:
3486 * @doc: the document
3487 * @name: the element name
3489 * Search in the DtDs whether an element accept Mixed content (or ANY)
3490 * basically if it is supposed to accept text childs
3492 * returns 0 if no, 1 if yes, and -1 if no element description is available
3496 xmlIsMixedElement(xmlDocPtr doc
, const xmlChar
*name
) {
3497 xmlElementPtr elemDecl
;
3499 if ((doc
== NULL
) || (doc
->intSubset
== NULL
)) return(-1);
3501 elemDecl
= xmlGetDtdElementDesc(doc
->intSubset
, name
);
3502 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
))
3503 elemDecl
= xmlGetDtdElementDesc(doc
->extSubset
, name
);
3504 if (elemDecl
== NULL
) return(-1);
3505 switch (elemDecl
->etype
) {
3506 case XML_ELEMENT_TYPE_UNDEFINED
:
3508 case XML_ELEMENT_TYPE_ELEMENT
:
3510 case XML_ELEMENT_TYPE_EMPTY
:
3512 * return 1 for EMPTY since we want VC error to pop up
3513 * on <empty> </empty> for example
3515 case XML_ELEMENT_TYPE_ANY
:
3516 case XML_ELEMENT_TYPE_MIXED
:
3522 #ifdef LIBXML_VALID_ENABLED
3525 xmlIsDocNameStartChar(xmlDocPtr doc
, int c
) {
3526 if ((doc
== NULL
) || (doc
->properties
& XML_DOC_OLD10
) == 0) {
3528 * Use the new checks of production [4] [4a] amd [5] of the
3529 * Update 5 of XML-1.0
3531 if (((c
>= 'a') && (c
<= 'z')) ||
3532 ((c
>= 'A') && (c
<= 'Z')) ||
3533 (c
== '_') || (c
== ':') ||
3534 ((c
>= 0xC0) && (c
<= 0xD6)) ||
3535 ((c
>= 0xD8) && (c
<= 0xF6)) ||
3536 ((c
>= 0xF8) && (c
<= 0x2FF)) ||
3537 ((c
>= 0x370) && (c
<= 0x37D)) ||
3538 ((c
>= 0x37F) && (c
<= 0x1FFF)) ||
3539 ((c
>= 0x200C) && (c
<= 0x200D)) ||
3540 ((c
>= 0x2070) && (c
<= 0x218F)) ||
3541 ((c
>= 0x2C00) && (c
<= 0x2FEF)) ||
3542 ((c
>= 0x3001) && (c
<= 0xD7FF)) ||
3543 ((c
>= 0xF900) && (c
<= 0xFDCF)) ||
3544 ((c
>= 0xFDF0) && (c
<= 0xFFFD)) ||
3545 ((c
>= 0x10000) && (c
<= 0xEFFFF)))
3548 if (IS_LETTER(c
) || (c
== '_') || (c
== ':'))
3555 xmlIsDocNameChar(xmlDocPtr doc
, int c
) {
3556 if ((doc
== NULL
) || (doc
->properties
& XML_DOC_OLD10
) == 0) {
3558 * Use the new checks of production [4] [4a] amd [5] of the
3559 * Update 5 of XML-1.0
3561 if (((c
>= 'a') && (c
<= 'z')) ||
3562 ((c
>= 'A') && (c
<= 'Z')) ||
3563 ((c
>= '0') && (c
<= '9')) || /* !start */
3564 (c
== '_') || (c
== ':') ||
3565 (c
== '-') || (c
== '.') || (c
== 0xB7) || /* !start */
3566 ((c
>= 0xC0) && (c
<= 0xD6)) ||
3567 ((c
>= 0xD8) && (c
<= 0xF6)) ||
3568 ((c
>= 0xF8) && (c
<= 0x2FF)) ||
3569 ((c
>= 0x300) && (c
<= 0x36F)) || /* !start */
3570 ((c
>= 0x370) && (c
<= 0x37D)) ||
3571 ((c
>= 0x37F) && (c
<= 0x1FFF)) ||
3572 ((c
>= 0x200C) && (c
<= 0x200D)) ||
3573 ((c
>= 0x203F) && (c
<= 0x2040)) || /* !start */
3574 ((c
>= 0x2070) && (c
<= 0x218F)) ||
3575 ((c
>= 0x2C00) && (c
<= 0x2FEF)) ||
3576 ((c
>= 0x3001) && (c
<= 0xD7FF)) ||
3577 ((c
>= 0xF900) && (c
<= 0xFDCF)) ||
3578 ((c
>= 0xFDF0) && (c
<= 0xFFFD)) ||
3579 ((c
>= 0x10000) && (c
<= 0xEFFFF)))
3582 if ((IS_LETTER(c
)) || (IS_DIGIT(c
)) ||
3583 (c
== '.') || (c
== '-') ||
3584 (c
== '_') || (c
== ':') ||
3585 (IS_COMBINING(c
)) ||
3593 * xmlValidateNameValue:
3594 * @doc: pointer to the document or NULL
3595 * @value: an Name value
3597 * Validate that the given value match Name production
3599 * returns 1 if valid or 0 otherwise
3603 xmlValidateNameValueInternal(xmlDocPtr doc
, const xmlChar
*value
) {
3607 if (value
== NULL
) return(0);
3609 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3611 if (!xmlIsDocNameStartChar(doc
, val
))
3614 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3616 while (xmlIsDocNameChar(doc
, val
)) {
3617 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3621 if (val
!= 0) return(0);
3627 * xmlValidateNameValue:
3628 * @value: an Name value
3630 * Validate that the given value match Name production
3632 * returns 1 if valid or 0 otherwise
3636 xmlValidateNameValue(const xmlChar
*value
) {
3637 return(xmlValidateNameValueInternal(NULL
, value
));
3641 * xmlValidateNamesValueInternal:
3642 * @doc: pointer to the document or NULL
3643 * @value: an Names value
3645 * Validate that the given value match Names production
3647 * returns 1 if valid or 0 otherwise
3651 xmlValidateNamesValueInternal(xmlDocPtr doc
, const xmlChar
*value
) {
3655 if (value
== NULL
) return(0);
3657 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3660 if (!xmlIsDocNameStartChar(doc
, val
))
3663 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3665 while (xmlIsDocNameChar(doc
, val
)) {
3666 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3670 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3671 while (val
== 0x20) {
3672 while (val
== 0x20) {
3673 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3677 if (!xmlIsDocNameStartChar(doc
, val
))
3680 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3683 while (xmlIsDocNameChar(doc
, val
)) {
3684 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3689 if (val
!= 0) return(0);
3695 * xmlValidateNamesValue:
3696 * @value: an Names value
3698 * Validate that the given value match Names production
3700 * returns 1 if valid or 0 otherwise
3704 xmlValidateNamesValue(const xmlChar
*value
) {
3705 return(xmlValidateNamesValueInternal(NULL
, value
));
3709 * xmlValidateNmtokenValueInternal:
3710 * @doc: pointer to the document or NULL
3711 * @value: an Nmtoken value
3713 * Validate that the given value match Nmtoken production
3715 * [ VC: Name Token ]
3717 * returns 1 if valid or 0 otherwise
3721 xmlValidateNmtokenValueInternal(xmlDocPtr doc
, const xmlChar
*value
) {
3725 if (value
== NULL
) return(0);
3727 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3730 if (!xmlIsDocNameChar(doc
, val
))
3733 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3735 while (xmlIsDocNameChar(doc
, val
)) {
3736 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3740 if (val
!= 0) return(0);
3746 * xmlValidateNmtokenValue:
3747 * @value: an Nmtoken value
3749 * Validate that the given value match Nmtoken production
3751 * [ VC: Name Token ]
3753 * returns 1 if valid or 0 otherwise
3757 xmlValidateNmtokenValue(const xmlChar
*value
) {
3758 return(xmlValidateNmtokenValueInternal(NULL
, value
));
3762 * xmlValidateNmtokensValueInternal:
3763 * @doc: pointer to the document or NULL
3764 * @value: an Nmtokens value
3766 * Validate that the given value match Nmtokens production
3768 * [ VC: Name Token ]
3770 * returns 1 if valid or 0 otherwise
3774 xmlValidateNmtokensValueInternal(xmlDocPtr doc
, const xmlChar
*value
) {
3778 if (value
== NULL
) return(0);
3780 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3783 while (IS_BLANK(val
)) {
3784 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3788 if (!xmlIsDocNameChar(doc
, val
))
3791 while (xmlIsDocNameChar(doc
, val
)) {
3792 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3796 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3797 while (val
== 0x20) {
3798 while (val
== 0x20) {
3799 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3802 if (val
== 0) return(1);
3804 if (!xmlIsDocNameChar(doc
, val
))
3807 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3810 while (xmlIsDocNameChar(doc
, val
)) {
3811 val
= xmlStringCurrentChar(NULL
, cur
, &len
);
3816 if (val
!= 0) return(0);
3822 * xmlValidateNmtokensValue:
3823 * @value: an Nmtokens value
3825 * Validate that the given value match Nmtokens production
3827 * [ VC: Name Token ]
3829 * returns 1 if valid or 0 otherwise
3833 xmlValidateNmtokensValue(const xmlChar
*value
) {
3834 return(xmlValidateNmtokensValueInternal(NULL
, value
));
3838 * xmlValidateNotationDecl:
3839 * @ctxt: the validation context
3840 * @doc: a document instance
3841 * @nota: a notation definition
3843 * Try to validate a single notation definition
3844 * basically it does the following checks as described by the
3845 * XML-1.0 recommendation:
3846 * - it seems that no validity constraint exists on notation declarations
3847 * But this function get called anyway ...
3849 * returns 1 if valid or 0 otherwise
3853 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED
, xmlDocPtr doc ATTRIBUTE_UNUSED
,
3854 xmlNotationPtr nota ATTRIBUTE_UNUSED
) {
3861 * xmlValidateAttributeValueInternal:
3862 * @doc: the document
3863 * @type: an attribute type
3864 * @value: an attribute value
3866 * Validate that the given attribute value match the proper production
3868 * returns 1 if valid or 0 otherwise
3872 xmlValidateAttributeValueInternal(xmlDocPtr doc
, xmlAttributeType type
,
3873 const xmlChar
*value
) {
3875 case XML_ATTRIBUTE_ENTITIES
:
3876 case XML_ATTRIBUTE_IDREFS
:
3877 return(xmlValidateNamesValueInternal(doc
, value
));
3878 case XML_ATTRIBUTE_ENTITY
:
3879 case XML_ATTRIBUTE_IDREF
:
3880 case XML_ATTRIBUTE_ID
:
3881 case XML_ATTRIBUTE_NOTATION
:
3882 return(xmlValidateNameValueInternal(doc
, value
));
3883 case XML_ATTRIBUTE_NMTOKENS
:
3884 case XML_ATTRIBUTE_ENUMERATION
:
3885 return(xmlValidateNmtokensValueInternal(doc
, value
));
3886 case XML_ATTRIBUTE_NMTOKEN
:
3887 return(xmlValidateNmtokenValueInternal(doc
, value
));
3888 case XML_ATTRIBUTE_CDATA
:
3895 * xmlValidateAttributeValue:
3896 * @type: an attribute type
3897 * @value: an attribute value
3899 * Validate that the given attribute value match the proper production
3902 * Values of type ID must match the Name production....
3905 * Values of type IDREF must match the Name production, and values
3906 * of type IDREFS must match Names ...
3908 * [ VC: Entity Name ]
3909 * Values of type ENTITY must match the Name production, values
3910 * of type ENTITIES must match Names ...
3912 * [ VC: Name Token ]
3913 * Values of type NMTOKEN must match the Nmtoken production; values
3914 * of type NMTOKENS must match Nmtokens.
3916 * returns 1 if valid or 0 otherwise
3919 xmlValidateAttributeValue(xmlAttributeType type
, const xmlChar
*value
) {
3920 return(xmlValidateAttributeValueInternal(NULL
, type
, value
));
3924 * xmlValidateAttributeValue2:
3925 * @ctxt: the validation context
3926 * @doc: the document
3927 * @name: the attribute name (used for error reporting only)
3928 * @type: the attribute type
3929 * @value: the attribute value
3931 * Validate that the given attribute value match a given type.
3932 * This typically cannot be done before having finished parsing
3936 * Values of type IDREF must match one of the declared IDs
3937 * Values of type IDREFS must match a sequence of the declared IDs
3938 * each Name must match the value of an ID attribute on some element
3939 * in the XML document; i.e. IDREF values must match the value of
3942 * [ VC: Entity Name ]
3943 * Values of type ENTITY must match one declared entity
3944 * Values of type ENTITIES must match a sequence of declared entities
3946 * [ VC: Notation Attributes ]
3947 * all notation names in the declaration must be declared.
3949 * returns 1 if valid or 0 otherwise
3953 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
3954 const xmlChar
*name
, xmlAttributeType type
, const xmlChar
*value
) {
3957 case XML_ATTRIBUTE_IDREFS
:
3958 case XML_ATTRIBUTE_IDREF
:
3959 case XML_ATTRIBUTE_ID
:
3960 case XML_ATTRIBUTE_NMTOKENS
:
3961 case XML_ATTRIBUTE_ENUMERATION
:
3962 case XML_ATTRIBUTE_NMTOKEN
:
3963 case XML_ATTRIBUTE_CDATA
:
3965 case XML_ATTRIBUTE_ENTITY
: {
3968 ent
= xmlGetDocEntity(doc
, value
);
3969 /* yeah it's a bit messy... */
3970 if ((ent
== NULL
) && (doc
->standalone
== 1)) {
3971 doc
->standalone
= 0;
3972 ent
= xmlGetDocEntity(doc
, value
);
3975 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
3976 XML_DTD_UNKNOWN_ENTITY
,
3977 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3980 } else if (ent
->etype
!= XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
3981 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
3982 XML_DTD_ENTITY_TYPE
,
3983 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3989 case XML_ATTRIBUTE_ENTITIES
: {
3990 xmlChar
*dup
, *nam
= NULL
, *cur
, save
;
3993 dup
= xmlStrdup(value
);
3999 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
))) cur
++;
4002 ent
= xmlGetDocEntity(doc
, nam
);
4004 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
4005 XML_DTD_UNKNOWN_ENTITY
,
4006 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
4009 } else if (ent
->etype
!= XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
4010 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
4011 XML_DTD_ENTITY_TYPE
,
4012 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
4019 while (IS_BLANK_CH(*cur
)) cur
++;
4024 case XML_ATTRIBUTE_NOTATION
: {
4025 xmlNotationPtr nota
;
4027 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
4028 if ((nota
== NULL
) && (doc
->extSubset
!= NULL
))
4029 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
4032 xmlErrValidNode(ctxt
, (xmlNodePtr
) doc
,
4033 XML_DTD_UNKNOWN_NOTATION
,
4034 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
4045 * xmlValidCtxtNormalizeAttributeValue:
4046 * @ctxt: the validation context
4047 * @doc: the document
4049 * @name: the attribute name
4050 * @value: the attribute value
4051 * @ctxt: the validation context or NULL
4053 * Does the validation related extra step of the normalization of attribute
4056 * If the declared value is not CDATA, then the XML processor must further
4057 * process the normalized attribute value by discarding any leading and
4058 * trailing space (#x20) characters, and by replacing sequences of space
4059 * (#x20) characters by single space (#x20) character.
4061 * Also check VC: Standalone Document Declaration in P32, and update
4062 * ctxt->valid accordingly
4064 * returns a new normalized string if normalization is needed, NULL otherwise
4065 * the caller must free the returned value.
4069 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4070 xmlNodePtr elem
, const xmlChar
*name
, const xmlChar
*value
) {
4072 xmlAttributePtr attrDecl
= NULL
;
4075 if (doc
== NULL
) return(NULL
);
4076 if (elem
== NULL
) return(NULL
);
4077 if (name
== NULL
) return(NULL
);
4078 if (value
== NULL
) return(NULL
);
4080 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
4084 fullname
= xmlBuildQName(elem
->name
, elem
->ns
->prefix
, fn
, 50);
4085 if (fullname
== NULL
)
4087 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullname
, name
);
4088 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
4089 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, fullname
, name
);
4090 if (attrDecl
!= NULL
)
4093 if ((fullname
!= fn
) && (fullname
!= elem
->name
))
4096 if ((attrDecl
== NULL
) && (doc
->intSubset
!= NULL
))
4097 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, name
);
4098 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
4099 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, elem
->name
, name
);
4100 if (attrDecl
!= NULL
)
4104 if (attrDecl
== NULL
)
4106 if (attrDecl
->atype
== XML_ATTRIBUTE_CDATA
)
4109 ret
= xmlStrdup(value
);
4112 xmlValidNormalizeString(ret
);
4113 if ((doc
->standalone
) && (extsubset
== 1) && (!xmlStrEqual(value
, ret
))) {
4114 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOT_STANDALONE
,
4115 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
4116 name
, elem
->name
, NULL
);
4123 * xmlValidNormalizeAttributeValue:
4124 * @doc: the document
4126 * @name: the attribute name
4127 * @value: the attribute value
4129 * Does the validation related extra step of the normalization of attribute
4132 * If the declared value is not CDATA, then the XML processor must further
4133 * process the normalized attribute value by discarding any leading and
4134 * trailing space (#x20) characters, and by replacing sequences of space
4135 * (#x20) characters by single space (#x20) character.
4137 * Returns a new normalized string if normalization is needed, NULL otherwise
4138 * the caller must free the returned value.
4142 xmlValidNormalizeAttributeValue(xmlDocPtr doc
, xmlNodePtr elem
,
4143 const xmlChar
*name
, const xmlChar
*value
) {
4145 xmlAttributePtr attrDecl
= NULL
;
4147 if (doc
== NULL
) return(NULL
);
4148 if (elem
== NULL
) return(NULL
);
4149 if (name
== NULL
) return(NULL
);
4150 if (value
== NULL
) return(NULL
);
4152 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
4156 fullname
= xmlBuildQName(elem
->name
, elem
->ns
->prefix
, fn
, 50);
4157 if (fullname
== NULL
)
4159 if ((fullname
!= fn
) && (fullname
!= elem
->name
))
4162 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, elem
->name
, name
);
4163 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4164 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, elem
->name
, name
);
4166 if (attrDecl
== NULL
)
4168 if (attrDecl
->atype
== XML_ATTRIBUTE_CDATA
)
4171 ret
= xmlStrdup(value
);
4174 xmlValidNormalizeString(ret
);
4179 xmlValidateAttributeIdCallback(void *payload
, void *data
,
4180 const xmlChar
*name ATTRIBUTE_UNUSED
) {
4181 xmlAttributePtr attr
= (xmlAttributePtr
) payload
;
4182 int *count
= (int *) data
;
4183 if (attr
->atype
== XML_ATTRIBUTE_ID
) (*count
)++;
4187 * xmlValidateAttributeDecl:
4188 * @ctxt: the validation context
4189 * @doc: a document instance
4190 * @attr: an attribute definition
4192 * Try to validate a single attribute definition
4193 * basically it does the following checks as described by the
4194 * XML-1.0 recommendation:
4195 * - [ VC: Attribute Default Legal ]
4196 * - [ VC: Enumeration ]
4197 * - [ VC: ID Attribute Default ]
4199 * The ID/IDREF uniqueness and matching are done separately
4201 * returns 1 if valid or 0 otherwise
4205 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4206 xmlAttributePtr attr
) {
4210 if(attr
== NULL
) return(1);
4212 /* Attribute Default Legal */
4214 if (attr
->defaultValue
!= NULL
) {
4215 val
= xmlValidateAttributeValueInternal(doc
, attr
->atype
,
4216 attr
->defaultValue
);
4218 xmlErrValidNode(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ATTRIBUTE_DEFAULT
,
4219 "Syntax of default value for attribute %s of %s is not valid\n",
4220 attr
->name
, attr
->elem
, NULL
);
4225 /* ID Attribute Default */
4226 if ((attr
->atype
== XML_ATTRIBUTE_ID
)&&
4227 (attr
->def
!= XML_ATTRIBUTE_IMPLIED
) &&
4228 (attr
->def
!= XML_ATTRIBUTE_REQUIRED
)) {
4229 xmlErrValidNode(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ID_FIXED
,
4230 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4231 attr
->name
, attr
->elem
, NULL
);
4235 /* One ID per Element Type */
4236 if (attr
->atype
== XML_ATTRIBUTE_ID
) {
4239 /* the trick is that we parse DtD as their own internal subset */
4240 xmlElementPtr elem
= xmlGetDtdElementDesc(doc
->intSubset
,
4243 nbId
= xmlScanIDAttributeDecl(NULL
, elem
, 0);
4245 xmlAttributeTablePtr table
;
4248 * The attribute may be declared in the internal subset and the
4249 * element in the external subset.
4252 if (doc
->intSubset
!= NULL
) {
4253 table
= (xmlAttributeTablePtr
) doc
->intSubset
->attributes
;
4254 xmlHashScan3(table
, NULL
, NULL
, attr
->elem
,
4255 xmlValidateAttributeIdCallback
, &nbId
);
4260 xmlErrValidNodeNr(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ID_SUBSET
,
4261 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4262 attr
->elem
, nbId
, attr
->name
);
4263 } else if (doc
->extSubset
!= NULL
) {
4265 elem
= xmlGetDtdElementDesc(doc
->extSubset
, attr
->elem
);
4267 extId
= xmlScanIDAttributeDecl(NULL
, elem
, 0);
4270 xmlErrValidNodeNr(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ID_SUBSET
,
4271 "Element %s has %d ID attribute defined in the external subset : %s\n",
4272 attr
->elem
, extId
, attr
->name
);
4273 } else if (extId
+ nbId
> 1) {
4274 xmlErrValidNode(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ID_SUBSET
,
4275 "Element %s has ID attributes defined in the internal and external subset : %s\n",
4276 attr
->elem
, attr
->name
, NULL
);
4281 /* Validity Constraint: Enumeration */
4282 if ((attr
->defaultValue
!= NULL
) && (attr
->tree
!= NULL
)) {
4283 xmlEnumerationPtr tree
= attr
->tree
;
4284 while (tree
!= NULL
) {
4285 if (xmlStrEqual(tree
->name
, attr
->defaultValue
)) break;
4289 xmlErrValidNode(ctxt
, (xmlNodePtr
) attr
, XML_DTD_ATTRIBUTE_VALUE
,
4290 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4291 attr
->defaultValue
, attr
->name
, attr
->elem
);
4300 * xmlValidateElementDecl:
4301 * @ctxt: the validation context
4302 * @doc: a document instance
4303 * @elem: an element definition
4305 * Try to validate a single element definition
4306 * basically it does the following checks as described by the
4307 * XML-1.0 recommendation:
4308 * - [ VC: One ID per Element Type ]
4309 * - [ VC: No Duplicate Types ]
4310 * - [ VC: Unique Element Type Declaration ]
4312 * returns 1 if valid or 0 otherwise
4316 xmlValidateElementDecl(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4317 xmlElementPtr elem
) {
4323 if (elem
== NULL
) return(1);
4326 #ifdef LIBXML_REGEXP_ENABLED
4327 /* Build the regexp associated to the content model */
4328 ret
= xmlValidBuildContentModel(ctxt
, elem
);
4332 /* No Duplicate Types */
4333 if (elem
->etype
== XML_ELEMENT_TYPE_MIXED
) {
4334 xmlElementContentPtr cur
, next
;
4335 const xmlChar
*name
;
4337 cur
= elem
->content
;
4338 while (cur
!= NULL
) {
4339 if (cur
->type
!= XML_ELEMENT_CONTENT_OR
) break;
4340 if (cur
->c1
== NULL
) break;
4341 if (cur
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
4342 name
= cur
->c1
->name
;
4344 while (next
!= NULL
) {
4345 if (next
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
4346 if ((xmlStrEqual(next
->name
, name
)) &&
4347 (xmlStrEqual(next
->prefix
, cur
->c1
->prefix
))) {
4348 if (cur
->c1
->prefix
== NULL
) {
4349 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_CONTENT_ERROR
,
4350 "Definition of %s has duplicate references of %s\n",
4351 elem
->name
, name
, NULL
);
4353 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_CONTENT_ERROR
,
4354 "Definition of %s has duplicate references of %s:%s\n",
4355 elem
->name
, cur
->c1
->prefix
, name
);
4361 if (next
->c1
== NULL
) break;
4362 if (next
->c1
->type
!= XML_ELEMENT_CONTENT_ELEMENT
) break;
4363 if ((xmlStrEqual(next
->c1
->name
, name
)) &&
4364 (xmlStrEqual(next
->c1
->prefix
, cur
->c1
->prefix
))) {
4365 if (cur
->c1
->prefix
== NULL
) {
4366 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_CONTENT_ERROR
,
4367 "Definition of %s has duplicate references to %s\n",
4368 elem
->name
, name
, NULL
);
4370 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_CONTENT_ERROR
,
4371 "Definition of %s has duplicate references to %s:%s\n",
4372 elem
->name
, cur
->c1
->prefix
, name
);
4383 /* VC: Unique Element Type Declaration */
4384 tst
= xmlGetDtdElementDesc(doc
->intSubset
, elem
->name
);
4385 if ((tst
!= NULL
) && (tst
!= elem
) &&
4386 ((tst
->prefix
== elem
->prefix
) ||
4387 (xmlStrEqual(tst
->prefix
, elem
->prefix
))) &&
4388 (tst
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
)) {
4389 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_ELEM_REDEFINED
,
4390 "Redefinition of element %s\n",
4391 elem
->name
, NULL
, NULL
);
4394 tst
= xmlGetDtdElementDesc(doc
->extSubset
, elem
->name
);
4395 if ((tst
!= NULL
) && (tst
!= elem
) &&
4396 ((tst
->prefix
== elem
->prefix
) ||
4397 (xmlStrEqual(tst
->prefix
, elem
->prefix
))) &&
4398 (tst
->etype
!= XML_ELEMENT_TYPE_UNDEFINED
)) {
4399 xmlErrValidNode(ctxt
, (xmlNodePtr
) elem
, XML_DTD_ELEM_REDEFINED
,
4400 "Redefinition of element %s\n",
4401 elem
->name
, NULL
, NULL
);
4404 /* One ID per Element Type
4405 * already done when registering the attribute
4406 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4413 * xmlValidateOneAttribute:
4414 * @ctxt: the validation context
4415 * @doc: a document instance
4416 * @elem: an element instance
4417 * @attr: an attribute instance
4418 * @value: the attribute value (without entities processing)
4420 * Try to validate a single attribute for an element
4421 * basically it does the following checks as described by the
4422 * XML-1.0 recommendation:
4423 * - [ VC: Attribute Value Type ]
4424 * - [ VC: Fixed Attribute Default ]
4425 * - [ VC: Entity Name ]
4426 * - [ VC: Name Token ]
4429 * - [ VC: Entity Name ]
4430 * - [ VC: Notation Attributes ]
4432 * The ID/IDREF uniqueness and matching are done separately
4434 * returns 1 if valid or 0 otherwise
4438 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4439 xmlNodePtr elem
, xmlAttrPtr attr
, const xmlChar
*value
)
4441 xmlAttributePtr attrDecl
= NULL
;
4446 if ((elem
== NULL
) || (elem
->name
== NULL
)) return(0);
4447 if ((attr
== NULL
) || (attr
->name
== NULL
)) return(0);
4449 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
)) {
4453 fullname
= xmlBuildQName(elem
->name
, elem
->ns
->prefix
, fn
, 50);
4454 if (fullname
== NULL
)
4456 if (attr
->ns
!= NULL
) {
4457 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, fullname
,
4458 attr
->name
, attr
->ns
->prefix
);
4459 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4460 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, fullname
,
4461 attr
->name
, attr
->ns
->prefix
);
4463 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullname
, attr
->name
);
4464 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4465 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
4466 fullname
, attr
->name
);
4468 if ((fullname
!= fn
) && (fullname
!= elem
->name
))
4471 if (attrDecl
== NULL
) {
4472 if (attr
->ns
!= NULL
) {
4473 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, elem
->name
,
4474 attr
->name
, attr
->ns
->prefix
);
4475 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4476 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, elem
->name
,
4477 attr
->name
, attr
->ns
->prefix
);
4479 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
,
4480 elem
->name
, attr
->name
);
4481 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4482 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
4483 elem
->name
, attr
->name
);
4488 /* Validity Constraint: Attribute Value Type */
4489 if (attrDecl
== NULL
) {
4490 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_ATTRIBUTE
,
4491 "No declaration for attribute %s of element %s\n",
4492 attr
->name
, elem
->name
, NULL
);
4495 attr
->atype
= attrDecl
->atype
;
4497 val
= xmlValidateAttributeValueInternal(doc
, attrDecl
->atype
, value
);
4499 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4500 "Syntax of value for attribute %s of %s is not valid\n",
4501 attr
->name
, elem
->name
, NULL
);
4505 /* Validity constraint: Fixed Attribute Default */
4506 if (attrDecl
->def
== XML_ATTRIBUTE_FIXED
) {
4507 if (!xmlStrEqual(value
, attrDecl
->defaultValue
)) {
4508 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_DEFAULT
,
4509 "Value for attribute %s of %s is different from default \"%s\"\n",
4510 attr
->name
, elem
->name
, attrDecl
->defaultValue
);
4515 /* Validity Constraint: ID uniqueness */
4516 if (attrDecl
->atype
== XML_ATTRIBUTE_ID
) {
4517 if (xmlAddID(ctxt
, doc
, value
, attr
) == NULL
)
4521 if ((attrDecl
->atype
== XML_ATTRIBUTE_IDREF
) ||
4522 (attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
)) {
4523 if (xmlAddRef(ctxt
, doc
, value
, attr
) == NULL
)
4527 /* Validity Constraint: Notation Attributes */
4528 if (attrDecl
->atype
== XML_ATTRIBUTE_NOTATION
) {
4529 xmlEnumerationPtr tree
= attrDecl
->tree
;
4530 xmlNotationPtr nota
;
4532 /* First check that the given NOTATION was declared */
4533 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
4535 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
4538 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_NOTATION
,
4539 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4540 value
, attr
->name
, elem
->name
);
4544 /* Second, verify that it's among the list */
4545 while (tree
!= NULL
) {
4546 if (xmlStrEqual(tree
->name
, value
)) break;
4550 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOTATION_VALUE
,
4551 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4552 value
, attr
->name
, elem
->name
);
4557 /* Validity Constraint: Enumeration */
4558 if (attrDecl
->atype
== XML_ATTRIBUTE_ENUMERATION
) {
4559 xmlEnumerationPtr tree
= attrDecl
->tree
;
4560 while (tree
!= NULL
) {
4561 if (xmlStrEqual(tree
->name
, value
)) break;
4565 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4566 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4567 value
, attr
->name
, elem
->name
);
4572 /* Fixed Attribute Default */
4573 if ((attrDecl
->def
== XML_ATTRIBUTE_FIXED
) &&
4574 (!xmlStrEqual(attrDecl
->defaultValue
, value
))) {
4575 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4576 "Value for attribute %s of %s must be \"%s\"\n",
4577 attr
->name
, elem
->name
, attrDecl
->defaultValue
);
4581 /* Extra check for the attribute value */
4582 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, attr
->name
,
4583 attrDecl
->atype
, value
);
4589 * xmlValidateOneNamespace:
4590 * @ctxt: the validation context
4591 * @doc: a document instance
4592 * @elem: an element instance
4593 * @prefix: the namespace prefix
4594 * @ns: an namespace declaration instance
4595 * @value: the attribute value (without entities processing)
4597 * Try to validate a single namespace declaration for an element
4598 * basically it does the following checks as described by the
4599 * XML-1.0 recommendation:
4600 * - [ VC: Attribute Value Type ]
4601 * - [ VC: Fixed Attribute Default ]
4602 * - [ VC: Entity Name ]
4603 * - [ VC: Name Token ]
4606 * - [ VC: Entity Name ]
4607 * - [ VC: Notation Attributes ]
4609 * The ID/IDREF uniqueness and matching are done separately
4611 * returns 1 if valid or 0 otherwise
4615 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
4616 xmlNodePtr elem
, const xmlChar
*prefix
, xmlNsPtr ns
, const xmlChar
*value
) {
4617 /* xmlElementPtr elemDecl; */
4618 xmlAttributePtr attrDecl
= NULL
;
4623 if ((elem
== NULL
) || (elem
->name
== NULL
)) return(0);
4624 if ((ns
== NULL
) || (ns
->href
== NULL
)) return(0);
4626 if (prefix
!= NULL
) {
4630 fullname
= xmlBuildQName(elem
->name
, prefix
, fn
, 50);
4631 if (fullname
== NULL
) {
4632 xmlVErrMemory(ctxt
, "Validating namespace");
4635 if (ns
->prefix
!= NULL
) {
4636 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, fullname
,
4637 ns
->prefix
, BAD_CAST
"xmlns");
4638 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4639 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, fullname
,
4640 ns
->prefix
, BAD_CAST
"xmlns");
4642 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
, fullname
,
4644 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4645 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
, fullname
,
4648 if ((fullname
!= fn
) && (fullname
!= elem
->name
))
4651 if (attrDecl
== NULL
) {
4652 if (ns
->prefix
!= NULL
) {
4653 attrDecl
= xmlGetDtdQAttrDesc(doc
->intSubset
, elem
->name
,
4654 ns
->prefix
, BAD_CAST
"xmlns");
4655 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4656 attrDecl
= xmlGetDtdQAttrDesc(doc
->extSubset
, elem
->name
,
4657 ns
->prefix
, BAD_CAST
"xmlns");
4659 attrDecl
= xmlGetDtdAttrDesc(doc
->intSubset
,
4660 elem
->name
, BAD_CAST
"xmlns");
4661 if ((attrDecl
== NULL
) && (doc
->extSubset
!= NULL
))
4662 attrDecl
= xmlGetDtdAttrDesc(doc
->extSubset
,
4663 elem
->name
, BAD_CAST
"xmlns");
4668 /* Validity Constraint: Attribute Value Type */
4669 if (attrDecl
== NULL
) {
4670 if (ns
->prefix
!= NULL
) {
4671 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_ATTRIBUTE
,
4672 "No declaration for attribute xmlns:%s of element %s\n",
4673 ns
->prefix
, elem
->name
, NULL
);
4675 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_ATTRIBUTE
,
4676 "No declaration for attribute xmlns of element %s\n",
4677 elem
->name
, NULL
, NULL
);
4682 val
= xmlValidateAttributeValueInternal(doc
, attrDecl
->atype
, value
);
4684 if (ns
->prefix
!= NULL
) {
4685 xmlErrValidNode(ctxt
, elem
, XML_DTD_INVALID_DEFAULT
,
4686 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4687 ns
->prefix
, elem
->name
, NULL
);
4689 xmlErrValidNode(ctxt
, elem
, XML_DTD_INVALID_DEFAULT
,
4690 "Syntax of value for attribute xmlns of %s is not valid\n",
4691 elem
->name
, NULL
, NULL
);
4696 /* Validity constraint: Fixed Attribute Default */
4697 if (attrDecl
->def
== XML_ATTRIBUTE_FIXED
) {
4698 if (!xmlStrEqual(value
, attrDecl
->defaultValue
)) {
4699 if (ns
->prefix
!= NULL
) {
4700 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_DEFAULT
,
4701 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4702 ns
->prefix
, elem
->name
, attrDecl
->defaultValue
);
4704 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_DEFAULT
,
4705 "Value for attribute xmlns of %s is different from default \"%s\"\n",
4706 elem
->name
, attrDecl
->defaultValue
, NULL
);
4713 * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4714 * xmlAddID and xmlAddRef for namespace declarations, but it makes
4715 * no practical sense to use ID types anyway.
4718 /* Validity Constraint: ID uniqueness */
4719 if (attrDecl
->atype
== XML_ATTRIBUTE_ID
) {
4720 if (xmlAddID(ctxt
, doc
, value
, (xmlAttrPtr
) ns
) == NULL
)
4724 if ((attrDecl
->atype
== XML_ATTRIBUTE_IDREF
) ||
4725 (attrDecl
->atype
== XML_ATTRIBUTE_IDREFS
)) {
4726 if (xmlAddRef(ctxt
, doc
, value
, (xmlAttrPtr
) ns
) == NULL
)
4731 /* Validity Constraint: Notation Attributes */
4732 if (attrDecl
->atype
== XML_ATTRIBUTE_NOTATION
) {
4733 xmlEnumerationPtr tree
= attrDecl
->tree
;
4734 xmlNotationPtr nota
;
4736 /* First check that the given NOTATION was declared */
4737 nota
= xmlGetDtdNotationDesc(doc
->intSubset
, value
);
4739 nota
= xmlGetDtdNotationDesc(doc
->extSubset
, value
);
4742 if (ns
->prefix
!= NULL
) {
4743 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_NOTATION
,
4744 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4745 value
, ns
->prefix
, elem
->name
);
4747 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_NOTATION
,
4748 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4749 value
, elem
->name
, NULL
);
4754 /* Second, verify that it's among the list */
4755 while (tree
!= NULL
) {
4756 if (xmlStrEqual(tree
->name
, value
)) break;
4760 if (ns
->prefix
!= NULL
) {
4761 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOTATION_VALUE
,
4762 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4763 value
, ns
->prefix
, elem
->name
);
4765 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOTATION_VALUE
,
4766 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4767 value
, elem
->name
, NULL
);
4773 /* Validity Constraint: Enumeration */
4774 if (attrDecl
->atype
== XML_ATTRIBUTE_ENUMERATION
) {
4775 xmlEnumerationPtr tree
= attrDecl
->tree
;
4776 while (tree
!= NULL
) {
4777 if (xmlStrEqual(tree
->name
, value
)) break;
4781 if (ns
->prefix
!= NULL
) {
4782 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4783 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4784 value
, ns
->prefix
, elem
->name
);
4786 xmlErrValidNode(ctxt
, elem
, XML_DTD_ATTRIBUTE_VALUE
,
4787 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4788 value
, elem
->name
, NULL
);
4794 /* Fixed Attribute Default */
4795 if ((attrDecl
->def
== XML_ATTRIBUTE_FIXED
) &&
4796 (!xmlStrEqual(attrDecl
->defaultValue
, value
))) {
4797 if (ns
->prefix
!= NULL
) {
4798 xmlErrValidNode(ctxt
, elem
, XML_DTD_ELEM_NAMESPACE
,
4799 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4800 ns
->prefix
, elem
->name
, attrDecl
->defaultValue
);
4802 xmlErrValidNode(ctxt
, elem
, XML_DTD_ELEM_NAMESPACE
,
4803 "Value for attribute xmlns of %s must be \"%s\"\n",
4804 elem
->name
, attrDecl
->defaultValue
, NULL
);
4809 /* Extra check for the attribute value */
4810 if (ns
->prefix
!= NULL
) {
4811 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, ns
->prefix
,
4812 attrDecl
->atype
, value
);
4814 ret
&= xmlValidateAttributeValue2(ctxt
, doc
, BAD_CAST
"xmlns",
4815 attrDecl
->atype
, value
);
4821 #ifndef LIBXML_REGEXP_ENABLED
4823 * xmlValidateSkipIgnorable:
4824 * @ctxt: the validation context
4825 * @child: the child list
4827 * Skip ignorable elements w.r.t. the validation process
4829 * returns the first element to consider for validation of the content model
4833 xmlValidateSkipIgnorable(xmlNodePtr child
) {
4834 while (child
!= NULL
) {
4835 switch (child
->type
) {
4836 /* These things are ignored (skipped) during validation. */
4838 case XML_COMMENT_NODE
:
4839 case XML_XINCLUDE_START
:
4840 case XML_XINCLUDE_END
:
4841 child
= child
->next
;
4844 if (xmlIsBlankNode(child
))
4845 child
= child
->next
;
4849 /* keep current node */
4858 * xmlValidateElementType:
4859 * @ctxt: the validation context
4861 * Try to validate the content model of an element internal function
4863 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4864 * reference is found and -3 if the validation succeeded but
4865 * the content model is not determinist.
4869 xmlValidateElementType(xmlValidCtxtPtr ctxt
) {
4871 int determinist
= 1;
4873 NODE
= xmlValidateSkipIgnorable(NODE
);
4874 if ((NODE
== NULL
) && (CONT
== NULL
))
4876 if ((NODE
== NULL
) &&
4877 ((CONT
->ocur
== XML_ELEMENT_CONTENT_MULT
) ||
4878 (CONT
->ocur
== XML_ELEMENT_CONTENT_OPT
))) {
4881 if (CONT
== NULL
) return(-1);
4882 if ((NODE
!= NULL
) && (NODE
->type
== XML_ENTITY_REF_NODE
))
4886 * We arrive here when more states need to be examined
4891 * We just recovered from a rollback generated by a possible
4892 * epsilon transition, go directly to the analysis phase
4894 if (STATE
== ROLLBACK_PARENT
) {
4895 DEBUG_VALID_MSG("restored parent branch");
4896 DEBUG_VALID_STATE(NODE
, CONT
)
4901 DEBUG_VALID_STATE(NODE
, CONT
)
4903 * we may have to save a backup state here. This is the equivalent
4904 * of handling epsilon transition in NFAs.
4906 if ((CONT
!= NULL
) &&
4907 ((CONT
->parent
== NULL
) ||
4908 (CONT
->parent
== (xmlElementContentPtr
) 1) ||
4909 (CONT
->parent
->type
!= XML_ELEMENT_CONTENT_OR
)) &&
4910 ((CONT
->ocur
== XML_ELEMENT_CONTENT_MULT
) ||
4911 (CONT
->ocur
== XML_ELEMENT_CONTENT_OPT
) ||
4912 ((CONT
->ocur
== XML_ELEMENT_CONTENT_PLUS
) && (OCCURRENCE
)))) {
4913 DEBUG_VALID_MSG("saving parent branch");
4914 if (vstateVPush(ctxt
, CONT
, NODE
, DEPTH
, OCCURS
, ROLLBACK_PARENT
) < 0)
4920 * Check first if the content matches
4922 switch (CONT
->type
) {
4923 case XML_ELEMENT_CONTENT_PCDATA
:
4925 DEBUG_VALID_MSG("pcdata failed no node");
4929 if (NODE
->type
== XML_TEXT_NODE
) {
4930 DEBUG_VALID_MSG("pcdata found, skip to next");
4932 * go to next element in the content model
4933 * skipping ignorable elems
4937 NODE
= xmlValidateSkipIgnorable(NODE
);
4938 if ((NODE
!= NULL
) &&
4939 (NODE
->type
== XML_ENTITY_REF_NODE
))
4941 } while ((NODE
!= NULL
) &&
4942 ((NODE
->type
!= XML_ELEMENT_NODE
) &&
4943 (NODE
->type
!= XML_TEXT_NODE
) &&
4944 (NODE
->type
!= XML_CDATA_SECTION_NODE
)));
4948 DEBUG_VALID_MSG("pcdata failed");
4953 case XML_ELEMENT_CONTENT_ELEMENT
:
4955 DEBUG_VALID_MSG("element failed no node");
4959 ret
= ((NODE
->type
== XML_ELEMENT_NODE
) &&
4960 (xmlStrEqual(NODE
->name
, CONT
->name
)));
4962 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
4963 ret
= (CONT
->prefix
== NULL
);
4964 } else if (CONT
->prefix
== NULL
) {
4967 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->prefix
);
4971 DEBUG_VALID_MSG("element found, skip to next");
4973 * go to next element in the content model
4974 * skipping ignorable elems
4978 NODE
= xmlValidateSkipIgnorable(NODE
);
4979 if ((NODE
!= NULL
) &&
4980 (NODE
->type
== XML_ENTITY_REF_NODE
))
4982 } while ((NODE
!= NULL
) &&
4983 ((NODE
->type
!= XML_ELEMENT_NODE
) &&
4984 (NODE
->type
!= XML_TEXT_NODE
) &&
4985 (NODE
->type
!= XML_CDATA_SECTION_NODE
)));
4987 DEBUG_VALID_MSG("element failed");
4992 case XML_ELEMENT_CONTENT_OR
:
4994 * Small optimization.
4996 if (CONT
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
4997 if ((NODE
== NULL
) ||
4998 (!xmlStrEqual(NODE
->name
, CONT
->c1
->name
))) {
5003 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
5004 ret
= (CONT
->c1
->prefix
== NULL
);
5005 } else if (CONT
->c1
->prefix
== NULL
) {
5008 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->c1
->prefix
);
5018 * save the second branch 'or' branch
5020 DEBUG_VALID_MSG("saving 'or' branch");
5021 if (vstateVPush(ctxt
, CONT
->c2
, NODE
, DEPTH
+ 1,
5022 OCCURS
, ROLLBACK_OR
) < 0)
5027 case XML_ELEMENT_CONTENT_SEQ
:
5029 * Small optimization.
5031 if ((CONT
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
) &&
5032 ((CONT
->c1
->ocur
== XML_ELEMENT_CONTENT_OPT
) ||
5033 (CONT
->c1
->ocur
== XML_ELEMENT_CONTENT_MULT
))) {
5034 if ((NODE
== NULL
) ||
5035 (!xmlStrEqual(NODE
->name
, CONT
->c1
->name
))) {
5040 if ((NODE
->ns
== NULL
) || (NODE
->ns
->prefix
== NULL
)) {
5041 ret
= (CONT
->c1
->prefix
== NULL
);
5042 } else if (CONT
->c1
->prefix
== NULL
) {
5045 ret
= xmlStrEqual(NODE
->ns
->prefix
, CONT
->c1
->prefix
);
5059 * At this point handle going up in the tree
5062 DEBUG_VALID_MSG("error found returning");
5066 while (CONT
!= NULL
) {
5068 * First do the analysis depending on the occurrence model at
5072 switch (CONT
->ocur
) {
5075 case XML_ELEMENT_CONTENT_ONCE
:
5076 cur
= ctxt
->vstate
->node
;
5077 DEBUG_VALID_MSG("Once branch failed, rollback");
5078 if (vstateVPop(ctxt
) < 0 ) {
5079 DEBUG_VALID_MSG("exhaustion, failed");
5082 if (cur
!= ctxt
->vstate
->node
)
5085 case XML_ELEMENT_CONTENT_PLUS
:
5086 if (OCCURRENCE
== 0) {
5087 cur
= ctxt
->vstate
->node
;
5088 DEBUG_VALID_MSG("Plus branch failed, rollback");
5089 if (vstateVPop(ctxt
) < 0 ) {
5090 DEBUG_VALID_MSG("exhaustion, failed");
5093 if (cur
!= ctxt
->vstate
->node
)
5097 DEBUG_VALID_MSG("Plus branch found");
5100 case XML_ELEMENT_CONTENT_MULT
:
5101 #ifdef DEBUG_VALID_ALGO
5102 if (OCCURRENCE
== 0) {
5103 DEBUG_VALID_MSG("Mult branch failed");
5105 DEBUG_VALID_MSG("Mult branch found");
5110 case XML_ELEMENT_CONTENT_OPT
:
5111 DEBUG_VALID_MSG("Option branch failed");
5116 switch (CONT
->ocur
) {
5117 case XML_ELEMENT_CONTENT_OPT
:
5118 DEBUG_VALID_MSG("Option branch succeeded");
5121 case XML_ELEMENT_CONTENT_ONCE
:
5122 DEBUG_VALID_MSG("Once branch succeeded");
5125 case XML_ELEMENT_CONTENT_PLUS
:
5126 if (STATE
== ROLLBACK_PARENT
) {
5127 DEBUG_VALID_MSG("Plus branch rollback");
5132 DEBUG_VALID_MSG("Plus branch exhausted");
5136 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
5139 case XML_ELEMENT_CONTENT_MULT
:
5140 if (STATE
== ROLLBACK_PARENT
) {
5141 DEBUG_VALID_MSG("Mult branch rollback");
5146 DEBUG_VALID_MSG("Mult branch exhausted");
5150 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
5151 /* SET_OCCURRENCE; */
5158 * Then act accordingly at the parent level
5161 if ((CONT
->parent
== NULL
) ||
5162 (CONT
->parent
== (xmlElementContentPtr
) 1))
5165 switch (CONT
->parent
->type
) {
5166 case XML_ELEMENT_CONTENT_PCDATA
:
5167 DEBUG_VALID_MSG("Error: parent pcdata");
5169 case XML_ELEMENT_CONTENT_ELEMENT
:
5170 DEBUG_VALID_MSG("Error: parent element");
5172 case XML_ELEMENT_CONTENT_OR
:
5174 DEBUG_VALID_MSG("Or succeeded");
5175 CONT
= CONT
->parent
;
5178 DEBUG_VALID_MSG("Or failed");
5179 CONT
= CONT
->parent
;
5183 case XML_ELEMENT_CONTENT_SEQ
:
5185 DEBUG_VALID_MSG("Sequence failed");
5186 CONT
= CONT
->parent
;
5188 } else if (CONT
== CONT
->parent
->c1
) {
5189 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5190 CONT
= CONT
->parent
->c2
;
5193 DEBUG_VALID_MSG("Sequence succeeded");
5194 CONT
= CONT
->parent
;
5202 cur
= ctxt
->vstate
->node
;
5203 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5204 if (vstateVPop(ctxt
) < 0 ) {
5205 DEBUG_VALID_MSG("exhaustion, failed");
5208 if (cur
!= ctxt
->vstate
->node
)
5215 cur
= ctxt
->vstate
->node
;
5216 DEBUG_VALID_MSG("Failure, rollback");
5217 if (vstateVPop(ctxt
) < 0 ) {
5218 DEBUG_VALID_MSG("exhaustion, failed");
5221 if (cur
!= ctxt
->vstate
->node
)
5225 return(determinist
);
5230 * xmlSnprintfElements:
5231 * @buf: an output buffer
5232 * @size: the size of the buffer
5233 * @content: An element
5234 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5236 * This will dump the list of elements to the buffer
5237 * Intended just for the debug routine
5240 xmlSnprintfElements(char *buf
, int size
, xmlNodePtr node
, int glob
) {
5244 if (node
== NULL
) return;
5245 if (glob
) strcat(buf
, "(");
5247 while (cur
!= NULL
) {
5249 if (size
- len
< 50) {
5250 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
5251 strcat(buf
, " ...");
5254 switch (cur
->type
) {
5255 case XML_ELEMENT_NODE
:
5256 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
5257 if (size
- len
< xmlStrlen(cur
->ns
->prefix
) + 10) {
5258 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
5259 strcat(buf
, " ...");
5262 strcat(buf
, (char *) cur
->ns
->prefix
);
5265 if (size
- len
< xmlStrlen(cur
->name
) + 10) {
5266 if ((size
- len
> 4) && (buf
[len
- 1] != '.'))
5267 strcat(buf
, " ...");
5270 strcat(buf
, (char *) cur
->name
);
5271 if (cur
->next
!= NULL
)
5275 if (xmlIsBlankNode(cur
))
5277 /* Falls through. */
5278 case XML_CDATA_SECTION_NODE
:
5279 case XML_ENTITY_REF_NODE
:
5280 strcat(buf
, "CDATA");
5281 if (cur
->next
!= NULL
)
5284 case XML_ATTRIBUTE_NODE
:
5285 case XML_DOCUMENT_NODE
:
5286 case XML_HTML_DOCUMENT_NODE
:
5287 case XML_DOCUMENT_TYPE_NODE
:
5288 case XML_DOCUMENT_FRAG_NODE
:
5289 case XML_NOTATION_NODE
:
5290 case XML_NAMESPACE_DECL
:
5292 if (cur
->next
!= NULL
)
5295 case XML_ENTITY_NODE
:
5298 case XML_COMMENT_NODE
:
5299 case XML_ELEMENT_DECL
:
5300 case XML_ATTRIBUTE_DECL
:
5301 case XML_ENTITY_DECL
:
5302 case XML_XINCLUDE_START
:
5303 case XML_XINCLUDE_END
:
5308 if (glob
) strcat(buf
, ")");
5312 * xmlValidateElementContent:
5313 * @ctxt: the validation context
5314 * @child: the child list
5315 * @elemDecl: pointer to the element declaration
5316 * @warn: emit the error message
5317 * @parent: the parent element (for error reporting)
5319 * Try to validate the content model of an element
5321 * returns 1 if valid or 0 if not and -1 in case of error
5325 xmlValidateElementContent(xmlValidCtxtPtr ctxt
, xmlNodePtr child
,
5326 xmlElementPtr elemDecl
, int warn
, xmlNodePtr parent
) {
5328 #ifndef LIBXML_REGEXP_ENABLED
5329 xmlNodePtr repl
= NULL
, last
= NULL
, tmp
;
5332 xmlElementContentPtr cont
;
5333 const xmlChar
*name
;
5335 if ((elemDecl
== NULL
) || (parent
== NULL
) || (ctxt
== NULL
))
5337 cont
= elemDecl
->content
;
5338 name
= elemDecl
->name
;
5340 #ifdef LIBXML_REGEXP_ENABLED
5341 /* Build the regexp associated to the content model */
5342 if (elemDecl
->contModel
== NULL
)
5343 ret
= xmlValidBuildContentModel(ctxt
, elemDecl
);
5344 if (elemDecl
->contModel
== NULL
) {
5347 xmlRegExecCtxtPtr exec
;
5349 if (!xmlRegexpIsDeterminist(elemDecl
->contModel
)) {
5354 ctxt
->nodeTab
= NULL
;
5355 exec
= xmlRegNewExecCtxt(elemDecl
->contModel
, NULL
, NULL
);
5358 while (cur
!= NULL
) {
5359 switch (cur
->type
) {
5360 case XML_ENTITY_REF_NODE
:
5362 * Push the current node to be able to roll back
5363 * and process within the entity
5365 if ((cur
->children
!= NULL
) &&
5366 (cur
->children
->children
!= NULL
)) {
5367 nodeVPush(ctxt
, cur
);
5368 cur
= cur
->children
->children
;
5373 if (xmlIsBlankNode(cur
))
5377 case XML_CDATA_SECTION_NODE
:
5381 case XML_ELEMENT_NODE
:
5382 if ((cur
->ns
!= NULL
) && (cur
->ns
->prefix
!= NULL
)) {
5386 fullname
= xmlBuildQName(cur
->name
,
5387 cur
->ns
->prefix
, fn
, 50);
5388 if (fullname
== NULL
) {
5392 ret
= xmlRegExecPushString(exec
, fullname
, NULL
);
5393 if ((fullname
!= fn
) && (fullname
!= cur
->name
))
5396 ret
= xmlRegExecPushString(exec
, cur
->name
, NULL
);
5403 * Switch to next element
5406 while (cur
== NULL
) {
5407 cur
= nodeVPop(ctxt
);
5413 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
5415 xmlRegFreeExecCtxt(exec
);
5418 #else /* LIBXML_REGEXP_ENABLED */
5420 * Allocate the stack
5422 ctxt
->vstateMax
= 8;
5423 ctxt
->vstateTab
= (xmlValidState
*) xmlMalloc(
5424 ctxt
->vstateMax
* sizeof(ctxt
->vstateTab
[0]));
5425 if (ctxt
->vstateTab
== NULL
) {
5426 xmlVErrMemory(ctxt
, "malloc failed");
5430 * The first entry in the stack is reserved to the current state
5434 ctxt
->nodeTab
= NULL
;
5435 ctxt
->vstate
= &ctxt
->vstateTab
[0];
5442 ret
= xmlValidateElementType(ctxt
);
5443 if ((ret
== -3) && (warn
)) {
5446 xmlSnprintfElementContent(expr
, 5000, elemDecl
->content
, 1);
5447 xmlErrValidNode(ctxt
, (xmlNodePtr
) elemDecl
,
5448 XML_DTD_CONTENT_NOT_DETERMINIST
,
5449 "Content model of %s is not deterministic: %s\n",
5450 name
, BAD_CAST expr
, NULL
);
5451 } else if (ret
== -2) {
5453 * An entities reference appeared at this level.
5454 * Build a minimal representation of this node content
5455 * sufficient to run the validation process on it
5457 DEBUG_VALID_MSG("Found an entity reference, linearizing");
5459 while (cur
!= NULL
) {
5460 switch (cur
->type
) {
5461 case XML_ENTITY_REF_NODE
:
5463 * Push the current node to be able to roll back
5464 * and process within the entity
5466 if ((cur
->children
!= NULL
) &&
5467 (cur
->children
->children
!= NULL
)) {
5468 nodeVPush(ctxt
, cur
);
5469 cur
= cur
->children
->children
;
5474 if (xmlIsBlankNode(cur
))
5476 /* no break on purpose */
5477 case XML_CDATA_SECTION_NODE
:
5478 /* no break on purpose */
5479 case XML_ELEMENT_NODE
:
5481 * Allocate a new node and minimally fills in
5484 tmp
= (xmlNodePtr
) xmlMalloc(sizeof(xmlNode
));
5486 xmlVErrMemory(ctxt
, "malloc failed");
5487 xmlFreeNodeList(repl
);
5491 tmp
->type
= cur
->type
;
5492 tmp
->name
= cur
->name
;
5495 tmp
->content
= NULL
;
5502 if (cur
->type
== XML_CDATA_SECTION_NODE
) {
5504 * E59 spaces in CDATA does not match the
5507 tmp
->content
= xmlStrdup(BAD_CAST
"CDATA");
5514 * Switch to next element
5517 while (cur
== NULL
) {
5518 cur
= nodeVPop(ctxt
);
5526 * Relaunch the validation
5528 ctxt
->vstate
= &ctxt
->vstateTab
[0];
5535 ret
= xmlValidateElementType(ctxt
);
5537 #endif /* LIBXML_REGEXP_ENABLED */
5538 if ((warn
) && ((ret
!= 1) && (ret
!= -3))) {
5544 xmlSnprintfElementContent(&expr
[0], 5000, cont
, 1);
5546 #ifndef LIBXML_REGEXP_ENABLED
5548 xmlSnprintfElements(&list
[0], 5000, repl
, 1);
5550 #endif /* LIBXML_REGEXP_ENABLED */
5551 xmlSnprintfElements(&list
[0], 5000, child
, 1);
5554 xmlErrValidNode(ctxt
, parent
, XML_DTD_CONTENT_MODEL
,
5555 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5556 name
, BAD_CAST expr
, BAD_CAST list
);
5558 xmlErrValidNode(ctxt
, parent
, XML_DTD_CONTENT_MODEL
,
5559 "Element content does not follow the DTD, expecting %s, got %s\n",
5560 BAD_CAST expr
, BAD_CAST list
, NULL
);
5564 xmlErrValidNode(ctxt
, parent
, XML_DTD_CONTENT_MODEL
,
5565 "Element %s content does not follow the DTD\n",
5568 xmlErrValidNode(ctxt
, parent
, XML_DTD_CONTENT_MODEL
,
5569 "Element content does not follow the DTD\n",
5578 #ifndef LIBXML_REGEXP_ENABLED
5581 * Deallocate the copy if done, and free up the validation stack
5583 while (repl
!= NULL
) {
5588 ctxt
->vstateMax
= 0;
5589 if (ctxt
->vstateTab
!= NULL
) {
5590 xmlFree(ctxt
->vstateTab
);
5591 ctxt
->vstateTab
= NULL
;
5596 if (ctxt
->nodeTab
!= NULL
) {
5597 xmlFree(ctxt
->nodeTab
);
5598 ctxt
->nodeTab
= NULL
;
5605 * xmlValidateCdataElement:
5606 * @ctxt: the validation context
5607 * @doc: a document instance
5608 * @elem: an element instance
5610 * Check that an element follows #CDATA
5612 * returns 1 if valid or 0 otherwise
5615 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
5618 xmlNodePtr cur
, child
;
5620 if ((ctxt
== NULL
) || (doc
== NULL
) || (elem
== NULL
) ||
5621 (elem
->type
!= XML_ELEMENT_NODE
))
5624 child
= elem
->children
;
5627 while (cur
!= NULL
) {
5628 switch (cur
->type
) {
5629 case XML_ENTITY_REF_NODE
:
5631 * Push the current node to be able to roll back
5632 * and process within the entity
5634 if ((cur
->children
!= NULL
) &&
5635 (cur
->children
->children
!= NULL
)) {
5636 nodeVPush(ctxt
, cur
);
5637 cur
= cur
->children
->children
;
5641 case XML_COMMENT_NODE
:
5644 case XML_CDATA_SECTION_NODE
:
5651 * Switch to next element
5654 while (cur
== NULL
) {
5655 cur
= nodeVPop(ctxt
);
5664 if (ctxt
->nodeTab
!= NULL
) {
5665 xmlFree(ctxt
->nodeTab
);
5666 ctxt
->nodeTab
= NULL
;
5671 #ifdef LIBXML_REGEXP_ENABLED
5673 * xmlValidateCheckMixed:
5674 * @ctxt: the validation context
5675 * @cont: the mixed content model
5676 * @qname: the qualified name as appearing in the serialization
5678 * Check if the given node is part of the content model.
5680 * Returns 1 if yes, 0 if no, -1 in case of error
5683 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt
,
5684 xmlElementContentPtr cont
, const xmlChar
*qname
) {
5685 const xmlChar
*name
;
5687 name
= xmlSplitQName3(qname
, &plen
);
5690 while (cont
!= NULL
) {
5691 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
5692 if ((cont
->prefix
== NULL
) && (xmlStrEqual(cont
->name
, qname
)))
5694 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
5695 (cont
->c1
!= NULL
) &&
5696 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)){
5697 if ((cont
->c1
->prefix
== NULL
) &&
5698 (xmlStrEqual(cont
->c1
->name
, qname
)))
5700 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
5701 (cont
->c1
== NULL
) ||
5702 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)){
5703 xmlErrValid(NULL
, XML_DTD_MIXED_CORRUPT
,
5704 "Internal: MIXED struct corrupted\n",
5711 while (cont
!= NULL
) {
5712 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
5713 if ((cont
->prefix
!= NULL
) &&
5714 (xmlStrncmp(cont
->prefix
, qname
, plen
) == 0) &&
5715 (xmlStrEqual(cont
->name
, name
)))
5717 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
5718 (cont
->c1
!= NULL
) &&
5719 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)){
5720 if ((cont
->c1
->prefix
!= NULL
) &&
5721 (xmlStrncmp(cont
->c1
->prefix
, qname
, plen
) == 0) &&
5722 (xmlStrEqual(cont
->c1
->name
, name
)))
5724 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
5725 (cont
->c1
== NULL
) ||
5726 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)){
5727 xmlErrValid(ctxt
, XML_DTD_MIXED_CORRUPT
,
5728 "Internal: MIXED struct corrupted\n",
5737 #endif /* LIBXML_REGEXP_ENABLED */
5740 * xmlValidGetElemDecl:
5741 * @ctxt: the validation context
5742 * @doc: a document instance
5743 * @elem: an element instance
5744 * @extsubset: pointer, (out) indicate if the declaration was found
5745 * in the external subset.
5747 * Finds a declaration associated to an element in the document.
5749 * returns the pointer to the declaration or NULL if not found.
5751 static xmlElementPtr
5752 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
5753 xmlNodePtr elem
, int *extsubset
) {
5754 xmlElementPtr elemDecl
= NULL
;
5755 const xmlChar
*prefix
= NULL
;
5757 if ((ctxt
== NULL
) || (doc
== NULL
) ||
5758 (elem
== NULL
) || (elem
->name
== NULL
))
5760 if (extsubset
!= NULL
)
5764 * Fetch the declaration for the qualified name
5766 if ((elem
->ns
!= NULL
) && (elem
->ns
->prefix
!= NULL
))
5767 prefix
= elem
->ns
->prefix
;
5769 if (prefix
!= NULL
) {
5770 elemDecl
= xmlGetDtdQElementDesc(doc
->intSubset
,
5771 elem
->name
, prefix
);
5772 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
5773 elemDecl
= xmlGetDtdQElementDesc(doc
->extSubset
,
5774 elem
->name
, prefix
);
5775 if ((elemDecl
!= NULL
) && (extsubset
!= NULL
))
5781 * Fetch the declaration for the non qualified name
5782 * This is "non-strict" validation should be done on the
5783 * full QName but in that case being flexible makes sense.
5785 if (elemDecl
== NULL
) {
5786 elemDecl
= xmlGetDtdElementDesc(doc
->intSubset
, elem
->name
);
5787 if ((elemDecl
== NULL
) && (doc
->extSubset
!= NULL
)) {
5788 elemDecl
= xmlGetDtdElementDesc(doc
->extSubset
, elem
->name
);
5789 if ((elemDecl
!= NULL
) && (extsubset
!= NULL
))
5793 if (elemDecl
== NULL
) {
5794 xmlErrValidNode(ctxt
, elem
,
5795 XML_DTD_UNKNOWN_ELEM
,
5796 "No declaration for element %s\n",
5797 elem
->name
, NULL
, NULL
);
5802 #ifdef LIBXML_REGEXP_ENABLED
5804 * xmlValidatePushElement:
5805 * @ctxt: the validation context
5806 * @doc: a document instance
5807 * @elem: an element instance
5808 * @qname: the qualified name as appearing in the serialization
5810 * Push a new element start on the validation stack.
5812 * returns 1 if no validation problem was found or 0 otherwise
5815 xmlValidatePushElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
5816 xmlNodePtr elem
, const xmlChar
*qname
) {
5818 xmlElementPtr eDecl
;
5823 /* printf("PushElem %s\n", qname); */
5824 if ((ctxt
->vstateNr
> 0) && (ctxt
->vstate
!= NULL
)) {
5825 xmlValidStatePtr state
= ctxt
->vstate
;
5826 xmlElementPtr elemDecl
;
5829 * Check the new element against the content model of the new elem.
5831 if (state
->elemDecl
!= NULL
) {
5832 elemDecl
= state
->elemDecl
;
5834 switch(elemDecl
->etype
) {
5835 case XML_ELEMENT_TYPE_UNDEFINED
:
5838 case XML_ELEMENT_TYPE_EMPTY
:
5839 xmlErrValidNode(ctxt
, state
->node
,
5841 "Element %s was declared EMPTY this one has content\n",
5842 state
->node
->name
, NULL
, NULL
);
5845 case XML_ELEMENT_TYPE_ANY
:
5846 /* I don't think anything is required then */
5848 case XML_ELEMENT_TYPE_MIXED
:
5849 /* simple case of declared as #PCDATA */
5850 if ((elemDecl
->content
!= NULL
) &&
5851 (elemDecl
->content
->type
==
5852 XML_ELEMENT_CONTENT_PCDATA
)) {
5853 xmlErrValidNode(ctxt
, state
->node
,
5855 "Element %s was declared #PCDATA but contains non text nodes\n",
5856 state
->node
->name
, NULL
, NULL
);
5859 ret
= xmlValidateCheckMixed(ctxt
, elemDecl
->content
,
5862 xmlErrValidNode(ctxt
, state
->node
,
5863 XML_DTD_INVALID_CHILD
,
5864 "Element %s is not declared in %s list of possible children\n",
5865 qname
, state
->node
->name
, NULL
);
5869 case XML_ELEMENT_TYPE_ELEMENT
:
5872 * VC: Standalone Document Declaration
5873 * - element types with element content, if white space
5874 * occurs directly within any instance of those types.
5876 if (state
->exec
!= NULL
) {
5877 ret
= xmlRegExecPushString(state
->exec
, qname
, NULL
);
5879 xmlErrValidNode(ctxt
, state
->node
,
5880 XML_DTD_CONTENT_MODEL
,
5881 "Element %s content does not follow the DTD, Misplaced %s\n",
5882 state
->node
->name
, qname
, NULL
);
5892 eDecl
= xmlValidGetElemDecl(ctxt
, doc
, elem
, &extsubset
);
5893 vstateVPush(ctxt
, eDecl
, elem
);
5898 * xmlValidatePushCData:
5899 * @ctxt: the validation context
5900 * @data: some character data read
5901 * @len: the length of the data
5903 * check the CData parsed for validation in the current stack
5905 * returns 1 if no validation problem was found or 0 otherwise
5908 xmlValidatePushCData(xmlValidCtxtPtr ctxt
, const xmlChar
*data
, int len
) {
5911 /* printf("CDATA %s %d\n", data, len); */
5916 if ((ctxt
->vstateNr
> 0) && (ctxt
->vstate
!= NULL
)) {
5917 xmlValidStatePtr state
= ctxt
->vstate
;
5918 xmlElementPtr elemDecl
;
5921 * Check the new element against the content model of the new elem.
5923 if (state
->elemDecl
!= NULL
) {
5924 elemDecl
= state
->elemDecl
;
5926 switch(elemDecl
->etype
) {
5927 case XML_ELEMENT_TYPE_UNDEFINED
:
5930 case XML_ELEMENT_TYPE_EMPTY
:
5931 xmlErrValidNode(ctxt
, state
->node
,
5933 "Element %s was declared EMPTY this one has content\n",
5934 state
->node
->name
, NULL
, NULL
);
5937 case XML_ELEMENT_TYPE_ANY
:
5939 case XML_ELEMENT_TYPE_MIXED
:
5941 case XML_ELEMENT_TYPE_ELEMENT
: {
5944 for (i
= 0;i
< len
;i
++) {
5945 if (!IS_BLANK_CH(data
[i
])) {
5946 xmlErrValidNode(ctxt
, state
->node
,
5947 XML_DTD_CONTENT_MODEL
,
5948 "Element %s content does not follow the DTD, Text not allowed\n",
5949 state
->node
->name
, NULL
, NULL
);
5956 * VC: Standalone Document Declaration
5957 * element types with element content, if white space
5958 * occurs directly within any instance of those types.
5970 * xmlValidatePopElement:
5971 * @ctxt: the validation context
5972 * @doc: a document instance
5973 * @elem: an element instance
5974 * @qname: the qualified name as appearing in the serialization
5976 * Pop the element end from the validation stack.
5978 * returns 1 if no validation problem was found or 0 otherwise
5981 xmlValidatePopElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc ATTRIBUTE_UNUSED
,
5982 xmlNodePtr elem ATTRIBUTE_UNUSED
,
5983 const xmlChar
*qname ATTRIBUTE_UNUSED
) {
5988 /* printf("PopElem %s\n", qname); */
5989 if ((ctxt
->vstateNr
> 0) && (ctxt
->vstate
!= NULL
)) {
5990 xmlValidStatePtr state
= ctxt
->vstate
;
5991 xmlElementPtr elemDecl
;
5994 * Check the new element against the content model of the new elem.
5996 if (state
->elemDecl
!= NULL
) {
5997 elemDecl
= state
->elemDecl
;
5999 if (elemDecl
->etype
== XML_ELEMENT_TYPE_ELEMENT
) {
6000 if (state
->exec
!= NULL
) {
6001 ret
= xmlRegExecPushString(state
->exec
, NULL
, NULL
);
6003 xmlErrValidNode(ctxt
, state
->node
,
6004 XML_DTD_CONTENT_MODEL
,
6005 "Element %s content does not follow the DTD, Expecting more children\n",
6006 state
->node
->name
, NULL
,NULL
);
6010 * previous validation errors should not generate
6022 #endif /* LIBXML_REGEXP_ENABLED */
6025 * xmlValidateOneElement:
6026 * @ctxt: the validation context
6027 * @doc: a document instance
6028 * @elem: an element instance
6030 * Try to validate a single element and it's attributes,
6031 * basically it does the following checks as described by the
6032 * XML-1.0 recommendation:
6033 * - [ VC: Element Valid ]
6034 * - [ VC: Required Attribute ]
6035 * Then call xmlValidateOneAttribute() for each attribute present.
6037 * The ID/IDREF checkings are done separately
6039 * returns 1 if valid or 0 otherwise
6043 xmlValidateOneElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
,
6045 xmlElementPtr elemDecl
= NULL
;
6046 xmlElementContentPtr cont
;
6047 xmlAttributePtr attr
;
6050 const xmlChar
*name
;
6055 if (elem
== NULL
) return(0);
6056 switch (elem
->type
) {
6057 case XML_ATTRIBUTE_NODE
:
6058 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6059 "Attribute element not expected\n", NULL
, NULL
,NULL
);
6062 if (elem
->children
!= NULL
) {
6063 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6064 "Text element has children !\n",
6068 if (elem
->ns
!= NULL
) {
6069 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6070 "Text element has namespace !\n",
6074 if (elem
->content
== NULL
) {
6075 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6076 "Text element has no content !\n",
6081 case XML_XINCLUDE_START
:
6082 case XML_XINCLUDE_END
:
6084 case XML_CDATA_SECTION_NODE
:
6085 case XML_ENTITY_REF_NODE
:
6087 case XML_COMMENT_NODE
:
6089 case XML_ENTITY_NODE
:
6090 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6091 "Entity element not expected\n", NULL
, NULL
,NULL
);
6093 case XML_NOTATION_NODE
:
6094 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6095 "Notation element not expected\n", NULL
, NULL
,NULL
);
6097 case XML_DOCUMENT_NODE
:
6098 case XML_DOCUMENT_TYPE_NODE
:
6099 case XML_DOCUMENT_FRAG_NODE
:
6100 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6101 "Document element not expected\n", NULL
, NULL
,NULL
);
6103 case XML_HTML_DOCUMENT_NODE
:
6104 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6105 "HTML Document not expected\n", NULL
, NULL
,NULL
);
6107 case XML_ELEMENT_NODE
:
6110 xmlErrValidNode(ctxt
, elem
, XML_ERR_INTERNAL_ERROR
,
6111 "unknown element type\n", NULL
, NULL
,NULL
);
6116 * Fetch the declaration
6118 elemDecl
= xmlValidGetElemDecl(ctxt
, doc
, elem
, &extsubset
);
6119 if (elemDecl
== NULL
)
6123 * If vstateNr is not zero that means continuous validation is
6124 * activated, do not try to check the content model at that level.
6126 if (ctxt
->vstateNr
== 0) {
6127 /* Check that the element content matches the definition */
6128 switch (elemDecl
->etype
) {
6129 case XML_ELEMENT_TYPE_UNDEFINED
:
6130 xmlErrValidNode(ctxt
, elem
, XML_DTD_UNKNOWN_ELEM
,
6131 "No declaration for element %s\n",
6132 elem
->name
, NULL
, NULL
);
6134 case XML_ELEMENT_TYPE_EMPTY
:
6135 if (elem
->children
!= NULL
) {
6136 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOT_EMPTY
,
6137 "Element %s was declared EMPTY this one has content\n",
6138 elem
->name
, NULL
, NULL
);
6142 case XML_ELEMENT_TYPE_ANY
:
6143 /* I don't think anything is required then */
6145 case XML_ELEMENT_TYPE_MIXED
:
6147 /* simple case of declared as #PCDATA */
6148 if ((elemDecl
->content
!= NULL
) &&
6149 (elemDecl
->content
->type
== XML_ELEMENT_CONTENT_PCDATA
)) {
6150 ret
= xmlValidateOneCdataElement(ctxt
, doc
, elem
);
6152 xmlErrValidNode(ctxt
, elem
, XML_DTD_NOT_PCDATA
,
6153 "Element %s was declared #PCDATA but contains non text nodes\n",
6154 elem
->name
, NULL
, NULL
);
6158 child
= elem
->children
;
6159 /* Hum, this start to get messy */
6160 while (child
!= NULL
) {
6161 if (child
->type
== XML_ELEMENT_NODE
) {
6163 if ((child
->ns
!= NULL
) && (child
->ns
->prefix
!= NULL
)) {
6167 fullname
= xmlBuildQName(child
->name
, child
->ns
->prefix
,
6169 if (fullname
== NULL
)
6171 cont
= elemDecl
->content
;
6172 while (cont
!= NULL
) {
6173 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
6174 if (xmlStrEqual(cont
->name
, fullname
))
6176 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
6177 (cont
->c1
!= NULL
) &&
6178 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)){
6179 if (xmlStrEqual(cont
->c1
->name
, fullname
))
6181 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
6182 (cont
->c1
== NULL
) ||
6183 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)){
6184 xmlErrValid(NULL
, XML_DTD_MIXED_CORRUPT
,
6185 "Internal: MIXED struct corrupted\n",
6191 if ((fullname
!= fn
) && (fullname
!= child
->name
))
6196 cont
= elemDecl
->content
;
6197 while (cont
!= NULL
) {
6198 if (cont
->type
== XML_ELEMENT_CONTENT_ELEMENT
) {
6199 if (xmlStrEqual(cont
->name
, name
)) break;
6200 } else if ((cont
->type
== XML_ELEMENT_CONTENT_OR
) &&
6201 (cont
->c1
!= NULL
) &&
6202 (cont
->c1
->type
== XML_ELEMENT_CONTENT_ELEMENT
)) {
6203 if (xmlStrEqual(cont
->c1
->name
, name
)) break;
6204 } else if ((cont
->type
!= XML_ELEMENT_CONTENT_OR
) ||
6205 (cont
->c1
== NULL
) ||
6206 (cont
->c1
->type
!= XML_ELEMENT_CONTENT_PCDATA
)) {
6207 xmlErrValid(ctxt
, XML_DTD_MIXED_CORRUPT
,
6208 "Internal: MIXED struct corrupted\n",
6215 xmlErrValidNode(ctxt
, elem
, XML_DTD_INVALID_CHILD
,
6216 "Element %s is not declared in %s list of possible children\n",
6217 name
, elem
->name
, NULL
);
6222 child
= child
->next
;
6225 case XML_ELEMENT_TYPE_ELEMENT
:
6226 if ((doc
->standalone
== 1) && (extsubset
== 1)) {
6228 * VC: Standalone Document Declaration
6229 * - element types with element content, if white space
6230 * occurs directly within any instance of those types.
6232 child
= elem
->children
;
6233 while (child
!= NULL
) {
6234 if (child
->type
== XML_TEXT_NODE
) {
6235 const xmlChar
*content
= child
->content
;
6237 while (IS_BLANK_CH(*content
))
6239 if (*content
== 0) {
6240 xmlErrValidNode(ctxt
, elem
,
6241 XML_DTD_STANDALONE_WHITE_SPACE
,
6242 "standalone: %s declared in the external subset contains white spaces nodes\n",
6243 elem
->name
, NULL
, NULL
);
6251 child
= elem
->children
;
6252 cont
= elemDecl
->content
;
6253 tmp
= xmlValidateElementContent(ctxt
, child
, elemDecl
, 1, elem
);
6258 } /* not continuous */
6260 /* [ VC: Required Attribute ] */
6261 attr
= elemDecl
->attributes
;
6262 while (attr
!= NULL
) {
6263 if (attr
->def
== XML_ATTRIBUTE_REQUIRED
) {
6266 if ((attr
->prefix
== NULL
) &&
6267 (xmlStrEqual(attr
->name
, BAD_CAST
"xmlns"))) {
6271 while (ns
!= NULL
) {
6272 if (ns
->prefix
== NULL
)
6276 } else if (xmlStrEqual(attr
->prefix
, BAD_CAST
"xmlns")) {
6280 while (ns
!= NULL
) {
6281 if (xmlStrEqual(attr
->name
, ns
->prefix
))
6288 attrib
= elem
->properties
;
6289 while (attrib
!= NULL
) {
6290 if (xmlStrEqual(attrib
->name
, attr
->name
)) {
6291 if (attr
->prefix
!= NULL
) {
6292 xmlNsPtr nameSpace
= attrib
->ns
;
6294 if (nameSpace
== NULL
)
6295 nameSpace
= elem
->ns
;
6297 * qualified names handling is problematic, having a
6298 * different prefix should be possible but DTDs don't
6299 * allow to define the URI instead of the prefix :-(
6301 if (nameSpace
== NULL
) {
6304 } else if (!xmlStrEqual(nameSpace
->prefix
,
6312 * We should allow applications to define namespaces
6313 * for their application even if the DTD doesn't
6314 * carry one, otherwise, basically we would always
6320 attrib
= attrib
->next
;
6323 if (qualified
== -1) {
6324 if (attr
->prefix
== NULL
) {
6325 xmlErrValidNode(ctxt
, elem
, XML_DTD_MISSING_ATTRIBUTE
,
6326 "Element %s does not carry attribute %s\n",
6327 elem
->name
, attr
->name
, NULL
);
6330 xmlErrValidNode(ctxt
, elem
, XML_DTD_MISSING_ATTRIBUTE
,
6331 "Element %s does not carry attribute %s:%s\n",
6332 elem
->name
, attr
->prefix
,attr
->name
);
6335 } else if (qualified
== 0) {
6336 xmlErrValidWarning(ctxt
, elem
, XML_DTD_NO_PREFIX
,
6337 "Element %s required attribute %s:%s has no prefix\n",
6338 elem
->name
, attr
->prefix
, attr
->name
);
6339 } else if (qualified
== 1) {
6340 xmlErrValidWarning(ctxt
, elem
, XML_DTD_DIFFERENT_PREFIX
,
6341 "Element %s required attribute %s:%s has different prefix\n",
6342 elem
->name
, attr
->prefix
, attr
->name
);
6344 } else if (attr
->def
== XML_ATTRIBUTE_FIXED
) {
6346 * Special tests checking #FIXED namespace declarations
6347 * have the right value since this is not done as an
6348 * attribute checking
6350 if ((attr
->prefix
== NULL
) &&
6351 (xmlStrEqual(attr
->name
, BAD_CAST
"xmlns"))) {
6355 while (ns
!= NULL
) {
6356 if (ns
->prefix
== NULL
) {
6357 if (!xmlStrEqual(attr
->defaultValue
, ns
->href
)) {
6358 xmlErrValidNode(ctxt
, elem
,
6359 XML_DTD_ELEM_DEFAULT_NAMESPACE
,
6360 "Element %s namespace name for default namespace does not match the DTD\n",
6361 elem
->name
, NULL
, NULL
);
6368 } else if (xmlStrEqual(attr
->prefix
, BAD_CAST
"xmlns")) {
6372 while (ns
!= NULL
) {
6373 if (xmlStrEqual(attr
->name
, ns
->prefix
)) {
6374 if (!xmlStrEqual(attr
->defaultValue
, ns
->href
)) {
6375 xmlErrValidNode(ctxt
, elem
, XML_DTD_ELEM_NAMESPACE
,
6376 "Element %s namespace name for %s does not match the DTD\n",
6377 elem
->name
, ns
->prefix
, NULL
);
6394 * @ctxt: the validation context
6395 * @doc: a document instance
6397 * Try to validate a the root element
6398 * basically it does the following check as described by the
6399 * XML-1.0 recommendation:
6400 * - [ VC: Root Element Type ]
6401 * it doesn't try to recurse or apply other check to the element
6403 * returns 1 if valid or 0 otherwise
6407 xmlValidateRoot(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
6411 if (doc
== NULL
) return(0);
6413 root
= xmlDocGetRootElement(doc
);
6414 if ((root
== NULL
) || (root
->name
== NULL
)) {
6415 xmlErrValid(ctxt
, XML_DTD_NO_ROOT
,
6416 "no root element\n", NULL
);
6421 * When doing post validation against a separate DTD, those may
6422 * no internal subset has been generated
6424 if ((doc
->intSubset
!= NULL
) &&
6425 (doc
->intSubset
->name
!= NULL
)) {
6427 * Check first the document root against the NQName
6429 if (!xmlStrEqual(doc
->intSubset
->name
, root
->name
)) {
6430 if ((root
->ns
!= NULL
) && (root
->ns
->prefix
!= NULL
)) {
6434 fullname
= xmlBuildQName(root
->name
, root
->ns
->prefix
, fn
, 50);
6435 if (fullname
== NULL
) {
6436 xmlVErrMemory(ctxt
, NULL
);
6439 ret
= xmlStrEqual(doc
->intSubset
->name
, fullname
);
6440 if ((fullname
!= fn
) && (fullname
!= root
->name
))
6445 if ((xmlStrEqual(doc
->intSubset
->name
, BAD_CAST
"HTML")) &&
6446 (xmlStrEqual(root
->name
, BAD_CAST
"html")))
6448 xmlErrValidNode(ctxt
, root
, XML_DTD_ROOT_NAME
,
6449 "root and DTD name do not match '%s' and '%s'\n",
6450 root
->name
, doc
->intSubset
->name
, NULL
);
6460 * xmlValidateElement:
6461 * @ctxt: the validation context
6462 * @doc: a document instance
6463 * @elem: an element instance
6465 * Try to validate the subtree under an element
6467 * returns 1 if valid or 0 otherwise
6471 xmlValidateElement(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, xmlNodePtr root
) {
6475 const xmlChar
*value
;
6478 if (root
== NULL
) return(0);
6484 ret
&= xmlValidateOneElement(ctxt
, doc
, elem
);
6486 if (elem
->type
== XML_ELEMENT_NODE
) {
6487 attr
= elem
->properties
;
6488 while (attr
!= NULL
) {
6489 value
= xmlNodeListGetString(doc
, attr
->children
, 0);
6490 ret
&= xmlValidateOneAttribute(ctxt
, doc
, elem
, attr
, value
);
6492 xmlFree((char *)value
);
6497 while (ns
!= NULL
) {
6498 if (elem
->ns
== NULL
)
6499 ret
&= xmlValidateOneNamespace(ctxt
, doc
, elem
, NULL
,
6502 ret
&= xmlValidateOneNamespace(ctxt
, doc
, elem
,
6503 elem
->ns
->prefix
, ns
,
6508 if (elem
->children
!= NULL
) {
6509 elem
= elem
->children
;
6517 if (elem
->next
!= NULL
)
6519 elem
= elem
->parent
;
6530 * @ref: A reference to be validated
6531 * @ctxt: Validation context
6532 * @name: Name of ID we are searching for
6536 xmlValidateRef(xmlRefPtr ref
, xmlValidCtxtPtr ctxt
,
6537 const xmlChar
*name
) {
6543 if ((ref
->attr
== NULL
) && (ref
->name
== NULL
))
6547 xmlChar
*dup
, *str
= NULL
, *cur
, save
;
6549 dup
= xmlStrdup(name
);
6557 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
))) cur
++;
6560 id
= xmlGetID(ctxt
->doc
, str
);
6562 xmlErrValidNodeNr(ctxt
, NULL
, XML_DTD_UNKNOWN_ID
,
6563 "attribute %s line %d references an unknown ID \"%s\"\n",
6564 ref
->name
, ref
->lineno
, str
);
6570 while (IS_BLANK_CH(*cur
)) cur
++;
6573 } else if (attr
->atype
== XML_ATTRIBUTE_IDREF
) {
6574 id
= xmlGetID(ctxt
->doc
, name
);
6576 xmlErrValidNode(ctxt
, attr
->parent
, XML_DTD_UNKNOWN_ID
,
6577 "IDREF attribute %s references an unknown ID \"%s\"\n",
6578 attr
->name
, name
, NULL
);
6581 } else if (attr
->atype
== XML_ATTRIBUTE_IDREFS
) {
6582 xmlChar
*dup
, *str
= NULL
, *cur
, save
;
6584 dup
= xmlStrdup(name
);
6586 xmlVErrMemory(ctxt
, "IDREFS split");
6593 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
))) cur
++;
6596 id
= xmlGetID(ctxt
->doc
, str
);
6598 xmlErrValidNode(ctxt
, attr
->parent
, XML_DTD_UNKNOWN_ID
,
6599 "IDREFS attribute %s references an unknown ID \"%s\"\n",
6600 attr
->name
, str
, NULL
);
6606 while (IS_BLANK_CH(*cur
)) cur
++;
6613 * xmlWalkValidateList:
6614 * @data: Contents of current link
6615 * @user: Value supplied by the user
6617 * Returns 0 to abort the walk or 1 to continue
6620 xmlWalkValidateList(const void *data
, void *user
)
6622 xmlValidateMemoPtr memo
= (xmlValidateMemoPtr
)user
;
6623 xmlValidateRef((xmlRefPtr
)data
, memo
->ctxt
, memo
->name
);
6628 * xmlValidateCheckRefCallback:
6629 * @ref_list: List of references
6630 * @ctxt: Validation context
6631 * @name: Name of ID we are searching for
6635 xmlValidateCheckRefCallback(void *payload
, void *data
, const xmlChar
*name
) {
6636 xmlListPtr ref_list
= (xmlListPtr
) payload
;
6637 xmlValidCtxtPtr ctxt
= (xmlValidCtxtPtr
) data
;
6638 xmlValidateMemo memo
;
6640 if (ref_list
== NULL
)
6645 xmlListWalk(ref_list
, xmlWalkValidateList
, &memo
);
6650 * xmlValidateDocumentFinal:
6651 * @ctxt: the validation context
6652 * @doc: a document instance
6654 * Does the final step for the document validation once all the
6655 * incremental validation steps have been completed
6657 * basically it does the following checks described by the XML Rec
6659 * Check all the IDREF/IDREFS attributes definition for validity
6661 * returns 1 if valid or 0 otherwise
6665 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
6666 xmlRefTablePtr table
;
6672 xmlErrValid(ctxt
, XML_DTD_NO_DOC
,
6673 "xmlValidateDocumentFinal: doc == NULL\n", NULL
);
6677 /* trick to get correct line id report */
6679 ctxt
->flags
&= ~XML_VCTXT_USE_PCTXT
;
6682 * Check all the NOTATION/NOTATIONS attributes
6685 * Check all the ENTITY/ENTITIES attributes definition for validity
6688 * Check all the IDREF/IDREFS attributes definition for validity
6690 table
= (xmlRefTablePtr
) doc
->refs
;
6693 xmlHashScan(table
, xmlValidateCheckRefCallback
, ctxt
);
6696 return(ctxt
->valid
);
6701 * @ctxt: the validation context
6702 * @doc: a document instance
6703 * @dtd: a dtd instance
6705 * Try to validate the document against the dtd instance
6707 * Basically it does check all the definitions in the DtD.
6708 * Note the the internal subset (if present) is de-coupled
6709 * (i.e. not used), which could give problems if ID or IDREF
6712 * returns 1 if valid or 0 otherwise
6716 xmlValidateDtd(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
, xmlDtdPtr dtd
) {
6718 xmlDtdPtr oldExt
, oldInt
;
6721 if (dtd
== NULL
) return(0);
6722 if (doc
== NULL
) return(0);
6723 oldExt
= doc
->extSubset
;
6724 oldInt
= doc
->intSubset
;
6725 doc
->extSubset
= dtd
;
6726 doc
->intSubset
= NULL
;
6727 ret
= xmlValidateRoot(ctxt
, doc
);
6729 doc
->extSubset
= oldExt
;
6730 doc
->intSubset
= oldInt
;
6733 if (doc
->ids
!= NULL
) {
6734 xmlFreeIDTable(doc
->ids
);
6737 if (doc
->refs
!= NULL
) {
6738 xmlFreeRefTable(doc
->refs
);
6741 root
= xmlDocGetRootElement(doc
);
6742 ret
= xmlValidateElement(ctxt
, doc
, root
);
6743 ret
&= xmlValidateDocumentFinal(ctxt
, doc
);
6744 doc
->extSubset
= oldExt
;
6745 doc
->intSubset
= oldInt
;
6750 xmlValidateNotationCallback(void *payload
, void *data
,
6751 const xmlChar
*name ATTRIBUTE_UNUSED
) {
6752 xmlEntityPtr cur
= (xmlEntityPtr
) payload
;
6753 xmlValidCtxtPtr ctxt
= (xmlValidCtxtPtr
) data
;
6756 if (cur
->etype
== XML_EXTERNAL_GENERAL_UNPARSED_ENTITY
) {
6757 xmlChar
*notation
= cur
->content
;
6759 if (notation
!= NULL
) {
6762 ret
= xmlValidateNotationUse(ctxt
, cur
->doc
, notation
);
6771 xmlValidateAttributeCallback(void *payload
, void *data
,
6772 const xmlChar
*name ATTRIBUTE_UNUSED
) {
6773 xmlAttributePtr cur
= (xmlAttributePtr
) payload
;
6774 xmlValidCtxtPtr ctxt
= (xmlValidCtxtPtr
) data
;
6777 xmlElementPtr elem
= NULL
;
6781 switch (cur
->atype
) {
6782 case XML_ATTRIBUTE_CDATA
:
6783 case XML_ATTRIBUTE_ID
:
6784 case XML_ATTRIBUTE_IDREF
:
6785 case XML_ATTRIBUTE_IDREFS
:
6786 case XML_ATTRIBUTE_NMTOKEN
:
6787 case XML_ATTRIBUTE_NMTOKENS
:
6788 case XML_ATTRIBUTE_ENUMERATION
:
6790 case XML_ATTRIBUTE_ENTITY
:
6791 case XML_ATTRIBUTE_ENTITIES
:
6792 case XML_ATTRIBUTE_NOTATION
:
6793 if (cur
->defaultValue
!= NULL
) {
6795 ret
= xmlValidateAttributeValue2(ctxt
, ctxt
->doc
, cur
->name
,
6796 cur
->atype
, cur
->defaultValue
);
6797 if ((ret
== 0) && (ctxt
->valid
== 1))
6800 if (cur
->tree
!= NULL
) {
6801 xmlEnumerationPtr tree
= cur
->tree
;
6802 while (tree
!= NULL
) {
6803 ret
= xmlValidateAttributeValue2(ctxt
, ctxt
->doc
,
6804 cur
->name
, cur
->atype
, tree
->name
);
6805 if ((ret
== 0) && (ctxt
->valid
== 1))
6811 if (cur
->atype
== XML_ATTRIBUTE_NOTATION
) {
6813 if (cur
->elem
== NULL
) {
6814 xmlErrValid(ctxt
, XML_ERR_INTERNAL_ERROR
,
6815 "xmlValidateAttributeCallback(%s): internal error\n",
6816 (const char *) cur
->name
);
6821 elem
= xmlGetDtdElementDesc(doc
->intSubset
, cur
->elem
);
6822 if ((elem
== NULL
) && (doc
!= NULL
))
6823 elem
= xmlGetDtdElementDesc(doc
->extSubset
, cur
->elem
);
6824 if ((elem
== NULL
) && (cur
->parent
!= NULL
) &&
6825 (cur
->parent
->type
== XML_DTD_NODE
))
6826 elem
= xmlGetDtdElementDesc((xmlDtdPtr
) cur
->parent
, cur
->elem
);
6828 xmlErrValidNode(ctxt
, NULL
, XML_DTD_UNKNOWN_ELEM
,
6829 "attribute %s: could not find decl for element %s\n",
6830 cur
->name
, cur
->elem
, NULL
);
6833 if (elem
->etype
== XML_ELEMENT_TYPE_EMPTY
) {
6834 xmlErrValidNode(ctxt
, NULL
, XML_DTD_EMPTY_NOTATION
,
6835 "NOTATION attribute %s declared for EMPTY element %s\n",
6836 cur
->name
, cur
->elem
, NULL
);
6843 * xmlValidateDtdFinal:
6844 * @ctxt: the validation context
6845 * @doc: a document instance
6847 * Does the final step for the dtds validation once all the
6848 * subsets have been parsed
6850 * basically it does the following checks described by the XML Rec
6851 * - check that ENTITY and ENTITIES type attributes default or
6852 * possible values matches one of the defined entities.
6853 * - check that NOTATION type attributes default or
6854 * possible values matches one of the defined notations.
6856 * returns 1 if valid or 0 if invalid and -1 if not well-formed
6860 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
6862 xmlAttributeTablePtr table
;
6863 xmlEntitiesTablePtr entities
;
6865 if ((doc
== NULL
) || (ctxt
== NULL
)) return(0);
6866 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
))
6870 dtd
= doc
->intSubset
;
6871 if ((dtd
!= NULL
) && (dtd
->attributes
!= NULL
)) {
6872 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
6873 xmlHashScan(table
, xmlValidateAttributeCallback
, ctxt
);
6875 if ((dtd
!= NULL
) && (dtd
->entities
!= NULL
)) {
6876 entities
= (xmlEntitiesTablePtr
) dtd
->entities
;
6877 xmlHashScan(entities
, xmlValidateNotationCallback
, ctxt
);
6879 dtd
= doc
->extSubset
;
6880 if ((dtd
!= NULL
) && (dtd
->attributes
!= NULL
)) {
6881 table
= (xmlAttributeTablePtr
) dtd
->attributes
;
6882 xmlHashScan(table
, xmlValidateAttributeCallback
, ctxt
);
6884 if ((dtd
!= NULL
) && (dtd
->entities
!= NULL
)) {
6885 entities
= (xmlEntitiesTablePtr
) dtd
->entities
;
6886 xmlHashScan(entities
, xmlValidateNotationCallback
, ctxt
);
6888 return(ctxt
->valid
);
6892 * xmlValidateDocument:
6893 * @ctxt: the validation context
6894 * @doc: a document instance
6896 * Try to validate the document instance
6898 * basically it does the all the checks described by the XML Rec
6899 * i.e. validates the internal and external subset (if present)
6900 * and validate the document tree.
6902 * returns 1 if valid or 0 otherwise
6906 xmlValidateDocument(xmlValidCtxtPtr ctxt
, xmlDocPtr doc
) {
6912 if ((doc
->intSubset
== NULL
) && (doc
->extSubset
== NULL
)) {
6913 xmlErrValid(ctxt
, XML_DTD_NO_DTD
,
6914 "no DTD found!\n", NULL
);
6917 if ((doc
->intSubset
!= NULL
) && ((doc
->intSubset
->SystemID
!= NULL
) ||
6918 (doc
->intSubset
->ExternalID
!= NULL
)) && (doc
->extSubset
== NULL
)) {
6920 if (doc
->intSubset
->SystemID
!= NULL
) {
6921 sysID
= xmlBuildURI(doc
->intSubset
->SystemID
,
6923 if (sysID
== NULL
) {
6924 xmlErrValid(ctxt
, XML_DTD_LOAD_ERROR
,
6925 "Could not build URI for external subset \"%s\"\n",
6926 (const char *) doc
->intSubset
->SystemID
);
6931 doc
->extSubset
= xmlParseDTD(doc
->intSubset
->ExternalID
,
6932 (const xmlChar
*)sysID
);
6935 if (doc
->extSubset
== NULL
) {
6936 if (doc
->intSubset
->SystemID
!= NULL
) {
6937 xmlErrValid(ctxt
, XML_DTD_LOAD_ERROR
,
6938 "Could not load the external subset \"%s\"\n",
6939 (const char *) doc
->intSubset
->SystemID
);
6941 xmlErrValid(ctxt
, XML_DTD_LOAD_ERROR
,
6942 "Could not load the external subset \"%s\"\n",
6943 (const char *) doc
->intSubset
->ExternalID
);
6949 if (doc
->ids
!= NULL
) {
6950 xmlFreeIDTable(doc
->ids
);
6953 if (doc
->refs
!= NULL
) {
6954 xmlFreeRefTable(doc
->refs
);
6957 ret
= xmlValidateDtdFinal(ctxt
, doc
);
6958 if (!xmlValidateRoot(ctxt
, doc
)) return(0);
6960 root
= xmlDocGetRootElement(doc
);
6961 ret
&= xmlValidateElement(ctxt
, doc
, root
);
6962 ret
&= xmlValidateDocumentFinal(ctxt
, doc
);
6966 /************************************************************************
6968 * Routines for dynamic validation editing *
6970 ************************************************************************/
6973 * xmlValidGetPotentialChildren:
6974 * @ctree: an element content tree
6975 * @names: an array to store the list of child names
6976 * @len: a pointer to the number of element in the list
6977 * @max: the size of the array
6979 * Build/extend a list of potential children allowed by the content tree
6981 * returns the number of element in the list, or -1 in case of error.
6985 xmlValidGetPotentialChildren(xmlElementContent
*ctree
,
6986 const xmlChar
**names
,
6987 int *len
, int max
) {
6990 if ((ctree
== NULL
) || (names
== NULL
) || (len
== NULL
))
6992 if (*len
>= max
) return(*len
);
6994 switch (ctree
->type
) {
6995 case XML_ELEMENT_CONTENT_PCDATA
:
6996 for (i
= 0; i
< *len
;i
++)
6997 if (xmlStrEqual(BAD_CAST
"#PCDATA", names
[i
])) return(*len
);
6998 names
[(*len
)++] = BAD_CAST
"#PCDATA";
7000 case XML_ELEMENT_CONTENT_ELEMENT
:
7001 for (i
= 0; i
< *len
;i
++)
7002 if (xmlStrEqual(ctree
->name
, names
[i
])) return(*len
);
7003 names
[(*len
)++] = ctree
->name
;
7005 case XML_ELEMENT_CONTENT_SEQ
:
7006 xmlValidGetPotentialChildren(ctree
->c1
, names
, len
, max
);
7007 xmlValidGetPotentialChildren(ctree
->c2
, names
, len
, max
);
7009 case XML_ELEMENT_CONTENT_OR
:
7010 xmlValidGetPotentialChildren(ctree
->c1
, names
, len
, max
);
7011 xmlValidGetPotentialChildren(ctree
->c2
, names
, len
, max
);
7019 * Dummy function to suppress messages while we try out valid elements
7021 static void XMLCDECL
xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED
,
7022 const char *msg ATTRIBUTE_UNUSED
, ...) {
7027 * xmlValidGetValidElements:
7028 * @prev: an element to insert after
7029 * @next: an element to insert next
7030 * @names: an array to store the list of child names
7031 * @max: the size of the array
7033 * This function returns the list of authorized children to insert
7034 * within an existing tree while respecting the validity constraints
7035 * forced by the Dtd. The insertion point is defined using @prev and
7036 * @next in the following ways:
7037 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
7038 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
7039 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
7040 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
7041 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
7043 * pointers to the element names are inserted at the beginning of the array
7044 * and do not need to be freed.
7046 * returns the number of element in the list, or -1 in case of error. If
7047 * the function returns the value @max the caller is invited to grow the
7048 * receiving array and retry.
7052 xmlValidGetValidElements(xmlNode
*prev
, xmlNode
*next
, const xmlChar
**names
,
7055 int nb_valid_elements
= 0;
7056 const xmlChar
*elements
[256]={0};
7057 int nb_elements
= 0, i
;
7058 const xmlChar
*name
;
7066 xmlNode
*parent_childs
;
7067 xmlNode
*parent_last
;
7069 xmlElement
*element_desc
;
7071 if (prev
== NULL
&& next
== NULL
)
7074 if (names
== NULL
) return(-1);
7075 if (max
<= 0) return(-1);
7077 memset(&vctxt
, 0, sizeof (xmlValidCtxt
));
7078 vctxt
.error
= xmlNoValidityErr
; /* this suppresses err/warn output */
7080 nb_valid_elements
= 0;
7081 ref_node
= prev
? prev
: next
;
7082 parent
= ref_node
->parent
;
7085 * Retrieves the parent element declaration
7087 element_desc
= xmlGetDtdElementDesc(parent
->doc
->intSubset
,
7089 if ((element_desc
== NULL
) && (parent
->doc
->extSubset
!= NULL
))
7090 element_desc
= xmlGetDtdElementDesc(parent
->doc
->extSubset
,
7092 if (element_desc
== NULL
) return(-1);
7095 * Do a backup of the current tree structure
7097 prev_next
= prev
? prev
->next
: NULL
;
7098 next_prev
= next
? next
->prev
: NULL
;
7099 parent_childs
= parent
->children
;
7100 parent_last
= parent
->last
;
7103 * Creates a dummy node and insert it into the tree
7105 test_node
= xmlNewDocNode (ref_node
->doc
, NULL
, BAD_CAST
"<!dummy?>", NULL
);
7106 if (test_node
== NULL
)
7109 test_node
->parent
= parent
;
7110 test_node
->prev
= prev
;
7111 test_node
->next
= next
;
7112 name
= test_node
->name
;
7114 if (prev
) prev
->next
= test_node
;
7115 else parent
->children
= test_node
;
7117 if (next
) next
->prev
= test_node
;
7118 else parent
->last
= test_node
;
7121 * Insert each potential child node and check if the parent is
7124 nb_elements
= xmlValidGetPotentialChildren(element_desc
->content
,
7125 elements
, &nb_elements
, 256);
7127 for (i
= 0;i
< nb_elements
;i
++) {
7128 test_node
->name
= elements
[i
];
7129 if (xmlValidateOneElement(&vctxt
, parent
->doc
, parent
)) {
7132 for (j
= 0; j
< nb_valid_elements
;j
++)
7133 if (xmlStrEqual(elements
[i
], names
[j
])) break;
7134 names
[nb_valid_elements
++] = elements
[i
];
7135 if (nb_valid_elements
>= max
) break;
7140 * Restore the tree structure
7142 if (prev
) prev
->next
= prev_next
;
7143 if (next
) next
->prev
= next_prev
;
7144 parent
->children
= parent_childs
;
7145 parent
->last
= parent_last
;
7148 * Free up the dummy node
7150 test_node
->name
= name
;
7151 xmlFreeNode(test_node
);
7153 return(nb_valid_elements
);
7155 #endif /* LIBXML_VALID_ENABLED */