2
* valid.c : part of the code use to do the DTD handling and the validity
5
* See Copyright for the status of this software.
19
#include <libxml/xmlmemory.h>
20
#include <libxml/hash.h>
21
#include <libxml/uri.h>
22
#include <libxml/valid.h>
23
#include <libxml/parser.h>
24
#include <libxml/parserInternals.h>
25
#include <libxml/xmlerror.h>
26
#include <libxml/list.h>
27
#include <libxml/globals.h>
29
static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
31
/* #define DEBUG_VALID_ALGO */
32
/* #define DEBUG_REGEXP_ALGO */
35
xmlGenericError(xmlGenericErrorContext, \
36
"Unimplemented block at %s:%d\n", \
39
#ifdef LIBXML_VALID_ENABLED
41
xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
42
const xmlChar *value);
44
/************************************************************************
46
* Error handling routines *
48
************************************************************************/
52
* @ctxt: an XML validation parser context
53
* @extra: extra informations
55
* Handle an out of memory error
58
xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
60
xmlGenericErrorFunc channel = NULL;
61
xmlParserCtxtPtr pctxt = NULL;
65
channel = ctxt->error;
66
data = ctxt->userData;
67
/* Use the special values to detect if it is part of a parsing
69
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
70
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
71
long delta = (char *) ctxt - (char *) ctxt->userData;
72
if ((delta > 0) && (delta < 250))
73
pctxt = ctxt->userData;
77
__xmlRaiseError(NULL, channel, data,
78
pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
79
XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
80
"Memory allocation failed : %s\n", extra);
82
__xmlRaiseError(NULL, channel, data,
83
pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
84
XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
85
"Memory allocation failed\n");
90
* @ctxt: an XML validation parser context
91
* @error: the error number
92
* @extra: extra informations
94
* Handle a validation error
97
xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
98
const char *msg, const char *extra)
100
xmlGenericErrorFunc channel = NULL;
101
xmlParserCtxtPtr pctxt = NULL;
105
channel = ctxt->error;
106
data = ctxt->userData;
107
/* Use the special values to detect if it is part of a parsing
109
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
110
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
111
long delta = (char *) ctxt - (char *) ctxt->userData;
112
if ((delta > 0) && (delta < 250))
113
pctxt = ctxt->userData;
117
__xmlRaiseError(NULL, channel, data,
118
pctxt, NULL, XML_FROM_VALID, error,
119
XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
122
__xmlRaiseError(NULL, channel, data,
123
pctxt, NULL, XML_FROM_VALID, error,
124
XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
128
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
131
* @ctxt: an XML validation parser context
132
* @node: the node raising the error
133
* @error: the error number
134
* @str1: extra informations
135
* @str2: extra informations
136
* @str3: extra informations
138
* Handle a validation error, provide contextual informations
141
xmlErrValidNode(xmlValidCtxtPtr ctxt,
142
xmlNodePtr node, xmlParserErrors error,
143
const char *msg, const xmlChar * str1,
144
const xmlChar * str2, const xmlChar * str3)
146
xmlStructuredErrorFunc schannel = NULL;
147
xmlGenericErrorFunc channel = NULL;
148
xmlParserCtxtPtr pctxt = NULL;
152
channel = ctxt->error;
153
data = ctxt->userData;
154
/* Use the special values to detect if it is part of a parsing
156
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
157
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
158
long delta = (char *) ctxt - (char *) ctxt->userData;
159
if ((delta > 0) && (delta < 250))
160
pctxt = ctxt->userData;
163
__xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
164
XML_ERR_ERROR, NULL, 0,
167
(const char *) str3, 0, 0, msg, str1, str2, str3);
169
#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
171
#ifdef LIBXML_VALID_ENABLED
174
* @ctxt: an XML validation parser context
175
* @node: the node raising the error
176
* @error: the error number
177
* @str1: extra informations
178
* @int2: extra informations
179
* @str3: extra informations
181
* Handle a validation error, provide contextual informations
184
xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
185
xmlNodePtr node, xmlParserErrors error,
186
const char *msg, const xmlChar * str1,
187
int int2, const xmlChar * str3)
189
xmlStructuredErrorFunc schannel = NULL;
190
xmlGenericErrorFunc channel = NULL;
191
xmlParserCtxtPtr pctxt = NULL;
195
channel = ctxt->error;
196
data = ctxt->userData;
197
/* Use the special values to detect if it is part of a parsing
199
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
200
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
201
long delta = (char *) ctxt - (char *) ctxt->userData;
202
if ((delta > 0) && (delta < 250))
203
pctxt = ctxt->userData;
206
__xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
207
XML_ERR_ERROR, NULL, 0,
210
NULL, int2, 0, msg, str1, int2, str3);
214
* xmlErrValidWarning:
215
* @ctxt: an XML validation parser context
216
* @node: the node raising the error
217
* @error: the error number
218
* @str1: extra information
219
* @str2: extra information
220
* @str3: extra information
222
* Handle a validation error, provide contextual information
225
xmlErrValidWarning(xmlValidCtxtPtr ctxt,
226
xmlNodePtr node, xmlParserErrors error,
227
const char *msg, const xmlChar * str1,
228
const xmlChar * str2, const xmlChar * str3)
230
xmlStructuredErrorFunc schannel = NULL;
231
xmlGenericErrorFunc channel = NULL;
232
xmlParserCtxtPtr pctxt = NULL;
236
channel = ctxt->warning;
237
data = ctxt->userData;
238
/* Use the special values to detect if it is part of a parsing
240
if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
241
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
242
long delta = (char *) ctxt - (char *) ctxt->userData;
243
if ((delta > 0) && (delta < 250))
244
pctxt = ctxt->userData;
247
__xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
248
XML_ERR_WARNING, NULL, 0,
251
(const char *) str3, 0, 0, msg, str1, str2, str3);
256
#ifdef LIBXML_REGEXP_ENABLED
258
* If regexp are enabled we can do continuous validation without the
259
* need of a tree to validate the content model. this is done in each
261
* Each xmlValidState represent the validation state associated to the
262
* set of nodes currently open from the document root to the current element.
266
typedef struct _xmlValidState {
267
xmlElementPtr elemDecl; /* pointer to the content model */
268
xmlNodePtr node; /* pointer to the current node */
269
xmlRegExecCtxtPtr exec; /* regexp runtime */
274
vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
275
if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
276
ctxt->vstateMax = 10;
277
ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
278
sizeof(ctxt->vstateTab[0]));
279
if (ctxt->vstateTab == NULL) {
280
xmlVErrMemory(ctxt, "malloc failed");
285
if (ctxt->vstateNr >= ctxt->vstateMax) {
288
tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
289
2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
291
xmlVErrMemory(ctxt, "realloc failed");
294
ctxt->vstateMax *= 2;
295
ctxt->vstateTab = tmp;
297
ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
298
ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
299
ctxt->vstateTab[ctxt->vstateNr].node = node;
300
if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
301
if (elemDecl->contModel == NULL)
302
xmlValidBuildContentModel(ctxt, elemDecl);
303
if (elemDecl->contModel != NULL) {
304
ctxt->vstateTab[ctxt->vstateNr].exec =
305
xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
307
ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
308
xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
309
XML_ERR_INTERNAL_ERROR,
310
"Failed to build content model regexp for %s\n",
311
node->name, NULL, NULL);
314
return(ctxt->vstateNr++);
318
vstateVPop(xmlValidCtxtPtr ctxt) {
319
xmlElementPtr elemDecl;
321
if (ctxt->vstateNr < 1) return(-1);
323
elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
324
ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
325
ctxt->vstateTab[ctxt->vstateNr].node = NULL;
326
if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
327
xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
329
ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
330
if (ctxt->vstateNr >= 1)
331
ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
334
return(ctxt->vstateNr);
337
#else /* not LIBXML_REGEXP_ENABLED */
339
* If regexp are not enabled, it uses a home made algorithm less
340
* complex and easier to
341
* debug/maintain than a generic NFA -> DFA state based algo. The
342
* only restriction is on the deepness of the tree limited by the
343
* size of the occurs bitfield
345
* this is the content of a saved state for rollbacks
348
#define ROLLBACK_OR 0
349
#define ROLLBACK_PARENT 1
351
typedef struct _xmlValidState {
352
xmlElementContentPtr cont; /* pointer to the content model subtree */
353
xmlNodePtr node; /* pointer to the current node in the list */
354
long occurs;/* bitfield for multiple occurrences */
355
unsigned char depth; /* current depth in the overall tree */
356
unsigned char state; /* ROLLBACK_XXX */
359
#define MAX_RECURSE 25000
360
#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
361
#define CONT ctxt->vstate->cont
362
#define NODE ctxt->vstate->node
363
#define DEPTH ctxt->vstate->depth
364
#define OCCURS ctxt->vstate->occurs
365
#define STATE ctxt->vstate->state
367
#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
368
#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
370
#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
371
#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
374
vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
375
xmlNodePtr node, unsigned char depth, long occurs,
376
unsigned char state) {
377
int i = ctxt->vstateNr - 1;
379
if (ctxt->vstateNr > MAX_RECURSE) {
382
if (ctxt->vstateTab == NULL) {
384
ctxt->vstateTab = (xmlValidState *) xmlMalloc(
385
ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
386
if (ctxt->vstateTab == NULL) {
387
xmlVErrMemory(ctxt, "malloc failed");
391
if (ctxt->vstateNr >= ctxt->vstateMax) {
394
tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
395
2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
397
xmlVErrMemory(ctxt, "malloc failed");
400
ctxt->vstateMax *= 2;
401
ctxt->vstateTab = tmp;
402
ctxt->vstate = &ctxt->vstateTab[0];
405
* Don't push on the stack a state already here
407
if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
408
(ctxt->vstateTab[i].node == node) &&
409
(ctxt->vstateTab[i].depth == depth) &&
410
(ctxt->vstateTab[i].occurs == occurs) &&
411
(ctxt->vstateTab[i].state == state))
412
return(ctxt->vstateNr);
413
ctxt->vstateTab[ctxt->vstateNr].cont = cont;
414
ctxt->vstateTab[ctxt->vstateNr].node = node;
415
ctxt->vstateTab[ctxt->vstateNr].depth = depth;
416
ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
417
ctxt->vstateTab[ctxt->vstateNr].state = state;
418
return(ctxt->vstateNr++);
422
vstateVPop(xmlValidCtxtPtr ctxt) {
423
if (ctxt->vstateNr <= 1) return(-1);
425
ctxt->vstate = &ctxt->vstateTab[0];
426
ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
427
ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
428
ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
429
ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
430
ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
431
return(ctxt->vstateNr);
434
#endif /* LIBXML_REGEXP_ENABLED */
437
nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
439
if (ctxt->nodeMax <= 0) {
442
(xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
443
sizeof(ctxt->nodeTab[0]));
444
if (ctxt->nodeTab == NULL) {
445
xmlVErrMemory(ctxt, "malloc failed");
450
if (ctxt->nodeNr >= ctxt->nodeMax) {
452
tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
453
ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
455
xmlVErrMemory(ctxt, "realloc failed");
461
ctxt->nodeTab[ctxt->nodeNr] = value;
463
return (ctxt->nodeNr++);
466
nodeVPop(xmlValidCtxtPtr ctxt)
470
if (ctxt->nodeNr <= 0)
473
if (ctxt->nodeNr > 0)
474
ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
477
ret = ctxt->nodeTab[ctxt->nodeNr];
478
ctxt->nodeTab[ctxt->nodeNr] = NULL;
482
#ifdef DEBUG_VALID_ALGO
484
xmlValidPrintNode(xmlNodePtr cur) {
486
xmlGenericError(xmlGenericErrorContext, "null");
490
case XML_ELEMENT_NODE:
491
xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
494
xmlGenericError(xmlGenericErrorContext, "text ");
496
case XML_CDATA_SECTION_NODE:
497
xmlGenericError(xmlGenericErrorContext, "cdata ");
499
case XML_ENTITY_REF_NODE:
500
xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
503
xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
505
case XML_COMMENT_NODE:
506
xmlGenericError(xmlGenericErrorContext, "comment ");
508
case XML_ATTRIBUTE_NODE:
509
xmlGenericError(xmlGenericErrorContext, "?attr? ");
511
case XML_ENTITY_NODE:
512
xmlGenericError(xmlGenericErrorContext, "?ent? ");
514
case XML_DOCUMENT_NODE:
515
xmlGenericError(xmlGenericErrorContext, "?doc? ");
517
case XML_DOCUMENT_TYPE_NODE:
518
xmlGenericError(xmlGenericErrorContext, "?doctype? ");
520
case XML_DOCUMENT_FRAG_NODE:
521
xmlGenericError(xmlGenericErrorContext, "?frag? ");
523
case XML_NOTATION_NODE:
524
xmlGenericError(xmlGenericErrorContext, "?nota? ");
526
case XML_HTML_DOCUMENT_NODE:
527
xmlGenericError(xmlGenericErrorContext, "?html? ");
529
#ifdef LIBXML_DOCB_ENABLED
530
case XML_DOCB_DOCUMENT_NODE:
531
xmlGenericError(xmlGenericErrorContext, "?docb? ");
535
xmlGenericError(xmlGenericErrorContext, "?dtd? ");
537
case XML_ELEMENT_DECL:
538
xmlGenericError(xmlGenericErrorContext, "?edecl? ");
540
case XML_ATTRIBUTE_DECL:
541
xmlGenericError(xmlGenericErrorContext, "?adecl? ");
543
case XML_ENTITY_DECL:
544
xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
546
case XML_NAMESPACE_DECL:
547
xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
549
case XML_XINCLUDE_START:
550
xmlGenericError(xmlGenericErrorContext, "incstart ");
552
case XML_XINCLUDE_END:
553
xmlGenericError(xmlGenericErrorContext, "incend ");
559
xmlValidPrintNodeList(xmlNodePtr cur) {
561
xmlGenericError(xmlGenericErrorContext, "null ");
562
while (cur != NULL) {
563
xmlValidPrintNode(cur);
569
xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
573
xmlGenericError(xmlGenericErrorContext, "valid: ");
574
xmlValidPrintNodeList(cur);
575
xmlGenericError(xmlGenericErrorContext, "against ");
576
xmlSnprintfElementContent(expr, 5000, cont, 1);
577
xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
581
xmlValidDebugState(xmlValidStatePtr state) {
582
xmlGenericError(xmlGenericErrorContext, "(");
583
if (state->cont == NULL)
584
xmlGenericError(xmlGenericErrorContext, "null,");
586
switch (state->cont->type) {
587
case XML_ELEMENT_CONTENT_PCDATA:
588
xmlGenericError(xmlGenericErrorContext, "pcdata,");
590
case XML_ELEMENT_CONTENT_ELEMENT:
591
xmlGenericError(xmlGenericErrorContext, "%s,",
594
case XML_ELEMENT_CONTENT_SEQ:
595
xmlGenericError(xmlGenericErrorContext, "seq,");
597
case XML_ELEMENT_CONTENT_OR:
598
xmlGenericError(xmlGenericErrorContext, "or,");
601
xmlValidPrintNode(state->node);
602
xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
603
state->depth, state->occurs, state->state);
607
xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
610
xmlGenericError(xmlGenericErrorContext, "state: ");
611
xmlValidDebugState(ctxt->vstate);
612
xmlGenericError(xmlGenericErrorContext, " stack: %d ",
614
for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
615
xmlValidDebugState(&ctxt->vstateTab[j]);
616
xmlGenericError(xmlGenericErrorContext, "\n");
620
#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
623
#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
624
#define DEBUG_VALID_MSG(m) \
625
xmlGenericError(xmlGenericErrorContext, "%s\n", m);
628
#define DEBUG_VALID_STATE(n,c)
629
#define DEBUG_VALID_MSG(m)
632
/* TODO: use hash table for accesses to elem and attribute definitions */
636
if (doc == NULL) return(0); \
637
else if ((doc->intSubset == NULL) && \
638
(doc->extSubset == NULL)) return(0)
640
#ifdef LIBXML_REGEXP_ENABLED
642
/************************************************************************
644
* Content model validation based on the regexps *
646
************************************************************************/
649
* xmlValidBuildAContentModel:
650
* @content: the content model
651
* @ctxt: the schema parser context
652
* @name: the element name whose content is being built
654
* Generate the automata sequence needed for that type
656
* Returns 1 if successful or 0 in case of error.
659
xmlValidBuildAContentModel(xmlElementContentPtr content,
660
xmlValidCtxtPtr ctxt,
661
const xmlChar *name) {
662
if (content == NULL) {
663
xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
664
"Found NULL content in content model of %s\n",
668
switch (content->type) {
669
case XML_ELEMENT_CONTENT_PCDATA:
670
xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
671
"Found PCDATA in content model of %s\n",
675
case XML_ELEMENT_CONTENT_ELEMENT: {
676
xmlAutomataStatePtr oldstate = ctxt->state;
680
fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
681
if (fullname == NULL) {
682
xmlVErrMemory(ctxt, "Building content model");
686
switch (content->ocur) {
687
case XML_ELEMENT_CONTENT_ONCE:
688
ctxt->state = xmlAutomataNewTransition(ctxt->am,
689
ctxt->state, NULL, fullname, NULL);
691
case XML_ELEMENT_CONTENT_OPT:
692
ctxt->state = xmlAutomataNewTransition(ctxt->am,
693
ctxt->state, NULL, fullname, NULL);
694
xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
696
case XML_ELEMENT_CONTENT_PLUS:
697
ctxt->state = xmlAutomataNewTransition(ctxt->am,
698
ctxt->state, NULL, fullname, NULL);
699
xmlAutomataNewTransition(ctxt->am, ctxt->state,
700
ctxt->state, fullname, NULL);
702
case XML_ELEMENT_CONTENT_MULT:
703
ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
705
xmlAutomataNewTransition(ctxt->am,
706
ctxt->state, ctxt->state, fullname, NULL);
709
if ((fullname != fn) && (fullname != content->name))
713
case XML_ELEMENT_CONTENT_SEQ: {
714
xmlAutomataStatePtr oldstate, oldend;
715
xmlElementContentOccur ocur;
718
* Simply iterate over the content
720
oldstate = ctxt->state;
721
ocur = content->ocur;
722
if (ocur != XML_ELEMENT_CONTENT_ONCE) {
723
ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
724
oldstate = ctxt->state;
727
xmlValidBuildAContentModel(content->c1, ctxt, name);
728
content = content->c2;
729
} while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
730
(content->ocur == XML_ELEMENT_CONTENT_ONCE));
731
xmlValidBuildAContentModel(content, ctxt, name);
732
oldend = ctxt->state;
733
ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
735
case XML_ELEMENT_CONTENT_ONCE:
737
case XML_ELEMENT_CONTENT_OPT:
738
xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
740
case XML_ELEMENT_CONTENT_MULT:
741
xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
742
xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
744
case XML_ELEMENT_CONTENT_PLUS:
745
xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
750
case XML_ELEMENT_CONTENT_OR: {
751
xmlAutomataStatePtr oldstate, oldend;
752
xmlElementContentOccur ocur;
754
ocur = content->ocur;
755
if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
756
(ocur == XML_ELEMENT_CONTENT_MULT)) {
757
ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
760
oldstate = ctxt->state;
761
oldend = xmlAutomataNewState(ctxt->am);
764
* iterate over the subtypes and remerge the end with an
768
ctxt->state = oldstate;
769
xmlValidBuildAContentModel(content->c1, ctxt, name);
770
xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
771
content = content->c2;
772
} while ((content->type == XML_ELEMENT_CONTENT_OR) &&
773
(content->ocur == XML_ELEMENT_CONTENT_ONCE));
774
ctxt->state = oldstate;
775
xmlValidBuildAContentModel(content, ctxt, name);
776
xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
777
ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
779
case XML_ELEMENT_CONTENT_ONCE:
781
case XML_ELEMENT_CONTENT_OPT:
782
xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
784
case XML_ELEMENT_CONTENT_MULT:
785
xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
786
xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
788
case XML_ELEMENT_CONTENT_PLUS:
789
xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
795
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
796
"ContentModel broken for element %s\n",
797
(const char *) name);
803
* xmlValidBuildContentModel:
804
* @ctxt: a validation context
805
* @elem: an element declaration node
807
* (Re)Build the automata associated to the content model of this
810
* Returns 1 in case of success, 0 in case of error
813
xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
815
if ((ctxt == NULL) || (elem == NULL))
817
if (elem->type != XML_ELEMENT_DECL)
819
if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
821
/* TODO: should we rebuild in this case ? */
822
if (elem->contModel != NULL) {
823
if (!xmlRegexpIsDeterminist(elem->contModel)) {
830
ctxt->am = xmlNewAutomata();
831
if (ctxt->am == NULL) {
832
xmlErrValidNode(ctxt, (xmlNodePtr) elem,
833
XML_ERR_INTERNAL_ERROR,
834
"Cannot create automata for element %s\n",
835
elem->name, NULL, NULL);
838
ctxt->state = xmlAutomataGetInitState(ctxt->am);
839
xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
840
xmlAutomataSetFinalState(ctxt->am, ctxt->state);
841
elem->contModel = xmlAutomataCompile(ctxt->am);
842
if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
845
xmlSnprintfElementContent(expr, 5000, elem->content, 1);
846
xmlErrValidNode(ctxt, (xmlNodePtr) elem,
847
XML_DTD_CONTENT_NOT_DETERMINIST,
848
"Content model of %s is not determinist: %s\n",
849
elem->name, BAD_CAST expr, NULL);
850
#ifdef DEBUG_REGEXP_ALGO
851
xmlRegexpPrint(stderr, elem->contModel);
855
xmlFreeAutomata(ctxt->am);
860
xmlFreeAutomata(ctxt->am);
865
#endif /* LIBXML_REGEXP_ENABLED */
867
/****************************************************************
869
* Util functions for data allocation/deallocation *
871
****************************************************************/
876
* Allocate a validation context structure.
878
* Returns NULL if not, otherwise the new validation context structure
880
xmlValidCtxtPtr xmlNewValidCtxt(void) {
883
if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
884
xmlVErrMemory(NULL, "malloc failed");
888
(void) memset(ret, 0, sizeof (xmlValidCtxt));
895
* @cur: the validation context to free
897
* Free a validation context structure.
900
xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
901
if (cur->vstateTab != NULL)
902
xmlFree(cur->vstateTab);
903
if (cur->nodeTab != NULL)
904
xmlFree(cur->nodeTab);
908
#endif /* LIBXML_VALID_ENABLED */
911
* xmlNewDocElementContent:
913
* @name: the subelement name or NULL
914
* @type: the type of element content decl
916
* Allocate an element content structure for the document.
918
* Returns NULL if not, otherwise the new element content structure
921
xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
922
xmlElementContentType type) {
923
xmlElementContentPtr ret;
924
xmlDictPtr dict = NULL;
930
case XML_ELEMENT_CONTENT_ELEMENT:
932
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
933
"xmlNewElementContent : name == NULL !\n",
937
case XML_ELEMENT_CONTENT_PCDATA:
938
case XML_ELEMENT_CONTENT_SEQ:
939
case XML_ELEMENT_CONTENT_OR:
941
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
942
"xmlNewElementContent : name != NULL !\n",
947
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
948
"Internal: ELEMENT content corrupted invalid type\n",
952
ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
954
xmlVErrMemory(NULL, "malloc failed");
957
memset(ret, 0, sizeof(xmlElementContent));
959
ret->ocur = XML_ELEMENT_CONTENT_ONCE;
964
tmp = xmlSplitQName3(name, &l);
967
ret->name = xmlStrdup(name);
969
ret->name = xmlDictLookup(dict, name, -1);
972
ret->prefix = xmlStrndup(name, l);
973
ret->name = xmlStrdup(tmp);
975
ret->prefix = xmlDictLookup(dict, name, l);
976
ret->name = xmlDictLookup(dict, tmp, -1);
984
* xmlNewElementContent:
985
* @name: the subelement name or NULL
986
* @type: the type of element content decl
988
* Allocate an element content structure.
989
* Deprecated in favor of xmlNewDocElementContent
991
* Returns NULL if not, otherwise the new element content structure
994
xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
995
return(xmlNewDocElementContent(NULL, name, type));
999
* xmlCopyDocElementContent:
1000
* @doc: the document owning the element declaration
1001
* @cur: An element content pointer.
1003
* Build a copy of an element content description.
1005
* Returns the new xmlElementContentPtr or NULL in case of error.
1007
xmlElementContentPtr
1008
xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1009
xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1010
xmlDictPtr dict = NULL;
1012
if (cur == NULL) return(NULL);
1017
ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1019
xmlVErrMemory(NULL, "malloc failed");
1022
memset(ret, 0, sizeof(xmlElementContent));
1023
ret->type = cur->type;
1024
ret->ocur = cur->ocur;
1025
if (cur->name != NULL) {
1027
ret->name = xmlDictLookup(dict, cur->name, -1);
1029
ret->name = xmlStrdup(cur->name);
1032
if (cur->prefix != NULL) {
1034
ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1036
ret->prefix = xmlStrdup(cur->prefix);
1038
if (cur->c1 != NULL)
1039
ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1040
if (ret->c1 != NULL)
1041
ret->c1->parent = ret;
1042
if (cur->c2 != NULL) {
1045
while (cur != NULL) {
1046
tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1048
xmlVErrMemory(NULL, "malloc failed");
1051
memset(tmp, 0, sizeof(xmlElementContent));
1052
tmp->type = cur->type;
1053
tmp->ocur = cur->ocur;
1055
if (cur->name != NULL) {
1057
tmp->name = xmlDictLookup(dict, cur->name, -1);
1059
tmp->name = xmlStrdup(cur->name);
1062
if (cur->prefix != NULL) {
1064
tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1066
tmp->prefix = xmlStrdup(cur->prefix);
1068
if (cur->c1 != NULL)
1069
tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1070
if (tmp->c1 != NULL)
1071
tmp->c1->parent = ret;
1080
* xmlCopyElementContent:
1081
* @cur: An element content pointer.
1083
* Build a copy of an element content description.
1084
* Deprecated, use xmlCopyDocElementContent instead
1086
* Returns the new xmlElementContentPtr or NULL in case of error.
1088
xmlElementContentPtr
1089
xmlCopyElementContent(xmlElementContentPtr cur) {
1090
return(xmlCopyDocElementContent(NULL, cur));
1094
* xmlFreeDocElementContent:
1095
* @doc: the document owning the element declaration
1096
* @cur: the element content tree to free
1098
* Free an element content structure. The whole subtree is removed.
1101
xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1102
xmlElementContentPtr next;
1103
xmlDictPtr dict = NULL;
1108
while (cur != NULL) {
1110
switch (cur->type) {
1111
case XML_ELEMENT_CONTENT_PCDATA:
1112
case XML_ELEMENT_CONTENT_ELEMENT:
1113
case XML_ELEMENT_CONTENT_SEQ:
1114
case XML_ELEMENT_CONTENT_OR:
1117
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1118
"Internal: ELEMENT content corrupted invalid type\n",
1122
if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1124
if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1125
xmlFree((xmlChar *) cur->name);
1126
if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1127
xmlFree((xmlChar *) cur->prefix);
1129
if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1130
if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1138
* xmlFreeElementContent:
1139
* @cur: the element content tree to free
1141
* Free an element content structure. The whole subtree is removed.
1142
* Deprecated, use xmlFreeDocElementContent instead
1145
xmlFreeElementContent(xmlElementContentPtr cur) {
1146
xmlFreeDocElementContent(NULL, cur);
1149
#ifdef LIBXML_OUTPUT_ENABLED
1151
* xmlDumpElementContent:
1152
* @buf: An XML buffer
1153
* @content: An element table
1154
* @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1156
* This will dump the content of the element table as an XML DTD definition
1159
xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1160
if (content == NULL) return;
1162
if (glob) xmlBufferWriteChar(buf, "(");
1163
switch (content->type) {
1164
case XML_ELEMENT_CONTENT_PCDATA:
1165
xmlBufferWriteChar(buf, "#PCDATA");
1167
case XML_ELEMENT_CONTENT_ELEMENT:
1168
if (content->prefix != NULL) {
1169
xmlBufferWriteCHAR(buf, content->prefix);
1170
xmlBufferWriteChar(buf, ":");
1172
xmlBufferWriteCHAR(buf, content->name);
1174
case XML_ELEMENT_CONTENT_SEQ:
1175
if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1176
(content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1177
xmlDumpElementContent(buf, content->c1, 1);
1179
xmlDumpElementContent(buf, content->c1, 0);
1180
xmlBufferWriteChar(buf, " , ");
1181
if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1182
((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1183
(content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
1184
xmlDumpElementContent(buf, content->c2, 1);
1186
xmlDumpElementContent(buf, content->c2, 0);
1188
case XML_ELEMENT_CONTENT_OR:
1189
if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1190
(content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1191
xmlDumpElementContent(buf, content->c1, 1);
1193
xmlDumpElementContent(buf, content->c1, 0);
1194
xmlBufferWriteChar(buf, " | ");
1195
if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1196
((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1197
(content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
1198
xmlDumpElementContent(buf, content->c2, 1);
1200
xmlDumpElementContent(buf, content->c2, 0);
1203
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1204
"Internal: ELEMENT content corrupted invalid type\n",
1208
xmlBufferWriteChar(buf, ")");
1209
switch (content->ocur) {
1210
case XML_ELEMENT_CONTENT_ONCE:
1212
case XML_ELEMENT_CONTENT_OPT:
1213
xmlBufferWriteChar(buf, "?");
1215
case XML_ELEMENT_CONTENT_MULT:
1216
xmlBufferWriteChar(buf, "*");
1218
case XML_ELEMENT_CONTENT_PLUS:
1219
xmlBufferWriteChar(buf, "+");
1225
* xmlSprintfElementContent:
1226
* @buf: an output buffer
1227
* @content: An element table
1228
* @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1230
* Deprecated, unsafe, use xmlSnprintfElementContent
1233
xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1234
xmlElementContentPtr content ATTRIBUTE_UNUSED,
1235
int englob ATTRIBUTE_UNUSED) {
1237
#endif /* LIBXML_OUTPUT_ENABLED */
1240
* xmlSnprintfElementContent:
1241
* @buf: an output buffer
1242
* @size: the buffer size
1243
* @content: An element table
1244
* @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1246
* This will dump the content of the element content definition
1247
* Intended just for the debug routine
1250
xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
1253
if (content == NULL) return;
1255
if (size - len < 50) {
1256
if ((size - len > 4) && (buf[len - 1] != '.'))
1257
strcat(buf, " ...");
1260
if (englob) strcat(buf, "(");
1261
switch (content->type) {
1262
case XML_ELEMENT_CONTENT_PCDATA:
1263
strcat(buf, "#PCDATA");
1265
case XML_ELEMENT_CONTENT_ELEMENT:
1266
if (content->prefix != NULL) {
1267
if (size - len < xmlStrlen(content->prefix) + 10) {
1268
strcat(buf, " ...");
1271
strcat(buf, (char *) content->prefix);
1274
if (size - len < xmlStrlen(content->name) + 10) {
1275
strcat(buf, " ...");
1278
if (content->name != NULL)
1279
strcat(buf, (char *) content->name);
1281
case XML_ELEMENT_CONTENT_SEQ:
1282
if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1283
(content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1284
xmlSnprintfElementContent(buf, size, content->c1, 1);
1286
xmlSnprintfElementContent(buf, size, content->c1, 0);
1288
if (size - len < 50) {
1289
if ((size - len > 4) && (buf[len - 1] != '.'))
1290
strcat(buf, " ...");
1294
if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1295
(content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1296
(content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1297
xmlSnprintfElementContent(buf, size, content->c2, 1);
1299
xmlSnprintfElementContent(buf, size, content->c2, 0);
1301
case XML_ELEMENT_CONTENT_OR:
1302
if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1303
(content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1304
xmlSnprintfElementContent(buf, size, content->c1, 1);
1306
xmlSnprintfElementContent(buf, size, content->c1, 0);
1308
if (size - len < 50) {
1309
if ((size - len > 4) && (buf[len - 1] != '.'))
1310
strcat(buf, " ...");
1314
if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1315
(content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1316
(content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1317
xmlSnprintfElementContent(buf, size, content->c2, 1);
1319
xmlSnprintfElementContent(buf, size, content->c2, 0);
1324
switch (content->ocur) {
1325
case XML_ELEMENT_CONTENT_ONCE:
1327
case XML_ELEMENT_CONTENT_OPT:
1330
case XML_ELEMENT_CONTENT_MULT:
1333
case XML_ELEMENT_CONTENT_PLUS:
1339
/****************************************************************
1341
* Registration of DTD declarations *
1343
****************************************************************/
1349
* Deallocate the memory used by an element definition
1352
xmlFreeElement(xmlElementPtr elem) {
1353
if (elem == NULL) return;
1354
xmlUnlinkNode((xmlNodePtr) elem);
1355
xmlFreeDocElementContent(elem->doc, elem->content);
1356
if (elem->name != NULL)
1357
xmlFree((xmlChar *) elem->name);
1358
if (elem->prefix != NULL)
1359
xmlFree((xmlChar *) elem->prefix);
1360
#ifdef LIBXML_REGEXP_ENABLED
1361
if (elem->contModel != NULL)
1362
xmlRegFreeRegexp(elem->contModel);
1369
* xmlAddElementDecl:
1370
* @ctxt: the validation context
1371
* @dtd: pointer to the DTD
1372
* @name: the entity name
1373
* @type: the element type
1374
* @content: the element content tree or NULL
1376
* Register a new element declaration
1378
* Returns NULL if not, otherwise the entity
1381
xmlAddElementDecl(xmlValidCtxtPtr ctxt,
1382
xmlDtdPtr dtd, const xmlChar *name,
1383
xmlElementTypeVal type,
1384
xmlElementContentPtr content) {
1386
xmlElementTablePtr table;
1387
xmlAttributePtr oldAttributes = NULL;
1388
xmlChar *ns, *uqname;
1398
case XML_ELEMENT_TYPE_EMPTY:
1399
if (content != NULL) {
1400
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1401
"xmlAddElementDecl: content != NULL for EMPTY\n",
1406
case XML_ELEMENT_TYPE_ANY:
1407
if (content != NULL) {
1408
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1409
"xmlAddElementDecl: content != NULL for ANY\n",
1414
case XML_ELEMENT_TYPE_MIXED:
1415
if (content == NULL) {
1416
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1417
"xmlAddElementDecl: content == NULL for MIXED\n",
1422
case XML_ELEMENT_TYPE_ELEMENT:
1423
if (content == NULL) {
1424
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1425
"xmlAddElementDecl: content == NULL for ELEMENT\n",
1431
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1432
"Internal: ELEMENT decl corrupted invalid type\n",
1438
* check if name is a QName
1440
uqname = xmlSplitQName2(name, &ns);
1445
* Create the Element table if needed.
1447
table = (xmlElementTablePtr) dtd->elements;
1448
if (table == NULL) {
1449
xmlDictPtr dict = NULL;
1451
if (dtd->doc != NULL)
1452
dict = dtd->doc->dict;
1453
table = xmlHashCreateDict(0, dict);
1454
dtd->elements = (void *) table;
1456
if (table == NULL) {
1458
"xmlAddElementDecl: Table creation failed!\n");
1467
* lookup old attributes inserted on an undefined element in the
1470
if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1471
ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1472
if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1473
oldAttributes = ret->attributes;
1474
ret->attributes = NULL;
1475
xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1476
xmlFreeElement(ret);
1481
* The element may already be present if one of its attribute
1482
* was registered first
1484
ret = xmlHashLookup2(table, name, ns);
1486
if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1487
#ifdef LIBXML_VALID_ENABLED
1489
* The element is already defined in this DTD.
1491
xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1492
"Redefinition of element %s\n",
1494
#endif /* LIBXML_VALID_ENABLED */
1506
ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1508
xmlVErrMemory(ctxt, "malloc failed");
1515
memset(ret, 0, sizeof(xmlElement));
1516
ret->type = XML_ELEMENT_DECL;
1519
* fill the structure.
1521
ret->name = xmlStrdup(name);
1522
if (ret->name == NULL) {
1523
xmlVErrMemory(ctxt, "malloc failed");
1535
* Insertion must not fail
1537
if (xmlHashAddEntry2(table, name, ns, ret)) {
1538
#ifdef LIBXML_VALID_ENABLED
1540
* The element is already defined in this DTD.
1542
xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1543
"Redefinition of element %s\n",
1545
#endif /* LIBXML_VALID_ENABLED */
1546
xmlFreeElement(ret);
1552
* For new element, may have attributes from earlier
1553
* definition in internal subset
1555
ret->attributes = oldAttributes;
1559
* Finish to fill the structure.
1563
* Avoid a stupid copy when called by the parser
1564
* and flag it by setting a special parent value
1565
* so the parser doesn't unallocate it.
1567
if ((ctxt != NULL) &&
1568
((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1569
(ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
1570
ret->content = content;
1571
if (content != NULL)
1572
content->parent = (xmlElementContentPtr) 1;
1574
ret->content = xmlCopyDocElementContent(dtd->doc, content);
1578
* Link it to the DTD
1581
ret->doc = dtd->doc;
1582
if (dtd->last == NULL) {
1583
dtd->children = dtd->last = (xmlNodePtr) ret;
1585
dtd->last->next = (xmlNodePtr) ret;
1586
ret->prev = dtd->last;
1587
dtd->last = (xmlNodePtr) ret;
1595
* xmlFreeElementTable:
1596
* @table: An element table
1598
* Deallocate the memory used by an element hash table.
1601
xmlFreeElementTable(xmlElementTablePtr table) {
1602
xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1605
#ifdef LIBXML_TREE_ENABLED
1610
* Build a copy of an element.
1612
* Returns the new xmlElementPtr or NULL in case of error.
1614
static xmlElementPtr
1615
xmlCopyElement(xmlElementPtr elem) {
1618
cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1620
xmlVErrMemory(NULL, "malloc failed");
1623
memset(cur, 0, sizeof(xmlElement));
1624
cur->type = XML_ELEMENT_DECL;
1625
cur->etype = elem->etype;
1626
if (elem->name != NULL)
1627
cur->name = xmlStrdup(elem->name);
1630
if (elem->prefix != NULL)
1631
cur->prefix = xmlStrdup(elem->prefix);
1634
cur->content = xmlCopyElementContent(elem->content);
1635
/* TODO : rebuild the attribute list on the copy */
1636
cur->attributes = NULL;
1641
* xmlCopyElementTable:
1642
* @table: An element table
1644
* Build a copy of an element table.
1646
* Returns the new xmlElementTablePtr or NULL in case of error.
1649
xmlCopyElementTable(xmlElementTablePtr table) {
1650
return((xmlElementTablePtr) xmlHashCopy(table,
1651
(xmlHashCopier) xmlCopyElement));
1653
#endif /* LIBXML_TREE_ENABLED */
1655
#ifdef LIBXML_OUTPUT_ENABLED
1657
* xmlDumpElementDecl:
1658
* @buf: the XML buffer output
1659
* @elem: An element table
1661
* This will dump the content of the element declaration as an XML
1665
xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1666
if ((buf == NULL) || (elem == NULL))
1668
switch (elem->etype) {
1669
case XML_ELEMENT_TYPE_EMPTY:
1670
xmlBufferWriteChar(buf, "<!ELEMENT ");
1671
if (elem->prefix != NULL) {
1672
xmlBufferWriteCHAR(buf, elem->prefix);
1673
xmlBufferWriteChar(buf, ":");
1675
xmlBufferWriteCHAR(buf, elem->name);
1676
xmlBufferWriteChar(buf, " EMPTY>\n");
1678
case XML_ELEMENT_TYPE_ANY:
1679
xmlBufferWriteChar(buf, "<!ELEMENT ");
1680
if (elem->prefix != NULL) {
1681
xmlBufferWriteCHAR(buf, elem->prefix);
1682
xmlBufferWriteChar(buf, ":");
1684
xmlBufferWriteCHAR(buf, elem->name);
1685
xmlBufferWriteChar(buf, " ANY>\n");
1687
case XML_ELEMENT_TYPE_MIXED:
1688
xmlBufferWriteChar(buf, "<!ELEMENT ");
1689
if (elem->prefix != NULL) {
1690
xmlBufferWriteCHAR(buf, elem->prefix);
1691
xmlBufferWriteChar(buf, ":");
1693
xmlBufferWriteCHAR(buf, elem->name);
1694
xmlBufferWriteChar(buf, " ");
1695
xmlDumpElementContent(buf, elem->content, 1);
1696
xmlBufferWriteChar(buf, ">\n");
1698
case XML_ELEMENT_TYPE_ELEMENT:
1699
xmlBufferWriteChar(buf, "<!ELEMENT ");
1700
if (elem->prefix != NULL) {
1701
xmlBufferWriteCHAR(buf, elem->prefix);
1702
xmlBufferWriteChar(buf, ":");
1704
xmlBufferWriteCHAR(buf, elem->name);
1705
xmlBufferWriteChar(buf, " ");
1706
xmlDumpElementContent(buf, elem->content, 1);
1707
xmlBufferWriteChar(buf, ">\n");
1710
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1711
"Internal: ELEMENT struct corrupted invalid type\n",
1717
* xmlDumpElementDeclScan:
1718
* @elem: An element table
1719
* @buf: the XML buffer output
1721
* This routine is used by the hash scan function. It just reverses
1725
xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1726
xmlDumpElementDecl(buf, elem);
1730
* xmlDumpElementTable:
1731
* @buf: the XML buffer output
1732
* @table: An element table
1734
* This will dump the content of the element table as an XML DTD definition
1737
xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1738
if ((buf == NULL) || (table == NULL))
1740
xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
1742
#endif /* LIBXML_OUTPUT_ENABLED */
1745
* xmlCreateEnumeration:
1746
* @name: the enumeration name or NULL
1748
* create and initialize an enumeration attribute node.
1750
* Returns the xmlEnumerationPtr just created or NULL in case
1754
xmlCreateEnumeration(const xmlChar *name) {
1755
xmlEnumerationPtr ret;
1757
ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1759
xmlVErrMemory(NULL, "malloc failed");
1762
memset(ret, 0, sizeof(xmlEnumeration));
1765
ret->name = xmlStrdup(name);
1770
* xmlFreeEnumeration:
1771
* @cur: the tree to free.
1773
* free an enumeration attribute node (recursive).
1776
xmlFreeEnumeration(xmlEnumerationPtr cur) {
1777
if (cur == NULL) return;
1779
if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1781
if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1785
#ifdef LIBXML_TREE_ENABLED
1787
* xmlCopyEnumeration:
1788
* @cur: the tree to copy.
1790
* Copy an enumeration attribute node (recursive).
1792
* Returns the xmlEnumerationPtr just created or NULL in case
1796
xmlCopyEnumeration(xmlEnumerationPtr cur) {
1797
xmlEnumerationPtr ret;
1799
if (cur == NULL) return(NULL);
1800
ret = xmlCreateEnumeration((xmlChar *) cur->name);
1802
if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1803
else ret->next = NULL;
1807
#endif /* LIBXML_TREE_ENABLED */
1809
#ifdef LIBXML_OUTPUT_ENABLED
1811
* xmlDumpEnumeration:
1812
* @buf: the XML buffer output
1813
* @enum: An enumeration
1815
* This will dump the content of the enumeration
1818
xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1819
if ((buf == NULL) || (cur == NULL))
1822
xmlBufferWriteCHAR(buf, cur->name);
1823
if (cur->next == NULL)
1824
xmlBufferWriteChar(buf, ")");
1826
xmlBufferWriteChar(buf, " | ");
1827
xmlDumpEnumeration(buf, cur->next);
1830
#endif /* LIBXML_OUTPUT_ENABLED */
1832
#ifdef LIBXML_VALID_ENABLED
1834
* xmlScanIDAttributeDecl:
1835
* @ctxt: the validation context
1836
* @elem: the element name
1837
* @err: whether to raise errors here
1839
* Verify that the element don't have too many ID attributes
1842
* Returns the number of ID attributes found.
1845
xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1846
xmlAttributePtr cur;
1849
if (elem == NULL) return(0);
1850
cur = elem->attributes;
1851
while (cur != NULL) {
1852
if (cur->atype == XML_ATTRIBUTE_ID) {
1854
if ((ret > 1) && (err))
1855
xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1856
"Element %s has too many ID attributes defined : %s\n",
1857
elem->name, cur->name, NULL);
1863
#endif /* LIBXML_VALID_ENABLED */
1867
* @elem: An attribute
1869
* Deallocate the memory used by an attribute definition
1872
xmlFreeAttribute(xmlAttributePtr attr) {
1875
if (attr == NULL) return;
1876
if (attr->doc != NULL)
1877
dict = attr->doc->dict;
1880
xmlUnlinkNode((xmlNodePtr) attr);
1881
if (attr->tree != NULL)
1882
xmlFreeEnumeration(attr->tree);
1884
if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1885
xmlFree((xmlChar *) attr->elem);
1886
if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1887
xmlFree((xmlChar *) attr->name);
1888
if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1889
xmlFree((xmlChar *) attr->prefix);
1890
if ((attr->defaultValue != NULL) &&
1891
(!xmlDictOwns(dict, attr->defaultValue)))
1892
xmlFree((xmlChar *) attr->defaultValue);
1894
if (attr->elem != NULL)
1895
xmlFree((xmlChar *) attr->elem);
1896
if (attr->name != NULL)
1897
xmlFree((xmlChar *) attr->name);
1898
if (attr->defaultValue != NULL)
1899
xmlFree((xmlChar *) attr->defaultValue);
1900
if (attr->prefix != NULL)
1901
xmlFree((xmlChar *) attr->prefix);
1908
* xmlAddAttributeDecl:
1909
* @ctxt: the validation context
1910
* @dtd: pointer to the DTD
1911
* @elem: the element name
1912
* @name: the attribute name
1913
* @ns: the attribute namespace prefix
1914
* @type: the attribute type
1915
* @def: the attribute default type
1916
* @defaultValue: the attribute default value
1917
* @tree: if it's an enumeration, the associated list
1919
* Register a new attribute declaration
1920
* Note that @tree becomes the ownership of the DTD
1922
* Returns NULL if not new, otherwise the attribute decl
1925
xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
1926
xmlDtdPtr dtd, const xmlChar *elem,
1927
const xmlChar *name, const xmlChar *ns,
1928
xmlAttributeType type, xmlAttributeDefault def,
1929
const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1930
xmlAttributePtr ret;
1931
xmlAttributeTablePtr table;
1932
xmlElementPtr elemDef;
1933
xmlDictPtr dict = NULL;
1936
xmlFreeEnumeration(tree);
1940
xmlFreeEnumeration(tree);
1944
xmlFreeEnumeration(tree);
1947
if (dtd->doc != NULL)
1948
dict = dtd->doc->dict;
1950
#ifdef LIBXML_VALID_ENABLED
1952
* Check the type and possibly the default value.
1955
case XML_ATTRIBUTE_CDATA:
1957
case XML_ATTRIBUTE_ID:
1959
case XML_ATTRIBUTE_IDREF:
1961
case XML_ATTRIBUTE_IDREFS:
1963
case XML_ATTRIBUTE_ENTITY:
1965
case XML_ATTRIBUTE_ENTITIES:
1967
case XML_ATTRIBUTE_NMTOKEN:
1969
case XML_ATTRIBUTE_NMTOKENS:
1971
case XML_ATTRIBUTE_ENUMERATION:
1973
case XML_ATTRIBUTE_NOTATION:
1976
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1977
"Internal: ATTRIBUTE struct corrupted invalid type\n",
1979
xmlFreeEnumeration(tree);
1982
if ((defaultValue != NULL) &&
1983
(!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
1984
xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1985
"Attribute %s of %s: invalid default value\n",
1986
elem, name, defaultValue);
1987
defaultValue = NULL;
1991
#endif /* LIBXML_VALID_ENABLED */
1994
* Check first that an attribute defined in the external subset wasn't
1995
* already defined in the internal subset
1997
if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1998
(dtd->doc->intSubset != NULL) &&
1999
(dtd->doc->intSubset->attributes != NULL)) {
2000
ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2002
xmlFreeEnumeration(tree);
2008
* Create the Attribute table if needed.
2010
table = (xmlAttributeTablePtr) dtd->attributes;
2011
if (table == NULL) {
2012
table = xmlHashCreateDict(0, dict);
2013
dtd->attributes = (void *) table;
2015
if (table == NULL) {
2017
"xmlAddAttributeDecl: Table creation failed!\n");
2018
xmlFreeEnumeration(tree);
2023
ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2025
xmlVErrMemory(ctxt, "malloc failed");
2026
xmlFreeEnumeration(tree);
2029
memset(ret, 0, sizeof(xmlAttribute));
2030
ret->type = XML_ATTRIBUTE_DECL;
2033
* fill the structure.
2037
* doc must be set before possible error causes call
2038
* to xmlFreeAttribute (because it's used to check on
2041
ret->doc = dtd->doc;
2043
ret->name = xmlDictLookup(dict, name, -1);
2044
ret->prefix = xmlDictLookup(dict, ns, -1);
2045
ret->elem = xmlDictLookup(dict, elem, -1);
2047
ret->name = xmlStrdup(name);
2048
ret->prefix = xmlStrdup(ns);
2049
ret->elem = xmlStrdup(elem);
2053
if (defaultValue != NULL) {
2055
ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2057
ret->defaultValue = xmlStrdup(defaultValue);
2062
* Search the DTD for previous declarations of the ATTLIST
2064
if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2065
#ifdef LIBXML_VALID_ENABLED
2067
* The attribute is already defined in this DTD.
2069
xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2070
"Attribute %s of element %s: already defined\n",
2072
#endif /* LIBXML_VALID_ENABLED */
2073
xmlFreeAttribute(ret);
2079
* Multiple ID per element
2081
elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2082
if (elemDef != NULL) {
2084
#ifdef LIBXML_VALID_ENABLED
2085
if ((type == XML_ATTRIBUTE_ID) &&
2086
(xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2087
xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2088
"Element %s has too may ID attributes defined : %s\n",
2093
#endif /* LIBXML_VALID_ENABLED */
2096
* Insert namespace default def first they need to be
2099
if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2100
((ret->prefix != NULL &&
2101
(xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2102
ret->nexth = elemDef->attributes;
2103
elemDef->attributes = ret;
2105
xmlAttributePtr tmp = elemDef->attributes;
2107
while ((tmp != NULL) &&
2108
((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2109
((ret->prefix != NULL &&
2110
(xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2111
if (tmp->nexth == NULL)
2116
ret->nexth = tmp->nexth;
2119
ret->nexth = elemDef->attributes;
2120
elemDef->attributes = ret;
2126
* Link it to the DTD
2129
if (dtd->last == NULL) {
2130
dtd->children = dtd->last = (xmlNodePtr) ret;
2132
dtd->last->next = (xmlNodePtr) ret;
2133
ret->prev = dtd->last;
2134
dtd->last = (xmlNodePtr) ret;
2140
* xmlFreeAttributeTable:
2141
* @table: An attribute table
2143
* Deallocate the memory used by an entities hash table.
2146
xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2147
xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
2150
#ifdef LIBXML_TREE_ENABLED
2153
* @attr: An attribute
2155
* Build a copy of an attribute.
2157
* Returns the new xmlAttributePtr or NULL in case of error.
2159
static xmlAttributePtr
2160
xmlCopyAttribute(xmlAttributePtr attr) {
2161
xmlAttributePtr cur;
2163
cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2165
xmlVErrMemory(NULL, "malloc failed");
2168
memset(cur, 0, sizeof(xmlAttribute));
2169
cur->type = XML_ATTRIBUTE_DECL;
2170
cur->atype = attr->atype;
2171
cur->def = attr->def;
2172
cur->tree = xmlCopyEnumeration(attr->tree);
2173
if (attr->elem != NULL)
2174
cur->elem = xmlStrdup(attr->elem);
2175
if (attr->name != NULL)
2176
cur->name = xmlStrdup(attr->name);
2177
if (attr->prefix != NULL)
2178
cur->prefix = xmlStrdup(attr->prefix);
2179
if (attr->defaultValue != NULL)
2180
cur->defaultValue = xmlStrdup(attr->defaultValue);
2185
* xmlCopyAttributeTable:
2186
* @table: An attribute table
2188
* Build a copy of an attribute table.
2190
* Returns the new xmlAttributeTablePtr or NULL in case of error.
2192
xmlAttributeTablePtr
2193
xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2194
return((xmlAttributeTablePtr) xmlHashCopy(table,
2195
(xmlHashCopier) xmlCopyAttribute));
2197
#endif /* LIBXML_TREE_ENABLED */
2199
#ifdef LIBXML_OUTPUT_ENABLED
2201
* xmlDumpAttributeDecl:
2202
* @buf: the XML buffer output
2203
* @attr: An attribute declaration
2205
* This will dump the content of the attribute declaration as an XML
2209
xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2210
if ((buf == NULL) || (attr == NULL))
2212
xmlBufferWriteChar(buf, "<!ATTLIST ");
2213
xmlBufferWriteCHAR(buf, attr->elem);
2214
xmlBufferWriteChar(buf, " ");
2215
if (attr->prefix != NULL) {
2216
xmlBufferWriteCHAR(buf, attr->prefix);
2217
xmlBufferWriteChar(buf, ":");
2219
xmlBufferWriteCHAR(buf, attr->name);
2220
switch (attr->atype) {
2221
case XML_ATTRIBUTE_CDATA:
2222
xmlBufferWriteChar(buf, " CDATA");
2224
case XML_ATTRIBUTE_ID:
2225
xmlBufferWriteChar(buf, " ID");
2227
case XML_ATTRIBUTE_IDREF:
2228
xmlBufferWriteChar(buf, " IDREF");
2230
case XML_ATTRIBUTE_IDREFS:
2231
xmlBufferWriteChar(buf, " IDREFS");
2233
case XML_ATTRIBUTE_ENTITY:
2234
xmlBufferWriteChar(buf, " ENTITY");
2236
case XML_ATTRIBUTE_ENTITIES:
2237
xmlBufferWriteChar(buf, " ENTITIES");
2239
case XML_ATTRIBUTE_NMTOKEN:
2240
xmlBufferWriteChar(buf, " NMTOKEN");
2242
case XML_ATTRIBUTE_NMTOKENS:
2243
xmlBufferWriteChar(buf, " NMTOKENS");
2245
case XML_ATTRIBUTE_ENUMERATION:
2246
xmlBufferWriteChar(buf, " (");
2247
xmlDumpEnumeration(buf, attr->tree);
2249
case XML_ATTRIBUTE_NOTATION:
2250
xmlBufferWriteChar(buf, " NOTATION (");
2251
xmlDumpEnumeration(buf, attr->tree);
2254
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2255
"Internal: ATTRIBUTE struct corrupted invalid type\n",
2258
switch (attr->def) {
2259
case XML_ATTRIBUTE_NONE:
2261
case XML_ATTRIBUTE_REQUIRED:
2262
xmlBufferWriteChar(buf, " #REQUIRED");
2264
case XML_ATTRIBUTE_IMPLIED:
2265
xmlBufferWriteChar(buf, " #IMPLIED");
2267
case XML_ATTRIBUTE_FIXED:
2268
xmlBufferWriteChar(buf, " #FIXED");
2271
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2272
"Internal: ATTRIBUTE struct corrupted invalid def\n",
2275
if (attr->defaultValue != NULL) {
2276
xmlBufferWriteChar(buf, " ");
2277
xmlBufferWriteQuotedString(buf, attr->defaultValue);
2279
xmlBufferWriteChar(buf, ">\n");
2283
* xmlDumpAttributeDeclScan:
2284
* @attr: An attribute declaration
2285
* @buf: the XML buffer output
2287
* This is used with the hash scan function - just reverses arguments
2290
xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2291
xmlDumpAttributeDecl(buf, attr);
2295
* xmlDumpAttributeTable:
2296
* @buf: the XML buffer output
2297
* @table: An attribute table
2299
* This will dump the content of the attribute table as an XML DTD definition
2302
xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2303
if ((buf == NULL) || (table == NULL))
2305
xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
2307
#endif /* LIBXML_OUTPUT_ENABLED */
2309
/************************************************************************
2313
************************************************************************/
2318
* Deallocate the memory used by an notation definition
2321
xmlFreeNotation(xmlNotationPtr nota) {
2322
if (nota == NULL) return;
2323
if (nota->name != NULL)
2324
xmlFree((xmlChar *) nota->name);
2325
if (nota->PublicID != NULL)
2326
xmlFree((xmlChar *) nota->PublicID);
2327
if (nota->SystemID != NULL)
2328
xmlFree((xmlChar *) nota->SystemID);
2334
* xmlAddNotationDecl:
2335
* @dtd: pointer to the DTD
2336
* @ctxt: the validation context
2337
* @name: the entity name
2338
* @PublicID: the public identifier or NULL
2339
* @SystemID: the system identifier or NULL
2341
* Register a new notation declaration
2343
* Returns NULL if not, otherwise the entity
2346
xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
2347
const xmlChar *name,
2348
const xmlChar *PublicID, const xmlChar *SystemID) {
2350
xmlNotationTablePtr table;
2358
if ((PublicID == NULL) && (SystemID == NULL)) {
2363
* Create the Notation table if needed.
2365
table = (xmlNotationTablePtr) dtd->notations;
2366
if (table == NULL) {
2367
xmlDictPtr dict = NULL;
2368
if (dtd->doc != NULL)
2369
dict = dtd->doc->dict;
2371
dtd->notations = table = xmlHashCreateDict(0, dict);
2373
if (table == NULL) {
2375
"xmlAddNotationDecl: Table creation failed!\n");
2379
ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2381
xmlVErrMemory(ctxt, "malloc failed");
2384
memset(ret, 0, sizeof(xmlNotation));
2387
* fill the structure.
2389
ret->name = xmlStrdup(name);
2390
if (SystemID != NULL)
2391
ret->SystemID = xmlStrdup(SystemID);
2392
if (PublicID != NULL)
2393
ret->PublicID = xmlStrdup(PublicID);
2397
* Check the DTD for previous declarations of the ATTLIST
2399
if (xmlHashAddEntry(table, name, ret)) {
2400
#ifdef LIBXML_VALID_ENABLED
2401
xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2402
"xmlAddNotationDecl: %s already defined\n",
2403
(const char *) name);
2404
#endif /* LIBXML_VALID_ENABLED */
2405
xmlFreeNotation(ret);
2412
* xmlFreeNotationTable:
2413
* @table: An notation table
2415
* Deallocate the memory used by an entities hash table.
2418
xmlFreeNotationTable(xmlNotationTablePtr table) {
2419
xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2422
#ifdef LIBXML_TREE_ENABLED
2427
* Build a copy of a notation.
2429
* Returns the new xmlNotationPtr or NULL in case of error.
2431
static xmlNotationPtr
2432
xmlCopyNotation(xmlNotationPtr nota) {
2435
cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2437
xmlVErrMemory(NULL, "malloc failed");
2440
if (nota->name != NULL)
2441
cur->name = xmlStrdup(nota->name);
2444
if (nota->PublicID != NULL)
2445
cur->PublicID = xmlStrdup(nota->PublicID);
2447
cur->PublicID = NULL;
2448
if (nota->SystemID != NULL)
2449
cur->SystemID = xmlStrdup(nota->SystemID);
2451
cur->SystemID = NULL;
2456
* xmlCopyNotationTable:
2457
* @table: A notation table
2459
* Build a copy of a notation table.
2461
* Returns the new xmlNotationTablePtr or NULL in case of error.
2464
xmlCopyNotationTable(xmlNotationTablePtr table) {
2465
return((xmlNotationTablePtr) xmlHashCopy(table,
2466
(xmlHashCopier) xmlCopyNotation));
2468
#endif /* LIBXML_TREE_ENABLED */
2470
#ifdef LIBXML_OUTPUT_ENABLED
2472
* xmlDumpNotationDecl:
2473
* @buf: the XML buffer output
2474
* @nota: A notation declaration
2476
* This will dump the content the notation declaration as an XML DTD definition
2479
xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2480
if ((buf == NULL) || (nota == NULL))
2482
xmlBufferWriteChar(buf, "<!NOTATION ");
2483
xmlBufferWriteCHAR(buf, nota->name);
2484
if (nota->PublicID != NULL) {
2485
xmlBufferWriteChar(buf, " PUBLIC ");
2486
xmlBufferWriteQuotedString(buf, nota->PublicID);
2487
if (nota->SystemID != NULL) {
2488
xmlBufferWriteChar(buf, " ");
2489
xmlBufferWriteQuotedString(buf, nota->SystemID);
2492
xmlBufferWriteChar(buf, " SYSTEM ");
2493
xmlBufferWriteQuotedString(buf, nota->SystemID);
2495
xmlBufferWriteChar(buf, " >\n");
2499
* xmlDumpNotationDeclScan:
2500
* @nota: A notation declaration
2501
* @buf: the XML buffer output
2503
* This is called with the hash scan function, and just reverses args
2506
xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2507
xmlDumpNotationDecl(buf, nota);
2511
* xmlDumpNotationTable:
2512
* @buf: the XML buffer output
2513
* @table: A notation table
2515
* This will dump the content of the notation table as an XML DTD definition
2518
xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2519
if ((buf == NULL) || (table == NULL))
2521
xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
2523
#endif /* LIBXML_OUTPUT_ENABLED */
2525
/************************************************************************
2529
************************************************************************/
2534
* Free a string if it is not owned by the "dict" dictionnary in the
2537
#define DICT_FREE(str) \
2538
if ((str) && ((!dict) || \
2539
(xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2540
xmlFree((char *)(str));
2546
* Deallocate the memory used by an id definition
2549
xmlFreeID(xmlIDPtr id) {
2550
xmlDictPtr dict = NULL;
2552
if (id == NULL) return;
2554
if (id->doc != NULL)
2555
dict = id->doc->dict;
2557
if (id->value != NULL)
2558
DICT_FREE(id->value)
2559
if (id->name != NULL)
2567
* @ctxt: the validation context
2568
* @doc: pointer to the document
2569
* @value: the value name
2570
* @attr: the attribute holding the ID
2572
* Register a new id declaration
2574
* Returns NULL if not, otherwise the new xmlIDPtr
2577
xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2580
xmlIDTablePtr table;
2585
if (value == NULL) {
2593
* Create the ID table if needed.
2595
table = (xmlIDTablePtr) doc->ids;
2596
if (table == NULL) {
2597
doc->ids = table = xmlHashCreateDict(0, doc->dict);
2599
if (table == NULL) {
2601
"xmlAddID: Table creation failed!\n");
2605
ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2607
xmlVErrMemory(ctxt, "malloc failed");
2612
* fill the structure.
2614
ret->value = xmlStrdup(value);
2616
if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2618
* Operating in streaming mode, attr is gonna disapear
2620
if (doc->dict != NULL)
2621
ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2623
ret->name = xmlStrdup(attr->name);
2629
ret->lineno = xmlGetLineNo(attr->parent);
2631
if (xmlHashAddEntry(table, value, ret) < 0) {
2632
#ifdef LIBXML_VALID_ENABLED
2634
* The id is already defined in this DTD.
2636
if ((ctxt != NULL) && (ctxt->error != NULL)) {
2637
xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2638
"ID %s already defined\n",
2641
#endif /* LIBXML_VALID_ENABLED */
2646
attr->atype = XML_ATTRIBUTE_ID;
2652
* @table: An id table
2654
* Deallocate the memory used by an ID hash table.
2657
xmlFreeIDTable(xmlIDTablePtr table) {
2658
xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2663
* @doc: the document
2664
* @elem: the element carrying the attribute
2665
* @attr: the attribute
2667
* Determine whether an attribute is of type ID. In case we have DTD(s)
2668
* then this is done if DTD loading has been requested. In the case
2669
* of HTML documents parsed with the HTML parser, then ID detection is
2670
* done systematically.
2672
* Returns 0 or 1 depending on the lookup result
2675
xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2676
if ((attr == NULL) || (attr->name == NULL)) return(0);
2677
if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2678
(!strcmp((char *) attr->name, "id")) &&
2679
(!strcmp((char *) attr->ns->prefix, "xml")))
2681
if (doc == NULL) return(0);
2682
if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2683
(doc->type != XML_HTML_DOCUMENT_NODE)) {
2685
} else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2686
if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2687
((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2688
((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2691
} else if (elem == NULL) {
2694
xmlAttributePtr attrDecl = NULL;
2696
xmlChar felem[50], fattr[50];
2697
xmlChar *fullelemname, *fullattrname;
2699
fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2700
xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2701
(xmlChar *)elem->name;
2703
fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2704
xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2705
(xmlChar *)attr->name;
2707
if (fullelemname != NULL && fullattrname != NULL) {
2708
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2710
if ((attrDecl == NULL) && (doc->extSubset != NULL))
2711
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2715
if ((fullattrname != fattr) && (fullattrname != attr->name))
2716
xmlFree(fullattrname);
2717
if ((fullelemname != felem) && (fullelemname != elem->name))
2718
xmlFree(fullelemname);
2720
if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2728
* @doc: the document
2729
* @attr: the attribute
2731
* Remove the given attribute from the ID table maintained internally.
2733
* Returns -1 if the lookup failed and 0 otherwise
2736
xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2737
xmlIDTablePtr table;
2741
if (doc == NULL) return(-1);
2742
if (attr == NULL) return(-1);
2743
table = (xmlIDTablePtr) doc->ids;
2749
ID = xmlNodeListGetString(doc, attr->children, 1);
2752
id = xmlHashLookup(table, ID);
2753
if (id == NULL || id->attr != attr) {
2757
xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
2765
* @doc: pointer to the document
2768
* Search the attribute declaring the given ID
2770
* Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2773
xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2774
xmlIDTablePtr table;
2785
table = (xmlIDTablePtr) doc->ids;
2789
id = xmlHashLookup(table, ID);
2792
if (id->attr == NULL) {
2794
* We are operating on a stream, return a well known reference
2795
* since the attribute node doesn't exist anymore
2797
return((xmlAttrPtr) doc);
2802
/************************************************************************
2806
************************************************************************/
2807
typedef struct xmlRemoveMemo_t
2813
typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2815
typedef struct xmlValidateMemo_t
2817
xmlValidCtxtPtr ctxt;
2818
const xmlChar *name;
2821
typedef xmlValidateMemo *xmlValidateMemoPtr;
2827
* Deallocate the memory used by a ref definition
2830
xmlFreeRef(xmlLinkPtr lk) {
2831
xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2832
if (ref == NULL) return;
2833
if (ref->value != NULL)
2834
xmlFree((xmlChar *)ref->value);
2835
if (ref->name != NULL)
2836
xmlFree((xmlChar *)ref->name);
2842
* @list_ref: A list of references.
2844
* Deallocate the memory used by a list of references
2847
xmlFreeRefList(xmlListPtr list_ref) {
2848
if (list_ref == NULL) return;
2849
xmlListDelete(list_ref);
2854
* @data: Contents of current link
2855
* @user: Value supplied by the user
2857
* Returns 0 to abort the walk or 1 to continue
2860
xmlWalkRemoveRef(const void *data, const void *user)
2862
xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2863
xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2864
xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2866
if (attr0 == attr1) { /* Matched: remove and terminate walk */
2867
xmlListRemoveFirst(ref_list, (void *)data);
2875
* @data0: Value supplied by the user
2876
* @data1: Value supplied by the user
2878
* Do nothing, return 0. Used to create unordered lists.
2881
xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2882
const void *data1 ATTRIBUTE_UNUSED)
2889
* @ctxt: the validation context
2890
* @doc: pointer to the document
2891
* @value: the value name
2892
* @attr: the attribute holding the Ref
2894
* Register a new ref declaration
2896
* Returns NULL if not, otherwise the new xmlRefPtr
2899
xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2902
xmlRefTablePtr table;
2903
xmlListPtr ref_list;
2908
if (value == NULL) {
2916
* Create the Ref table if needed.
2918
table = (xmlRefTablePtr) doc->refs;
2919
if (table == NULL) {
2920
doc->refs = table = xmlHashCreateDict(0, doc->dict);
2922
if (table == NULL) {
2924
"xmlAddRef: Table creation failed!\n");
2928
ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2930
xmlVErrMemory(ctxt, "malloc failed");
2935
* fill the structure.
2937
ret->value = xmlStrdup(value);
2938
if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2940
* Operating in streaming mode, attr is gonna disapear
2942
ret->name = xmlStrdup(attr->name);
2948
ret->lineno = xmlGetLineNo(attr->parent);
2950
/* To add a reference :-
2951
* References are maintained as a list of references,
2952
* Lookup the entry, if no entry create new nodelist
2953
* Add the owning node to the NodeList
2957
if (NULL == (ref_list = xmlHashLookup(table, value))) {
2958
if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
2959
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2960
"xmlAddRef: Reference list creation failed!\n",
2964
if (xmlHashAddEntry(table, value, ref_list) < 0) {
2965
xmlListDelete(ref_list);
2966
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2967
"xmlAddRef: Reference list insertion failed!\n",
2972
if (xmlListAppend(ref_list, ret) != 0) {
2973
xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2974
"xmlAddRef: Reference list insertion failed!\n",
2981
if (ret->value != NULL)
2982
xmlFree((char *)ret->value);
2983
if (ret->name != NULL)
2984
xmlFree((char *)ret->name);
2992
* @table: An ref table
2994
* Deallocate the memory used by an Ref hash table.
2997
xmlFreeRefTable(xmlRefTablePtr table) {
2998
xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
3003
* @doc: the document
3004
* @elem: the element carrying the attribute
3005
* @attr: the attribute
3007
* Determine whether an attribute is of type Ref. In case we have DTD(s)
3008
* then this is simple, otherwise we use an heuristic: name Ref (upper
3011
* Returns 0 or 1 depending on the lookup result
3014
xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
3019
if (doc == NULL) return(0);
3022
if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3024
} else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3028
xmlAttributePtr attrDecl;
3030
if (elem == NULL) return(0);
3031
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3032
if ((attrDecl == NULL) && (doc->extSubset != NULL))
3033
attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3034
elem->name, attr->name);
3036
if ((attrDecl != NULL) &&
3037
(attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3038
attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3046
* @doc: the document
3047
* @attr: the attribute
3049
* Remove the given attribute from the Ref table maintained internally.
3051
* Returns -1 if the lookup failed and 0 otherwise
3054
xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
3055
xmlListPtr ref_list;
3056
xmlRefTablePtr table;
3058
xmlRemoveMemo target;
3060
if (doc == NULL) return(-1);
3061
if (attr == NULL) return(-1);
3062
table = (xmlRefTablePtr) doc->refs;
3068
ID = xmlNodeListGetString(doc, attr->children, 1);
3071
ref_list = xmlHashLookup(table, ID);
3073
if(ref_list == NULL) {
3077
/* At this point, ref_list refers to a list of references which
3078
* have the same key as the supplied attr. Our list of references
3079
* is ordered by reference address and we don't have that information
3080
* here to use when removing. We'll have to walk the list and
3081
* check for a matching attribute, when we find one stop the walk
3082
* and remove the entry.
3083
* The list is ordered by reference, so that means we don't have the
3084
* key. Passing the list and the reference to the walker means we
3085
* will have enough data to be able to remove the entry.
3087
target.l = ref_list;
3090
/* Remove the supplied attr from our list */
3091
xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3093
/*If the list is empty then remove the list entry in the hash */
3094
if (xmlListEmpty(ref_list))
3095
xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
3103
* @doc: pointer to the document
3106
* Find the set of references for the supplied ID.
3108
* Returns NULL if not found, otherwise node set for the ID.
3111
xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
3112
xmlRefTablePtr table;
3122
table = (xmlRefTablePtr) doc->refs;
3126
return (xmlHashLookup(table, ID));
3129
/************************************************************************
3131
* Routines for validity checking *
3133
************************************************************************/
3136
* xmlGetDtdElementDesc:
3137
* @dtd: a pointer to the DtD to search
3138
* @name: the element name
3140
* Search the DTD for the description of this element
3142
* returns the xmlElementPtr if found or NULL
3146
xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3147
xmlElementTablePtr table;
3149
xmlChar *uqname = NULL, *prefix = NULL;
3151
if ((dtd == NULL) || (name == NULL)) return(NULL);
3152
if (dtd->elements == NULL)
3154
table = (xmlElementTablePtr) dtd->elements;
3156
uqname = xmlSplitQName2(name, &prefix);
3159
cur = xmlHashLookup2(table, name, prefix);
3160
if (prefix != NULL) xmlFree(prefix);
3161
if (uqname != NULL) xmlFree(uqname);
3165
* xmlGetDtdElementDesc2:
3166
* @dtd: a pointer to the DtD to search
3167
* @name: the element name
3168
* @create: create an empty description if not found
3170
* Search the DTD for the description of this element
3172
* returns the xmlElementPtr if found or NULL
3175
static xmlElementPtr
3176
xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3177
xmlElementTablePtr table;
3179
xmlChar *uqname = NULL, *prefix = NULL;
3181
if (dtd == NULL) return(NULL);
3182
if (dtd->elements == NULL) {
3183
xmlDictPtr dict = NULL;
3185
if (dtd->doc != NULL)
3186
dict = dtd->doc->dict;
3191
* Create the Element table if needed.
3193
table = (xmlElementTablePtr) dtd->elements;
3194
if (table == NULL) {
3195
table = xmlHashCreateDict(0, dict);
3196
dtd->elements = (void *) table;
3198
if (table == NULL) {
3199
xmlVErrMemory(NULL, "element table allocation failed");
3203
table = (xmlElementTablePtr) dtd->elements;
3205
uqname = xmlSplitQName2(name, &prefix);
3208
cur = xmlHashLookup2(table, name, prefix);
3209
if ((cur == NULL) && (create)) {
3210
cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3212
xmlVErrMemory(NULL, "malloc failed");
3215
memset(cur, 0, sizeof(xmlElement));
3216
cur->type = XML_ELEMENT_DECL;
3219
* fill the structure.
3221
cur->name = xmlStrdup(name);
3222
cur->prefix = xmlStrdup(prefix);
3223
cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3225
xmlHashAddEntry2(table, name, prefix, cur);
3227
if (prefix != NULL) xmlFree(prefix);
3228
if (uqname != NULL) xmlFree(uqname);
3233
* xmlGetDtdQElementDesc:
3234
* @dtd: a pointer to the DtD to search
3235
* @name: the element name
3236
* @prefix: the element namespace prefix
3238
* Search the DTD for the description of this element
3240
* returns the xmlElementPtr if found or NULL
3244
xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3245
const xmlChar *prefix) {
3246
xmlElementTablePtr table;
3248
if (dtd == NULL) return(NULL);
3249
if (dtd->elements == NULL) return(NULL);
3250
table = (xmlElementTablePtr) dtd->elements;
3252
return(xmlHashLookup2(table, name, prefix));
3256
* xmlGetDtdAttrDesc:
3257
* @dtd: a pointer to the DtD to search
3258
* @elem: the element name
3259
* @name: the attribute name
3261
* Search the DTD for the description of this attribute on
3264
* returns the xmlAttributePtr if found or NULL
3268
xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3269
xmlAttributeTablePtr table;
3270
xmlAttributePtr cur;
3271
xmlChar *uqname = NULL, *prefix = NULL;
3273
if (dtd == NULL) return(NULL);
3274
if (dtd->attributes == NULL) return(NULL);
3276
table = (xmlAttributeTablePtr) dtd->attributes;
3280
uqname = xmlSplitQName2(name, &prefix);
3282
if (uqname != NULL) {
3283
cur = xmlHashLookup3(table, uqname, prefix, elem);
3284
if (prefix != NULL) xmlFree(prefix);
3285
if (uqname != NULL) xmlFree(uqname);
3287
cur = xmlHashLookup3(table, name, NULL, elem);
3292
* xmlGetDtdQAttrDesc:
3293
* @dtd: a pointer to the DtD to search
3294
* @elem: the element name
3295
* @name: the attribute name
3296
* @prefix: the attribute namespace prefix
3298
* Search the DTD for the description of this qualified attribute on
3301
* returns the xmlAttributePtr if found or NULL
3305
xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3306
const xmlChar *prefix) {
3307
xmlAttributeTablePtr table;
3309
if (dtd == NULL) return(NULL);
3310
if (dtd->attributes == NULL) return(NULL);
3311
table = (xmlAttributeTablePtr) dtd->attributes;
3313
return(xmlHashLookup3(table, name, prefix, elem));
3317
* xmlGetDtdNotationDesc:
3318
* @dtd: a pointer to the DtD to search
3319
* @name: the notation name
3321
* Search the DTD for the description of this notation
3323
* returns the xmlNotationPtr if found or NULL
3327
xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3328
xmlNotationTablePtr table;
3330
if (dtd == NULL) return(NULL);
3331
if (dtd->notations == NULL) return(NULL);
3332
table = (xmlNotationTablePtr) dtd->notations;
3334
return(xmlHashLookup(table, name));
3337
#if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3339
* xmlValidateNotationUse:
3340
* @ctxt: the validation context
3341
* @doc: the document
3342
* @notationName: the notation name to check
3344
* Validate that the given name match a notation declaration.
3345
* - [ VC: Notation Declared ]
3347
* returns 1 if valid or 0 otherwise
3351
xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3352
const xmlChar *notationName) {
3353
xmlNotationPtr notaDecl;
3354
if ((doc == NULL) || (doc->intSubset == NULL) ||
3355
(notationName == NULL)) return(-1);
3357
notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3358
if ((notaDecl == NULL) && (doc->extSubset != NULL))
3359
notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3361
if ((notaDecl == NULL) && (ctxt != NULL)) {
3362
xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3363
"NOTATION %s is not declared\n",
3364
notationName, NULL, NULL);
3369
#endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3372
* xmlIsMixedElement:
3373
* @doc: the document
3374
* @name: the element name
3376
* Search in the DtDs whether an element accept Mixed content (or ANY)
3377
* basically if it is supposed to accept text childs
3379
* returns 0 if no, 1 if yes, and -1 if no element description is available
3383
xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3384
xmlElementPtr elemDecl;
3386
if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3388
elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3389
if ((elemDecl == NULL) && (doc->extSubset != NULL))
3390
elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3391
if (elemDecl == NULL) return(-1);
3392
switch (elemDecl->etype) {
3393
case XML_ELEMENT_TYPE_UNDEFINED:
3395
case XML_ELEMENT_TYPE_ELEMENT:
3397
case XML_ELEMENT_TYPE_EMPTY:
3399
* return 1 for EMPTY since we want VC error to pop up
3400
* on <empty> </empty> for example
3402
case XML_ELEMENT_TYPE_ANY:
3403
case XML_ELEMENT_TYPE_MIXED:
3409
#ifdef LIBXML_VALID_ENABLED
3412
xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3413
if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3415
* Use the new checks of production [4] [4a] amd [5] of the
3416
* Update 5 of XML-1.0
3418
if (((c >= 'a') && (c <= 'z')) ||
3419
((c >= 'A') && (c <= 'Z')) ||
3420
(c == '_') || (c == ':') ||
3421
((c >= 0xC0) && (c <= 0xD6)) ||
3422
((c >= 0xD8) && (c <= 0xF6)) ||
3423
((c >= 0xF8) && (c <= 0x2FF)) ||
3424
((c >= 0x370) && (c <= 0x37D)) ||
3425
((c >= 0x37F) && (c <= 0x1FFF)) ||
3426
((c >= 0x200C) && (c <= 0x200D)) ||
3427
((c >= 0x2070) && (c <= 0x218F)) ||
3428
((c >= 0x2C00) && (c <= 0x2FEF)) ||
3429
((c >= 0x3001) && (c <= 0xD7FF)) ||
3430
((c >= 0xF900) && (c <= 0xFDCF)) ||
3431
((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3432
((c >= 0x10000) && (c <= 0xEFFFF)))
3435
if (IS_LETTER(c) || (c == '_') || (c == ':'))
3442
xmlIsDocNameChar(xmlDocPtr doc, int c) {
3443
if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3445
* Use the new checks of production [4] [4a] amd [5] of the
3446
* Update 5 of XML-1.0
3448
if (((c >= 'a') && (c <= 'z')) ||
3449
((c >= 'A') && (c <= 'Z')) ||
3450
((c >= '0') && (c <= '9')) || /* !start */
3451
(c == '_') || (c == ':') ||
3452
(c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3453
((c >= 0xC0) && (c <= 0xD6)) ||
3454
((c >= 0xD8) && (c <= 0xF6)) ||
3455
((c >= 0xF8) && (c <= 0x2FF)) ||
3456
((c >= 0x300) && (c <= 0x36F)) || /* !start */
3457
((c >= 0x370) && (c <= 0x37D)) ||
3458
((c >= 0x37F) && (c <= 0x1FFF)) ||
3459
((c >= 0x200C) && (c <= 0x200D)) ||
3460
((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3461
((c >= 0x2070) && (c <= 0x218F)) ||
3462
((c >= 0x2C00) && (c <= 0x2FEF)) ||
3463
((c >= 0x3001) && (c <= 0xD7FF)) ||
3464
((c >= 0xF900) && (c <= 0xFDCF)) ||
3465
((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3466
((c >= 0x10000) && (c <= 0xEFFFF)))
3469
if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3470
(c == '.') || (c == '-') ||
3471
(c == '_') || (c == ':') ||
3472
(IS_COMBINING(c)) ||
3480
* xmlValidateNameValue:
3481
* @doc: pointer to the document or NULL
3482
* @value: an Name value
3484
* Validate that the given value match Name production
3486
* returns 1 if valid or 0 otherwise
3490
xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3494
if (value == NULL) return(0);
3496
val = xmlStringCurrentChar(NULL, cur, &len);
3498
if (!xmlIsDocNameStartChar(doc, val))
3501
val = xmlStringCurrentChar(NULL, cur, &len);
3503
while (xmlIsDocNameChar(doc, val)) {
3504
val = xmlStringCurrentChar(NULL, cur, &len);
3508
if (val != 0) return(0);
3514
* xmlValidateNameValue:
3515
* @value: an Name value
3517
* Validate that the given value match Name production
3519
* returns 1 if valid or 0 otherwise
3523
xmlValidateNameValue(const xmlChar *value) {
3524
return(xmlValidateNameValueInternal(NULL, value));
3528
* xmlValidateNamesValueInternal:
3529
* @doc: pointer to the document or NULL
3530
* @value: an Names value
3532
* Validate that the given value match Names production
3534
* returns 1 if valid or 0 otherwise
3538
xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3542
if (value == NULL) return(0);
3544
val = xmlStringCurrentChar(NULL, cur, &len);
3547
if (!xmlIsDocNameStartChar(doc, val))
3550
val = xmlStringCurrentChar(NULL, cur, &len);
3552
while (xmlIsDocNameChar(doc, val)) {
3553
val = xmlStringCurrentChar(NULL, cur, &len);
3557
/* Should not test IS_BLANK(val) here -- see erratum E20*/
3558
while (val == 0x20) {
3559
while (val == 0x20) {
3560
val = xmlStringCurrentChar(NULL, cur, &len);
3564
if (!xmlIsDocNameStartChar(doc, val))
3567
val = xmlStringCurrentChar(NULL, cur, &len);
3570
while (xmlIsDocNameChar(doc, val)) {
3571
val = xmlStringCurrentChar(NULL, cur, &len);
3576
if (val != 0) return(0);
3582
* xmlValidateNamesValue:
3583
* @value: an Names value
3585
* Validate that the given value match Names production
3587
* returns 1 if valid or 0 otherwise
3591
xmlValidateNamesValue(const xmlChar *value) {
3592
return(xmlValidateNamesValueInternal(NULL, value));
3596
* xmlValidateNmtokenValueInternal:
3597
* @doc: pointer to the document or NULL
3598
* @value: an Nmtoken value
3600
* Validate that the given value match Nmtoken production
3602
* [ VC: Name Token ]
3604
* returns 1 if valid or 0 otherwise
3608
xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3612
if (value == NULL) return(0);
3614
val = xmlStringCurrentChar(NULL, cur, &len);
3617
if (!xmlIsDocNameChar(doc, val))
3620
val = xmlStringCurrentChar(NULL, cur, &len);
3622
while (xmlIsDocNameChar(doc, val)) {
3623
val = xmlStringCurrentChar(NULL, cur, &len);
3627
if (val != 0) return(0);
3633
* xmlValidateNmtokenValue:
3634
* @value: an Nmtoken value
3636
* Validate that the given value match Nmtoken production
3638
* [ VC: Name Token ]
3640
* returns 1 if valid or 0 otherwise
3644
xmlValidateNmtokenValue(const xmlChar *value) {
3645
return(xmlValidateNmtokenValueInternal(NULL, value));
3649
* xmlValidateNmtokensValueInternal:
3650
* @doc: pointer to the document or NULL
3651
* @value: an Nmtokens value
3653
* Validate that the given value match Nmtokens production
3655
* [ VC: Name Token ]
3657
* returns 1 if valid or 0 otherwise
3661
xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3665
if (value == NULL) return(0);
3667
val = xmlStringCurrentChar(NULL, cur, &len);
3670
while (IS_BLANK(val)) {
3671
val = xmlStringCurrentChar(NULL, cur, &len);
3675
if (!xmlIsDocNameChar(doc, val))
3678
while (xmlIsDocNameChar(doc, val)) {
3679
val = xmlStringCurrentChar(NULL, cur, &len);
3683
/* Should not test IS_BLANK(val) here -- see erratum E20*/
3684
while (val == 0x20) {
3685
while (val == 0x20) {
3686
val = xmlStringCurrentChar(NULL, cur, &len);
3689
if (val == 0) return(1);
3691
if (!xmlIsDocNameChar(doc, val))
3694
val = xmlStringCurrentChar(NULL, cur, &len);
3697
while (xmlIsDocNameChar(doc, val)) {
3698
val = xmlStringCurrentChar(NULL, cur, &len);
3703
if (val != 0) return(0);
3709
* xmlValidateNmtokensValue:
3710
* @value: an Nmtokens value
3712
* Validate that the given value match Nmtokens production
3714
* [ VC: Name Token ]
3716
* returns 1 if valid or 0 otherwise
3720
xmlValidateNmtokensValue(const xmlChar *value) {
3721
return(xmlValidateNmtokensValueInternal(NULL, value));
3725
* xmlValidateNotationDecl:
3726
* @ctxt: the validation context
3727
* @doc: a document instance
3728
* @nota: a notation definition
3730
* Try to validate a single notation definition
3731
* basically it does the following checks as described by the
3732
* XML-1.0 recommendation:
3733
* - it seems that no validity constraint exists on notation declarations
3734
* But this function get called anyway ...
3736
* returns 1 if valid or 0 otherwise
3740
xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3741
xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3748
* xmlValidateAttributeValueInternal:
3749
* @doc: the document
3750
* @type: an attribute type
3751
* @value: an attribute value
3753
* Validate that the given attribute value match the proper production
3755
* returns 1 if valid or 0 otherwise
3759
xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3760
const xmlChar *value) {
3762
case XML_ATTRIBUTE_ENTITIES:
3763
case XML_ATTRIBUTE_IDREFS:
3764
return(xmlValidateNamesValueInternal(doc, value));
3765
case XML_ATTRIBUTE_ENTITY:
3766
case XML_ATTRIBUTE_IDREF:
3767
case XML_ATTRIBUTE_ID:
3768
case XML_ATTRIBUTE_NOTATION:
3769
return(xmlValidateNameValueInternal(doc, value));
3770
case XML_ATTRIBUTE_NMTOKENS:
3771
case XML_ATTRIBUTE_ENUMERATION:
3772
return(xmlValidateNmtokensValueInternal(doc, value));
3773
case XML_ATTRIBUTE_NMTOKEN:
3774
return(xmlValidateNmtokenValueInternal(doc, value));
3775
case XML_ATTRIBUTE_CDATA:
3782
* xmlValidateAttributeValue:
3783
* @type: an attribute type
3784
* @value: an attribute value
3786
* Validate that the given attribute value match the proper production
3789
* Values of type ID must match the Name production....
3792
* Values of type IDREF must match the Name production, and values
3793
* of type IDREFS must match Names ...
3795
* [ VC: Entity Name ]
3796
* Values of type ENTITY must match the Name production, values
3797
* of type ENTITIES must match Names ...
3799
* [ VC: Name Token ]
3800
* Values of type NMTOKEN must match the Nmtoken production; values
3801
* of type NMTOKENS must match Nmtokens.
3803
* returns 1 if valid or 0 otherwise
3806
xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3807
return(xmlValidateAttributeValueInternal(NULL, type, value));
3811
* xmlValidateAttributeValue2:
3812
* @ctxt: the validation context
3813
* @doc: the document
3814
* @name: the attribute name (used for error reporting only)
3815
* @type: the attribute type
3816
* @value: the attribute value
3818
* Validate that the given attribute value match a given type.
3819
* This typically cannot be done before having finished parsing
3823
* Values of type IDREF must match one of the declared IDs
3824
* Values of type IDREFS must match a sequence of the declared IDs
3825
* each Name must match the value of an ID attribute on some element
3826
* in the XML document; i.e. IDREF values must match the value of
3829
* [ VC: Entity Name ]
3830
* Values of type ENTITY must match one declared entity
3831
* Values of type ENTITIES must match a sequence of declared entities
3833
* [ VC: Notation Attributes ]
3834
* all notation names in the declaration must be declared.
3836
* returns 1 if valid or 0 otherwise
3840
xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3841
const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3844
case XML_ATTRIBUTE_IDREFS:
3845
case XML_ATTRIBUTE_IDREF:
3846
case XML_ATTRIBUTE_ID:
3847
case XML_ATTRIBUTE_NMTOKENS:
3848
case XML_ATTRIBUTE_ENUMERATION:
3849
case XML_ATTRIBUTE_NMTOKEN:
3850
case XML_ATTRIBUTE_CDATA:
3852
case XML_ATTRIBUTE_ENTITY: {
3855
ent = xmlGetDocEntity(doc, value);
3856
/* yeah it's a bit messy... */
3857
if ((ent == NULL) && (doc->standalone == 1)) {
3858
doc->standalone = 0;
3859
ent = xmlGetDocEntity(doc, value);
3862
xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3863
XML_DTD_UNKNOWN_ENTITY,
3864
"ENTITY attribute %s reference an unknown entity \"%s\"\n",
3867
} else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3868
xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3869
XML_DTD_ENTITY_TYPE,
3870
"ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3876
case XML_ATTRIBUTE_ENTITIES: {
3877
xmlChar *dup, *nam = NULL, *cur, save;
3880
dup = xmlStrdup(value);
3886
while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
3889
ent = xmlGetDocEntity(doc, nam);
3891
xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3892
XML_DTD_UNKNOWN_ENTITY,
3893
"ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3896
} else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3897
xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3898
XML_DTD_ENTITY_TYPE,
3899
"ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3906
while (IS_BLANK_CH(*cur)) cur++;
3911
case XML_ATTRIBUTE_NOTATION: {
3912
xmlNotationPtr nota;
3914
nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3915
if ((nota == NULL) && (doc->extSubset != NULL))
3916
nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3919
xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3920
XML_DTD_UNKNOWN_NOTATION,
3921
"NOTATION attribute %s reference an unknown notation \"%s\"\n",
3932
* xmlValidCtxtNormalizeAttributeValue:
3933
* @ctxt: the validation context
3934
* @doc: the document
3936
* @name: the attribute name
3937
* @value: the attribute value
3938
* @ctxt: the validation context or NULL
3940
* Does the validation related extra step of the normalization of attribute
3943
* If the declared value is not CDATA, then the XML processor must further
3944
* process the normalized attribute value by discarding any leading and
3945
* trailing space (#x20) characters, and by replacing sequences of space
3946
* (#x20) characters by single space (#x20) character.
3948
* Also check VC: Standalone Document Declaration in P32, and update
3949
* ctxt->valid accordingly
3951
* returns a new normalized string if normalization is needed, NULL otherwise
3952
* the caller must free the returned value.
3956
xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3957
xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3960
xmlAttributePtr attrDecl = NULL;
3963
if (doc == NULL) return(NULL);
3964
if (elem == NULL) return(NULL);
3965
if (name == NULL) return(NULL);
3966
if (value == NULL) return(NULL);
3968
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3972
fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3973
if (fullname == NULL)
3975
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
3976
if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3977
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3978
if (attrDecl != NULL)
3981
if ((fullname != fn) && (fullname != elem->name))
3984
if ((attrDecl == NULL) && (doc->intSubset != NULL))
3985
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3986
if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3987
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3988
if (attrDecl != NULL)
3992
if (attrDecl == NULL)
3994
if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3997
ret = xmlStrdup(value);
4002
while (*src == 0x20) src++;
4005
while (*src == 0x20) src++;
4013
if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4014
xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4015
"standalone: %s on %s value had to be normalized based on external subset declaration\n",
4016
name, elem->name, NULL);
4023
* xmlValidNormalizeAttributeValue:
4024
* @doc: the document
4026
* @name: the attribute name
4027
* @value: the attribute value
4029
* Does the validation related extra step of the normalization of attribute
4032
* If the declared value is not CDATA, then the XML processor must further
4033
* process the normalized attribute value by discarding any leading and
4034
* trailing space (#x20) characters, and by replacing sequences of space
4035
* (#x20) characters by single space (#x20) character.
4037
* Returns a new normalized string if normalization is needed, NULL otherwise
4038
* the caller must free the returned value.
4042
xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4043
const xmlChar *name, const xmlChar *value) {
4046
xmlAttributePtr attrDecl = NULL;
4048
if (doc == NULL) return(NULL);
4049
if (elem == NULL) return(NULL);
4050
if (name == NULL) return(NULL);
4051
if (value == NULL) return(NULL);
4053
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4057
fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4058
if (fullname == NULL)
4060
if ((fullname != fn) && (fullname != elem->name))
4063
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4064
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4065
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4067
if (attrDecl == NULL)
4069
if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4072
ret = xmlStrdup(value);
4077
while (*src == 0x20) src++;
4080
while (*src == 0x20) src++;
4092
xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
4093
const xmlChar* name ATTRIBUTE_UNUSED) {
4094
if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4098
* xmlValidateAttributeDecl:
4099
* @ctxt: the validation context
4100
* @doc: a document instance
4101
* @attr: an attribute definition
4103
* Try to validate a single attribute definition
4104
* basically it does the following checks as described by the
4105
* XML-1.0 recommendation:
4106
* - [ VC: Attribute Default Legal ]
4107
* - [ VC: Enumeration ]
4108
* - [ VC: ID Attribute Default ]
4110
* The ID/IDREF uniqueness and matching are done separately
4112
* returns 1 if valid or 0 otherwise
4116
xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4117
xmlAttributePtr attr) {
4121
if(attr == NULL) return(1);
4123
/* Attribute Default Legal */
4125
if (attr->defaultValue != NULL) {
4126
val = xmlValidateAttributeValueInternal(doc, attr->atype,
4127
attr->defaultValue);
4129
xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4130
"Syntax of default value for attribute %s of %s is not valid\n",
4131
attr->name, attr->elem, NULL);
4136
/* ID Attribute Default */
4137
if ((attr->atype == XML_ATTRIBUTE_ID)&&
4138
(attr->def != XML_ATTRIBUTE_IMPLIED) &&
4139
(attr->def != XML_ATTRIBUTE_REQUIRED)) {
4140
xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4141
"ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4142
attr->name, attr->elem, NULL);
4146
/* One ID per Element Type */
4147
if (attr->atype == XML_ATTRIBUTE_ID) {
4150
/* the trick is that we parse DtD as their own internal subset */
4151
xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4154
nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4156
xmlAttributeTablePtr table;
4159
* The attribute may be declared in the internal subset and the
4160
* element in the external subset.
4163
if (doc->intSubset != NULL) {
4164
table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4165
xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
4166
xmlValidateAttributeIdCallback, &nbId);
4171
xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4172
"Element %s has %d ID attribute defined in the internal subset : %s\n",
4173
attr->elem, nbId, attr->name);
4174
} else if (doc->extSubset != NULL) {
4176
elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4178
extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4181
xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4182
"Element %s has %d ID attribute defined in the external subset : %s\n",
4183
attr->elem, extId, attr->name);
4184
} else if (extId + nbId > 1) {
4185
xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4186
"Element %s has ID attributes defined in the internal and external subset : %s\n",
4187
attr->elem, attr->name, NULL);
4192
/* Validity Constraint: Enumeration */
4193
if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4194
xmlEnumerationPtr tree = attr->tree;
4195
while (tree != NULL) {
4196
if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4200
xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4201
"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4202
attr->defaultValue, attr->name, attr->elem);
4211
* xmlValidateElementDecl:
4212
* @ctxt: the validation context
4213
* @doc: a document instance
4214
* @elem: an element definition
4216
* Try to validate a single element definition
4217
* basically it does the following checks as described by the
4218
* XML-1.0 recommendation:
4219
* - [ VC: One ID per Element Type ]
4220
* - [ VC: No Duplicate Types ]
4221
* - [ VC: Unique Element Type Declaration ]
4223
* returns 1 if valid or 0 otherwise
4227
xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4228
xmlElementPtr elem) {
4234
if (elem == NULL) return(1);
4237
#ifdef LIBXML_REGEXP_ENABLED
4238
/* Build the regexp associated to the content model */
4239
ret = xmlValidBuildContentModel(ctxt, elem);
4243
/* No Duplicate Types */
4244
if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4245
xmlElementContentPtr cur, next;
4246
const xmlChar *name;
4248
cur = elem->content;
4249
while (cur != NULL) {
4250
if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4251
if (cur->c1 == NULL) break;
4252
if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4253
name = cur->c1->name;
4255
while (next != NULL) {
4256
if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4257
if ((xmlStrEqual(next->name, name)) &&
4258
(xmlStrEqual(next->prefix, cur->c1->prefix))) {
4259
if (cur->c1->prefix == NULL) {
4260
xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4261
"Definition of %s has duplicate references of %s\n",
4262
elem->name, name, NULL);
4264
xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4265
"Definition of %s has duplicate references of %s:%s\n",
4266
elem->name, cur->c1->prefix, name);
4272
if (next->c1 == NULL) break;
4273
if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4274
if ((xmlStrEqual(next->c1->name, name)) &&
4275
(xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4276
if (cur->c1->prefix == NULL) {
4277
xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4278
"Definition of %s has duplicate references to %s\n",
4279
elem->name, name, NULL);
4281
xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4282
"Definition of %s has duplicate references to %s:%s\n",
4283
elem->name, cur->c1->prefix, name);
4294
/* VC: Unique Element Type Declaration */
4295
tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4296
if ((tst != NULL ) && (tst != elem) &&
4297
((tst->prefix == elem->prefix) ||
4298
(xmlStrEqual(tst->prefix, elem->prefix))) &&
4299
(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4300
xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4301
"Redefinition of element %s\n",
4302
elem->name, NULL, NULL);
4305
tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4306
if ((tst != NULL ) && (tst != elem) &&
4307
((tst->prefix == elem->prefix) ||
4308
(xmlStrEqual(tst->prefix, elem->prefix))) &&
4309
(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4310
xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4311
"Redefinition of element %s\n",
4312
elem->name, NULL, NULL);
4315
/* One ID per Element Type
4316
* already done when registering the attribute
4317
if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4324
* xmlValidateOneAttribute:
4325
* @ctxt: the validation context
4326
* @doc: a document instance
4327
* @elem: an element instance
4328
* @attr: an attribute instance
4329
* @value: the attribute value (without entities processing)
4331
* Try to validate a single attribute for an element
4332
* basically it does the following checks as described by the
4333
* XML-1.0 recommendation:
4334
* - [ VC: Attribute Value Type ]
4335
* - [ VC: Fixed Attribute Default ]
4336
* - [ VC: Entity Name ]
4337
* - [ VC: Name Token ]
4340
* - [ VC: Entity Name ]
4341
* - [ VC: Notation Attributes ]
4343
* The ID/IDREF uniqueness and matching are done separately
4345
* returns 1 if valid or 0 otherwise
4349
xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4350
xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4352
xmlAttributePtr attrDecl = NULL;
4357
if ((elem == NULL) || (elem->name == NULL)) return(0);
4358
if ((attr == NULL) || (attr->name == NULL)) return(0);
4360
if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4364
fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4365
if (fullname == NULL)
4367
if (attr->ns != NULL) {
4368
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4369
attr->name, attr->ns->prefix);
4370
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4371
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4372
attr->name, attr->ns->prefix);
4374
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4375
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4376
attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4377
fullname, attr->name);
4379
if ((fullname != fn) && (fullname != elem->name))
4382
if (attrDecl == NULL) {
4383
if (attr->ns != NULL) {
4384
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4385
attr->name, attr->ns->prefix);
4386
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4387
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4388
attr->name, attr->ns->prefix);
4390
attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4391
elem->name, attr->name);
4392
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4393
attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4394
elem->name, attr->name);
4399
/* Validity Constraint: Attribute Value Type */
4400
if (attrDecl == NULL) {
4401
xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4402
"No declaration for attribute %s of element %s\n",
4403
attr->name, elem->name, NULL);
4406
attr->atype = attrDecl->atype;
4408
val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4410
xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4411
"Syntax of value for attribute %s of %s is not valid\n",
4412
attr->name, elem->name, NULL);
4416
/* Validity constraint: Fixed Attribute Default */
4417
if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4418
if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4419
xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4420
"Value for attribute %s of %s is different from default \"%s\"\n",
4421
attr->name, elem->name, attrDecl->defaultValue);
4426
/* Validity Constraint: ID uniqueness */
4427
if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4428
if (xmlAddID(ctxt, doc, value, attr) == NULL)
4432
if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4433
(attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4434
if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4438
/* Validity Constraint: Notation Attributes */
4439
if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4440
xmlEnumerationPtr tree = attrDecl->tree;
4441
xmlNotationPtr nota;
4443
/* First check that the given NOTATION was declared */
4444
nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4446
nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4449
xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4450
"Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4451
value, attr->name, elem->name);
4455
/* Second, verify that it's among the list */
4456
while (tree != NULL) {
4457
if (xmlStrEqual(tree->name, value)) break;
4461
xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4462
"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4463
value, attr->name, elem->name);
4468
/* Validity Constraint: Enumeration */
4469
if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4470
xmlEnumerationPtr tree = attrDecl->tree;
4471
while (tree != NULL) {
4472
if (xmlStrEqual(tree->name, value)) break;
4476
xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4477
"Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4478
value, attr->name, elem->name);
4483
/* Fixed Attribute Default */
4484
if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4485
(!xmlStrEqual(attrDecl->defaultValue, value))) {
4486
xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4487
"Value for attribute %s of %s must be \"%s\"\n",
4488
attr->name, elem->name, attrDecl->defaultValue);
4492
/* Extra check for the attribute value */
4493
ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4494
attrDecl->atype, value);
4500
* xmlValidateOneNamespace:
4501
* @ctxt: the validation context
4502
* @doc: a document instance
4503
* @elem: an element instance
4504
* @prefix: the namespace prefix
4505
* @ns: an namespace declaration instance
4506
* @value: the attribute value (without entities processing)
4508
* Try to validate a single namespace declaration for an element
4509
* basically it does the following checks as described by the
4510
* XML-1.0 recommendation:
4511
* - [ VC: Attribute Value Type ]
4512
* - [ VC: Fixed Attribute Default ]
4513
* - [ VC: Entity Name ]
4514
* - [ VC: Name Token ]
4517
* - [ VC: Entity Name ]
4518
* - [ VC: Notation Attributes ]
4520
* The ID/IDREF uniqueness and matching are done separately
4522
* returns 1 if valid or 0 otherwise
4526
xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4527
xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4528
/* xmlElementPtr elemDecl; */
4529
xmlAttributePtr attrDecl = NULL;
4534
if ((elem == NULL) || (elem->name == NULL)) return(0);
4535
if ((ns == NULL) || (ns->href == NULL)) return(0);
4537
if (prefix != NULL) {
4541
fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4542
if (fullname == NULL) {
4543
xmlVErrMemory(ctxt, "Validating namespace");
4546
if (ns->prefix != NULL) {
4547
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4548
ns->prefix, BAD_CAST "xmlns");
4549
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4550
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4551
ns->prefix, BAD_CAST "xmlns");
4553
attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4555
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4556
attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4559
if ((fullname != fn) && (fullname != elem->name))
4562
if (attrDecl == NULL) {
4563
if (ns->prefix != NULL) {
4564
attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4565
ns->prefix, BAD_CAST "xmlns");
4566
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4567
attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4568
ns->prefix, BAD_CAST "xmlns");
4570
attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4571
elem->name, BAD_CAST "xmlns");
4572
if ((attrDecl == NULL) && (doc->extSubset != NULL))
4573
attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4574
elem->name, BAD_CAST "xmlns");
4579
/* Validity Constraint: Attribute Value Type */
4580
if (attrDecl == NULL) {
4581
if (ns->prefix != NULL) {
4582
xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4583
"No declaration for attribute xmlns:%s of element %s\n",
4584
ns->prefix, elem->name, NULL);
4586
xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4587
"No declaration for attribute xmlns of element %s\n",
4588
elem->name, NULL, NULL);
4593
val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4595
if (ns->prefix != NULL) {
4596
xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4597
"Syntax of value for attribute xmlns:%s of %s is not valid\n",
4598
ns->prefix, elem->name, NULL);
4600
xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4601
"Syntax of value for attribute xmlns of %s is not valid\n",
4602
elem->name, NULL, NULL);
4607
/* Validity constraint: Fixed Attribute Default */
4608
if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4609
if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4610
if (ns->prefix != NULL) {
4611
xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4612
"Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4613
ns->prefix, elem->name, attrDecl->defaultValue);
4615
xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4616
"Value for attribute xmlns of %s is different from default \"%s\"\n",
4617
elem->name, attrDecl->defaultValue, NULL);
4623
/* Validity Constraint: ID uniqueness */
4624
if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4625
if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4629
if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4630
(attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4631
if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4635
/* Validity Constraint: Notation Attributes */
4636
if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4637
xmlEnumerationPtr tree = attrDecl->tree;
4638
xmlNotationPtr nota;
4640
/* First check that the given NOTATION was declared */
4641
nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4643
nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4646
if (ns->prefix != NULL) {
4647
xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4648
"Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4649
value, ns->prefix, elem->name);
4651
xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4652
"Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4653
value, elem->name, NULL);
4658
/* Second, verify that it's among the list */
4659
while (tree != NULL) {
4660
if (xmlStrEqual(tree->name, value)) break;
4664
if (ns->prefix != NULL) {
4665
xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4666
"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4667
value, ns->prefix, elem->name);
4669
xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4670
"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4671
value, elem->name, NULL);
4677
/* Validity Constraint: Enumeration */
4678
if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4679
xmlEnumerationPtr tree = attrDecl->tree;
4680
while (tree != NULL) {
4681
if (xmlStrEqual(tree->name, value)) break;
4685
if (ns->prefix != NULL) {
4686
xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4687
"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4688
value, ns->prefix, elem->name);
4690
xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4691
"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4692
value, elem->name, NULL);
4698
/* Fixed Attribute Default */
4699
if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4700
(!xmlStrEqual(attrDecl->defaultValue, value))) {
4701
if (ns->prefix != NULL) {
4702
xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4703
"Value for attribute xmlns:%s of %s must be \"%s\"\n",
4704
ns->prefix, elem->name, attrDecl->defaultValue);
4706
xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4707
"Value for attribute xmlns of %s must be \"%s\"\n",
4708
elem->name, attrDecl->defaultValue, NULL);
4713
/* Extra check for the attribute value */
4714
if (ns->prefix != NULL) {
4715
ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4716
attrDecl->atype, value);
4718
ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4719
attrDecl->atype, value);
4725
#ifndef LIBXML_REGEXP_ENABLED
4727
* xmlValidateSkipIgnorable:
4728
* @ctxt: the validation context
4729
* @child: the child list
4731
* Skip ignorable elements w.r.t. the validation process
4733
* returns the first element to consider for validation of the content model
4737
xmlValidateSkipIgnorable(xmlNodePtr child) {
4738
while (child != NULL) {
4739
switch (child->type) {
4740
/* These things are ignored (skipped) during validation. */
4742
case XML_COMMENT_NODE:
4743
case XML_XINCLUDE_START:
4744
case XML_XINCLUDE_END:
4745
child = child->next;
4748
if (xmlIsBlankNode(child))
4749
child = child->next;
4753
/* keep current node */
4762
* xmlValidateElementType:
4763
* @ctxt: the validation context
4765
* Try to validate the content model of an element internal function
4767
* returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4768
* reference is found and -3 if the validation succeeded but
4769
* the content model is not determinist.
4773
xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4775
int determinist = 1;
4777
NODE = xmlValidateSkipIgnorable(NODE);
4778
if ((NODE == NULL) && (CONT == NULL))
4780
if ((NODE == NULL) &&
4781
((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4782
(CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4785
if (CONT == NULL) return(-1);
4786
if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4790
* We arrive here when more states need to be examined
4795
* We just recovered from a rollback generated by a possible
4796
* epsilon transition, go directly to the analysis phase
4798
if (STATE == ROLLBACK_PARENT) {
4799
DEBUG_VALID_MSG("restored parent branch");
4800
DEBUG_VALID_STATE(NODE, CONT)
4805
DEBUG_VALID_STATE(NODE, CONT)
4807
* we may have to save a backup state here. This is the equivalent
4808
* of handling epsilon transition in NFAs.
4810
if ((CONT != NULL) &&
4811
((CONT->parent == NULL) ||
4812
(CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4813
((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4814
(CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4815
((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4816
DEBUG_VALID_MSG("saving parent branch");
4817
if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4823
* Check first if the content matches
4825
switch (CONT->type) {
4826
case XML_ELEMENT_CONTENT_PCDATA:
4828
DEBUG_VALID_MSG("pcdata failed no node");
4832
if (NODE->type == XML_TEXT_NODE) {
4833
DEBUG_VALID_MSG("pcdata found, skip to next");
4835
* go to next element in the content model
4836
* skipping ignorable elems
4840
NODE = xmlValidateSkipIgnorable(NODE);
4841
if ((NODE != NULL) &&
4842
(NODE->type == XML_ENTITY_REF_NODE))
4844
} while ((NODE != NULL) &&
4845
((NODE->type != XML_ELEMENT_NODE) &&
4846
(NODE->type != XML_TEXT_NODE) &&
4847
(NODE->type != XML_CDATA_SECTION_NODE)));
4851
DEBUG_VALID_MSG("pcdata failed");
4856
case XML_ELEMENT_CONTENT_ELEMENT:
4858
DEBUG_VALID_MSG("element failed no node");
4862
ret = ((NODE->type == XML_ELEMENT_NODE) &&
4863
(xmlStrEqual(NODE->name, CONT->name)));
4865
if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4866
ret = (CONT->prefix == NULL);
4867
} else if (CONT->prefix == NULL) {
4870
ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4874
DEBUG_VALID_MSG("element found, skip to next");
4876
* go to next element in the content model
4877
* skipping ignorable elems
4881
NODE = xmlValidateSkipIgnorable(NODE);
4882
if ((NODE != NULL) &&
4883
(NODE->type == XML_ENTITY_REF_NODE))
4885
} while ((NODE != NULL) &&
4886
((NODE->type != XML_ELEMENT_NODE) &&
4887
(NODE->type != XML_TEXT_NODE) &&
4888
(NODE->type != XML_CDATA_SECTION_NODE)));
4890
DEBUG_VALID_MSG("element failed");
4895
case XML_ELEMENT_CONTENT_OR:
4897
* Small optimization.
4899
if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4900
if ((NODE == NULL) ||
4901
(!xmlStrEqual(NODE->name, CONT->c1->name))) {
4906
if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4907
ret = (CONT->c1->prefix == NULL);
4908
} else if (CONT->c1->prefix == NULL) {
4911
ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4921
* save the second branch 'or' branch
4923
DEBUG_VALID_MSG("saving 'or' branch");
4924
if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4925
OCCURS, ROLLBACK_OR) < 0)
4930
case XML_ELEMENT_CONTENT_SEQ:
4932
* Small optimization.
4934
if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4935
((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4936
(CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4937
if ((NODE == NULL) ||
4938
(!xmlStrEqual(NODE->name, CONT->c1->name))) {
4943
if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4944
ret = (CONT->c1->prefix == NULL);
4945
} else if (CONT->c1->prefix == NULL) {
4948
ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4962
* At this point handle going up in the tree
4965
DEBUG_VALID_MSG("error found returning");
4969
while (CONT != NULL) {
4971
* First do the analysis depending on the occurrence model at
4975
switch (CONT->ocur) {
4978
case XML_ELEMENT_CONTENT_ONCE:
4979
cur = ctxt->vstate->node;
4980
DEBUG_VALID_MSG("Once branch failed, rollback");
4981
if (vstateVPop(ctxt) < 0 ) {
4982
DEBUG_VALID_MSG("exhaustion, failed");
4985
if (cur != ctxt->vstate->node)
4988
case XML_ELEMENT_CONTENT_PLUS:
4989
if (OCCURRENCE == 0) {
4990
cur = ctxt->vstate->node;
4991
DEBUG_VALID_MSG("Plus branch failed, rollback");
4992
if (vstateVPop(ctxt) < 0 ) {
4993
DEBUG_VALID_MSG("exhaustion, failed");
4996
if (cur != ctxt->vstate->node)
5000
DEBUG_VALID_MSG("Plus branch found");
5003
case XML_ELEMENT_CONTENT_MULT:
5004
#ifdef DEBUG_VALID_ALGO
5005
if (OCCURRENCE == 0) {
5006
DEBUG_VALID_MSG("Mult branch failed");
5008
DEBUG_VALID_MSG("Mult branch found");
5013
case XML_ELEMENT_CONTENT_OPT:
5014
DEBUG_VALID_MSG("Option branch failed");
5019
switch (CONT->ocur) {
5020
case XML_ELEMENT_CONTENT_OPT:
5021
DEBUG_VALID_MSG("Option branch succeeded");
5024
case XML_ELEMENT_CONTENT_ONCE:
5025
DEBUG_VALID_MSG("Once branch succeeded");
5028
case XML_ELEMENT_CONTENT_PLUS:
5029
if (STATE == ROLLBACK_PARENT) {
5030
DEBUG_VALID_MSG("Plus branch rollback");
5035
DEBUG_VALID_MSG("Plus branch exhausted");
5039
DEBUG_VALID_MSG("Plus branch succeeded, continuing");
5042
case XML_ELEMENT_CONTENT_MULT:
5043
if (STATE == ROLLBACK_PARENT) {
5044
DEBUG_VALID_MSG("Mult branch rollback");
5049
DEBUG_VALID_MSG("Mult branch exhausted");
5053
DEBUG_VALID_MSG("Mult branch succeeded, continuing");
5054
/* SET_OCCURRENCE; */
5061
* Then act accordingly at the parent level
5064
if (CONT->parent == NULL)
5067
switch (CONT->parent->type) {
5068
case XML_ELEMENT_CONTENT_PCDATA:
5069
DEBUG_VALID_MSG("Error: parent pcdata");
5071
case XML_ELEMENT_CONTENT_ELEMENT:
5072
DEBUG_VALID_MSG("Error: parent element");
5074
case XML_ELEMENT_CONTENT_OR:
5076
DEBUG_VALID_MSG("Or succeeded");
5077
CONT = CONT->parent;
5080
DEBUG_VALID_MSG("Or failed");
5081
CONT = CONT->parent;
5085
case XML_ELEMENT_CONTENT_SEQ:
5087
DEBUG_VALID_MSG("Sequence failed");
5088
CONT = CONT->parent;
5090
} else if (CONT == CONT->parent->c1) {
5091
DEBUG_VALID_MSG("Sequence testing 2nd branch");
5092
CONT = CONT->parent->c2;
5095
DEBUG_VALID_MSG("Sequence succeeded");
5096
CONT = CONT->parent;
5104
cur = ctxt->vstate->node;
5105
DEBUG_VALID_MSG("Failed, remaining input, rollback");
5106
if (vstateVPop(ctxt) < 0 ) {
5107
DEBUG_VALID_MSG("exhaustion, failed");
5110
if (cur != ctxt->vstate->node)
5117
cur = ctxt->vstate->node;
5118
DEBUG_VALID_MSG("Failure, rollback");
5119
if (vstateVPop(ctxt) < 0 ) {
5120
DEBUG_VALID_MSG("exhaustion, failed");
5123
if (cur != ctxt->vstate->node)
5127
return(determinist);
5132
* xmlSnprintfElements:
5133
* @buf: an output buffer
5134
* @size: the size of the buffer
5135
* @content: An element
5136
* @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5138
* This will dump the list of elements to the buffer
5139
* Intended just for the debug routine
5142
xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
5146
if (node == NULL) return;
5147
if (glob) strcat(buf, "(");
5149
while (cur != NULL) {
5151
if (size - len < 50) {
5152
if ((size - len > 4) && (buf[len - 1] != '.'))
5153
strcat(buf, " ...");
5156
switch (cur->type) {
5157
case XML_ELEMENT_NODE:
5158
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5159
if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
5160
if ((size - len > 4) && (buf[len - 1] != '.'))
5161
strcat(buf, " ...");
5164
strcat(buf, (char *) cur->ns->prefix);
5167
if (size - len < xmlStrlen(cur->name) + 10) {
5168
if ((size - len > 4) && (buf[len - 1] != '.'))
5169
strcat(buf, " ...");
5172
strcat(buf, (char *) cur->name);
5173
if (cur->next != NULL)
5177
if (xmlIsBlankNode(cur))
5179
case XML_CDATA_SECTION_NODE:
5180
case XML_ENTITY_REF_NODE:
5181
strcat(buf, "CDATA");
5182
if (cur->next != NULL)
5185
case XML_ATTRIBUTE_NODE:
5186
case XML_DOCUMENT_NODE:
5187
#ifdef LIBXML_DOCB_ENABLED
5188
case XML_DOCB_DOCUMENT_NODE:
5190
case XML_HTML_DOCUMENT_NODE:
5191
case XML_DOCUMENT_TYPE_NODE:
5192
case XML_DOCUMENT_FRAG_NODE:
5193
case XML_NOTATION_NODE:
5194
case XML_NAMESPACE_DECL:
5196
if (cur->next != NULL)
5199
case XML_ENTITY_NODE:
5202
case XML_COMMENT_NODE:
5203
case XML_ELEMENT_DECL:
5204
case XML_ATTRIBUTE_DECL:
5205
case XML_ENTITY_DECL:
5206
case XML_XINCLUDE_START:
5207
case XML_XINCLUDE_END:
5212
if (glob) strcat(buf, ")");
5216
* xmlValidateElementContent:
5217
* @ctxt: the validation context
5218
* @child: the child list
5219
* @elemDecl: pointer to the element declaration
5220
* @warn: emit the error message
5221
* @parent: the parent element (for error reporting)
5223
* Try to validate the content model of an element
5225
* returns 1 if valid or 0 if not and -1 in case of error
5229
xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
5230
xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5232
#ifndef LIBXML_REGEXP_ENABLED
5233
xmlNodePtr repl = NULL, last = NULL, tmp;
5236
xmlElementContentPtr cont;
5237
const xmlChar *name;
5239
if ((elemDecl == NULL) || (parent == NULL))
5241
cont = elemDecl->content;
5242
name = elemDecl->name;
5244
#ifdef LIBXML_REGEXP_ENABLED
5245
/* Build the regexp associated to the content model */
5246
if (elemDecl->contModel == NULL)
5247
ret = xmlValidBuildContentModel(ctxt, elemDecl);
5248
if (elemDecl->contModel == NULL) {
5251
xmlRegExecCtxtPtr exec;
5253
if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5258
ctxt->nodeTab = NULL;
5259
exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5262
while (cur != NULL) {
5263
switch (cur->type) {
5264
case XML_ENTITY_REF_NODE:
5266
* Push the current node to be able to roll back
5267
* and process within the entity
5269
if ((cur->children != NULL) &&
5270
(cur->children->children != NULL)) {
5271
nodeVPush(ctxt, cur);
5272
cur = cur->children->children;
5277
if (xmlIsBlankNode(cur))
5281
case XML_CDATA_SECTION_NODE:
5285
case XML_ELEMENT_NODE:
5286
if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5290
fullname = xmlBuildQName(cur->name,
5291
cur->ns->prefix, fn, 50);
5292
if (fullname == NULL) {
5296
ret = xmlRegExecPushString(exec, fullname, NULL);
5297
if ((fullname != fn) && (fullname != cur->name))
5300
ret = xmlRegExecPushString(exec, cur->name, NULL);
5307
* Switch to next element
5310
while (cur == NULL) {
5311
cur = nodeVPop(ctxt);
5317
ret = xmlRegExecPushString(exec, NULL, NULL);
5319
xmlRegFreeExecCtxt(exec);
5322
#else /* LIBXML_REGEXP_ENABLED */
5324
* Allocate the stack
5326
ctxt->vstateMax = 8;
5327
ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5328
ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5329
if (ctxt->vstateTab == NULL) {
5330
xmlVErrMemory(ctxt, "malloc failed");
5334
* The first entry in the stack is reserved to the current state
5338
ctxt->nodeTab = NULL;
5339
ctxt->vstate = &ctxt->vstateTab[0];
5346
ret = xmlValidateElementType(ctxt);
5347
if ((ret == -3) && (warn)) {
5348
xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5349
"Content model for Element %s is ambiguous\n",
5351
} else if (ret == -2) {
5353
* An entities reference appeared at this level.
5354
* Buid a minimal representation of this node content
5355
* sufficient to run the validation process on it
5357
DEBUG_VALID_MSG("Found an entity reference, linearizing");
5359
while (cur != NULL) {
5360
switch (cur->type) {
5361
case XML_ENTITY_REF_NODE:
5363
* Push the current node to be able to roll back
5364
* and process within the entity
5366
if ((cur->children != NULL) &&
5367
(cur->children->children != NULL)) {
5368
nodeVPush(ctxt, cur);
5369
cur = cur->children->children;
5374
if (xmlIsBlankNode(cur))
5376
/* no break on purpose */
5377
case XML_CDATA_SECTION_NODE:
5378
/* no break on purpose */
5379
case XML_ELEMENT_NODE:
5381
* Allocate a new node and minimally fills in
5384
tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5386
xmlVErrMemory(ctxt, "malloc failed");
5387
xmlFreeNodeList(repl);
5391
tmp->type = cur->type;
5392
tmp->name = cur->name;
5395
tmp->content = NULL;
5402
if (cur->type == XML_CDATA_SECTION_NODE) {
5404
* E59 spaces in CDATA does not match the
5407
tmp->content = xmlStrdup(BAD_CAST "CDATA");
5414
* Switch to next element
5417
while (cur == NULL) {
5418
cur = nodeVPop(ctxt);
5426
* Relaunch the validation
5428
ctxt->vstate = &ctxt->vstateTab[0];
5435
ret = xmlValidateElementType(ctxt);
5437
#endif /* LIBXML_REGEXP_ENABLED */
5438
if ((warn) && ((ret != 1) && (ret != -3))) {
5444
xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
5446
#ifndef LIBXML_REGEXP_ENABLED
5448
xmlSnprintfElements(&list[0], 5000, repl, 1);
5450
#endif /* LIBXML_REGEXP_ENABLED */
5451
xmlSnprintfElements(&list[0], 5000, child, 1);
5454
xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5455
"Element %s content does not follow the DTD, expecting %s, got %s\n",
5456
name, BAD_CAST expr, BAD_CAST list);
5458
xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5459
"Element content does not follow the DTD, expecting %s, got %s\n",
5460
BAD_CAST expr, BAD_CAST list, NULL);
5464
xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5465
"Element %s content does not follow the DTD\n",
5468
xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5469
"Element content does not follow the DTD\n",
5478
#ifndef LIBXML_REGEXP_ENABLED
5481
* Deallocate the copy if done, and free up the validation stack
5483
while (repl != NULL) {
5488
ctxt->vstateMax = 0;
5489
if (ctxt->vstateTab != NULL) {
5490
xmlFree(ctxt->vstateTab);
5491
ctxt->vstateTab = NULL;
5496
if (ctxt->nodeTab != NULL) {
5497
xmlFree(ctxt->nodeTab);
5498
ctxt->nodeTab = NULL;
5505
* xmlValidateCdataElement:
5506
* @ctxt: the validation context
5507
* @doc: a document instance
5508
* @elem: an element instance
5510
* Check that an element follows #CDATA
5512
* returns 1 if valid or 0 otherwise
5515
xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5518
xmlNodePtr cur, child;
5520
if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
5521
(elem->type != XML_ELEMENT_NODE))
5524
child = elem->children;
5527
while (cur != NULL) {
5528
switch (cur->type) {
5529
case XML_ENTITY_REF_NODE:
5531
* Push the current node to be able to roll back
5532
* and process within the entity
5534
if ((cur->children != NULL) &&
5535
(cur->children->children != NULL)) {
5536
nodeVPush(ctxt, cur);
5537
cur = cur->children->children;
5541
case XML_COMMENT_NODE:
5544
case XML_CDATA_SECTION_NODE:
5551
* Switch to next element
5554
while (cur == NULL) {
5555
cur = nodeVPop(ctxt);
5564
if (ctxt->nodeTab != NULL) {
5565
xmlFree(ctxt->nodeTab);
5566
ctxt->nodeTab = NULL;
5572
* xmlValidateCheckMixed:
5573
* @ctxt: the validation context
5574
* @cont: the mixed content model
5575
* @qname: the qualified name as appearing in the serialization
5577
* Check if the given node is part of the content model.
5579
* Returns 1 if yes, 0 if no, -1 in case of error
5582
xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
5583
xmlElementContentPtr cont, const xmlChar *qname) {
5584
const xmlChar *name;
5586
name = xmlSplitQName3(qname, &plen);
5589
while (cont != NULL) {
5590
if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5591
if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5593
} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5594
(cont->c1 != NULL) &&
5595
(cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5596
if ((cont->c1->prefix == NULL) &&
5597
(xmlStrEqual(cont->c1->name, qname)))
5599
} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5600
(cont->c1 == NULL) ||
5601
(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5602
xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5603
"Internal: MIXED struct corrupted\n",
5610
while (cont != NULL) {
5611
if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5612
if ((cont->prefix != NULL) &&
5613
(xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5614
(xmlStrEqual(cont->name, name)))
5616
} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5617
(cont->c1 != NULL) &&
5618
(cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5619
if ((cont->c1->prefix != NULL) &&
5620
(xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5621
(xmlStrEqual(cont->c1->name, name)))
5623
} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5624
(cont->c1 == NULL) ||
5625
(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5626
xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5627
"Internal: MIXED struct corrupted\n",
5638
* xmlValidGetElemDecl:
5639
* @ctxt: the validation context
5640
* @doc: a document instance
5641
* @elem: an element instance
5642
* @extsubset: pointer, (out) indicate if the declaration was found
5643
* in the external subset.
5645
* Finds a declaration associated to an element in the document.
5647
* returns the pointer to the declaration or NULL if not found.
5649
static xmlElementPtr
5650
xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5651
xmlNodePtr elem, int *extsubset) {
5652
xmlElementPtr elemDecl = NULL;
5653
const xmlChar *prefix = NULL;
5655
if ((ctxt == NULL) || (doc == NULL) ||
5656
(elem == NULL) || (elem->name == NULL))
5658
if (extsubset != NULL)
5662
* Fetch the declaration for the qualified name
5664
if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5665
prefix = elem->ns->prefix;
5667
if (prefix != NULL) {
5668
elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5669
elem->name, prefix);
5670
if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5671
elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5672
elem->name, prefix);
5673
if ((elemDecl != NULL) && (extsubset != NULL))
5679
* Fetch the declaration for the non qualified name
5680
* This is "non-strict" validation should be done on the
5681
* full QName but in that case being flexible makes sense.
5683
if (elemDecl == NULL) {
5684
elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5685
if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5686
elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5687
if ((elemDecl != NULL) && (extsubset != NULL))
5691
if (elemDecl == NULL) {
5692
xmlErrValidNode(ctxt, elem,
5693
XML_DTD_UNKNOWN_ELEM,
5694
"No declaration for element %s\n",
5695
elem->name, NULL, NULL);
5700
#ifdef LIBXML_REGEXP_ENABLED
5702
* xmlValidatePushElement:
5703
* @ctxt: the validation context
5704
* @doc: a document instance
5705
* @elem: an element instance
5706
* @qname: the qualified name as appearing in the serialization
5708
* Push a new element start on the validation stack.
5710
* returns 1 if no validation problem was found or 0 otherwise
5713
xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5714
xmlNodePtr elem, const xmlChar *qname) {
5716
xmlElementPtr eDecl;
5721
/* printf("PushElem %s\n", qname); */
5722
if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5723
xmlValidStatePtr state = ctxt->vstate;
5724
xmlElementPtr elemDecl;
5727
* Check the new element agaisnt the content model of the new elem.
5729
if (state->elemDecl != NULL) {
5730
elemDecl = state->elemDecl;
5732
switch(elemDecl->etype) {
5733
case XML_ELEMENT_TYPE_UNDEFINED:
5736
case XML_ELEMENT_TYPE_EMPTY:
5737
xmlErrValidNode(ctxt, state->node,
5739
"Element %s was declared EMPTY this one has content\n",
5740
state->node->name, NULL, NULL);
5743
case XML_ELEMENT_TYPE_ANY:
5744
/* I don't think anything is required then */
5746
case XML_ELEMENT_TYPE_MIXED:
5747
/* simple case of declared as #PCDATA */
5748
if ((elemDecl->content != NULL) &&
5749
(elemDecl->content->type ==
5750
XML_ELEMENT_CONTENT_PCDATA)) {
5751
xmlErrValidNode(ctxt, state->node,
5753
"Element %s was declared #PCDATA but contains non text nodes\n",
5754
state->node->name, NULL, NULL);
5757
ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5760
xmlErrValidNode(ctxt, state->node,
5761
XML_DTD_INVALID_CHILD,
5762
"Element %s is not declared in %s list of possible children\n",
5763
qname, state->node->name, NULL);
5767
case XML_ELEMENT_TYPE_ELEMENT:
5770
* VC: Standalone Document Declaration
5771
* - element types with element content, if white space
5772
* occurs directly within any instance of those types.
5774
if (state->exec != NULL) {
5775
ret = xmlRegExecPushString(state->exec, qname, NULL);
5777
xmlErrValidNode(ctxt, state->node,
5778
XML_DTD_CONTENT_MODEL,
5779
"Element %s content does not follow the DTD, Misplaced %s\n",
5780
state->node->name, qname, NULL);
5790
eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5791
vstateVPush(ctxt, eDecl, elem);
5796
* xmlValidatePushCData:
5797
* @ctxt: the validation context
5798
* @data: some character data read
5799
* @len: the length of the data
5801
* check the CData parsed for validation in the current stack
5803
* returns 1 if no validation problem was found or 0 otherwise
5806
xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5809
/* printf("CDATA %s %d\n", data, len); */
5814
if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5815
xmlValidStatePtr state = ctxt->vstate;
5816
xmlElementPtr elemDecl;
5819
* Check the new element agaisnt the content model of the new elem.
5821
if (state->elemDecl != NULL) {
5822
elemDecl = state->elemDecl;
5824
switch(elemDecl->etype) {
5825
case XML_ELEMENT_TYPE_UNDEFINED:
5828
case XML_ELEMENT_TYPE_EMPTY:
5829
xmlErrValidNode(ctxt, state->node,
5831
"Element %s was declared EMPTY this one has content\n",
5832
state->node->name, NULL, NULL);
5835
case XML_ELEMENT_TYPE_ANY:
5837
case XML_ELEMENT_TYPE_MIXED:
5839
case XML_ELEMENT_TYPE_ELEMENT:
5843
for (i = 0;i < len;i++) {
5844
if (!IS_BLANK_CH(data[i])) {
5845
xmlErrValidNode(ctxt, state->node,
5846
XML_DTD_CONTENT_MODEL,
5847
"Element %s content does not follow the DTD, Text not allowed\n",
5848
state->node->name, NULL, NULL);
5855
* VC: Standalone Document Declaration
5856
* element types with element content, if white space
5857
* occurs directly within any instance of those types.
5869
* xmlValidatePopElement:
5870
* @ctxt: the validation context
5871
* @doc: a document instance
5872
* @elem: an element instance
5873
* @qname: the qualified name as appearing in the serialization
5875
* Pop the element end from the validation stack.
5877
* returns 1 if no validation problem was found or 0 otherwise
5880
xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
5881
xmlNodePtr elem ATTRIBUTE_UNUSED,
5882
const xmlChar *qname ATTRIBUTE_UNUSED) {
5887
/* printf("PopElem %s\n", qname); */
5888
if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5889
xmlValidStatePtr state = ctxt->vstate;
5890
xmlElementPtr elemDecl;
5893
* Check the new element agaisnt the content model of the new elem.
5895
if (state->elemDecl != NULL) {
5896
elemDecl = state->elemDecl;
5898
if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5899
if (state->exec != NULL) {
5900
ret = xmlRegExecPushString(state->exec, NULL, NULL);
5902
xmlErrValidNode(ctxt, state->node,
5903
XML_DTD_CONTENT_MODEL,
5904
"Element %s content does not follow the DTD, Expecting more child\n",
5905
state->node->name, NULL,NULL);
5908
* previous validation errors should not generate
5920
#endif /* LIBXML_REGEXP_ENABLED */
5923
* xmlValidateOneElement:
5924
* @ctxt: the validation context
5925
* @doc: a document instance
5926
* @elem: an element instance
5928
* Try to validate a single element and it's attributes,
5929
* basically it does the following checks as described by the
5930
* XML-1.0 recommendation:
5931
* - [ VC: Element Valid ]
5932
* - [ VC: Required Attribute ]
5933
* Then call xmlValidateOneAttribute() for each attribute present.
5935
* The ID/IDREF checkings are done separately
5937
* returns 1 if valid or 0 otherwise
5941
xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5943
xmlElementPtr elemDecl = NULL;
5944
xmlElementContentPtr cont;
5945
xmlAttributePtr attr;
5948
const xmlChar *name;
5953
if (elem == NULL) return(0);
5954
switch (elem->type) {
5955
case XML_ATTRIBUTE_NODE:
5956
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5957
"Attribute element not expected\n", NULL, NULL ,NULL);
5960
if (elem->children != NULL) {
5961
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5962
"Text element has children !\n",
5966
if (elem->ns != NULL) {
5967
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5968
"Text element has namespace !\n",
5972
if (elem->content == NULL) {
5973
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5974
"Text element has no content !\n",
5979
case XML_XINCLUDE_START:
5980
case XML_XINCLUDE_END:
5982
case XML_CDATA_SECTION_NODE:
5983
case XML_ENTITY_REF_NODE:
5985
case XML_COMMENT_NODE:
5987
case XML_ENTITY_NODE:
5988
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5989
"Entity element not expected\n", NULL, NULL ,NULL);
5991
case XML_NOTATION_NODE:
5992
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5993
"Notation element not expected\n", NULL, NULL ,NULL);
5995
case XML_DOCUMENT_NODE:
5996
case XML_DOCUMENT_TYPE_NODE:
5997
case XML_DOCUMENT_FRAG_NODE:
5998
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5999
"Document element not expected\n", NULL, NULL ,NULL);
6001
case XML_HTML_DOCUMENT_NODE:
6002
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6003
"HTML Document not expected\n", NULL, NULL ,NULL);
6005
case XML_ELEMENT_NODE:
6008
xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6009
"unknown element type\n", NULL, NULL ,NULL);
6014
* Fetch the declaration
6016
elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
6017
if (elemDecl == NULL)
6021
* If vstateNr is not zero that means continuous validation is
6022
* activated, do not try to check the content model at that level.
6024
if (ctxt->vstateNr == 0) {
6025
/* Check that the element content matches the definition */
6026
switch (elemDecl->etype) {
6027
case XML_ELEMENT_TYPE_UNDEFINED:
6028
xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
6029
"No declaration for element %s\n",
6030
elem->name, NULL, NULL);
6032
case XML_ELEMENT_TYPE_EMPTY:
6033
if (elem->children != NULL) {
6034
xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
6035
"Element %s was declared EMPTY this one has content\n",
6036
elem->name, NULL, NULL);
6040
case XML_ELEMENT_TYPE_ANY:
6041
/* I don't think anything is required then */
6043
case XML_ELEMENT_TYPE_MIXED:
6045
/* simple case of declared as #PCDATA */
6046
if ((elemDecl->content != NULL) &&
6047
(elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
6048
ret = xmlValidateOneCdataElement(ctxt, doc, elem);
6050
xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
6051
"Element %s was declared #PCDATA but contains non text nodes\n",
6052
elem->name, NULL, NULL);
6056
child = elem->children;
6057
/* Hum, this start to get messy */
6058
while (child != NULL) {
6059
if (child->type == XML_ELEMENT_NODE) {
6061
if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
6065
fullname = xmlBuildQName(child->name, child->ns->prefix,
6067
if (fullname == NULL)
6069
cont = elemDecl->content;
6070
while (cont != NULL) {
6071
if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6072
if (xmlStrEqual(cont->name, fullname))
6074
} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6075
(cont->c1 != NULL) &&
6076
(cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
6077
if (xmlStrEqual(cont->c1->name, fullname))
6079
} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6080
(cont->c1 == NULL) ||
6081
(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
6082
xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
6083
"Internal: MIXED struct corrupted\n",
6089
if ((fullname != fn) && (fullname != child->name))
6094
cont = elemDecl->content;
6095
while (cont != NULL) {
6096
if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6097
if (xmlStrEqual(cont->name, name)) break;
6098
} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6099
(cont->c1 != NULL) &&
6100
(cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6101
if (xmlStrEqual(cont->c1->name, name)) break;
6102
} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6103
(cont->c1 == NULL) ||
6104
(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
6105
xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6106
"Internal: MIXED struct corrupted\n",
6113
xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
6114
"Element %s is not declared in %s list of possible children\n",
6115
name, elem->name, NULL);
6120
child = child->next;
6123
case XML_ELEMENT_TYPE_ELEMENT:
6124
if ((doc->standalone == 1) && (extsubset == 1)) {
6126
* VC: Standalone Document Declaration
6127
* - element types with element content, if white space
6128
* occurs directly within any instance of those types.
6130
child = elem->children;
6131
while (child != NULL) {
6132
if (child->type == XML_TEXT_NODE) {
6133
const xmlChar *content = child->content;
6135
while (IS_BLANK_CH(*content))
6137
if (*content == 0) {
6138
xmlErrValidNode(ctxt, elem,
6139
XML_DTD_STANDALONE_WHITE_SPACE,
6140
"standalone: %s declared in the external subset contains white spaces nodes\n",
6141
elem->name, NULL, NULL);
6149
child = elem->children;
6150
cont = elemDecl->content;
6151
tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
6156
} /* not continuous */
6158
/* [ VC: Required Attribute ] */
6159
attr = elemDecl->attributes;
6160
while (attr != NULL) {
6161
if (attr->def == XML_ATTRIBUTE_REQUIRED) {
6164
if ((attr->prefix == NULL) &&
6165
(xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6169
while (ns != NULL) {
6170
if (ns->prefix == NULL)
6174
} else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6178
while (ns != NULL) {
6179
if (xmlStrEqual(attr->name, ns->prefix))
6186
attrib = elem->properties;
6187
while (attrib != NULL) {
6188
if (xmlStrEqual(attrib->name, attr->name)) {
6189
if (attr->prefix != NULL) {
6190
xmlNsPtr nameSpace = attrib->ns;
6192
if (nameSpace == NULL)
6193
nameSpace = elem->ns;
6195
* qualified names handling is problematic, having a
6196
* different prefix should be possible but DTDs don't
6197
* allow to define the URI instead of the prefix :-(
6199
if (nameSpace == NULL) {
6202
} else if (!xmlStrEqual(nameSpace->prefix,
6210
* We should allow applications to define namespaces
6211
* for their application even if the DTD doesn't
6212
* carry one, otherwise, basically we would always
6218
attrib = attrib->next;
6221
if (qualified == -1) {
6222
if (attr->prefix == NULL) {
6223
xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6224
"Element %s does not carry attribute %s\n",
6225
elem->name, attr->name, NULL);
6228
xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6229
"Element %s does not carry attribute %s:%s\n",
6230
elem->name, attr->prefix,attr->name);
6233
} else if (qualified == 0) {
6234
xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
6235
"Element %s required attribute %s:%s has no prefix\n",
6236
elem->name, attr->prefix, attr->name);
6237
} else if (qualified == 1) {
6238
xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
6239
"Element %s required attribute %s:%s has different prefix\n",
6240
elem->name, attr->prefix, attr->name);
6242
} else if (attr->def == XML_ATTRIBUTE_FIXED) {
6244
* Special tests checking #FIXED namespace declarations
6245
* have the right value since this is not done as an
6246
* attribute checking
6248
if ((attr->prefix == NULL) &&
6249
(xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6253
while (ns != NULL) {
6254
if (ns->prefix == NULL) {
6255
if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6256
xmlErrValidNode(ctxt, elem,
6257
XML_DTD_ELEM_DEFAULT_NAMESPACE,
6258
"Element %s namespace name for default namespace does not match the DTD\n",
6259
elem->name, NULL, NULL);
6266
} else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6270
while (ns != NULL) {
6271
if (xmlStrEqual(attr->name, ns->prefix)) {
6272
if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6273
xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
6274
"Element %s namespace name for %s does not match the DTD\n",
6275
elem->name, ns->prefix, NULL);
6292
* @ctxt: the validation context
6293
* @doc: a document instance
6295
* Try to validate a the root element
6296
* basically it does the following check as described by the
6297
* XML-1.0 recommendation:
6298
* - [ VC: Root Element Type ]
6299
* it doesn't try to recurse or apply other check to the element
6301
* returns 1 if valid or 0 otherwise
6305
xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6309
if (doc == NULL) return(0);
6311
root = xmlDocGetRootElement(doc);
6312
if ((root == NULL) || (root->name == NULL)) {
6313
xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6314
"no root element\n", NULL);
6319
* When doing post validation against a separate DTD, those may
6320
* no internal subset has been generated
6322
if ((doc->intSubset != NULL) &&
6323
(doc->intSubset->name != NULL)) {
6325
* Check first the document root against the NQName
6327
if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6328
if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
6332
fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6333
if (fullname == NULL) {
6334
xmlVErrMemory(ctxt, NULL);
6337
ret = xmlStrEqual(doc->intSubset->name, fullname);
6338
if ((fullname != fn) && (fullname != root->name))
6343
if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6344
(xmlStrEqual(root->name, BAD_CAST "html")))
6346
xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6347
"root and DTD name do not match '%s' and '%s'\n",
6348
root->name, doc->intSubset->name, NULL);
6358
* xmlValidateElement:
6359
* @ctxt: the validation context
6360
* @doc: a document instance
6361
* @elem: an element instance
6363
* Try to validate the subtree under an element
6365
* returns 1 if valid or 0 otherwise
6369
xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6373
const xmlChar *value;
6376
if (elem == NULL) return(0);
6379
* XInclude elements were added after parsing in the infoset,
6380
* they don't really mean anything validation wise.
6382
if ((elem->type == XML_XINCLUDE_START) ||
6383
(elem->type == XML_XINCLUDE_END) ||
6384
(elem->type == XML_NAMESPACE_DECL))
6390
* Entities references have to be handled separately
6392
if (elem->type == XML_ENTITY_REF_NODE) {
6396
ret &= xmlValidateOneElement(ctxt, doc, elem);
6397
if (elem->type == XML_ELEMENT_NODE) {
6398
attr = elem->properties;
6399
while (attr != NULL) {
6400
value = xmlNodeListGetString(doc, attr->children, 0);
6401
ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6403
xmlFree((char *)value);
6407
while (ns != NULL) {
6408
if (elem->ns == NULL)
6409
ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6412
ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6413
elem->ns->prefix, ns, ns->href);
6417
child = elem->children;
6418
while (child != NULL) {
6419
ret &= xmlValidateElement(ctxt, doc, child);
6420
child = child->next;
6428
* @ref: A reference to be validated
6429
* @ctxt: Validation context
6430
* @name: Name of ID we are searching for
6434
xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
6435
const xmlChar *name) {
6441
if ((ref->attr == NULL) && (ref->name == NULL))
6445
xmlChar *dup, *str = NULL, *cur, save;
6447
dup = xmlStrdup(name);
6455
while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6458
id = xmlGetID(ctxt->doc, str);
6460
xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
6461
"attribute %s line %d references an unknown ID \"%s\"\n",
6462
ref->name, ref->lineno, str);
6468
while (IS_BLANK_CH(*cur)) cur++;
6471
} else if (attr->atype == XML_ATTRIBUTE_IDREF) {
6472
id = xmlGetID(ctxt->doc, name);
6474
xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6475
"IDREF attribute %s references an unknown ID \"%s\"\n",
6476
attr->name, name, NULL);
6479
} else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6480
xmlChar *dup, *str = NULL, *cur, save;
6482
dup = xmlStrdup(name);
6484
xmlVErrMemory(ctxt, "IDREFS split");
6491
while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6494
id = xmlGetID(ctxt->doc, str);
6496
xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6497
"IDREFS attribute %s references an unknown ID \"%s\"\n",
6498
attr->name, str, NULL);
6504
while (IS_BLANK_CH(*cur)) cur++;
6511
* xmlWalkValidateList:
6512
* @data: Contents of current link
6513
* @user: Value supplied by the user
6515
* Returns 0 to abort the walk or 1 to continue
6518
xmlWalkValidateList(const void *data, const void *user)
6520
xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6521
xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6526
* xmlValidateCheckRefCallback:
6527
* @ref_list: List of references
6528
* @ctxt: Validation context
6529
* @name: Name of ID we are searching for
6533
xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6534
const xmlChar *name) {
6535
xmlValidateMemo memo;
6537
if (ref_list == NULL)
6542
xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6547
* xmlValidateDocumentFinal:
6548
* @ctxt: the validation context
6549
* @doc: a document instance
6551
* Does the final step for the document validation once all the
6552
* incremental validation steps have been completed
6554
* basically it does the following checks described by the XML Rec
6556
* Check all the IDREF/IDREFS attributes definition for validity
6558
* returns 1 if valid or 0 otherwise
6562
xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6563
xmlRefTablePtr table;
6569
xmlErrValid(ctxt, XML_DTD_NO_DOC,
6570
"xmlValidateDocumentFinal: doc == NULL\n", NULL);
6574
/* trick to get correct line id report */
6575
save = ctxt->finishDtd;
6576
ctxt->finishDtd = 0;
6579
* Check all the NOTATION/NOTATIONS attributes
6582
* Check all the ENTITY/ENTITIES attributes definition for validity
6585
* Check all the IDREF/IDREFS attributes definition for validity
6587
table = (xmlRefTablePtr) doc->refs;
6590
xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6592
ctxt->finishDtd = save;
6593
return(ctxt->valid);
6598
* @ctxt: the validation context
6599
* @doc: a document instance
6600
* @dtd: a dtd instance
6602
* Try to validate the document against the dtd instance
6604
* Basically it does check all the definitions in the DtD.
6605
* Note the the internal subset (if present) is de-coupled
6606
* (i.e. not used), which could give problems if ID or IDREF
6609
* returns 1 if valid or 0 otherwise
6613
xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6615
xmlDtdPtr oldExt, oldInt;
6618
if (dtd == NULL) return(0);
6619
if (doc == NULL) return(0);
6620
oldExt = doc->extSubset;
6621
oldInt = doc->intSubset;
6622
doc->extSubset = dtd;
6623
doc->intSubset = NULL;
6624
ret = xmlValidateRoot(ctxt, doc);
6626
doc->extSubset = oldExt;
6627
doc->intSubset = oldInt;
6630
if (doc->ids != NULL) {
6631
xmlFreeIDTable(doc->ids);
6634
if (doc->refs != NULL) {
6635
xmlFreeRefTable(doc->refs);
6638
root = xmlDocGetRootElement(doc);
6639
ret = xmlValidateElement(ctxt, doc, root);
6640
ret &= xmlValidateDocumentFinal(ctxt, doc);
6641
doc->extSubset = oldExt;
6642
doc->intSubset = oldInt;
6647
xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6648
const xmlChar *name ATTRIBUTE_UNUSED) {
6651
if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6652
xmlChar *notation = cur->content;
6654
if (notation != NULL) {
6657
ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6666
xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
6667
const xmlChar *name ATTRIBUTE_UNUSED) {
6670
xmlElementPtr elem = NULL;
6674
switch (cur->atype) {
6675
case XML_ATTRIBUTE_CDATA:
6676
case XML_ATTRIBUTE_ID:
6677
case XML_ATTRIBUTE_IDREF :
6678
case XML_ATTRIBUTE_IDREFS:
6679
case XML_ATTRIBUTE_NMTOKEN:
6680
case XML_ATTRIBUTE_NMTOKENS:
6681
case XML_ATTRIBUTE_ENUMERATION:
6683
case XML_ATTRIBUTE_ENTITY:
6684
case XML_ATTRIBUTE_ENTITIES:
6685
case XML_ATTRIBUTE_NOTATION:
6686
if (cur->defaultValue != NULL) {
6688
ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6689
cur->atype, cur->defaultValue);
6690
if ((ret == 0) && (ctxt->valid == 1))
6693
if (cur->tree != NULL) {
6694
xmlEnumerationPtr tree = cur->tree;
6695
while (tree != NULL) {
6696
ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6697
cur->name, cur->atype, tree->name);
6698
if ((ret == 0) && (ctxt->valid == 1))
6704
if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6706
if (cur->elem == NULL) {
6707
xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
6708
"xmlValidateAttributeCallback(%s): internal error\n",
6709
(const char *) cur->name);
6714
elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6715
if ((elem == NULL) && (doc != NULL))
6716
elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6717
if ((elem == NULL) && (cur->parent != NULL) &&
6718
(cur->parent->type == XML_DTD_NODE))
6719
elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
6721
xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
6722
"attribute %s: could not find decl for element %s\n",
6723
cur->name, cur->elem, NULL);
6726
if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6727
xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
6728
"NOTATION attribute %s declared for EMPTY element %s\n",
6729
cur->name, cur->elem, NULL);
6736
* xmlValidateDtdFinal:
6737
* @ctxt: the validation context
6738
* @doc: a document instance
6740
* Does the final step for the dtds validation once all the
6741
* subsets have been parsed
6743
* basically it does the following checks described by the XML Rec
6744
* - check that ENTITY and ENTITIES type attributes default or
6745
* possible values matches one of the defined entities.
6746
* - check that NOTATION type attributes default or
6747
* possible values matches one of the defined notations.
6749
* returns 1 if valid or 0 if invalid and -1 if not well-formed
6753
xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6755
xmlAttributeTablePtr table;
6756
xmlEntitiesTablePtr entities;
6758
if ((doc == NULL) || (ctxt == NULL)) return(0);
6759
if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6763
dtd = doc->intSubset;
6764
if ((dtd != NULL) && (dtd->attributes != NULL)) {
6765
table = (xmlAttributeTablePtr) dtd->attributes;
6766
xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
6768
if ((dtd != NULL) && (dtd->entities != NULL)) {
6769
entities = (xmlEntitiesTablePtr) dtd->entities;
6770
xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6773
dtd = doc->extSubset;
6774
if ((dtd != NULL) && (dtd->attributes != NULL)) {
6775
table = (xmlAttributeTablePtr) dtd->attributes;
6776
xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
6778
if ((dtd != NULL) && (dtd->entities != NULL)) {
6779
entities = (xmlEntitiesTablePtr) dtd->entities;
6780
xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6783
return(ctxt->valid);
6787
* xmlValidateDocument:
6788
* @ctxt: the validation context
6789
* @doc: a document instance
6791
* Try to validate the document instance
6793
* basically it does the all the checks described by the XML Rec
6794
* i.e. validates the internal and external subset (if present)
6795
* and validate the document tree.
6797
* returns 1 if valid or 0 otherwise
6801
xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6807
if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6808
xmlErrValid(ctxt, XML_DTD_NO_DTD,
6809
"no DTD found!\n", NULL);
6812
if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6813
(doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6815
if (doc->intSubset->SystemID != NULL) {
6816
sysID = xmlBuildURI(doc->intSubset->SystemID,
6818
if (sysID == NULL) {
6819
xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6820
"Could not build URI for external subset \"%s\"\n",
6821
(const char *) doc->intSubset->SystemID);
6826
doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6827
(const xmlChar *)sysID);
6830
if (doc->extSubset == NULL) {
6831
if (doc->intSubset->SystemID != NULL) {
6832
xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6833
"Could not load the external subset \"%s\"\n",
6834
(const char *) doc->intSubset->SystemID);
6836
xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6837
"Could not load the external subset \"%s\"\n",
6838
(const char *) doc->intSubset->ExternalID);
6844
if (doc->ids != NULL) {
6845
xmlFreeIDTable(doc->ids);
6848
if (doc->refs != NULL) {
6849
xmlFreeRefTable(doc->refs);
6852
ret = xmlValidateDtdFinal(ctxt, doc);
6853
if (!xmlValidateRoot(ctxt, doc)) return(0);
6855
root = xmlDocGetRootElement(doc);
6856
ret &= xmlValidateElement(ctxt, doc, root);
6857
ret &= xmlValidateDocumentFinal(ctxt, doc);
6861
/************************************************************************
6863
* Routines for dynamic validation editing *
6865
************************************************************************/
6868
* xmlValidGetPotentialChildren:
6869
* @ctree: an element content tree
6870
* @names: an array to store the list of child names
6871
* @len: a pointer to the number of element in the list
6872
* @max: the size of the array
6874
* Build/extend a list of potential children allowed by the content tree
6876
* returns the number of element in the list, or -1 in case of error.
6880
xmlValidGetPotentialChildren(xmlElementContent *ctree,
6881
const xmlChar **names,
6882
int *len, int max) {
6885
if ((ctree == NULL) || (names == NULL) || (len == NULL))
6887
if (*len >= max) return(*len);
6889
switch (ctree->type) {
6890
case XML_ELEMENT_CONTENT_PCDATA:
6891
for (i = 0; i < *len;i++)
6892
if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6893
names[(*len)++] = BAD_CAST "#PCDATA";
6895
case XML_ELEMENT_CONTENT_ELEMENT:
6896
for (i = 0; i < *len;i++)
6897
if (xmlStrEqual(ctree->name, names[i])) return(*len);
6898
names[(*len)++] = ctree->name;
6900
case XML_ELEMENT_CONTENT_SEQ:
6901
xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6902
xmlValidGetPotentialChildren(ctree->c2, names, len, max);
6904
case XML_ELEMENT_CONTENT_OR:
6905
xmlValidGetPotentialChildren(ctree->c1, names, len, max);
6906
xmlValidGetPotentialChildren(ctree->c2, names, len, max);
6914
* Dummy function to suppress messages while we try out valid elements
6916
static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
6917
const char *msg ATTRIBUTE_UNUSED, ...) {
6922
* xmlValidGetValidElements:
6923
* @prev: an element to insert after
6924
* @next: an element to insert next
6925
* @names: an array to store the list of child names
6926
* @max: the size of the array
6928
* This function returns the list of authorized children to insert
6929
* within an existing tree while respecting the validity constraints
6930
* forced by the Dtd. The insertion point is defined using @prev and
6931
* @next in the following ways:
6932
* to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6933
* to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6934
* to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6935
* to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6936
* to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6938
* pointers to the element names are inserted at the beginning of the array
6939
* and do not need to be freed.
6941
* returns the number of element in the list, or -1 in case of error. If
6942
* the function returns the value @max the caller is invited to grow the
6943
* receiving array and retry.
6947
xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
6950
int nb_valid_elements = 0;
6951
const xmlChar *elements[256];
6952
int nb_elements = 0, i;
6953
const xmlChar *name;
6961
xmlNode *parent_childs;
6962
xmlNode *parent_last;
6964
xmlElement *element_desc;
6966
if (prev == NULL && next == NULL)
6969
if (names == NULL) return(-1);
6970
if (max <= 0) return(-1);
6972
memset(&vctxt, 0, sizeof (xmlValidCtxt));
6973
vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
6975
nb_valid_elements = 0;
6976
ref_node = prev ? prev : next;
6977
parent = ref_node->parent;
6980
* Retrieves the parent element declaration
6982
element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6984
if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6985
element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6987
if (element_desc == NULL) return(-1);
6990
* Do a backup of the current tree structure
6992
prev_next = prev ? prev->next : NULL;
6993
next_prev = next ? next->prev : NULL;
6994
parent_childs = parent->children;
6995
parent_last = parent->last;
6998
* Creates a dummy node and insert it into the tree
7000
test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
7001
test_node->parent = parent;
7002
test_node->prev = prev;
7003
test_node->next = next;
7004
name = test_node->name;
7006
if (prev) prev->next = test_node;
7007
else parent->children = test_node;
7009
if (next) next->prev = test_node;
7010
else parent->last = test_node;
7013
* Insert each potential child node and check if the parent is
7016
nb_elements = xmlValidGetPotentialChildren(element_desc->content,
7017
elements, &nb_elements, 256);
7019
for (i = 0;i < nb_elements;i++) {
7020
test_node->name = elements[i];
7021
if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
7024
for (j = 0; j < nb_valid_elements;j++)
7025
if (xmlStrEqual(elements[i], names[j])) break;
7026
names[nb_valid_elements++] = elements[i];
7027
if (nb_valid_elements >= max) break;
7032
* Restore the tree structure
7034
if (prev) prev->next = prev_next;
7035
if (next) next->prev = next_prev;
7036
parent->children = parent_childs;
7037
parent->last = parent_last;
7040
* Free up the dummy node
7042
test_node->name = name;
7043
xmlFreeNode(test_node);
7045
return(nb_valid_elements);
7047
#endif /* LIBXML_VALID_ENABLED */
7049
#define bottom_valid
7050
#include "elfgcchack.h"