2 * relaxng.c : implementation of the Relax-NG handling and validity checking
4 * See Copyright for the status of this software.
6 * Daniel Veillard <veillard@redhat.com>
12 * - simplification of the resulting compiled trees:
15 * - handle namespace declarations as attributes.
16 * - add support for DTD compatibility spec
17 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
23 #ifdef LIBXML_SCHEMAS_ENABLED
27 #include <libxml/xmlmemory.h>
28 #include <libxml/parser.h>
29 #include <libxml/parserInternals.h>
30 #include <libxml/hash.h>
31 #include <libxml/uri.h>
33 #include <libxml/relaxng.h>
35 #include <libxml/xmlschemastypes.h>
36 #include <libxml/xmlautomata.h>
37 #include <libxml/xmlregexp.h>
38 #include <libxml/xmlschemastypes.h>
41 * The Relax-NG namespace
43 static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
44 "http://relaxng.org/ns/structure/1.0";
46 #define IS_RELAXNG(node, type) \
47 ((node != NULL) && (node->ns != NULL) && \
48 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
49 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
52 /* #define DEBUG 1 */ /* very verbose output */
53 /* #define DEBUG_CONTENT 1 */
54 /* #define DEBUG_TYPE 1 */
55 /* #define DEBUG_VALID 1 */
56 /* #define DEBUG_INTERLEAVE 1 */
57 /* #define DEBUG_LIST 1 */
59 #define UNBOUNDED (1 << 30)
61 xmlGenericError(xmlGenericErrorContext, \
62 "Unimplemented block at %s:%d\n", \
65 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema;
66 typedef xmlRelaxNGSchema *xmlRelaxNGSchemaPtr;
68 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine;
69 typedef xmlRelaxNGDefine *xmlRelaxNGDefinePtr;
71 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument;
72 typedef xmlRelaxNGDocument *xmlRelaxNGDocumentPtr;
74 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude;
75 typedef xmlRelaxNGInclude *xmlRelaxNGIncludePtr;
78 XML_RELAXNG_COMBINE_UNDEFINED = 0, /* undefined */
79 XML_RELAXNG_COMBINE_CHOICE, /* choice */
80 XML_RELAXNG_COMBINE_INTERLEAVE /* interleave */
84 XML_RELAXNG_CONTENT_ERROR = -1,
85 XML_RELAXNG_CONTENT_EMPTY = 0,
86 XML_RELAXNG_CONTENT_SIMPLE,
87 XML_RELAXNG_CONTENT_COMPLEX
88 } xmlRelaxNGContentType;
90 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar;
91 typedef xmlRelaxNGGrammar *xmlRelaxNGGrammarPtr;
93 struct _xmlRelaxNGGrammar {
94 xmlRelaxNGGrammarPtr parent;/* the parent grammar if any */
95 xmlRelaxNGGrammarPtr children;/* the children grammar if any */
96 xmlRelaxNGGrammarPtr next; /* the next grammar if any */
97 xmlRelaxNGDefinePtr start; /* <start> content */
98 xmlRelaxNGCombine combine; /* the default combine value */
99 xmlRelaxNGDefinePtr startList;/* list of <start> definitions */
100 xmlHashTablePtr defs; /* define* */
101 xmlHashTablePtr refs; /* references */
106 XML_RELAXNG_NOOP = -1, /* a no operation from simplification */
107 XML_RELAXNG_EMPTY = 0, /* an empty pattern */
108 XML_RELAXNG_NOT_ALLOWED, /* not allowed top */
109 XML_RELAXNG_EXCEPT, /* except present in nameclass defs */
110 XML_RELAXNG_TEXT, /* textual content */
111 XML_RELAXNG_ELEMENT, /* an element */
112 XML_RELAXNG_DATATYPE, /* extenal data type definition */
113 XML_RELAXNG_PARAM, /* extenal data type parameter */
114 XML_RELAXNG_VALUE, /* value from an extenal data type definition */
115 XML_RELAXNG_LIST, /* a list of patterns */
116 XML_RELAXNG_ATTRIBUTE, /* an attrbute following a pattern */
117 XML_RELAXNG_DEF, /* a definition */
118 XML_RELAXNG_REF, /* reference to a definition */
119 XML_RELAXNG_EXTERNALREF, /* reference to an external def */
120 XML_RELAXNG_PARENTREF, /* reference to a def in the parent grammar */
121 XML_RELAXNG_OPTIONAL, /* optional patterns */
122 XML_RELAXNG_ZEROORMORE, /* zero or more non empty patterns */
123 XML_RELAXNG_ONEORMORE, /* one or more non empty patterns */
124 XML_RELAXNG_CHOICE, /* a choice between non empty patterns */
125 XML_RELAXNG_GROUP, /* a pair/group of non empty patterns */
126 XML_RELAXNG_INTERLEAVE, /* interleaving choice of non-empty patterns */
127 XML_RELAXNG_START /* Used to keep track of starts on grammars */
130 struct _xmlRelaxNGDefine {
131 xmlRelaxNGType type; /* the type of definition */
132 xmlNodePtr node; /* the node in the source */
133 xmlChar *name; /* the element local name if present */
134 xmlChar *ns; /* the namespace local name if present */
135 xmlChar *value; /* value when available */
136 void *data; /* data lib or specific pointer */
137 int depth; /* used for the cycle detection */
138 xmlRelaxNGDefinePtr content;/* the expected content */
139 xmlRelaxNGDefinePtr parent; /* the parent definition, if any */
140 xmlRelaxNGDefinePtr next; /* list within grouping sequences */
141 xmlRelaxNGDefinePtr attrs; /* list of attributes for elements */
142 xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
143 xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
149 * A RelaxNGs definition
152 xmlRelaxNGGrammarPtr topgrammar;
155 xmlHashTablePtr defs; /* define */
156 xmlHashTablePtr refs; /* references */
157 xmlHashTablePtr documents; /* all the documents loaded */
158 xmlHashTablePtr includes; /* all the includes loaded */
159 int defNr; /* number of defines used */
160 xmlRelaxNGDefinePtr *defTab;/* pointer to the allocated definitions */
161 void *_private; /* unused by the library for users or bindings */
165 XML_RELAXNG_ERR_OK = 0,
166 XML_RELAXNG_ERR_NOROOT = 1,
168 } xmlRelaxNGValidError;
170 #define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
171 #define XML_RELAXNG_IN_ONEORMORE (1 << 1)
172 #define XML_RELAXNG_IN_LIST (1 << 2)
173 #define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
174 #define XML_RELAXNG_IN_START (1 << 4)
175 #define XML_RELAXNG_IN_OOMGROUP (1 << 5)
176 #define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
177 #define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
178 #define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
179 #define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
181 struct _xmlRelaxNGParserCtxt {
182 void *userData; /* user specific data block */
183 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
184 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
185 xmlRelaxNGValidError err;
187 xmlRelaxNGPtr schema; /* The schema in use */
188 xmlRelaxNGGrammarPtr grammar; /* the current grammar */
189 xmlRelaxNGGrammarPtr parentgrammar;/* the parent grammar */
190 int flags; /* parser flags */
191 int nbErrors; /* number of errors at parse time */
192 int nbWarnings; /* number of warnings at parse time */
193 const xmlChar *define; /* the current define scope */
194 xmlRelaxNGDefinePtr def; /* the current define */
197 xmlHashTablePtr interleaves; /* keep track of all the interleaves */
199 xmlHashTablePtr documents; /* all the documents loaded */
200 xmlHashTablePtr includes; /* all the includes loaded */
204 int defNr; /* number of defines used */
205 int defMax; /* number of defines aloocated */
206 xmlRelaxNGDefinePtr *defTab; /* pointer to the allocated definitions */
211 /* the document stack */
212 xmlRelaxNGDocumentPtr doc; /* Current parsed external ref */
213 int docNr; /* Depth of the parsing stack */
214 int docMax; /* Max depth of the parsing stack */
215 xmlRelaxNGDocumentPtr *docTab; /* array of docs */
217 /* the include stack */
218 xmlRelaxNGIncludePtr inc; /* Current parsed include */
219 int incNr; /* Depth of the include parsing stack */
220 int incMax; /* Max depth of the parsing stack */
221 xmlRelaxNGIncludePtr *incTab; /* array of incs */
224 #define FLAGS_IGNORABLE 1
225 #define FLAGS_NEGATIVE 2
228 * xmlRelaxNGInterleaveGroup:
230 * A RelaxNGs partition set associated to lists of definitions
232 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup;
233 typedef xmlRelaxNGInterleaveGroup *xmlRelaxNGInterleaveGroupPtr;
234 struct _xmlRelaxNGInterleaveGroup {
235 xmlRelaxNGDefinePtr rule; /* the rule to satisfy */
236 xmlRelaxNGDefinePtr *defs; /* the array of element definitions */
237 xmlRelaxNGDefinePtr *attrs; /* the array of attributes definitions */
241 * xmlRelaxNGPartitions:
243 * A RelaxNGs partition associated to an interleave group
245 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition;
246 typedef xmlRelaxNGPartition *xmlRelaxNGPartitionPtr;
247 struct _xmlRelaxNGPartition {
248 int nbgroups; /* number of groups in the partitions */
249 xmlRelaxNGInterleaveGroupPtr *groups;
253 * xmlRelaxNGValidState:
255 * A RelaxNGs validation state
258 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState;
259 typedef xmlRelaxNGValidState *xmlRelaxNGValidStatePtr;
260 struct _xmlRelaxNGValidState {
261 xmlNodePtr node; /* the current node */
262 xmlNodePtr seq; /* the sequence of children left to validate */
263 int nbAttrs; /* the number of attributes */
264 int nbAttrLeft; /* the number of attributes left to validate */
265 xmlChar *value; /* the value when operating on string */
266 xmlChar *endvalue; /* the end value when operating on string */
267 xmlAttrPtr attrs[1]; /* the array of attributes */
271 * xmlRelaxNGValidCtxt:
273 * A RelaxNGs validation context
276 struct _xmlRelaxNGValidCtxt {
277 void *userData; /* user specific data block */
278 xmlRelaxNGValidityErrorFunc error; /* the callback in case of errors */
279 xmlRelaxNGValidityWarningFunc warning;/* the callback in case of warning */
281 xmlRelaxNGPtr schema; /* The schema in use */
282 xmlDocPtr doc; /* the document being validated */
283 xmlRelaxNGValidStatePtr state; /* the current validation state */
284 int flags; /* validation flags */
285 int depth; /* validation depth */
291 * Structure associated to a RelaxNGs document element
293 struct _xmlRelaxNGInclude {
294 xmlChar *href; /* the normalized href value */
295 xmlDocPtr doc; /* the associated XML document */
296 xmlRelaxNGDefinePtr content;/* the definitions */
297 xmlRelaxNGPtr schema; /* the schema */
301 * xmlRelaxNGDocument:
303 * Structure associated to a RelaxNGs document element
305 struct _xmlRelaxNGDocument {
306 xmlChar *href; /* the normalized href value */
307 xmlDocPtr doc; /* the associated XML document */
308 xmlRelaxNGDefinePtr content;/* the definitions */
309 xmlRelaxNGPtr schema; /* the schema */
313 /************************************************************************
315 * Preliminary type checking interfaces *
317 ************************************************************************/
319 * xmlRelaxNGTypeHave:
320 * @data: data needed for the library
321 * @type: the type name
322 * @value: the value to check
324 * Function provided by a type library to check if a type is exported
326 * Returns 1 if yes, 0 if no and -1 in case of error.
328 typedef int (*xmlRelaxNGTypeHave) (void *data, const xmlChar *type);
331 * xmlRelaxNGTypeCheck:
332 * @data: data needed for the library
333 * @type: the type name
334 * @value: the value to check
336 * Function provided by a type library to check if a value match a type
338 * Returns 1 if yes, 0 if no and -1 in case of error.
340 typedef int (*xmlRelaxNGTypeCheck) (void *data, const xmlChar *type,
341 const xmlChar *value);
344 * xmlRelaxNGTypeCompare:
345 * @data: data needed for the library
346 * @type: the type name
347 * @value1: the first value
348 * @value2: the second value
350 * Function provided by a type library to compare two values accordingly
353 * Returns 1 if yes, 0 if no and -1 in case of error.
355 typedef int (*xmlRelaxNGTypeCompare) (void *data, const xmlChar *type,
356 const xmlChar *value1,
357 const xmlChar *value2);
358 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary;
359 typedef xmlRelaxNGTypeLibrary *xmlRelaxNGTypeLibraryPtr;
360 struct _xmlRelaxNGTypeLibrary {
361 const xmlChar *namespace; /* the datatypeLibrary value */
362 void *data; /* data needed for the library */
363 xmlRelaxNGTypeHave have; /* the export function */
364 xmlRelaxNGTypeCheck check; /* the checking function */
365 xmlRelaxNGTypeCompare comp; /* the compare function */
368 /************************************************************************
370 * Allocation functions *
372 ************************************************************************/
373 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
374 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
375 static void xmlRelaxNGNormExtSpace(xmlChar *value);
378 * xmlRelaxNGFreeDocument:
379 * @docu: a document structure
381 * Deallocate a RelaxNG document structure.
384 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu)
389 if (docu->href != NULL)
391 if (docu->doc != NULL)
392 xmlFreeDoc(docu->doc);
393 if (docu->schema != NULL)
394 xmlRelaxNGFree(docu->schema);
399 * xmlRelaxNGFreeInclude:
400 * @incl: a include structure
402 * Deallocate a RelaxNG include structure.
405 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl)
410 if (incl->href != NULL)
412 if (incl->doc != NULL)
413 xmlFreeDoc(incl->doc);
414 if (incl->schema != NULL)
415 xmlRelaxNGFree(incl->schema);
420 * xmlRelaxNGNewRelaxNG:
421 * @ctxt: a Relax-NG validation context (optional)
423 * Allocate a new RelaxNG structure.
425 * Returns the newly allocated structure or NULL in case or error
428 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt)
432 ret = (xmlRelaxNGPtr) xmlMalloc(sizeof(xmlRelaxNG));
434 if ((ctxt != NULL) && (ctxt->error != NULL))
435 ctxt->error(ctxt->userData, "Out of memory\n");
439 memset(ret, 0, sizeof(xmlRelaxNG));
446 * @schema: a schema structure
448 * Deallocate a RelaxNG structure.
451 xmlRelaxNGFree(xmlRelaxNGPtr schema)
456 if (schema->topgrammar != NULL)
457 xmlRelaxNGFreeGrammar(schema->topgrammar);
458 if (schema->doc != NULL)
459 xmlFreeDoc(schema->doc);
460 if (schema->documents != NULL)
461 xmlHashFree(schema->documents, (xmlHashDeallocator)
462 xmlRelaxNGFreeDocument);
463 if (schema->includes != NULL)
464 xmlHashFree(schema->includes, (xmlHashDeallocator)
465 xmlRelaxNGFreeInclude);
466 if (schema->defTab != NULL) {
469 for (i = 0;i < schema->defNr;i++)
470 xmlRelaxNGFreeDefine(schema->defTab[i]);
471 xmlFree(schema->defTab);
478 * xmlRelaxNGNewGrammar:
479 * @ctxt: a Relax-NG validation context (optional)
481 * Allocate a new RelaxNG grammar.
483 * Returns the newly allocated structure or NULL in case or error
485 static xmlRelaxNGGrammarPtr
486 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt)
488 xmlRelaxNGGrammarPtr ret;
490 ret = (xmlRelaxNGGrammarPtr) xmlMalloc(sizeof(xmlRelaxNGGrammar));
492 if ((ctxt != NULL) && (ctxt->error != NULL))
493 ctxt->error(ctxt->userData, "Out of memory\n");
497 memset(ret, 0, sizeof(xmlRelaxNGGrammar));
503 * xmlRelaxNGFreeGrammar:
504 * @grammar: a grammar structure
506 * Deallocate a RelaxNG grammar structure.
509 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar)
514 if (grammar->next != NULL) {
515 xmlRelaxNGFreeGrammar(grammar->next);
517 if (grammar->refs != NULL) {
518 xmlHashFree(grammar->refs, NULL);
520 if (grammar->defs != NULL) {
521 xmlHashFree(grammar->defs, NULL);
528 * xmlRelaxNGNewDefine:
529 * @ctxt: a Relax-NG validation context
530 * @node: the node in the input document.
532 * Allocate a new RelaxNG define.
534 * Returns the newly allocated structure or NULL in case or error
536 static xmlRelaxNGDefinePtr
537 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node)
539 xmlRelaxNGDefinePtr ret;
541 if (ctxt->defMax == 0) {
544 ctxt->defTab = (xmlRelaxNGDefinePtr *)
545 xmlMalloc(ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
546 if (ctxt->defTab == NULL) {
547 if ((ctxt != NULL) && (ctxt->error != NULL))
548 ctxt->error(ctxt->userData, "Out of memory\n");
552 } else if (ctxt->defMax <= ctxt->defNr) {
553 xmlRelaxNGDefinePtr *tmp;
555 tmp = (xmlRelaxNGDefinePtr *) xmlRealloc(ctxt->defTab,
556 ctxt->defMax * sizeof(xmlRelaxNGDefinePtr));
558 if ((ctxt != NULL) && (ctxt->error != NULL))
559 ctxt->error(ctxt->userData, "Out of memory\n");
565 ret = (xmlRelaxNGDefinePtr) xmlMalloc(sizeof(xmlRelaxNGDefine));
567 if ((ctxt != NULL) && (ctxt->error != NULL))
568 ctxt->error(ctxt->userData, "Out of memory\n");
572 memset(ret, 0, sizeof(xmlRelaxNGDefine));
573 ctxt->defTab[ctxt->defNr++] = ret;
580 * xmlRelaxNGFreePartition:
581 * @partitions: a partition set structure
583 * Deallocate RelaxNG partition set structures.
586 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions) {
587 xmlRelaxNGInterleaveGroupPtr group;
590 if (partitions != NULL) {
591 if (partitions->groups != NULL) {
592 for (j = 0;j < partitions->nbgroups;j++) {
593 group = partitions->groups[j];
595 if (group->defs != NULL)
596 xmlFree(group->defs);
597 if (group->attrs != NULL)
598 xmlFree(group->attrs);
602 xmlFree(partitions->groups);
608 * xmlRelaxNGFreeDefine:
609 * @define: a define structure
611 * Deallocate a RelaxNG define structure.
614 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define)
619 if ((define->data != NULL) &&
620 (define->type == XML_RELAXNG_INTERLEAVE))
621 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
622 if (define->name != NULL)
623 xmlFree(define->name);
624 if (define->ns != NULL)
626 if (define->value != NULL)
627 xmlFree(define->value);
632 * xmlRelaxNGNewValidState:
633 * @ctxt: a Relax-NG validation context
634 * @node: the current node or NULL for the document
636 * Allocate a new RelaxNG validation state
638 * Returns the newly allocated structure or NULL in case or error
640 static xmlRelaxNGValidStatePtr
641 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt, xmlNodePtr node)
643 xmlRelaxNGValidStatePtr ret;
645 xmlAttrPtr attrs[MAX_ATTR];
647 xmlNodePtr root = NULL;
650 root = xmlDocGetRootElement(ctxt->doc);
654 attr = node->properties;
655 while (attr != NULL) {
656 if (nbAttrs < MAX_ATTR)
657 attrs[nbAttrs++] = attr;
664 if (nbAttrs < MAX_ATTR)
665 attrs[nbAttrs] = NULL;
666 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(sizeof(xmlRelaxNGValidState) +
667 nbAttrs * sizeof(xmlAttrPtr));
669 if ((ctxt != NULL) && (ctxt->error != NULL))
670 ctxt->error(ctxt->userData, "Out of memory\n");
674 ret->endvalue = NULL;
676 ret->node = (xmlNodePtr) ctxt->doc;
681 ret->seq = node->children;
682 ret->nbAttrs = nbAttrs;
684 if (nbAttrs < MAX_ATTR) {
685 memcpy(&(ret->attrs[0]), attrs,
686 sizeof(xmlAttrPtr) * (nbAttrs + 1));
688 attr = node->properties;
690 while (attr != NULL) {
691 ret->attrs[nbAttrs++] = attr;
694 ret->attrs[nbAttrs] = NULL;
698 ret->nbAttrLeft = ret->nbAttrs;
703 * xmlRelaxNGCopyValidState:
704 * @ctxt: a Relax-NG validation context
705 * @state: a validation state
707 * Copy the validation state
709 * Returns the newly allocated structure or NULL in case or error
711 static xmlRelaxNGValidStatePtr
712 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt,
713 xmlRelaxNGValidStatePtr state)
715 xmlRelaxNGValidStatePtr ret;
721 size = sizeof(xmlRelaxNGValidState) +
722 state->nbAttrs * sizeof(xmlAttrPtr);
723 ret = (xmlRelaxNGValidStatePtr) xmlMalloc(size);
725 if ((ctxt != NULL) && (ctxt->error != NULL))
726 ctxt->error(ctxt->userData, "Out of memory\n");
729 memcpy(ret, state, size);
734 * xmlRelaxNGEqualValidState:
735 * @ctxt: a Relax-NG validation context
736 * @state1: a validation state
737 * @state2: a validation state
739 * Compare the validation states for equality
741 * Returns 1 if equald, 0 otherwise
744 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
745 xmlRelaxNGValidStatePtr state1,
746 xmlRelaxNGValidStatePtr state2)
750 if ((state1 == NULL) || (state2 == NULL))
752 if (state1 == state2)
754 if (state1->node != state2->node)
756 if (state1->seq != state2->seq)
758 if (state1->nbAttrLeft != state2->nbAttrLeft)
760 if (state1->nbAttrs != state2->nbAttrs)
762 if (state1->endvalue != state2->endvalue)
764 if ((state1->value != state2->value) &&
765 (!xmlStrEqual(state1->value, state2->value)))
767 for (i = 0;i < state1->nbAttrs;i++) {
768 if (state1->attrs[i] != state2->attrs[i])
775 * xmlRelaxNGFreeValidState:
776 * @state: a validation state structure
778 * Deallocate a RelaxNG validation state structure.
781 xmlRelaxNGFreeValidState(xmlRelaxNGValidStatePtr state)
789 /************************************************************************
791 * Document functions *
793 ************************************************************************/
794 static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
798 * xmlRelaxNGIncludePush:
799 * @ctxt: the parser context
800 * @value: the element doc
802 * Pushes a new include on top of the include stack
804 * Returns 0 in case of error, the index in the stack otherwise
807 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt,
808 xmlRelaxNGIncludePtr value)
810 if (ctxt->incTab == NULL) {
813 ctxt->incTab = (xmlRelaxNGIncludePtr *) xmlMalloc(
814 ctxt->incMax * sizeof(ctxt->incTab[0]));
815 if (ctxt->incTab == NULL) {
816 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
820 if (ctxt->incNr >= ctxt->incMax) {
823 (xmlRelaxNGIncludePtr *) xmlRealloc(ctxt->incTab,
825 sizeof(ctxt->incTab[0]));
826 if (ctxt->incTab == NULL) {
827 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
831 ctxt->incTab[ctxt->incNr] = value;
833 return (ctxt->incNr++);
837 * xmlRelaxNGIncludePop:
838 * @ctxt: the parser context
840 * Pops the top include from the include stack
842 * Returns the include just removed
844 static xmlRelaxNGIncludePtr
845 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt)
847 xmlRelaxNGIncludePtr ret;
849 if (ctxt->incNr <= 0)
853 ctxt->inc = ctxt->incTab[ctxt->incNr - 1];
856 ret = ctxt->incTab[ctxt->incNr];
857 ctxt->incTab[ctxt->incNr] = 0;
862 * xmlRelaxNGLoadInclude:
863 * @ctxt: the parser context
864 * @URL: the normalized URL
865 * @node: the include node.
866 * @ns: the namespace passed from the context.
868 * First lookup if the document is already loaded into the parser context,
869 * check against recursion. If not found the resource is loaded and
870 * the content is preprocessed before being returned back to the caller.
872 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
874 static xmlRelaxNGIncludePtr
875 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
876 xmlNodePtr node, const xmlChar *ns) {
877 xmlRelaxNGIncludePtr ret = NULL;
880 xmlNodePtr root, tmp, tmp2, cur;
883 * check against recursion in the stack
885 for (i = 0;i < ctxt->incNr;i++) {
886 if (xmlStrEqual(ctxt->incTab[i]->href, URL)) {
887 if (ctxt->error != NULL)
888 ctxt->error(ctxt->userData,
889 "Detected an externalRef recursion for %s\n",
897 * Lookup in the hash table
899 if (ctxt->includes == NULL) {
900 ctxt->includes = xmlHashCreate(10);
901 if (ctxt->includes == NULL) {
902 if (ctxt->error != NULL)
903 ctxt->error(ctxt->userData,
904 "Failed to allocate hash table for document\n");
910 ret = xmlHashLookup2(ctxt->includes, BAD_CAST "", URL);
912 ret = xmlHashLookup2(ctxt->includes, ns, URL);
921 doc = xmlParseFile((const char *) URL);
923 if (ctxt->error != NULL)
924 ctxt->error(ctxt->userData,
925 "xmlRelaxNG: could not load %s\n", URL);
931 * Allocate the document structures and register it first.
933 ret = (xmlRelaxNGIncludePtr) xmlMalloc(sizeof(xmlRelaxNGInclude));
935 if (ctxt->error != NULL)
936 ctxt->error(ctxt->userData,
937 "xmlRelaxNG: allocate memory for doc %s\n", URL);
942 memset(ret, 0, sizeof(xmlRelaxNGInclude));
944 ret->href = xmlStrdup(URL);
947 * transmit the ns if needed
950 root = xmlDocGetRootElement(doc);
952 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
953 xmlSetProp(root, BAD_CAST"ns", ns);
959 * push it on the stack and register it in the hash table
962 xmlHashAddEntry2(ctxt->includes, BAD_CAST "", URL, ret);
964 xmlHashAddEntry2(ctxt->includes, ns, URL, ret);
965 xmlRelaxNGIncludePush(ctxt, ret);
968 * Some preprocessing of the document content, this include recursing
969 * in the include stack.
971 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
978 * Pop up the include from the stack
980 xmlRelaxNGIncludePop(ctxt);
983 * Check that the top element is a grammar
985 root = xmlDocGetRootElement(doc);
987 if (ctxt->error != NULL)
988 ctxt->error(ctxt->userData,
989 "xmlRelaxNG: included document is empty %s\n", URL);
993 if (!IS_RELAXNG(root, "grammar")) {
994 if (ctxt->error != NULL)
995 ctxt->error(ctxt->userData,
996 "xmlRelaxNG: included document %s root is not a grammar\n",
1003 * Elimination of redefined rules in the include.
1005 cur = node->children;
1006 while (cur != NULL) {
1007 if (IS_RELAXNG(cur, "start")) {
1010 tmp = root->children;
1011 while (tmp != NULL) {
1013 if (IS_RELAXNG(tmp, "start")) {
1021 if (ctxt->error != NULL)
1022 ctxt->error(ctxt->userData,
1023 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1027 } else if (IS_RELAXNG(cur, "define")) {
1028 xmlChar *name, *name2;
1030 name = xmlGetProp(cur, BAD_CAST "name");
1032 if (ctxt->error != NULL)
1033 ctxt->error(ctxt->userData,
1034 "xmlRelaxNG: include %s has define without name\n",
1040 xmlRelaxNGNormExtSpace(name);
1041 tmp = root->children;
1042 while (tmp != NULL) {
1044 if (IS_RELAXNG(tmp, "define")) {
1045 name2 = xmlGetProp(tmp, BAD_CAST "name");
1046 xmlRelaxNGNormExtSpace(name2);
1047 if (name2 != NULL) {
1048 if (xmlStrEqual(name, name2)) {
1059 if (ctxt->error != NULL)
1060 ctxt->error(ctxt->userData,
1061 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1076 * xmlRelaxNGDocumentPush:
1077 * @ctxt: the parser context
1078 * @value: the element doc
1080 * Pushes a new doc on top of the doc stack
1082 * Returns 0 in case of error, the index in the stack otherwise
1085 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt,
1086 xmlRelaxNGDocumentPtr value)
1088 if (ctxt->docTab == NULL) {
1091 ctxt->docTab = (xmlRelaxNGDocumentPtr *) xmlMalloc(
1092 ctxt->docMax * sizeof(ctxt->docTab[0]));
1093 if (ctxt->docTab == NULL) {
1094 xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
1098 if (ctxt->docNr >= ctxt->docMax) {
1101 (xmlRelaxNGDocumentPtr *) xmlRealloc(ctxt->docTab,
1103 sizeof(ctxt->docTab[0]));
1104 if (ctxt->docTab == NULL) {
1105 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
1109 ctxt->docTab[ctxt->docNr] = value;
1111 return (ctxt->docNr++);
1115 * xmlRelaxNGDocumentPop:
1116 * @ctxt: the parser context
1118 * Pops the top doc from the doc stack
1120 * Returns the doc just removed
1122 static xmlRelaxNGDocumentPtr
1123 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt)
1125 xmlRelaxNGDocumentPtr ret;
1127 if (ctxt->docNr <= 0)
1130 if (ctxt->docNr > 0)
1131 ctxt->doc = ctxt->docTab[ctxt->docNr - 1];
1134 ret = ctxt->docTab[ctxt->docNr];
1135 ctxt->docTab[ctxt->docNr] = 0;
1140 * xmlRelaxNGLoadExternalRef:
1141 * @ctxt: the parser context
1142 * @URL: the normalized URL
1143 * @ns: the inherited ns if any
1145 * First lookup if the document is already loaded into the parser context,
1146 * check against recursion. If not found the resource is loaded and
1147 * the content is preprocessed before being returned back to the caller.
1149 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1151 static xmlRelaxNGDocumentPtr
1152 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *URL,
1153 const xmlChar *ns) {
1154 xmlRelaxNGDocumentPtr ret = NULL;
1160 * check against recursion in the stack
1162 for (i = 0;i < ctxt->docNr;i++) {
1163 if (xmlStrEqual(ctxt->docTab[i]->href, URL)) {
1164 if (ctxt->error != NULL)
1165 ctxt->error(ctxt->userData,
1166 "Detected an externalRef recursion for %s\n",
1174 * Lookup in the hash table
1176 if (ctxt->documents == NULL) {
1177 ctxt->documents = xmlHashCreate(10);
1178 if (ctxt->documents == NULL) {
1179 if (ctxt->error != NULL)
1180 ctxt->error(ctxt->userData,
1181 "Failed to allocate hash table for document\n");
1187 ret = xmlHashLookup2(ctxt->documents, BAD_CAST "", URL);
1189 ret = xmlHashLookup2(ctxt->documents, ns, URL);
1198 doc = xmlParseFile((const char *) URL);
1200 if (ctxt->error != NULL)
1201 ctxt->error(ctxt->userData,
1202 "xmlRelaxNG: could not load %s\n", URL);
1208 * Allocate the document structures and register it first.
1210 ret = (xmlRelaxNGDocumentPtr) xmlMalloc(sizeof(xmlRelaxNGDocument));
1212 if (ctxt->error != NULL)
1213 ctxt->error(ctxt->userData,
1214 "xmlRelaxNG: allocate memory for doc %s\n", URL);
1219 memset(ret, 0, sizeof(xmlRelaxNGDocument));
1221 ret->href = xmlStrdup(URL);
1224 * transmit the ns if needed
1227 root = xmlDocGetRootElement(doc);
1229 if (xmlHasProp(root, BAD_CAST"ns") == NULL) {
1230 xmlSetProp(root, BAD_CAST"ns", ns);
1236 * push it on the stack and register it in the hash table
1239 xmlHashAddEntry2(ctxt->documents, BAD_CAST "", URL, ret);
1241 xmlHashAddEntry2(ctxt->documents, ns, URL, ret);
1242 xmlRelaxNGDocumentPush(ctxt, ret);
1245 * Some preprocessing of the document content
1247 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
1253 xmlRelaxNGDocumentPop(ctxt);
1258 /************************************************************************
1262 ************************************************************************/
1264 #define VALID_CTXT() \
1265 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) \
1266 xmlGenericError(xmlGenericErrorContext, \
1267 "error detected at %s:%d\n", \
1268 __FILE__, __LINE__);
1270 #define VALID_ERROR(a) \
1271 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) \
1272 if (ctxt->error != NULL) ctxt->error(ctxt->userData, a)
1273 #define VALID_ERROR2(a, b) \
1274 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) \
1275 if (ctxt->error != NULL) ctxt->error(ctxt->userData, a, b)
1276 #define VALID_ERROR3(a, b, c) \
1277 if (((ctxt->flags & 1) == 0) || (ctxt->flags & 2)) \
1278 if (ctxt->error != NULL) ctxt->error(ctxt->userData, a, b, c)
1282 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def) {
1286 case XML_RELAXNG_EMPTY: return("empty");
1287 case XML_RELAXNG_NOT_ALLOWED: return("notAllowed");
1288 case XML_RELAXNG_EXCEPT: return("except");
1289 case XML_RELAXNG_TEXT: return("text");
1290 case XML_RELAXNG_ELEMENT: return("element");
1291 case XML_RELAXNG_DATATYPE: return("datatype");
1292 case XML_RELAXNG_VALUE: return("value");
1293 case XML_RELAXNG_LIST: return("list");
1294 case XML_RELAXNG_ATTRIBUTE: return("attribute");
1295 case XML_RELAXNG_DEF: return("def");
1296 case XML_RELAXNG_REF: return("ref");
1297 case XML_RELAXNG_EXTERNALREF: return("externalRef");
1298 case XML_RELAXNG_PARENTREF: return("parentRef");
1299 case XML_RELAXNG_OPTIONAL: return("optional");
1300 case XML_RELAXNG_ZEROORMORE: return("zeroOrMore");
1301 case XML_RELAXNG_ONEORMORE: return("oneOrMore");
1302 case XML_RELAXNG_CHOICE: return("choice");
1303 case XML_RELAXNG_GROUP: return("group");
1304 case XML_RELAXNG_INTERLEAVE: return("interleave");
1305 case XML_RELAXNG_START: return("start");
1313 * xmlRelaxNGErrorContext:
1314 * @ctxt: the parsing context
1315 * @schema: the schema being built
1316 * @node: the node being processed
1317 * @child: the child being processed
1319 * Dump a RelaxNGType structure
1322 xmlRelaxNGErrorContext(xmlRelaxNGParserCtxtPtr ctxt, xmlRelaxNGPtr schema,
1323 xmlNodePtr node, xmlNodePtr child)
1326 const xmlChar *file = NULL;
1327 const xmlChar *name = NULL;
1328 const char *type = "error";
1330 if ((ctxt == NULL) || (ctxt->error == NULL))
1337 if ((node->type == XML_DOCUMENT_NODE) ||
1338 (node->type == XML_HTML_DOCUMENT_NODE)) {
1339 xmlDocPtr doc = (xmlDocPtr) node;
1344 * Try to find contextual informations to report
1346 if (node->type == XML_ELEMENT_NODE) {
1347 line = (int) node->content;
1348 } else if ((node->prev != NULL) &&
1349 (node->prev->type == XML_ELEMENT_NODE)) {
1350 line = (int) node->prev->content;
1351 } else if ((node->parent != NULL) &&
1352 (node->parent->type == XML_ELEMENT_NODE)) {
1353 line = (int) node->parent->content;
1355 if ((node->doc != NULL) && (node->doc->URL != NULL))
1356 file = node->doc->URL;
1357 if (node->name != NULL)
1363 type = "compilation error";
1364 else if (schema != NULL)
1365 type = "runtime error";
1367 if ((file != NULL) && (line != 0) && (name != NULL))
1368 ctxt->error(ctxt->userData, "%s: file %s line %d element %s\n",
1369 type, file, line, name);
1370 else if ((file != NULL) && (name != NULL))
1371 ctxt->error(ctxt->userData, "%s: file %s element %s\n",
1373 else if ((file != NULL) && (line != 0))
1374 ctxt->error(ctxt->userData, "%s: file %s line %d\n", type, file, line);
1375 else if (file != NULL)
1376 ctxt->error(ctxt->userData, "%s: file %s\n", type, file);
1377 else if (name != NULL)
1378 ctxt->error(ctxt->userData, "%s: element %s\n", type, name);
1380 ctxt->error(ctxt->userData, "%s\n", type);
1384 /************************************************************************
1386 * Type library hooks *
1388 ************************************************************************/
1389 static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
1390 const xmlChar *str);
1393 * xmlRelaxNGSchemaTypeHave:
1394 * @data: data needed for the library
1395 * @type: the type name
1397 * Check if the given type is provided by
1398 * the W3C XMLSchema Datatype library.
1400 * Returns 1 if yes, 0 if no and -1 in case of error.
1403 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED,
1404 const xmlChar *type) {
1405 xmlSchemaTypePtr typ;
1409 typ = xmlSchemaGetPredefinedType(type,
1410 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1417 * xmlRelaxNGSchemaTypeCheck:
1418 * @data: data needed for the library
1419 * @type: the type name
1420 * @value: the value to check
1422 * Check if the given type and value are validated by
1423 * the W3C XMLSchema Datatype library.
1425 * Returns 1 if yes, 0 if no and -1 in case of error.
1428 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED,
1429 const xmlChar *type,
1430 const xmlChar *value) {
1431 xmlSchemaTypePtr typ;
1435 * TODO: the type should be cached ab provided back, interface subject
1437 * TODO: handle facets, may require an additional interface and keep
1438 * the value returned from the validation.
1440 if ((type == NULL) || (value == NULL))
1442 typ = xmlSchemaGetPredefinedType(type,
1443 BAD_CAST "http://www.w3.org/2001/XMLSchema");
1446 ret = xmlSchemaValidatePredefinedType(typ, value, NULL);
1455 * xmlRelaxNGSchemaTypeCompare:
1456 * @data: data needed for the library
1457 * @type: the type name
1458 * @value1: the first value
1459 * @value2: the second value
1461 * Compare two values accordingly a type from the W3C XMLSchema
1464 * Returns 1 if yes, 0 if no and -1 in case of error.
1467 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED,
1468 const xmlChar *type ATTRIBUTE_UNUSED,
1469 const xmlChar *value1 ATTRIBUTE_UNUSED,
1470 const xmlChar *value2 ATTRIBUTE_UNUSED) {
1476 * xmlRelaxNGDefaultTypeHave:
1477 * @data: data needed for the library
1478 * @type: the type name
1480 * Check if the given type is provided by
1481 * the default datatype library.
1483 * Returns 1 if yes, 0 if no and -1 in case of error.
1486 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED, const xmlChar *type) {
1489 if (xmlStrEqual(type, BAD_CAST "string"))
1491 if (xmlStrEqual(type, BAD_CAST "token"))
1497 * xmlRelaxNGDefaultTypeCheck:
1498 * @data: data needed for the library
1499 * @type: the type name
1500 * @value: the value to check
1502 * Check if the given type and value are validated by
1503 * the default datatype library.
1505 * Returns 1 if yes, 0 if no and -1 in case of error.
1508 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED,
1509 const xmlChar *type ATTRIBUTE_UNUSED,
1510 const xmlChar *value ATTRIBUTE_UNUSED) {
1513 if (xmlStrEqual(type, BAD_CAST "string"))
1515 if (xmlStrEqual(type, BAD_CAST "token")) {
1517 const xmlChar *cur = value;
1520 if (!IS_BLANK(*cur))
1532 * xmlRelaxNGDefaultTypeCompare:
1533 * @data: data needed for the library
1534 * @type: the type name
1535 * @value1: the first value
1536 * @value2: the second value
1538 * Compare two values accordingly a type from the default
1541 * Returns 1 if yes, 0 if no and -1 in case of error.
1544 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED,
1545 const xmlChar *type ATTRIBUTE_UNUSED,
1546 const xmlChar *value1 ATTRIBUTE_UNUSED,
1547 const xmlChar *value2 ATTRIBUTE_UNUSED) {
1550 if (xmlStrEqual(type, BAD_CAST "string")) {
1551 ret = xmlStrEqual(value1, value2);
1552 } else if (xmlStrEqual(type, BAD_CAST "token")) {
1553 if (!xmlStrEqual(value1, value2)) {
1554 xmlChar *nval, *nvalue;
1557 * TODO: trivial optimizations are possible by
1558 * computing at compile-time
1560 nval = xmlRelaxNGNormalize(NULL, value1);
1561 nvalue = xmlRelaxNGNormalize(NULL, value2);
1563 if ((nval == NULL) || (nvalue == NULL))
1565 else if (xmlStrEqual(nval, nvalue))
1579 static int xmlRelaxNGTypeInitialized = 0;
1580 static xmlHashTablePtr xmlRelaxNGRegisteredTypes = NULL;
1583 * xmlRelaxNGFreeTypeLibrary:
1584 * @lib: the type library structure
1585 * @namespace: the URI bound to the library
1587 * Free the structure associated to the type library
1590 xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib,
1591 const xmlChar *namespace ATTRIBUTE_UNUSED) {
1594 if (lib->namespace != NULL)
1595 xmlFree((xmlChar *)lib->namespace);
1600 * xmlRelaxNGRegisterTypeLibrary:
1601 * @namespace: the URI bound to the library
1602 * @data: data associated to the library
1603 * @have: the provide function
1604 * @check: the checking function
1605 * @comp: the comparison function
1607 * Register a new type library
1609 * Returns 0 in case of success and -1 in case of error.
1612 xmlRelaxNGRegisterTypeLibrary(const xmlChar *namespace, void *data,
1613 xmlRelaxNGTypeHave have, xmlRelaxNGTypeCheck check,
1614 xmlRelaxNGTypeCompare comp) {
1615 xmlRelaxNGTypeLibraryPtr lib;
1618 if ((xmlRelaxNGRegisteredTypes == NULL) || (namespace == NULL) ||
1619 (check == NULL) || (comp == NULL))
1621 if (xmlHashLookup(xmlRelaxNGRegisteredTypes, namespace) != NULL) {
1622 xmlGenericError(xmlGenericErrorContext,
1623 "Relax-NG types library '%s' already registered\n",
1627 lib = (xmlRelaxNGTypeLibraryPtr) xmlMalloc(sizeof(xmlRelaxNGTypeLibrary));
1629 xmlGenericError(xmlGenericErrorContext,
1630 "Relax-NG types library '%s' malloc() failed\n",
1634 memset(lib, 0, sizeof(xmlRelaxNGTypeLibrary));
1635 lib->namespace = xmlStrdup(namespace);
1640 ret = xmlHashAddEntry(xmlRelaxNGRegisteredTypes, namespace, lib);
1642 xmlGenericError(xmlGenericErrorContext,
1643 "Relax-NG types library failed to register '%s'\n",
1645 xmlRelaxNGFreeTypeLibrary(lib, namespace);
1652 * xmlRelaxNGInitTypes:
1654 * Initilize the default type libraries.
1656 * Returns 0 in case of success and -1 in case of error.
1659 xmlRelaxNGInitTypes(void) {
1660 if (xmlRelaxNGTypeInitialized != 0)
1662 xmlRelaxNGRegisteredTypes = xmlHashCreate(10);
1663 if (xmlRelaxNGRegisteredTypes == NULL) {
1664 xmlGenericError(xmlGenericErrorContext,
1665 "Failed to allocate sh table for Relax-NG types\n");
1668 xmlRelaxNGRegisterTypeLibrary(
1669 BAD_CAST "http://www.w3.org/2001/XMLSchema-datatypes",
1671 xmlRelaxNGSchemaTypeHave,
1672 xmlRelaxNGSchemaTypeCheck,
1673 xmlRelaxNGSchemaTypeCompare);
1674 xmlRelaxNGRegisterTypeLibrary(
1677 xmlRelaxNGDefaultTypeHave,
1678 xmlRelaxNGDefaultTypeCheck,
1679 xmlRelaxNGDefaultTypeCompare);
1680 xmlRelaxNGTypeInitialized = 1;
1685 * xmlRelaxNGCleanupTypes:
1687 * Cleanup the default Schemas type library associated to RelaxNG
1690 xmlRelaxNGCleanupTypes(void) {
1691 if (xmlRelaxNGTypeInitialized == 0)
1693 xmlSchemaCleanupTypes();
1694 xmlHashFree(xmlRelaxNGRegisteredTypes, (xmlHashDeallocator)
1695 xmlRelaxNGFreeTypeLibrary);
1696 xmlRelaxNGTypeInitialized = 0;
1699 /************************************************************************
1701 * Parsing functions *
1703 ************************************************************************/
1705 static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(
1706 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
1707 static xmlRelaxNGDefinePtr xmlRelaxNGParseElement(
1708 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
1709 static xmlRelaxNGDefinePtr xmlRelaxNGParsePatterns(
1710 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes, int group);
1711 static xmlRelaxNGDefinePtr xmlRelaxNGParsePattern(
1712 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
1713 static xmlRelaxNGPtr xmlRelaxNGParseDocument(
1714 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node);
1715 static int xmlRelaxNGParseGrammarContent(
1716 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
1717 static xmlRelaxNGDefinePtr xmlRelaxNGParseNameClass(
1718 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
1719 xmlRelaxNGDefinePtr def);
1720 static xmlRelaxNGGrammarPtr xmlRelaxNGParseGrammar(
1721 xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes);
1722 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
1723 xmlRelaxNGDefinePtr define, xmlNodePtr elem);
1726 #define IS_BLANK_NODE(n) \
1727 (((n)->type == XML_TEXT_NODE) && (xmlRelaxNGIsBlank((n)->content)))
1730 * xmlRelaxNGIsBlank:
1733 * Check if a string is ignorable c.f. 4.2. Whitespace
1735 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
1738 xmlRelaxNGIsBlank(xmlChar *str) {
1742 if (!(IS_BLANK(*str))) return(0);
1749 * xmlRelaxNGGetDataTypeLibrary:
1750 * @ctxt: a Relax-NG parser context
1751 * @node: the current data or value element
1753 * Applies algorithm from 4.3. datatypeLibrary attribute
1755 * Returns the datatypeLibary value or NULL if not found
1758 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
1760 xmlChar *ret, *escape;
1762 if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
1763 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
1769 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
1770 if (escape == NULL) {
1777 node = node->parent;
1778 while ((node != NULL) && (node->type == XML_ELEMENT_NODE)) {
1779 ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
1785 escape = xmlURIEscapeStr(ret, BAD_CAST ":/#?");
1786 if (escape == NULL) {
1792 node = node->parent;
1798 * xmlRelaxNGParseValue:
1799 * @ctxt: a Relax-NG parser context
1800 * @node: the data node.
1802 * parse the content of a RelaxNG value node.
1804 * Returns the definition pointer or NULL in case of error
1806 static xmlRelaxNGDefinePtr
1807 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
1808 xmlRelaxNGDefinePtr def = NULL;
1809 xmlRelaxNGTypeLibraryPtr lib;
1814 def = xmlRelaxNGNewDefine(ctxt, node);
1817 def->type = XML_RELAXNG_VALUE;
1819 type = xmlGetProp(node, BAD_CAST "type");
1821 xmlRelaxNGNormExtSpace(type);
1822 if (xmlValidateNCName(type, 0)) {
1823 if (ctxt->error != NULL)
1824 ctxt->error(ctxt->userData,
1825 "value type '%s' is not an NCName\n",
1829 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
1830 if (library == NULL)
1831 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
1836 lib = (xmlRelaxNGTypeLibraryPtr)
1837 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
1839 if (ctxt->error != NULL)
1840 ctxt->error(ctxt->userData,
1841 "Use of unregistered type library '%s'\n",
1847 if (lib->have == NULL) {
1848 if (ctxt->error != NULL)
1849 ctxt->error(ctxt->userData,
1850 "Internal error with type library '%s': no 'have'\n",
1854 tmp = lib->have(lib->data, def->name);
1856 if (ctxt->error != NULL)
1857 ctxt->error(ctxt->userData,
1858 "Error type '%s' is not exported by type library '%s'\n",
1859 def->name, library);
1865 if (node->children == NULL) {
1866 def->value = xmlStrdup(BAD_CAST "");
1867 } else if ((node->children->type != XML_TEXT_NODE) ||
1868 (node->children->next != NULL)) {
1869 if (ctxt->error != NULL)
1870 ctxt->error(ctxt->userData,
1871 "Expecting a single text value for <value>content\n");
1874 def->value = xmlNodeGetContent(node);
1875 if (def->value == NULL) {
1876 if (ctxt->error != NULL)
1877 ctxt->error(ctxt->userData,
1878 "Element <value> has no content\n");
1882 /* TODO check ahead of time that the value is okay per the type */
1887 * xmlRelaxNGParseData:
1888 * @ctxt: a Relax-NG parser context
1889 * @node: the data node.
1891 * parse the content of a RelaxNG data node.
1893 * Returns the definition pointer or NULL in case of error
1895 static xmlRelaxNGDefinePtr
1896 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
1897 xmlRelaxNGDefinePtr def = NULL, except, last = NULL;
1898 xmlRelaxNGDefinePtr param, lastparam = NULL;
1899 xmlRelaxNGTypeLibraryPtr lib;
1905 type = xmlGetProp(node, BAD_CAST "type");
1907 if (ctxt->error != NULL)
1908 ctxt->error(ctxt->userData,
1909 "data has no type\n");
1913 xmlRelaxNGNormExtSpace(type);
1914 if (xmlValidateNCName(type, 0)) {
1915 if (ctxt->error != NULL)
1916 ctxt->error(ctxt->userData,
1917 "data type '%s' is not an NCName\n",
1921 library = xmlRelaxNGGetDataTypeLibrary(ctxt, node);
1922 if (library == NULL)
1923 library = xmlStrdup(BAD_CAST "http://relaxng.org/ns/structure/1.0");
1925 def = xmlRelaxNGNewDefine(ctxt, node);
1930 def->type = XML_RELAXNG_DATATYPE;
1934 lib = (xmlRelaxNGTypeLibraryPtr)
1935 xmlHashLookup(xmlRelaxNGRegisteredTypes, library);
1937 if (ctxt->error != NULL)
1938 ctxt->error(ctxt->userData,
1939 "Use of unregistered type library '%s'\n",
1945 if (lib->have == NULL) {
1946 if (ctxt->error != NULL)
1947 ctxt->error(ctxt->userData,
1948 "Internal error with type library '%s': no 'have'\n",
1952 tmp = lib->have(lib->data, def->name);
1954 if (ctxt->error != NULL)
1955 ctxt->error(ctxt->userData,
1956 "Error type '%s' is not exported by type library '%s'\n",
1957 def->name, library);
1962 content = node->children;
1965 * Handle optional params
1967 while (content != NULL) {
1968 if (!xmlStrEqual(content->name, BAD_CAST "param"))
1970 if (xmlStrEqual(library,
1971 BAD_CAST"http://relaxng.org/ns/structure/1.0")) {
1972 if (ctxt->error != NULL)
1973 ctxt->error(ctxt->userData,
1974 "Type library '%s' does not allow type parameters\n",
1977 content = content->next;
1978 while ((content != NULL) &&
1979 (xmlStrEqual(content->name, BAD_CAST "param")))
1980 content = content->next;
1982 param = xmlRelaxNGNewDefine(ctxt, node);
1983 if (param != NULL) {
1984 param->type = XML_RELAXNG_PARAM;
1985 param->name = xmlGetProp(content, BAD_CAST "name");
1986 if (param->name == NULL) {
1987 if (ctxt->error != NULL)
1988 ctxt->error(ctxt->userData,
1989 "param has no name\n");
1992 param->value = xmlNodeGetContent(content);
1993 if (lastparam == NULL) {
1994 def->attrs = lastparam = param;
1996 lastparam->next = param;
2000 content = content->next;
2004 * Handle optional except
2006 if ((content != NULL) && (xmlStrEqual(content->name, BAD_CAST "except"))) {
2008 xmlRelaxNGDefinePtr tmp2, last2 = NULL;
2010 except = xmlRelaxNGNewDefine(ctxt, node);
2011 if (except == NULL) {
2014 except->type = XML_RELAXNG_EXCEPT;
2015 child = content->children;
2017 def->content = except;
2019 last->next = except;
2021 if (child == NULL) {
2022 if (ctxt->error != NULL)
2023 ctxt->error(ctxt->userData,
2024 "except has no content\n");
2027 while (child != NULL) {
2028 tmp2 = xmlRelaxNGParsePattern(ctxt, child);
2030 if (last2 == NULL) {
2031 except->content = last2 = tmp2;
2037 child = child->next;
2039 content = content->next;
2042 * Check there is no unhandled data
2044 if (content != NULL) {
2045 if (ctxt->error != NULL)
2046 ctxt->error(ctxt->userData,
2047 "Element data has unexpected content %s\n", content->name);
2054 static const xmlChar *invalidName = BAD_CAST "\1";
2057 * xmlRelaxNGCompareNameClasses:
2058 * @defs1: the first element/attribute defs
2059 * @defs2: the second element/attribute defs
2060 * @name: the restriction on the name
2061 * @ns: the restriction on the namespace
2063 * Compare the 2 lists of element definitions. The comparison is
2064 * that if both lists do not accept the same QNames, it returns 1
2065 * If the 2 lists can accept the same QName the comparison returns 0
2067 * Returns 1 disttinct, 0 if equal
2070 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1,
2071 xmlRelaxNGDefinePtr def2) {
2075 xmlRelaxNGValidCtxt ctxt;
2076 ctxt.flags = FLAGS_IGNORABLE;
2078 if ((def1->type == XML_RELAXNG_ELEMENT) ||
2079 (def1->type == XML_RELAXNG_ATTRIBUTE)) {
2080 if (def2->type == XML_RELAXNG_TEXT)
2082 if (def1->name != NULL) {
2083 node.name = def1->name;
2085 node.name = invalidName;
2088 if (def1->ns != NULL) {
2089 if (def1->ns[0] == 0) {
2095 ns.href = invalidName;
2097 if (xmlRelaxNGElementMatch(&ctxt, def2, &node)) {
2098 if (def1->nameClass != NULL) {
2099 ret = xmlRelaxNGCompareNameClasses(def1->nameClass, def2);
2106 } else if (def1->type == XML_RELAXNG_TEXT) {
2107 if (def2->type == XML_RELAXNG_TEXT)
2110 } else if (def1->type == XML_RELAXNG_EXCEPT) {
2119 if ((def2->type == XML_RELAXNG_ELEMENT) ||
2120 (def2->type == XML_RELAXNG_ATTRIBUTE)) {
2121 if (def2->name != NULL) {
2122 node.name = def2->name;
2124 node.name = invalidName;
2127 if (def2->ns != NULL) {
2128 if (def2->ns[0] == 0) {
2134 ns.href = invalidName;
2136 if (xmlRelaxNGElementMatch(&ctxt, def1, &node)) {
2137 if (def2->nameClass != NULL) {
2138 ret = xmlRelaxNGCompareNameClasses(def2->nameClass, def1);
2154 * xmlRelaxNGCompareElemDefLists:
2155 * @ctxt: a Relax-NG parser context
2156 * @defs1: the first list of element/attribute defs
2157 * @defs2: the second list of element/attribute defs
2159 * Compare the 2 lists of element or attribute definitions. The comparison
2160 * is that if both lists do not accept the same QNames, it returns 1
2161 * If the 2 lists can accept the same QName the comparison returns 0
2163 * Returns 1 disttinct, 0 if equal
2166 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
2167 xmlRelaxNGDefinePtr *def1,
2168 xmlRelaxNGDefinePtr *def2) {
2169 xmlRelaxNGDefinePtr *basedef2 = def2;
2171 if ((def1 == NULL) || (def2 == NULL))
2173 if ((*def1 == NULL) || (*def2 == NULL))
2175 while (*def1 != NULL) {
2176 while ((*def2) != NULL) {
2177 if (xmlRelaxNGCompareNameClasses(*def1, *def2) == 0)
2188 * xmlRelaxNGGetElements:
2189 * @ctxt: a Relax-NG parser context
2190 * @def: the definition definition
2191 * @eora: gather elements (0) or attributes (1)
2193 * Compute the list of top elements a definition can generate
2195 * Returns a list of elements or NULL if none was found.
2197 static xmlRelaxNGDefinePtr *
2198 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt,
2199 xmlRelaxNGDefinePtr def,
2201 xmlRelaxNGDefinePtr *ret = NULL, parent, cur, tmp;
2206 * Don't run that check in case of error. Infinite recursion
2209 if (ctxt->nbErrors != 0)
2214 while (cur != NULL) {
2215 if (((eora == 0) && ((cur->type == XML_RELAXNG_ELEMENT) ||
2216 (cur->type == XML_RELAXNG_TEXT))) ||
2217 ((eora == 1) && (cur->type == XML_RELAXNG_ATTRIBUTE))) {
2220 ret = (xmlRelaxNGDefinePtr *)
2221 xmlMalloc((max + 1) * sizeof(xmlRelaxNGDefinePtr));
2223 if (ctxt->error != NULL)
2224 ctxt->error(ctxt->userData,
2225 "Out of memory in element search\n");
2229 } else if (max <= len) {
2231 ret = xmlRealloc(ret, (max + 1) * sizeof(xmlRelaxNGDefinePtr));
2233 if (ctxt->error != NULL)
2234 ctxt->error(ctxt->userData,
2235 "Out of memory in element search\n");
2242 } else if ((cur->type == XML_RELAXNG_CHOICE) ||
2243 (cur->type == XML_RELAXNG_INTERLEAVE) ||
2244 (cur->type == XML_RELAXNG_GROUP) ||
2245 (cur->type == XML_RELAXNG_ONEORMORE) ||
2246 (cur->type == XML_RELAXNG_ZEROORMORE) ||
2247 (cur->type == XML_RELAXNG_OPTIONAL) ||
2248 (cur->type == XML_RELAXNG_REF) ||
2249 (cur->type == XML_RELAXNG_DEF)) {
2251 * Don't go within elements or attributes or string values.
2252 * Just gather the element top list
2254 if (cur->content != NULL) {
2258 while (tmp != NULL) {
2259 tmp->parent = parent;
2267 if (cur->next != NULL) {
2273 if (cur == NULL) break;
2274 if (cur == def) return(ret);
2275 if (cur->next != NULL) {
2279 } while (cur != NULL);
2285 * xmlRelaxNGCheckGroupAttrs:
2286 * @ctxt: a Relax-NG parser context
2287 * @def: the group definition
2289 * Detects violations of rule 7.3
2292 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt,
2293 xmlRelaxNGDefinePtr def) {
2294 xmlRelaxNGDefinePtr **list;
2295 xmlRelaxNGDefinePtr cur;
2296 int nbchild = 0, i, j, ret;
2298 if ((def == NULL) ||
2299 ((def->type != XML_RELAXNG_GROUP) &&
2300 (def->type != XML_RELAXNG_ELEMENT)))
2304 * Don't run that check in case of error. Infinite recursion
2307 if (ctxt->nbErrors != 0)
2311 while (cur != NULL) {
2316 while (cur != NULL) {
2321 list = (xmlRelaxNGDefinePtr **) xmlMalloc(nbchild *
2322 sizeof(xmlRelaxNGDefinePtr *));
2324 if (ctxt->error != NULL)
2325 ctxt->error(ctxt->userData,
2326 "Out of memory in group computation\n");
2332 while (cur != NULL) {
2333 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
2338 while (cur != NULL) {
2339 list[i] = xmlRelaxNGGetElements(ctxt, cur, 1);
2344 for (i = 0;i < nbchild;i++) {
2345 if (list[i] == NULL)
2347 for (j = 0;j < i;j++) {
2348 if (list[j] == NULL)
2350 ret = xmlRelaxNGCompareElemDefLists(ctxt, list[i], list[j]);
2352 if (ctxt->error != NULL)
2353 ctxt->error(ctxt->userData,
2354 "Attributes conflicts in group\n");
2359 for (i = 0;i < nbchild;i++) {
2360 if (list[i] != NULL)
2367 * xmlRelaxNGComputeInterleaves:
2368 * @def: the interleave definition
2369 * @ctxt: a Relax-NG parser context
2370 * @name: the definition name
2372 * A lot of work for preprocessing interleave definitions
2373 * is potentially needed to get a decent execution speed at runtime
2374 * - trying to get a total order on the element nodes generated
2375 * by the interleaves, order the list of interleave definitions
2376 * following that order.
2377 * - if <text/> is used to handle mixed content, it is better to
2378 * flag this in the define and simplify the runtime checking
2382 xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def,
2383 xmlRelaxNGParserCtxtPtr ctxt,
2384 xmlChar *name ATTRIBUTE_UNUSED) {
2385 xmlRelaxNGDefinePtr cur;
2387 xmlRelaxNGPartitionPtr partitions = NULL;
2388 xmlRelaxNGInterleaveGroupPtr *groups = NULL;
2389 xmlRelaxNGInterleaveGroupPtr group;
2395 * Don't run that check in case of error. Infinite recursion
2398 if (ctxt->nbErrors != 0)
2401 #ifdef DEBUG_INTERLEAVE
2402 xmlGenericError(xmlGenericErrorContext,
2403 "xmlRelaxNGComputeInterleaves(%s)\n",
2407 while (cur != NULL) {
2412 #ifdef DEBUG_INTERLEAVE
2413 xmlGenericError(xmlGenericErrorContext, " %d child\n", nbchild);
2415 groups = (xmlRelaxNGInterleaveGroupPtr *)
2416 xmlMalloc(nbchild * sizeof(xmlRelaxNGInterleaveGroupPtr));
2420 while (cur != NULL) {
2421 groups[nbgroups] = (xmlRelaxNGInterleaveGroupPtr)
2422 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup));
2423 if (groups[nbgroups] == NULL)
2425 groups[nbgroups]->rule = cur;
2426 groups[nbgroups]->defs = xmlRelaxNGGetElements(ctxt, cur, 0);
2427 groups[nbgroups]->attrs = xmlRelaxNGGetElements(ctxt, cur, 1);
2431 #ifdef DEBUG_INTERLEAVE
2432 xmlGenericError(xmlGenericErrorContext, " %d groups\n", nbgroups);
2436 * Let's check that all rules makes a partitions according to 7.4
2438 partitions = (xmlRelaxNGPartitionPtr)
2439 xmlMalloc(sizeof(xmlRelaxNGPartition));
2440 if (partitions == NULL)
2442 partitions->nbgroups = nbgroups;
2443 for (i = 0;i < nbgroups;i++) {
2445 for (j = i+1;j < nbgroups;j++) {
2446 if (groups[j] == NULL)
2448 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->defs,
2451 if (ctxt->error != NULL)
2452 ctxt->error(ctxt->userData,
2453 "Element or text conflicts in interleave\n");
2456 ret = xmlRelaxNGCompareElemDefLists(ctxt, group->attrs,
2459 if (ctxt->error != NULL)
2460 ctxt->error(ctxt->userData,
2461 "Attributes conflicts in interleave\n");
2466 partitions->groups = groups;
2469 * and save the partition list back in the def
2471 def->data = partitions;
2475 if (ctxt->error != NULL)
2476 ctxt->error(ctxt->userData,
2477 "Out of memory in interleave computation\n");
2479 if (groups != NULL) {
2480 for (i = 0;i < nbgroups;i++)
2481 if (groups[i] != NULL) {
2482 if (groups[i]->defs != NULL)
2483 xmlFree(groups[i]->defs);
2488 xmlRelaxNGFreePartition(partitions);
2492 * xmlRelaxNGParseInterleave:
2493 * @ctxt: a Relax-NG parser context
2494 * @node: the data node.
2496 * parse the content of a RelaxNG interleave node.
2498 * Returns the definition pointer or NULL in case of error
2500 static xmlRelaxNGDefinePtr
2501 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2502 xmlRelaxNGDefinePtr def = NULL;
2503 xmlRelaxNGDefinePtr last = NULL, cur;
2506 def = xmlRelaxNGNewDefine(ctxt, node);
2510 def->type = XML_RELAXNG_INTERLEAVE;
2512 if (ctxt->interleaves == NULL)
2513 ctxt->interleaves = xmlHashCreate(10);
2514 if (ctxt->interleaves == NULL) {
2515 if (ctxt->error != NULL)
2516 ctxt->error(ctxt->userData,
2517 "Failed to create interleaves hash table\n");
2522 snprintf(name, 32, "interleave%d", ctxt->nbInterleaves++);
2523 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST name, def) < 0) {
2524 if (ctxt->error != NULL)
2525 ctxt->error(ctxt->userData,
2526 "Failed to add %s to hash table\n", name);
2530 child = node->children;
2531 if (child == NULL) {
2532 if (ctxt->error != NULL)
2533 ctxt->error(ctxt->userData, "Element interleave is empty\n");
2536 while (child != NULL) {
2537 if (IS_RELAXNG(child, "element")) {
2538 cur = xmlRelaxNGParseElement(ctxt, child);
2540 cur = xmlRelaxNGParsePattern(ctxt, child);
2545 def->content = last = cur;
2551 child = child->next;
2558 * xmlRelaxNGParseInclude:
2559 * @ctxt: a Relax-NG parser context
2560 * @node: the include node
2562 * Integrate the content of an include node in the current grammar
2564 * Returns 0 in case of success or -1 in case of error
2567 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2568 xmlRelaxNGIncludePtr incl;
2572 incl = node->_private;
2574 if (ctxt->error != NULL)
2575 ctxt->error(ctxt->userData,
2576 "Include node has no data\n");
2580 root = xmlDocGetRootElement(incl->doc);
2582 if (ctxt->error != NULL)
2583 ctxt->error(ctxt->userData,
2584 "Include document is empty\n");
2588 if (!xmlStrEqual(root->name, BAD_CAST "grammar")) {
2589 if (ctxt->error != NULL)
2590 ctxt->error(ctxt->userData,
2591 "Include document root is not a grammar\n");
2597 * Merge the definition from both the include and the internal list
2599 if (root->children != NULL) {
2600 tmp = xmlRelaxNGParseGrammarContent(ctxt, root->children);
2604 if (node->children != NULL) {
2605 tmp = xmlRelaxNGParseGrammarContent(ctxt, node->children);
2613 * xmlRelaxNGParseDefine:
2614 * @ctxt: a Relax-NG parser context
2615 * @node: the define node
2617 * parse the content of a RelaxNG define element node.
2619 * Returns 0 in case of success or -1 in case of error
2622 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2625 xmlRelaxNGDefinePtr def;
2626 const xmlChar *olddefine;
2628 name = xmlGetProp(node, BAD_CAST "name");
2630 if (ctxt->error != NULL)
2631 ctxt->error(ctxt->userData,
2632 "define has no name\n");
2635 xmlRelaxNGNormExtSpace(name);
2636 if (xmlValidateNCName(name, 0)) {
2637 if (ctxt->error != NULL)
2638 ctxt->error(ctxt->userData,
2639 "define name '%s' is not an NCName\n",
2643 def = xmlRelaxNGNewDefine(ctxt, node);
2648 def->type = XML_RELAXNG_DEF;
2650 if (node->children == NULL) {
2651 if (ctxt->error != NULL)
2652 ctxt->error(ctxt->userData,
2653 "define has no children\n");
2656 olddefine = ctxt->define;
2657 ctxt->define = name;
2658 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
2659 ctxt->define = olddefine;
2661 if (ctxt->grammar->defs == NULL)
2662 ctxt->grammar->defs = xmlHashCreate(10);
2663 if (ctxt->grammar->defs == NULL) {
2664 if (ctxt->error != NULL)
2665 ctxt->error(ctxt->userData,
2666 "Could not create definition hash\n");
2670 tmp = xmlHashAddEntry(ctxt->grammar->defs, name, def);
2672 xmlRelaxNGDefinePtr prev;
2674 prev = xmlHashLookup(ctxt->grammar->defs, name);
2676 if (ctxt->error != NULL)
2677 ctxt->error(ctxt->userData,
2678 "Internal error on define aggregation of %s\n",
2683 while (prev->nextHash != NULL)
2684 prev = prev->nextHash;
2685 prev->nextHash = def;
2694 * xmlRelaxNGProcessExternalRef:
2695 * @ctxt: the parser context
2696 * @node: the externlRef node
2698 * Process and compile an externlRef node
2700 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
2702 static xmlRelaxNGDefinePtr
2703 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2704 xmlRelaxNGDocumentPtr docu;
2705 xmlNodePtr root, tmp;
2707 int newNs = 0, oldflags;
2708 xmlRelaxNGDefinePtr def;
2710 docu = node->_private;
2712 def = xmlRelaxNGNewDefine(ctxt, node);
2715 def->type = XML_RELAXNG_EXTERNALREF;
2717 if (docu->content == NULL) {
2719 * Then do the parsing for good
2721 root = xmlDocGetRootElement(docu->doc);
2723 if (ctxt->error != NULL)
2724 ctxt->error(ctxt->userData,
2725 "xmlRelaxNGParse: %s is empty\n",
2731 * ns transmission rules
2733 ns = xmlGetProp(root, BAD_CAST "ns");
2736 while ((tmp != NULL) &&
2737 (tmp->type == XML_ELEMENT_NODE)) {
2738 ns = xmlGetProp(tmp, BAD_CAST "ns");
2745 xmlSetProp(root, BAD_CAST "ns", ns);
2754 * Parsing to get a precompiled schemas.
2756 oldflags = ctxt->flags;
2757 ctxt->flags |= XML_RELAXNG_IN_EXTERNALREF;
2758 docu->schema = xmlRelaxNGParseDocument(ctxt, root);
2759 ctxt->flags = oldflags;
2760 if ((docu->schema != NULL) &&
2761 (docu->schema->topgrammar != NULL)) {
2762 docu->content = docu->schema->topgrammar->start;
2766 * the externalRef may be reused in a different ns context
2769 xmlUnsetProp(root, BAD_CAST "ns");
2772 def->content = docu->content;
2780 * xmlRelaxNGParsePattern:
2781 * @ctxt: a Relax-NG parser context
2782 * @node: the pattern node.
2784 * parse the content of a RelaxNG pattern node.
2786 * Returns the definition pointer or NULL in case of error or if no
2787 * pattern is generated.
2789 static xmlRelaxNGDefinePtr
2790 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
2791 xmlRelaxNGDefinePtr def = NULL;
2796 if (IS_RELAXNG(node, "element")) {
2797 def = xmlRelaxNGParseElement(ctxt, node);
2798 } else if (IS_RELAXNG(node, "attribute")) {
2799 def = xmlRelaxNGParseAttribute(ctxt, node);
2800 } else if (IS_RELAXNG(node, "empty")) {
2801 def = xmlRelaxNGNewDefine(ctxt, node);
2804 def->type = XML_RELAXNG_EMPTY;
2805 if (node->children != NULL) {
2806 if (ctxt->error != NULL)
2807 ctxt->error(ctxt->userData, "empty: had a child node\n");
2810 } else if (IS_RELAXNG(node, "text")) {
2811 def = xmlRelaxNGNewDefine(ctxt, node);
2814 def->type = XML_RELAXNG_TEXT;
2815 if (node->children != NULL) {
2816 if (ctxt->error != NULL)
2817 ctxt->error(ctxt->userData, "text: had a child node\n");
2820 } else if (IS_RELAXNG(node, "zeroOrMore")) {
2821 def = xmlRelaxNGNewDefine(ctxt, node);
2824 def->type = XML_RELAXNG_ZEROORMORE;
2825 if (node->children == NULL) {
2826 if (ctxt->error != NULL)
2827 ctxt->error(ctxt->userData,
2828 "Element %s is empty\n", node->name);
2831 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
2833 } else if (IS_RELAXNG(node, "oneOrMore")) {
2834 def = xmlRelaxNGNewDefine(ctxt, node);
2837 def->type = XML_RELAXNG_ONEORMORE;
2838 if (node->children == NULL) {
2839 if (ctxt->error != NULL)
2840 ctxt->error(ctxt->userData,
2841 "Element %s is empty\n", node->name);
2844 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
2846 } else if (IS_RELAXNG(node, "optional")) {
2847 def = xmlRelaxNGNewDefine(ctxt, node);
2850 def->type = XML_RELAXNG_OPTIONAL;
2851 if (node->children == NULL) {
2852 if (ctxt->error != NULL)
2853 ctxt->error(ctxt->userData,
2854 "Element %s is empty\n", node->name);
2857 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 1);
2859 } else if (IS_RELAXNG(node, "choice")) {
2860 def = xmlRelaxNGNewDefine(ctxt, node);
2863 def->type = XML_RELAXNG_CHOICE;
2864 if (node->children == NULL) {
2865 if (ctxt->error != NULL)
2866 ctxt->error(ctxt->userData,
2867 "Element %s is empty\n", node->name);
2870 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
2872 } else if (IS_RELAXNG(node, "group")) {
2873 def = xmlRelaxNGNewDefine(ctxt, node);
2876 def->type = XML_RELAXNG_GROUP;
2877 if (node->children == NULL) {
2878 if (ctxt->error != NULL)
2879 ctxt->error(ctxt->userData,
2880 "Element %s is empty\n", node->name);
2883 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
2885 } else if (IS_RELAXNG(node, "ref")) {
2886 def = xmlRelaxNGNewDefine(ctxt, node);
2889 def->type = XML_RELAXNG_REF;
2890 def->name = xmlGetProp(node, BAD_CAST "name");
2891 if (def->name == NULL) {
2892 if (ctxt->error != NULL)
2893 ctxt->error(ctxt->userData,
2894 "ref has no name\n");
2897 xmlRelaxNGNormExtSpace(def->name);
2898 if (xmlValidateNCName(def->name, 0)) {
2899 if (ctxt->error != NULL)
2900 ctxt->error(ctxt->userData,
2901 "ref name '%s' is not an NCName\n",
2906 if (node->children != NULL) {
2907 if (ctxt->error != NULL)
2908 ctxt->error(ctxt->userData,
2909 "ref is not empty\n");
2912 if (ctxt->grammar->refs == NULL)
2913 ctxt->grammar->refs = xmlHashCreate(10);
2914 if (ctxt->grammar->refs == NULL) {
2915 if (ctxt->error != NULL)
2916 ctxt->error(ctxt->userData,
2917 "Could not create references hash\n");
2923 tmp = xmlHashAddEntry(ctxt->grammar->refs, def->name, def);
2925 xmlRelaxNGDefinePtr prev;
2927 prev = (xmlRelaxNGDefinePtr)
2928 xmlHashLookup(ctxt->grammar->refs, def->name);
2930 if (def->name != NULL) {
2931 if (ctxt->error != NULL)
2932 ctxt->error(ctxt->userData,
2933 "Error refs definitions '%s'\n",
2936 if (ctxt->error != NULL)
2937 ctxt->error(ctxt->userData,
2938 "Error refs definitions\n");
2943 def->nextHash = prev->nextHash;
2944 prev->nextHash = def;
2948 } else if (IS_RELAXNG(node, "data")) {
2949 def = xmlRelaxNGParseData(ctxt, node);
2951 } else if (IS_RELAXNG(node, "define")) {
2952 xmlRelaxNGParseDefine(ctxt, node);
2955 } else if (IS_RELAXNG(node, "value")) {
2956 def = xmlRelaxNGParseValue(ctxt, node);
2957 } else if (IS_RELAXNG(node, "list")) {
2958 def = xmlRelaxNGNewDefine(ctxt, node);
2961 def->type = XML_RELAXNG_LIST;
2962 if (node->children == NULL) {
2963 if (ctxt->error != NULL)
2964 ctxt->error(ctxt->userData,
2965 "Element %s is empty\n", node->name);
2968 def->content = xmlRelaxNGParsePatterns(ctxt, node->children, 0);
2970 } else if (IS_RELAXNG(node, "interleave")) {
2971 def = xmlRelaxNGParseInterleave(ctxt, node);
2972 } else if (IS_RELAXNG(node, "externalRef")) {
2973 def = xmlRelaxNGProcessExternalRef(ctxt, node);
2974 } else if (IS_RELAXNG(node, "notAllowed")) {
2975 def = xmlRelaxNGNewDefine(ctxt, node);
2978 def->type = XML_RELAXNG_NOT_ALLOWED;
2979 if (node->children != NULL) {
2980 if (ctxt->error != NULL)
2981 ctxt->error(ctxt->userData,
2982 "xmlRelaxNGParse: notAllowed element is not empty\n");
2985 } else if (IS_RELAXNG(node, "grammar")) {
2986 xmlRelaxNGGrammarPtr grammar, old;
2987 xmlRelaxNGGrammarPtr oldparent;
2989 oldparent = ctxt->parentgrammar;
2990 old = ctxt->grammar;
2991 ctxt->parentgrammar = old;
2992 grammar = xmlRelaxNGParseGrammar(ctxt, node->children);
2994 ctxt->grammar = old;
2995 ctxt->parentgrammar = oldparent;
2996 if (grammar != NULL) {
2997 grammar->next = old->next;
2998 old->next = grammar;
3001 if (grammar != NULL)
3002 def = grammar->start;
3005 } else if (IS_RELAXNG(node, "parentRef")) {
3006 if (ctxt->parentgrammar == NULL) {
3007 if (ctxt->error != NULL)
3008 ctxt->error(ctxt->userData,
3009 "Use of parentRef without a parent grammar\n");
3013 def = xmlRelaxNGNewDefine(ctxt, node);
3016 def->type = XML_RELAXNG_PARENTREF;
3017 def->name = xmlGetProp(node, BAD_CAST "name");
3018 if (def->name == NULL) {
3019 if (ctxt->error != NULL)
3020 ctxt->error(ctxt->userData,
3021 "parentRef has no name\n");
3024 xmlRelaxNGNormExtSpace(def->name);
3025 if (xmlValidateNCName(def->name, 0)) {
3026 if (ctxt->error != NULL)
3027 ctxt->error(ctxt->userData,
3028 "parentRef name '%s' is not an NCName\n",
3033 if (node->children != NULL) {
3034 if (ctxt->error != NULL)
3035 ctxt->error(ctxt->userData,
3036 "parentRef is not empty\n");
3039 if (ctxt->parentgrammar->refs == NULL)
3040 ctxt->parentgrammar->refs = xmlHashCreate(10);
3041 if (ctxt->parentgrammar->refs == NULL) {
3042 if (ctxt->error != NULL)
3043 ctxt->error(ctxt->userData,
3044 "Could not create references hash\n");
3047 } else if (def->name != NULL) {
3050 tmp = xmlHashAddEntry(ctxt->parentgrammar->refs, def->name, def);
3052 xmlRelaxNGDefinePtr prev;
3054 prev = (xmlRelaxNGDefinePtr)
3055 xmlHashLookup(ctxt->parentgrammar->refs, def->name);
3057 if (ctxt->error != NULL)
3058 ctxt->error(ctxt->userData,
3059 "Internal error parentRef definitions '%s'\n",
3064 def->nextHash = prev->nextHash;
3065 prev->nextHash = def;
3069 } else if (IS_RELAXNG(node, "mixed")) {
3070 if (node->children == NULL) {
3071 if (ctxt->error != NULL)
3072 ctxt->error(ctxt->userData,
3073 "Mixed is empty\n");
3077 def = xmlRelaxNGParseInterleave(ctxt, node);
3079 xmlRelaxNGDefinePtr tmp;
3081 if ((def->content != NULL) && (def->content->next != NULL)) {
3082 tmp = xmlRelaxNGNewDefine(ctxt, node);
3084 tmp->type = XML_RELAXNG_GROUP;
3085 tmp->content = def->content;
3090 tmp = xmlRelaxNGNewDefine(ctxt, node);
3093 tmp->type = XML_RELAXNG_TEXT;
3094 tmp->next = def->content;
3099 if (ctxt->error != NULL)
3100 ctxt->error(ctxt->userData,
3101 "Unexpected node %s is not a pattern\n",
3110 * xmlRelaxNGParseAttribute:
3111 * @ctxt: a Relax-NG parser context
3112 * @node: the element node
3114 * parse the content of a RelaxNG attribute node.
3116 * Returns the definition pointer or NULL in case of error.
3118 static xmlRelaxNGDefinePtr
3119 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3120 xmlRelaxNGDefinePtr ret, cur;
3124 ret = xmlRelaxNGNewDefine(ctxt, node);
3127 ret->type = XML_RELAXNG_ATTRIBUTE;
3128 ret->parent = ctxt->def;
3129 child = node->children;
3130 if (child == NULL) {
3131 if (ctxt->error != NULL)
3132 ctxt->error(ctxt->userData,
3133 "xmlRelaxNGParseattribute: attribute has no children\n");
3137 old_flags = ctxt->flags;
3138 ctxt->flags |= XML_RELAXNG_IN_ATTRIBUTE;
3139 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3141 child = child->next;
3143 if (child != NULL) {
3144 cur = xmlRelaxNGParsePattern(ctxt, child);
3146 switch (cur->type) {
3147 case XML_RELAXNG_EMPTY:
3148 case XML_RELAXNG_NOT_ALLOWED:
3149 case XML_RELAXNG_TEXT:
3150 case XML_RELAXNG_ELEMENT:
3151 case XML_RELAXNG_DATATYPE:
3152 case XML_RELAXNG_VALUE:
3153 case XML_RELAXNG_LIST:
3154 case XML_RELAXNG_REF:
3155 case XML_RELAXNG_PARENTREF:
3156 case XML_RELAXNG_EXTERNALREF:
3157 case XML_RELAXNG_DEF:
3158 case XML_RELAXNG_ONEORMORE:
3159 case XML_RELAXNG_ZEROORMORE:
3160 case XML_RELAXNG_OPTIONAL:
3161 case XML_RELAXNG_CHOICE:
3162 case XML_RELAXNG_GROUP:
3163 case XML_RELAXNG_INTERLEAVE:
3164 case XML_RELAXNG_ATTRIBUTE:
3168 case XML_RELAXNG_START:
3169 case XML_RELAXNG_PARAM:
3170 case XML_RELAXNG_EXCEPT:
3171 if (ctxt->error != NULL)
3172 ctxt->error(ctxt->userData,
3173 "attribute has invalid content\n");
3176 case XML_RELAXNG_NOOP:
3178 if (ctxt->error != NULL)
3179 ctxt->error(ctxt->userData,
3180 "Internal error, noop found\n");
3185 child = child->next;
3187 if (child != NULL) {
3188 if (ctxt->error != NULL)
3189 ctxt->error(ctxt->userData, "attribute has multiple children\n");
3192 ctxt->flags = old_flags;
3197 * xmlRelaxNGParseExceptNameClass:
3198 * @ctxt: a Relax-NG parser context
3199 * @node: the except node
3200 * @attr: 1 if within an attribute, 0 if within an element
3202 * parse the content of a RelaxNG nameClass node.
3204 * Returns the definition pointer or NULL in case of error.
3206 static xmlRelaxNGDefinePtr
3207 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt,
3208 xmlNodePtr node, int attr) {
3209 xmlRelaxNGDefinePtr ret, cur, last = NULL;
3212 if (!IS_RELAXNG(node, "except")) {
3213 if (ctxt->error != NULL)
3214 ctxt->error(ctxt->userData,
3215 "Expecting an except node\n");
3219 if (node->next != NULL) {
3220 if (ctxt->error != NULL)
3221 ctxt->error(ctxt->userData,
3222 "exceptNameClass allows only a single except node\n");
3225 if (node->children == NULL) {
3226 if (ctxt->error != NULL)
3227 ctxt->error(ctxt->userData,
3228 "except has no content\n");
3233 ret = xmlRelaxNGNewDefine(ctxt, node);
3236 ret->type = XML_RELAXNG_EXCEPT;
3237 child = node->children;
3238 while (child != NULL) {
3239 cur = xmlRelaxNGNewDefine(ctxt, child);
3243 cur->type = XML_RELAXNG_ATTRIBUTE;
3245 cur->type = XML_RELAXNG_ELEMENT;
3247 if (xmlRelaxNGParseNameClass(ctxt, child, cur) != NULL) {
3255 child = child->next;
3262 * xmlRelaxNGParseNameClass:
3263 * @ctxt: a Relax-NG parser context
3264 * @node: the nameClass node
3265 * @def: the current definition
3267 * parse the content of a RelaxNG nameClass node.
3269 * Returns the definition pointer or NULL in case of error.
3271 static xmlRelaxNGDefinePtr
3272 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node,
3273 xmlRelaxNGDefinePtr def) {
3274 xmlRelaxNGDefinePtr ret, tmp;
3278 if ((IS_RELAXNG(node, "name")) || (IS_RELAXNG(node, "anyName")) ||
3279 (IS_RELAXNG(node, "nsName"))) {
3280 if ((def->type != XML_RELAXNG_ELEMENT) &&
3281 (def->type != XML_RELAXNG_ATTRIBUTE)) {
3282 ret = xmlRelaxNGNewDefine(ctxt, node);
3286 if (ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE)
3287 ret->type = XML_RELAXNG_ATTRIBUTE;
3289 ret->type = XML_RELAXNG_ELEMENT;
3292 if (IS_RELAXNG(node, "name")) {
3293 val = xmlNodeGetContent(node);
3294 xmlRelaxNGNormExtSpace(val);
3295 if (xmlValidateNCName(val, 0)) {
3296 if (ctxt->error != NULL) {
3297 if (node->parent != NULL)
3298 ctxt->error(ctxt->userData,
3299 "Element %s name '%s' is not an NCName\n",
3300 node->parent->name, val);
3302 ctxt->error(ctxt->userData,
3303 "name '%s' is not an NCName\n",
3309 val = xmlGetProp(node, BAD_CAST "ns");
3311 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3313 (xmlStrEqual(val, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
3314 ctxt->error(ctxt->userData,
3315 "Attribute with namespace '%s' is not allowed\n",
3319 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3322 (xmlStrEqual(ret->name, BAD_CAST "xmlns"))) {
3323 ctxt->error(ctxt->userData,
3324 "Attribute with QName 'xmlns' is not allowed\n",
3328 } else if (IS_RELAXNG(node, "anyName")) {
3331 if (node->children != NULL) {
3333 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
3334 (def->type == XML_RELAXNG_ATTRIBUTE));
3336 } else if (IS_RELAXNG(node, "nsName")) {
3338 ret->ns = xmlGetProp(node, BAD_CAST "ns");
3339 if (ret->ns == NULL) {
3340 if (ctxt->error != NULL)
3341 ctxt->error(ctxt->userData,
3342 "nsName has no ns attribute\n");
3345 if ((ctxt->flags & XML_RELAXNG_IN_ATTRIBUTE) &&
3346 (ret->ns != NULL) &&
3347 (xmlStrEqual(ret->ns, BAD_CAST "http://www.w3.org/2000/xmlns"))) {
3348 ctxt->error(ctxt->userData,
3349 "Attribute with namespace '%s' is not allowed\n",
3353 if (node->children != NULL) {
3355 xmlRelaxNGParseExceptNameClass(ctxt, node->children,
3356 (def->type == XML_RELAXNG_ATTRIBUTE));
3358 } else if (IS_RELAXNG(node, "choice")) {
3360 xmlRelaxNGDefinePtr last = NULL;
3362 ret = xmlRelaxNGNewDefine(ctxt, node);
3366 ret->type = XML_RELAXNG_CHOICE;
3368 if (node->children == NULL) {
3369 if (ctxt->error != NULL)
3370 ctxt->error(ctxt->userData,
3371 "Element choice is empty\n");
3375 child = node->children;
3376 while (child != NULL) {
3377 tmp = xmlRelaxNGParseNameClass(ctxt, child, ret);
3380 last = ret->nameClass = tmp;
3386 child = child->next;
3390 if (ctxt->error != NULL)
3391 ctxt->error(ctxt->userData,
3392 "expecting name, anyName, nsName or choice : got %s\n",
3398 if (def->nameClass == NULL) {
3399 def->nameClass = ret;
3401 tmp = def->nameClass;
3402 while (tmp->next != NULL) {
3412 * xmlRelaxNGParseElement:
3413 * @ctxt: a Relax-NG parser context
3414 * @node: the element node
3416 * parse the content of a RelaxNG element node.
3418 * Returns the definition pointer or NULL in case of error.
3420 static xmlRelaxNGDefinePtr
3421 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
3422 xmlRelaxNGDefinePtr ret, cur, last;
3424 const xmlChar *olddefine;
3426 ret = xmlRelaxNGNewDefine(ctxt, node);
3429 ret->type = XML_RELAXNG_ELEMENT;
3430 ret->parent = ctxt->def;
3431 child = node->children;
3432 if (child == NULL) {
3433 if (ctxt->error != NULL)
3434 ctxt->error(ctxt->userData,
3435 "xmlRelaxNGParseElement: element has no children\n");
3439 cur = xmlRelaxNGParseNameClass(ctxt, child, ret);
3441 child = child->next;
3443 if (child == NULL) {
3444 if (ctxt->error != NULL)
3445 ctxt->error(ctxt->userData,
3446 "xmlRelaxNGParseElement: element has no content\n");
3450 olddefine = ctxt->define;
3451 ctxt->define = NULL;
3453 while (child != NULL) {
3454 cur = xmlRelaxNGParsePattern(ctxt, child);
3457 switch (cur->type) {
3458 case XML_RELAXNG_EMPTY:
3459 case XML_RELAXNG_NOT_ALLOWED:
3460 case XML_RELAXNG_TEXT:
3461 case XML_RELAXNG_ELEMENT:
3462 case XML_RELAXNG_DATATYPE:
3463 case XML_RELAXNG_VALUE:
3464 case XML_RELAXNG_LIST:
3465 case XML_RELAXNG_REF:
3466 case XML_RELAXNG_PARENTREF:
3467 case XML_RELAXNG_EXTERNALREF:
3468 case XML_RELAXNG_DEF:
3469 case XML_RELAXNG_ZEROORMORE:
3470 case XML_RELAXNG_ONEORMORE:
3471 case XML_RELAXNG_OPTIONAL:
3472 case XML_RELAXNG_CHOICE:
3473 case XML_RELAXNG_GROUP:
3474 case XML_RELAXNG_INTERLEAVE:
3476 ret->content = last = cur;
3478 if ((last->type == XML_RELAXNG_ELEMENT) &&
3479 (ret->content == last)) {
3480 ret->content = xmlRelaxNGNewDefine(ctxt, node);
3481 if (ret->content != NULL) {
3482 ret->content->type = XML_RELAXNG_GROUP;
3483 ret->content->content = last;
3485 ret->content = last;
3492 case XML_RELAXNG_ATTRIBUTE:
3493 cur->next = ret->attrs;
3496 case XML_RELAXNG_START:
3497 case XML_RELAXNG_PARAM:
3498 case XML_RELAXNG_EXCEPT:
3502 case XML_RELAXNG_NOOP:
3504 if (ctxt->error != NULL)
3505 ctxt->error(ctxt->userData,
3506 "Internal error, noop found\n");
3511 child = child->next;
3513 ctxt->define = olddefine;
3518 * xmlRelaxNGParsePatterns:
3519 * @ctxt: a Relax-NG parser context
3520 * @nodes: list of nodes
3521 * @group: use an implicit <group> for elements
3523 * parse the content of a RelaxNG start node.
3525 * Returns the definition pointer or NULL in case of error.
3527 static xmlRelaxNGDefinePtr
3528 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes,
3530 xmlRelaxNGDefinePtr def = NULL, last = NULL, cur, parent;
3533 while (nodes != NULL) {
3534 if (IS_RELAXNG(nodes, "element")) {
3535 cur = xmlRelaxNGParseElement(ctxt, nodes);
3539 if ((group == 1) && (def->type == XML_RELAXNG_ELEMENT) &&
3541 def = xmlRelaxNGNewDefine(ctxt, nodes);
3542 def->type = XML_RELAXNG_GROUP;
3543 def->content = last;
3548 cur->parent = parent;
3550 cur = xmlRelaxNGParsePattern(ctxt, nodes);
3560 nodes = nodes->next;
3566 * xmlRelaxNGParseStart:
3567 * @ctxt: a Relax-NG parser context
3568 * @nodes: start children nodes
3570 * parse the content of a RelaxNG start node.
3572 * Returns 0 in case of success, -1 in case of error
3575 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
3577 xmlRelaxNGDefinePtr def = NULL, last;
3579 if (nodes == NULL) {
3580 if (ctxt->error != NULL)
3581 ctxt->error(ctxt->userData,
3582 "start has no children\n");
3586 if (IS_RELAXNG(nodes, "empty")) {
3587 def = xmlRelaxNGNewDefine(ctxt, nodes);
3590 def->type = XML_RELAXNG_EMPTY;
3591 if (nodes->children != NULL) {
3592 if (ctxt->error != NULL)
3593 ctxt->error(ctxt->userData, "element empty is not empty\n");
3596 } else if (IS_RELAXNG(nodes, "notAllowed")) {
3597 def = xmlRelaxNGNewDefine(ctxt, nodes);
3600 def->type = XML_RELAXNG_NOT_ALLOWED;
3601 if (nodes->children != NULL) {
3602 if (ctxt->error != NULL)
3603 ctxt->error(ctxt->userData,
3604 "element notAllowed is not empty\n");
3608 def = xmlRelaxNGParsePatterns(ctxt, nodes, 1);
3610 if (ctxt->grammar->start != NULL) {
3611 last = ctxt->grammar->start;
3612 while (last->next != NULL)
3616 ctxt->grammar->start = def;
3618 nodes = nodes->next;
3619 if (nodes != NULL) {
3620 if (ctxt->error != NULL)
3621 ctxt->error(ctxt->userData,
3622 "start more than one children\n");
3630 * xmlRelaxNGParseGrammarContent:
3631 * @ctxt: a Relax-NG parser context
3632 * @nodes: grammar children nodes
3634 * parse the content of a RelaxNG grammar node.
3636 * Returns 0 in case of success, -1 in case of error
3639 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes)
3643 if (nodes == NULL) {
3644 if (ctxt->error != NULL)
3645 ctxt->error(ctxt->userData,
3646 "grammar has no children\n");
3650 while (nodes != NULL) {
3651 if (IS_RELAXNG(nodes, "start")) {
3652 if (nodes->children == NULL) {
3653 if (ctxt->error != NULL)
3654 ctxt->error(ctxt->userData,
3655 "start has no children\n");
3658 tmp = xmlRelaxNGParseStart(ctxt, nodes->children);
3662 } else if (IS_RELAXNG(nodes, "define")) {
3663 tmp = xmlRelaxNGParseDefine(ctxt, nodes);
3666 } else if (IS_RELAXNG(nodes, "include")) {
3667 tmp = xmlRelaxNGParseInclude(ctxt, nodes);
3671 if (ctxt->error != NULL)
3672 ctxt->error(ctxt->userData,
3673 "grammar has unexpected child %s\n", nodes->name);
3677 nodes = nodes->next;
3683 * xmlRelaxNGCheckReference:
3685 * @ctxt: a Relax-NG parser context
3686 * @name: the name associated to the defines
3688 * Applies the 4.17. combine attribute rule for all the define
3689 * element of a given grammar using the same name.
3692 xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref,
3693 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
3694 xmlRelaxNGGrammarPtr grammar;
3695 xmlRelaxNGDefinePtr def, cur;
3697 grammar = ctxt->grammar;
3698 if (grammar == NULL) {
3699 if (ctxt->error != NULL)
3700 ctxt->error(ctxt->userData,
3701 "Internal error: no grammar in CheckReference %s\n",
3706 if (ref->content != NULL) {
3707 if (ctxt->error != NULL)
3708 ctxt->error(ctxt->userData,
3709 "Internal error: reference has content in CheckReference %s\n",
3714 if (grammar->defs != NULL) {
3715 def = xmlHashLookup(grammar->defs, name);
3718 while (cur != NULL) {
3720 cur = cur->nextHash;
3723 if (ctxt->error != NULL)
3724 ctxt->error(ctxt->userData,
3725 "Reference %s has no matching definition\n",
3730 if (ctxt->error != NULL)
3731 ctxt->error(ctxt->userData,
3732 "Reference %s has no matching definition\n",
3737 * TODO: make a closure and verify there is no loop !
3742 * xmlRelaxNGCheckCombine:
3743 * @define: the define(s) list
3744 * @ctxt: a Relax-NG parser context
3745 * @name: the name associated to the defines
3747 * Applies the 4.17. combine attribute rule for all the define
3748 * element of a given grammar using the same name.
3751 xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define,
3752 xmlRelaxNGParserCtxtPtr ctxt, const xmlChar *name) {
3754 int choiceOrInterleave = -1;
3756 xmlRelaxNGDefinePtr cur, last, tmp, tmp2;
3758 if (define->nextHash == NULL)
3761 while (cur != NULL) {
3762 combine = xmlGetProp(cur->node, BAD_CAST "combine");
3763 if (combine != NULL) {
3764 if (xmlStrEqual(combine, BAD_CAST "choice")) {
3765 if (choiceOrInterleave == -1)
3766 choiceOrInterleave = 1;
3767 else if (choiceOrInterleave == 0) {
3768 if (ctxt->error != NULL)
3769 ctxt->error(ctxt->userData,
3770 "Defines for %s use both 'choice' and 'interleave'\n",
3774 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
3775 if (choiceOrInterleave == -1)
3776 choiceOrInterleave = 0;
3777 else if (choiceOrInterleave == 1) {
3778 if (ctxt->error != NULL)
3779 ctxt->error(ctxt->userData,
3780 "Defines for %s use both 'choice' and 'interleave'\n",
3785 if (ctxt->error != NULL)
3786 ctxt->error(ctxt->userData,
3787 "Defines for %s use unknown combine value '%s''\n",
3796 if (ctxt->error != NULL)
3797 ctxt->error(ctxt->userData,
3798 "Some defines for %s lacks the combine attribute\n",
3804 cur = cur->nextHash;
3807 xmlGenericError(xmlGenericErrorContext,
3808 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
3809 name, choiceOrInterleave);
3811 if (choiceOrInterleave == -1)
3812 choiceOrInterleave = 0;
3813 cur = xmlRelaxNGNewDefine(ctxt, define->node);
3816 if (choiceOrInterleave == 0)
3817 cur->type = XML_RELAXNG_INTERLEAVE;
3819 cur->type = XML_RELAXNG_CHOICE;
3822 while (tmp != NULL) {
3823 if (tmp->content != NULL) {
3824 if (tmp->content->next != NULL) {
3826 * we need first to create a wrapper.
3828 tmp2 = xmlRelaxNGNewDefine(ctxt, tmp->content->node);
3831 tmp2->type = XML_RELAXNG_GROUP;
3832 tmp2->content = tmp->content;
3834 tmp2 = tmp->content;
3837 cur->content = tmp2;
3842 tmp->content = NULL;
3844 tmp = tmp->nextHash;
3846 define->content = cur;
3847 if (choiceOrInterleave == 0) {
3848 if (ctxt->interleaves == NULL)
3849 ctxt->interleaves = xmlHashCreate(10);
3850 if (ctxt->interleaves == NULL) {
3851 if (ctxt->error != NULL)
3852 ctxt->error(ctxt->userData,
3853 "Failed to create interleaves hash table\n");
3858 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
3859 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
3860 if (ctxt->error != NULL)
3861 ctxt->error(ctxt->userData,
3862 "Failed to add %s to hash table\n", tmpname);
3870 * xmlRelaxNGCombineStart:
3871 * @ctxt: a Relax-NG parser context
3872 * @grammar: the grammar
3874 * Applies the 4.17. combine rule for all the start
3875 * element of a given grammar.
3878 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt,
3879 xmlRelaxNGGrammarPtr grammar) {
3880 xmlRelaxNGDefinePtr starts;
3882 int choiceOrInterleave = -1;
3884 xmlRelaxNGDefinePtr cur;
3886 starts = grammar->start;
3887 if ((starts == NULL) || (starts->next == NULL))
3890 while (cur != NULL) {
3891 if ((cur->node == NULL) || (cur->node->parent == NULL) ||
3892 (!xmlStrEqual(cur->node->parent->name, BAD_CAST "start"))) {
3894 if (ctxt->error != NULL)
3895 ctxt->error(ctxt->userData,
3896 "Internal error: start element not found\n");
3899 combine = xmlGetProp(cur->node->parent, BAD_CAST "combine");
3902 if (combine != NULL) {
3903 if (xmlStrEqual(combine, BAD_CAST "choice")) {
3904 if (choiceOrInterleave == -1)
3905 choiceOrInterleave = 1;
3906 else if (choiceOrInterleave == 0) {
3907 if (ctxt->error != NULL)
3908 ctxt->error(ctxt->userData,
3909 "<start> use both 'choice' and 'interleave'\n");
3912 } else if (xmlStrEqual(combine, BAD_CAST "interleave")) {
3913 if (choiceOrInterleave == -1)
3914 choiceOrInterleave = 0;
3915 else if (choiceOrInterleave == 1) {
3916 if (ctxt->error != NULL)
3917 ctxt->error(ctxt->userData,
3918 "<start> use both 'choice' and 'interleave'\n");
3922 if (ctxt->error != NULL)
3923 ctxt->error(ctxt->userData,
3924 "<start> uses unknown combine value '%s''\n", combine);
3932 if (ctxt->error != NULL)
3933 ctxt->error(ctxt->userData,
3934 "Some <start> elements lacks the combine attribute\n");
3942 xmlGenericError(xmlGenericErrorContext,
3943 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
3944 choiceOrInterleave);
3946 if (choiceOrInterleave == -1)
3947 choiceOrInterleave = 0;
3948 cur = xmlRelaxNGNewDefine(ctxt, starts->node);
3951 if (choiceOrInterleave == 0)
3952 cur->type = XML_RELAXNG_INTERLEAVE;
3954 cur->type = XML_RELAXNG_CHOICE;
3955 cur->content = grammar->start;
3956 grammar->start = cur;
3957 if (choiceOrInterleave == 0) {
3958 if (ctxt->interleaves == NULL)
3959 ctxt->interleaves = xmlHashCreate(10);
3960 if (ctxt->interleaves == NULL) {
3961 if (ctxt->error != NULL)
3962 ctxt->error(ctxt->userData,
3963 "Failed to create interleaves hash table\n");
3968 snprintf(tmpname, 32, "interleave%d", ctxt->nbInterleaves++);
3969 if (xmlHashAddEntry(ctxt->interleaves, BAD_CAST tmpname, cur) < 0) {
3970 if (ctxt->error != NULL)
3971 ctxt->error(ctxt->userData,
3972 "Failed to add %s to hash table\n", tmpname);
3980 * xmlRelaxNGCheckCycles:
3981 * @ctxt: a Relax-NG parser context
3982 * @nodes: grammar children nodes
3983 * @depth: the counter
3987 * Returns 0 if check passed, and -1 in case of error
3990 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt,
3991 xmlRelaxNGDefinePtr cur, int depth) {
3994 while ((ret == 0) && (cur != NULL)) {
3995 if ((cur->type == XML_RELAXNG_REF) ||
3996 (cur->type == XML_RELAXNG_PARENTREF)) {
3997 if (cur->depth == -1) {
3999 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4001 } else if (depth == cur->depth) {
4002 if (ctxt->error != NULL)
4003 ctxt->error(ctxt->userData,
4004 "Detected a cycle in %s references\n", cur->name);
4008 } else if (cur->type == XML_RELAXNG_ELEMENT) {
4009 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth + 1);
4011 ret = xmlRelaxNGCheckCycles(ctxt, cur->content, depth);
4019 * xmlRelaxNGTryUnlink:
4020 * @ctxt: a Relax-NG parser context
4021 * @cur: the definition to unlink
4022 * @parent: the parent definition
4023 * @prev: the previous sibling definition
4025 * Try to unlink a definition. If not possble make it a NOOP
4027 * Returns the new prev definition
4029 static xmlRelaxNGDefinePtr
4030 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
4031 xmlRelaxNGDefinePtr cur,
4032 xmlRelaxNGDefinePtr parent,
4033 xmlRelaxNGDefinePtr prev) {
4035 prev->next = cur->next;
4037 if (parent != NULL) {
4038 if (parent->content == cur)
4039 parent->content = cur->next;
4040 else if (parent->attrs == cur)
4041 parent->attrs = cur->next;
4042 else if (parent->nameClass == cur)
4043 parent->nameClass = cur->next;
4045 cur->type = XML_RELAXNG_NOOP;
4053 * xmlRelaxNGSimplify:
4054 * @ctxt: a Relax-NG parser context
4055 * @nodes: grammar children nodes
4057 * Check for simplification of empty and notAllowed
4060 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt,
4061 xmlRelaxNGDefinePtr cur,
4062 xmlRelaxNGDefinePtr parent) {
4063 xmlRelaxNGDefinePtr prev = NULL;
4065 while (cur != NULL) {
4066 if ((cur->type == XML_RELAXNG_REF) ||
4067 (cur->type == XML_RELAXNG_PARENTREF)) {
4068 if (cur->depth != -3) {
4070 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4072 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
4073 cur->parent = parent;
4074 if ((parent != NULL) &&
4075 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4076 (parent->type == XML_RELAXNG_LIST) ||
4077 (parent->type == XML_RELAXNG_GROUP) ||
4078 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4079 (parent->type == XML_RELAXNG_ONEORMORE) ||
4080 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4081 parent->type = XML_RELAXNG_NOT_ALLOWED;
4084 if ((parent != NULL) &&
4085 (parent->type == XML_RELAXNG_CHOICE)) {
4086 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4089 } else if (cur->type == XML_RELAXNG_EMPTY){
4090 cur->parent = parent;
4091 if ((parent != NULL) &&
4092 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4093 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4094 parent->type = XML_RELAXNG_EMPTY;
4097 if ((parent != NULL) &&
4098 ((parent->type == XML_RELAXNG_GROUP) ||
4099 (parent->type == XML_RELAXNG_INTERLEAVE))) {
4100 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4104 cur->parent = parent;
4105 if (cur->content != NULL)
4106 xmlRelaxNGSimplify(ctxt, cur->content, cur);
4107 if (cur->attrs != NULL)
4108 xmlRelaxNGSimplify(ctxt, cur->attrs, cur);
4109 if (cur->nameClass != NULL)
4110 xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
4112 * This may result in a simplification
4114 if ((cur->type == XML_RELAXNG_GROUP) ||
4115 (cur->type == XML_RELAXNG_INTERLEAVE)) {
4116 if (cur->content == NULL)
4117 cur->type = XML_RELAXNG_EMPTY;
4118 else if (cur->content->next == NULL) {
4119 if ((parent == NULL) && (prev == NULL)) {
4120 cur->type = XML_RELAXNG_NOOP;
4121 } else if (prev == NULL) {
4122 parent->content = cur->content;
4123 cur->content->next = cur->next;
4126 cur->content->next = cur->next;
4127 prev->next = cur->content;
4133 * the current node may have been transformed back
4135 if ((cur->type == XML_RELAXNG_EXCEPT) &&
4136 (cur->content != NULL) &&
4137 (cur->content->type == XML_RELAXNG_NOT_ALLOWED)) {
4138 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4139 } else if (cur->type == XML_RELAXNG_NOT_ALLOWED) {
4140 if ((parent != NULL) &&
4141 ((parent->type == XML_RELAXNG_ATTRIBUTE) ||
4142 (parent->type == XML_RELAXNG_LIST) ||
4143 (parent->type == XML_RELAXNG_GROUP) ||
4144 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4145 (parent->type == XML_RELAXNG_ONEORMORE) ||
4146 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4147 parent->type = XML_RELAXNG_NOT_ALLOWED;
4150 if ((parent != NULL) &&
4151 (parent->type == XML_RELAXNG_CHOICE)) {
4152 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4155 } else if (cur->type == XML_RELAXNG_EMPTY){
4156 if ((parent != NULL) &&
4157 ((parent->type == XML_RELAXNG_ONEORMORE) ||
4158 (parent->type == XML_RELAXNG_ZEROORMORE))) {
4159 parent->type = XML_RELAXNG_EMPTY;
4162 if ((parent != NULL) &&
4163 ((parent->type == XML_RELAXNG_GROUP) ||
4164 (parent->type == XML_RELAXNG_INTERLEAVE) ||
4165 (parent->type == XML_RELAXNG_CHOICE))) {
4166 prev = xmlRelaxNGTryUnlink(ctxt, cur, parent, prev);
4178 * xmlRelaxNGGroupContentType:
4179 * @ct1: the first content type
4180 * @ct2: the second content type
4182 * Try to group 2 content types
4184 * Returns the content type
4186 static xmlRelaxNGContentType
4187 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1,
4188 xmlRelaxNGContentType ct2) {
4189 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
4190 (ct2 == XML_RELAXNG_CONTENT_ERROR))
4191 return(XML_RELAXNG_CONTENT_ERROR);
4192 if (ct1 == XML_RELAXNG_CONTENT_EMPTY)
4194 if (ct2 == XML_RELAXNG_CONTENT_EMPTY)
4196 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) &&
4197 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
4198 return(XML_RELAXNG_CONTENT_COMPLEX);
4199 return(XML_RELAXNG_CONTENT_ERROR);
4203 * xmlRelaxNGMaxContentType:
4204 * @ct1: the first content type
4205 * @ct2: the second content type
4207 * Compute the max content-type
4209 * Returns the content type
4211 static xmlRelaxNGContentType
4212 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1,
4213 xmlRelaxNGContentType ct2) {
4214 if ((ct1 == XML_RELAXNG_CONTENT_ERROR) ||
4215 (ct2 == XML_RELAXNG_CONTENT_ERROR))
4216 return(XML_RELAXNG_CONTENT_ERROR);
4217 if ((ct1 == XML_RELAXNG_CONTENT_SIMPLE) ||
4218 (ct2 == XML_RELAXNG_CONTENT_SIMPLE))
4219 return(XML_RELAXNG_CONTENT_SIMPLE);
4220 if ((ct1 == XML_RELAXNG_CONTENT_COMPLEX) ||
4221 (ct2 == XML_RELAXNG_CONTENT_COMPLEX))
4222 return(XML_RELAXNG_CONTENT_COMPLEX);
4223 return(XML_RELAXNG_CONTENT_EMPTY);
4227 * xmlRelaxNGCheckRules:
4228 * @ctxt: a Relax-NG parser context
4229 * @cur: the current definition
4230 * @flags: some accumulated flags
4231 * @ptype: the parent type
4233 * Check for rules in section 7.1 and 7.2
4235 * Returns the content type of @cur
4237 static xmlRelaxNGContentType
4238 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt,
4239 xmlRelaxNGDefinePtr cur, int flags,
4240 xmlRelaxNGType ptype) {
4242 xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
4244 while (cur != NULL) {
4245 ret = XML_RELAXNG_CONTENT_EMPTY;
4246 if ((cur->type == XML_RELAXNG_REF) ||
4247 (cur->type == XML_RELAXNG_PARENTREF)) {
4248 if (flags & XML_RELAXNG_IN_LIST) {
4249 if (ctxt->error != NULL)
4250 ctxt->error(ctxt->userData,
4251 "Found forbidden pattern list//ref\n");
4254 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4255 if (ctxt->error != NULL)
4256 ctxt->error(ctxt->userData,
4257 "Found forbidden pattern attribute//ref\n");
4260 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4261 if (ctxt->error != NULL)
4262 ctxt->error(ctxt->userData,
4263 "Found forbidden pattern data/except//ref\n");
4266 if (cur->depth > -4) {
4268 ret = xmlRelaxNGCheckRules(ctxt, cur->content,
4270 cur->depth = ret - 15 ;
4271 } else if (cur->depth == -4) {
4272 ret = XML_RELAXNG_CONTENT_COMPLEX;
4274 ret = (xmlRelaxNGContentType) cur->depth + 15;
4276 } else if (cur->type == XML_RELAXNG_ELEMENT) {
4278 * The 7.3 Attribute derivation rule for groups is plugged there
4280 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
4281 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4282 if (ctxt->error != NULL)
4283 ctxt->error(ctxt->userData,
4284 "Found forbidden pattern data/except//element(ref)\n");
4287 if (flags & XML_RELAXNG_IN_LIST) {
4288 if (ctxt->error != NULL)
4289 ctxt->error(ctxt->userData,
4290 "Found forbidden pattern list//element(ref)\n");
4293 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4294 if (ctxt->error != NULL)
4295 ctxt->error(ctxt->userData,
4296 "Found forbidden pattern attribute//element(ref)\n");
4300 * reset since in the simple form elements are only child
4304 ret = xmlRelaxNGCheckRules(ctxt, cur->attrs, nflags, cur->type);
4305 if (ret != XML_RELAXNG_CONTENT_EMPTY) {
4306 if (ctxt->error != NULL)
4307 ctxt->error(ctxt->userData,
4308 "Element %s attributes have a content type error\n",
4312 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4313 if (ret == XML_RELAXNG_CONTENT_ERROR) {
4314 if (ctxt->error != NULL)
4315 ctxt->error(ctxt->userData,
4316 "Element %s has a content type error\n",
4320 ret = XML_RELAXNG_CONTENT_COMPLEX;
4322 } else if (cur->type == XML_RELAXNG_ATTRIBUTE) {
4323 if (flags & XML_RELAXNG_IN_ATTRIBUTE) {
4324 if (ctxt->error != NULL)
4325 ctxt->error(ctxt->userData,
4326 "Found forbidden pattern attribute//attribute\n");
4329 if (flags & XML_RELAXNG_IN_LIST) {
4330 if (ctxt->error != NULL)
4331 ctxt->error(ctxt->userData,
4332 "Found forbidden pattern list//attribute\n");
4335 if (flags & XML_RELAXNG_IN_OOMGROUP) {
4336 if (ctxt->error != NULL)
4337 ctxt->error(ctxt->userData,
4338 "Found forbidden pattern oneOrMore//group//attribute\n");
4341 if (flags & XML_RELAXNG_IN_OOMINTERLEAVE) {
4342 if (ctxt->error != NULL)
4343 ctxt->error(ctxt->userData,
4344 "Found forbidden pattern oneOrMore//interleave//attribute\n");
4347 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4348 if (ctxt->error != NULL)
4349 ctxt->error(ctxt->userData,
4350 "Found forbidden pattern data/except//attribute\n");
4353 if (flags & XML_RELAXNG_IN_START) {
4354 if (ctxt->error != NULL)
4355 ctxt->error(ctxt->userData,
4356 "Found forbidden pattern start//attribute\n");
4359 nflags = flags | XML_RELAXNG_IN_ATTRIBUTE;
4360 xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4361 ret = XML_RELAXNG_CONTENT_EMPTY;
4362 } else if ((cur->type == XML_RELAXNG_ONEORMORE) ||
4363 (cur->type == XML_RELAXNG_ZEROORMORE)) {
4364 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4365 if (ctxt->error != NULL)
4366 ctxt->error(ctxt->userData,
4367 "Found forbidden pattern data/except//oneOrMore\n");
4370 if (flags & XML_RELAXNG_IN_START) {
4371 if (ctxt->error != NULL)
4372 ctxt->error(ctxt->userData,
4373 "Found forbidden pattern start//oneOrMore\n");
4376 nflags = flags | XML_RELAXNG_IN_ONEORMORE;
4377 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4378 ret = xmlRelaxNGGroupContentType(ret, ret);
4379 } else if (cur->type == XML_RELAXNG_LIST) {
4380 if (flags & XML_RELAXNG_IN_LIST) {
4381 if (ctxt->error != NULL)
4382 ctxt->error(ctxt->userData,
4383 "Found forbidden pattern list//list\n");
4386 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4387 if (ctxt->error != NULL)
4388 ctxt->error(ctxt->userData,
4389 "Found forbidden pattern data/except//list\n");
4392 if (flags & XML_RELAXNG_IN_START) {
4393 if (ctxt->error != NULL)
4394 ctxt->error(ctxt->userData,
4395 "Found forbidden pattern start//list\n");
4398 nflags = flags | XML_RELAXNG_IN_LIST;
4399 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4400 } else if (cur->type == XML_RELAXNG_GROUP) {
4401 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4402 if (ctxt->error != NULL)
4403 ctxt->error(ctxt->userData,
4404 "Found forbidden pattern data/except//group\n");
4407 if (flags & XML_RELAXNG_IN_START) {
4408 if (ctxt->error != NULL)
4409 ctxt->error(ctxt->userData,
4410 "Found forbidden pattern start//group\n");
4413 if (flags & XML_RELAXNG_IN_ONEORMORE)
4414 nflags = flags | XML_RELAXNG_IN_OOMGROUP;
4417 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4419 * The 7.3 Attribute derivation rule for groups is plugged there
4421 xmlRelaxNGCheckGroupAttrs(ctxt, cur);
4422 } else if (cur->type == XML_RELAXNG_INTERLEAVE) {
4423 if (flags & XML_RELAXNG_IN_LIST) {
4424 if (ctxt->error != NULL)
4425 ctxt->error(ctxt->userData,
4426 "Found forbidden pattern list//interleave\n");
4429 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4430 if (ctxt->error != NULL)
4431 ctxt->error(ctxt->userData,
4432 "Found forbidden pattern data/except//interleave\n");
4435 if (flags & XML_RELAXNG_IN_START) {
4436 if (ctxt->error != NULL)
4437 ctxt->error(ctxt->userData,
4438 "Found forbidden pattern start//interleave\n");
4441 if (flags & XML_RELAXNG_IN_ONEORMORE)
4442 nflags = flags | XML_RELAXNG_IN_OOMINTERLEAVE;
4445 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4446 } else if (cur->type == XML_RELAXNG_EXCEPT) {
4447 if ((cur->parent != NULL) &&
4448 (cur->parent->type == XML_RELAXNG_DATATYPE))
4449 nflags = flags | XML_RELAXNG_IN_DATAEXCEPT;
4452 ret = xmlRelaxNGCheckRules(ctxt, cur->content, nflags, cur->type);
4453 } else if (cur->type == XML_RELAXNG_DATATYPE) {
4454 if (flags & XML_RELAXNG_IN_START) {
4455 if (ctxt->error != NULL)
4456 ctxt->error(ctxt->userData,
4457 "Found forbidden pattern start//data\n");
4460 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
4461 ret = XML_RELAXNG_CONTENT_SIMPLE;
4462 } else if (cur->type == XML_RELAXNG_VALUE) {
4463 if (flags & XML_RELAXNG_IN_START) {
4464 if (ctxt->error != NULL)
4465 ctxt->error(ctxt->userData,
4466 "Found forbidden pattern start//value\n");
4469 xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
4470 ret = XML_RELAXNG_CONTENT_SIMPLE;
4471 } else if (cur->type == XML_RELAXNG_TEXT) {
4472 if (flags & XML_RELAXNG_IN_LIST) {
4473 if (ctxt->error != NULL)
4474 ctxt->error(ctxt->userData,
4475 "Found forbidden pattern list//text\n");
4478 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4479 if (ctxt->error != NULL)
4480 ctxt->error(ctxt->userData,
4481 "Found forbidden pattern data/except//text\n");
4484 if (flags & XML_RELAXNG_IN_START) {
4485 if (ctxt->error != NULL)
4486 ctxt->error(ctxt->userData,
4487 "Found forbidden pattern start//text\n");
4490 ret = XML_RELAXNG_CONTENT_COMPLEX;
4491 } else if (cur->type == XML_RELAXNG_EMPTY) {
4492 if (flags & XML_RELAXNG_IN_DATAEXCEPT) {
4493 if (ctxt->error != NULL)
4494 ctxt->error(ctxt->userData,
4495 "Found forbidden pattern data/except//empty\n");
4498 if (flags & XML_RELAXNG_IN_START) {
4499 if (ctxt->error != NULL)
4500 ctxt->error(ctxt->userData,
4501 "Found forbidden pattern start//empty\n");
4504 ret = XML_RELAXNG_CONTENT_EMPTY;
4506 ret = xmlRelaxNGCheckRules(ctxt, cur->content, flags, cur->type);
4509 if (ptype == XML_RELAXNG_GROUP) {
4510 val = xmlRelaxNGGroupContentType(val, ret);
4511 } else if (ptype == XML_RELAXNG_INTERLEAVE) {
4512 tmp = xmlRelaxNGGroupContentType(val, ret);
4513 if (tmp != XML_RELAXNG_CONTENT_ERROR)
4514 tmp = xmlRelaxNGMaxContentType(val, ret);
4515 } else if (ptype == XML_RELAXNG_CHOICE) {
4516 val = xmlRelaxNGMaxContentType(val, ret);
4517 } else if (ptype == XML_RELAXNG_LIST) {
4518 val = XML_RELAXNG_CONTENT_SIMPLE;
4519 } else if (ptype == XML_RELAXNG_EXCEPT) {
4520 if (ret == XML_RELAXNG_CONTENT_ERROR)
4521 val = XML_RELAXNG_CONTENT_ERROR;
4523 val = XML_RELAXNG_CONTENT_SIMPLE;
4525 val = xmlRelaxNGGroupContentType(val, ret);
4533 * xmlRelaxNGParseGrammar:
4534 * @ctxt: a Relax-NG parser context
4535 * @nodes: grammar children nodes
4537 * parse a Relax-NG <grammar> node
4539 * Returns the internal xmlRelaxNGGrammarPtr built or
4540 * NULL in case of error
4542 static xmlRelaxNGGrammarPtr
4543 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr nodes) {
4544 xmlRelaxNGGrammarPtr ret, tmp, old;
4546 ret = xmlRelaxNGNewGrammar(ctxt);
4551 * Link the new grammar in the tree
4553 ret->parent = ctxt->grammar;
4554 if (ctxt->grammar != NULL) {
4555 tmp = ctxt->grammar->children;
4557 ctxt->grammar->children = ret;
4559 while (tmp->next != NULL)
4565 old = ctxt->grammar;
4566 ctxt->grammar = ret;
4567 xmlRelaxNGParseGrammarContent(ctxt, nodes);
4568 ctxt->grammar = ret;
4569 if (ctxt->grammar == NULL) {
4570 if (ctxt->error != NULL)
4571 ctxt->error(ctxt->userData,
4572 "Failed to parse <grammar> content\n");
4574 } else if (ctxt->grammar->start == NULL) {
4575 if (ctxt->error != NULL)
4576 ctxt->error(ctxt->userData,
4577 "Element <grammar> has no <start>\n");
4582 * Apply 4.17 mergingd rules to defines and starts
4584 xmlRelaxNGCombineStart(ctxt, ret);
4585 if (ret->defs != NULL) {
4586 xmlHashScan(ret->defs, (xmlHashScanner) xmlRelaxNGCheckCombine,
4591 * link together defines and refs in this grammar
4593 if (ret->refs != NULL) {
4594 xmlHashScan(ret->refs, (xmlHashScanner) xmlRelaxNGCheckReference,
4597 ctxt->grammar = old;
4602 * xmlRelaxNGParseDocument:
4603 * @ctxt: a Relax-NG parser context
4604 * @node: the root node of the RelaxNG schema
4606 * parse a Relax-NG definition resource and build an internal
4607 * xmlRelaxNG struture which can be used to validate instances.
4609 * Returns the internal XML RelaxNG structure built or
4610 * NULL in case of error
4612 static xmlRelaxNGPtr
4613 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4614 xmlRelaxNGPtr schema = NULL;
4615 const xmlChar *olddefine;
4616 xmlRelaxNGGrammarPtr old;
4618 if ((ctxt == NULL) || (node == NULL))
4621 schema = xmlRelaxNGNewRelaxNG(ctxt);
4625 olddefine = ctxt->define;
4626 ctxt->define = NULL;
4627 if (IS_RELAXNG(node, "grammar")) {
4628 schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
4630 schema->topgrammar = xmlRelaxNGNewGrammar(ctxt);
4631 if (schema->topgrammar == NULL) {
4634 schema->topgrammar->parent = NULL;
4635 old = ctxt->grammar;
4636 ctxt->grammar = schema->topgrammar;
4637 xmlRelaxNGParseStart(ctxt, node);
4639 ctxt->grammar = old;
4641 ctxt->define = olddefine;
4642 if (schema->topgrammar->start != NULL) {
4643 xmlRelaxNGCheckCycles(ctxt, schema->topgrammar->start, 0);
4644 if ((ctxt->flags & XML_RELAXNG_IN_EXTERNALREF) == 0) {
4645 xmlRelaxNGSimplify(ctxt, schema->topgrammar->start, NULL);
4646 while ((schema->topgrammar->start != NULL) &&
4647 (schema->topgrammar->start->type == XML_RELAXNG_NOOP) &&
4648 (schema->topgrammar->start->next != NULL))
4649 schema->topgrammar->start = schema->topgrammar->start->content;
4650 xmlRelaxNGCheckRules(ctxt, schema->topgrammar->start,
4651 XML_RELAXNG_IN_START, XML_RELAXNG_NOOP);
4657 xmlGenericError(xmlGenericErrorContext,
4658 "xmlRelaxNGParseDocument() failed\n");
4664 /************************************************************************
4666 * Reading RelaxNGs *
4668 ************************************************************************/
4671 * xmlRelaxNGNewParserCtxt:
4672 * @URL: the location of the schema
4674 * Create an XML RelaxNGs parse context for that file/resource expected
4675 * to contain an XML RelaxNGs file.
4677 * Returns the parser context or NULL in case of error
4679 xmlRelaxNGParserCtxtPtr
4680 xmlRelaxNGNewParserCtxt(const char *URL) {
4681 xmlRelaxNGParserCtxtPtr ret;
4686 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
4688 xmlGenericError(xmlGenericErrorContext,
4689 "Failed to allocate new schama parser context for %s\n", URL);
4692 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
4693 ret->URL = xmlStrdup((const xmlChar *)URL);
4694 ret->error = xmlGenericError;
4695 ret->userData = xmlGenericErrorContext;
4700 * xmlRelaxNGNewMemParserCtxt:
4701 * @buffer: a pointer to a char array containing the schemas
4702 * @size: the size of the array
4704 * Create an XML RelaxNGs parse context for that memory buffer expected
4705 * to contain an XML RelaxNGs file.
4707 * Returns the parser context or NULL in case of error
4709 xmlRelaxNGParserCtxtPtr
4710 xmlRelaxNGNewMemParserCtxt(const char *buffer, int size) {
4711 xmlRelaxNGParserCtxtPtr ret;
4713 if ((buffer == NULL) || (size <= 0))
4716 ret = (xmlRelaxNGParserCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGParserCtxt));
4718 xmlGenericError(xmlGenericErrorContext,
4719 "Failed to allocate new schama parser context\n");
4722 memset(ret, 0, sizeof(xmlRelaxNGParserCtxt));
4723 ret->buffer = buffer;
4725 ret->error = xmlGenericError;
4726 ret->userData = xmlGenericErrorContext;
4731 * xmlRelaxNGFreeParserCtxt:
4732 * @ctxt: the schema parser context
4734 * Free the resources associated to the schema parser context
4737 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt) {
4740 if (ctxt->URL != NULL)
4742 if (ctxt->doc != NULL)
4743 xmlFreeDoc(ctxt->document);
4744 if (ctxt->interleaves != NULL)
4745 xmlHashFree(ctxt->interleaves, NULL);
4746 if (ctxt->documents != NULL)
4747 xmlHashFree(ctxt->documents, (xmlHashDeallocator)
4748 xmlRelaxNGFreeDocument);
4749 if (ctxt->includes != NULL)
4750 xmlHashFree(ctxt->includes, (xmlHashDeallocator)
4751 xmlRelaxNGFreeInclude);
4752 if (ctxt->docTab != NULL)
4753 xmlFree(ctxt->docTab);
4754 if (ctxt->incTab != NULL)
4755 xmlFree(ctxt->incTab);
4756 if (ctxt->defTab != NULL) {
4759 for (i = 0;i < ctxt->defNr;i++)
4760 xmlRelaxNGFreeDefine(ctxt->defTab[i]);
4761 xmlFree(ctxt->defTab);
4767 * xmlRelaxNGNormExtSpace:
4770 * Removes the leading and ending spaces of the value
4771 * The string is modified "in situ"
4774 xmlRelaxNGNormExtSpace(xmlChar *value) {
4775 xmlChar *start = value;
4776 xmlChar *cur = value;
4780 while (IS_BLANK(*cur)) cur++;
4783 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
4787 while (IS_BLANK(*cur)) cur++;
4795 while ((*cur != 0) && (!IS_BLANK(*cur)))
4801 /* don't try to normalize the inner spaces */
4802 while (IS_BLANK(*cur)) cur++;
4813 * xmlRelaxNGCheckAttributes:
4814 * @ctxt: a Relax-NG parser context
4815 * @node: a Relax-NG node
4817 * Check all the attributes on the given node
4820 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr node) {
4821 xmlAttrPtr cur, next;
4823 cur = node->properties;
4824 while (cur != NULL) {
4826 if ((cur->ns == NULL) ||
4827 (xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
4828 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
4829 if ((!xmlStrEqual(node->name, BAD_CAST "element")) &&
4830 (!xmlStrEqual(node->name, BAD_CAST "attribute")) &&
4831 (!xmlStrEqual(node->name, BAD_CAST "ref")) &&
4832 (!xmlStrEqual(node->name, BAD_CAST "parentRef")) &&
4833 (!xmlStrEqual(node->name, BAD_CAST "param")) &&
4834 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
4835 if (ctxt->error != NULL)
4836 ctxt->error(ctxt->userData,
4837 "Attribute %s is not allowed on %s\n",
4838 cur->name, node->name);
4841 } else if (xmlStrEqual(cur->name, BAD_CAST "type")) {
4842 if ((!xmlStrEqual(node->name, BAD_CAST "value")) &&
4843 (!xmlStrEqual(node->name, BAD_CAST "data"))) {
4844 if (ctxt->error != NULL)
4845 ctxt->error(ctxt->userData,
4846 "Attribute %s is not allowed on %s\n",
4847 cur->name, node->name);
4850 } else if (xmlStrEqual(cur->name, BAD_CAST "href")) {
4851 if ((!xmlStrEqual(node->name, BAD_CAST "externalRef")) &&
4852 (!xmlStrEqual(node->name, BAD_CAST "include"))) {
4853 if (ctxt->error != NULL)
4854 ctxt->error(ctxt->userData,
4855 "Attribute %s is not allowed on %s\n",
4856 cur->name, node->name);
4859 } else if (xmlStrEqual(cur->name, BAD_CAST "combine")) {
4860 if ((!xmlStrEqual(node->name, BAD_CAST "start")) &&
4861 (!xmlStrEqual(node->name, BAD_CAST "define"))) {
4862 if (ctxt->error != NULL)
4863 ctxt->error(ctxt->userData,
4864 "Attribute %s is not allowed on %s\n",
4865 cur->name, node->name);
4868 } else if (xmlStrEqual(cur->name, BAD_CAST "datatypeLibrary")) {
4872 val = xmlNodeListGetString(node->doc, cur->children, 1);
4875 uri = xmlParseURI((const char *) val);
4877 if (ctxt->error != NULL)
4878 ctxt->error(ctxt->userData,
4879 "Attribute %s contains invalid URI %s\n",
4883 if (uri->scheme == NULL) {
4884 if (ctxt->error != NULL)
4885 ctxt->error(ctxt->userData,
4886 "Attribute %s URI %s is not absolute\n",
4890 if (uri->fragment != NULL) {
4891 if (ctxt->error != NULL)
4892 ctxt->error(ctxt->userData,
4893 "Attribute %s URI %s has a fragment ID\n",
4902 } else if (!xmlStrEqual(cur->name, BAD_CAST "ns")) {
4903 if (ctxt->error != NULL)
4904 ctxt->error(ctxt->userData,
4905 "Unknown attribute %s on %s\n",
4906 cur->name, node->name);
4915 * xmlRelaxNGCleanupTree:
4916 * @ctxt: a Relax-NG parser context
4917 * @root: an xmlNodePtr subtree
4919 * Cleanup the subtree from unwanted nodes for parsing, resolve
4920 * Include and externalRef lookups.
4923 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt, xmlNodePtr root) {
4924 xmlNodePtr cur, delete;
4928 while (cur != NULL) {
4929 if (delete != NULL) {
4930 xmlUnlinkNode(delete);
4931 xmlFreeNode(delete);
4934 if (cur->type == XML_ELEMENT_NODE) {
4936 * Simplification 4.1. Annotations
4938 if ((cur->ns == NULL) ||
4939 (!xmlStrEqual(cur->ns->href, xmlRelaxNGNs))) {
4940 if ((cur->parent != NULL) &&
4941 (cur->parent->type == XML_ELEMENT_NODE) &&
4942 ((xmlStrEqual(cur->parent->name, BAD_CAST "name")) ||
4943 (xmlStrEqual(cur->parent->name, BAD_CAST "value")) ||
4944 (xmlStrEqual(cur->parent->name, BAD_CAST "param")))) {
4945 if (ctxt->error != NULL)
4946 ctxt->error(ctxt->userData,
4947 "element %s doesn't allow foreign elements\n",
4954 xmlRelaxNGCleanupAttributes(ctxt, cur);
4955 if (xmlStrEqual(cur->name, BAD_CAST "externalRef")) {
4956 xmlChar *href, *ns, *base, *URL;
4957 xmlRelaxNGDocumentPtr docu;
4960 ns = xmlGetProp(cur, BAD_CAST "ns");
4963 while ((tmp != NULL) &&
4964 (tmp->type == XML_ELEMENT_NODE)) {
4965 ns = xmlGetProp(tmp, BAD_CAST "ns");
4971 href = xmlGetProp(cur, BAD_CAST "href");
4973 if (ctxt->error != NULL)
4974 ctxt->error(ctxt->userData,
4975 "xmlRelaxNGParse: externalRef has no href attribute\n");
4980 base = xmlNodeGetBase(cur->doc, cur);
4981 URL = xmlBuildURI(href, base);
4983 if (ctxt->error != NULL)
4984 ctxt->error(ctxt->userData,
4985 "Failed to compute URL for externalRef %s\n", href);
4998 docu = xmlRelaxNGLoadExternalRef(ctxt, URL, ns);
5000 if (ctxt->error != NULL)
5001 ctxt->error(ctxt->userData,
5002 "Failed to load externalRef %s\n", URL);
5011 cur->_private = docu;
5012 } else if (xmlStrEqual(cur->name, BAD_CAST "include")) {
5013 xmlChar *href, *ns, *base, *URL;
5014 xmlRelaxNGIncludePtr incl;
5017 href = xmlGetProp(cur, BAD_CAST "href");
5019 if (ctxt->error != NULL)
5020 ctxt->error(ctxt->userData,
5021 "xmlRelaxNGParse: include has no href attribute\n");
5026 base = xmlNodeGetBase(cur->doc, cur);
5027 URL = xmlBuildURI(href, base);
5029 if (ctxt->error != NULL)
5030 ctxt->error(ctxt->userData,
5031 "Failed to compute URL for include %s\n", href);
5044 ns = xmlGetProp(cur, BAD_CAST "ns");
5047 while ((tmp != NULL) &&
5048 (tmp->type == XML_ELEMENT_NODE)) {
5049 ns = xmlGetProp(tmp, BAD_CAST "ns");
5055 incl = xmlRelaxNGLoadInclude(ctxt, URL, cur, ns);
5059 if (ctxt->error != NULL)
5060 ctxt->error(ctxt->userData,
5061 "Failed to load include %s\n", URL);
5068 cur->_private = incl;
5069 } else if ((xmlStrEqual(cur->name, BAD_CAST "element")) ||
5070 (xmlStrEqual(cur->name, BAD_CAST "attribute"))) {
5072 xmlNodePtr text = NULL;
5075 * Simplification 4.8. name attribute of element
5076 * and attribute elements
5078 name = xmlGetProp(cur, BAD_CAST "name");
5080 if (cur->children == NULL) {
5081 text = xmlNewChild(cur, cur->ns, BAD_CAST "name",
5085 node = xmlNewNode(cur->ns, BAD_CAST "name");
5087 xmlAddPrevSibling(cur->children, node);
5088 text = xmlNewText(name);
5089 xmlAddChild(node, text);
5094 if (ctxt->error != NULL)
5095 ctxt->error(ctxt->userData,
5096 "Failed to create a name %s element\n", name);
5099 xmlUnsetProp(cur, BAD_CAST "name");
5101 ns = xmlGetProp(cur, BAD_CAST "ns");
5104 xmlSetProp(text, BAD_CAST "ns", ns);
5105 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
5108 } else if (xmlStrEqual(cur->name,
5109 BAD_CAST "attribute")) {
5110 xmlSetProp(text, BAD_CAST "ns", BAD_CAST "");
5113 } else if ((xmlStrEqual(cur->name, BAD_CAST "name")) ||
5114 (xmlStrEqual(cur->name, BAD_CAST "nsName")) ||
5115 (xmlStrEqual(cur->name, BAD_CAST "value"))) {
5117 * Simplification 4.8. name attribute of element
5118 * and attribute elements
5120 if (xmlHasProp(cur, BAD_CAST "ns") == NULL) {
5125 while ((node != NULL) &&
5126 (node->type == XML_ELEMENT_NODE)) {
5127 ns = xmlGetProp(node, BAD_CAST "ns");
5131 node = node->parent;
5134 xmlSetProp(cur, BAD_CAST "ns", BAD_CAST "");
5136 xmlSetProp(cur, BAD_CAST "ns", ns);
5140 if (xmlStrEqual(cur->name, BAD_CAST "name")) {
5141 xmlChar *name, *local, *prefix;
5144 * Simplification: 4.10. QNames
5146 name = xmlNodeGetContent(cur);
5148 local = xmlSplitQName2(name, &prefix);
5149 if (local != NULL) {
5152 ns = xmlSearchNs(cur->doc, cur, prefix);
5154 if (ctxt->error != NULL)
5155 ctxt->error(ctxt->userData,
5156 "xmlRelaxNGParse: no namespace for prefix %s\n", prefix);
5159 xmlSetProp(cur, BAD_CAST "ns", ns->href);
5160 xmlNodeSetContent(cur, local);
5171 if (xmlStrEqual(cur->name, BAD_CAST "nsName")) {
5172 if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
5173 if (ctxt->error != NULL)
5174 ctxt->error(ctxt->userData,
5175 "Found nsName/except//nsName forbidden construct\n");
5179 } else if ((xmlStrEqual(cur->name, BAD_CAST "except")) &&
5181 int oldflags = ctxt->flags;
5186 if ((cur->parent != NULL) &&
5187 (xmlStrEqual(cur->parent->name, BAD_CAST "anyName"))) {
5188 ctxt->flags |= XML_RELAXNG_IN_ANYEXCEPT;
5189 xmlRelaxNGCleanupTree(ctxt, cur);
5190 ctxt->flags = oldflags;
5192 } else if ((cur->parent != NULL) &&
5193 (xmlStrEqual(cur->parent->name, BAD_CAST "nsName"))) {
5194 ctxt->flags |= XML_RELAXNG_IN_NSEXCEPT;
5195 xmlRelaxNGCleanupTree(ctxt, cur);
5196 ctxt->flags = oldflags;
5199 } else if (xmlStrEqual(cur->name, BAD_CAST "anyName")) {
5203 if (ctxt->flags & XML_RELAXNG_IN_ANYEXCEPT) {
5204 if (ctxt->error != NULL)
5205 ctxt->error(ctxt->userData,
5206 "Found anyName/except//anyName forbidden construct\n");
5208 } else if (ctxt->flags & XML_RELAXNG_IN_NSEXCEPT) {
5209 if (ctxt->error != NULL)
5210 ctxt->error(ctxt->userData,
5211 "Found nsName/except//anyName forbidden construct\n");
5216 * Thisd is not an else since "include" is transformed
5219 if (xmlStrEqual(cur->name, BAD_CAST "div")) {
5221 xmlNodePtr child, ins, tmp;
5224 * implements rule 4.11
5227 ns = xmlGetProp(cur, BAD_CAST "ns");
5229 child = cur->children;
5231 while (child != NULL) {
5233 if (!xmlHasProp(child, BAD_CAST "ns")) {
5234 xmlSetProp(child, BAD_CAST "ns", ns);
5238 xmlUnlinkNode(child);
5239 ins = xmlAddNextSibling(ins, child);
5250 * Simplification 4.2 whitespaces
5252 else if (cur->type == XML_TEXT_NODE) {
5253 if (IS_BLANK_NODE(cur)) {
5254 if (cur->parent->type == XML_ELEMENT_NODE) {
5255 if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value")) &&
5256 (!xmlStrEqual(cur->parent->name, BAD_CAST "param")))
5263 } else if (cur->type != XML_CDATA_SECTION_NODE) {
5271 if (cur->children != NULL) {
5272 if ((cur->children->type != XML_ENTITY_DECL) &&
5273 (cur->children->type != XML_ENTITY_REF_NODE) &&
5274 (cur->children->type != XML_ENTITY_NODE)) {
5275 cur = cur->children;
5280 if (cur->next != NULL) {
5293 if (cur->next != NULL) {
5297 } while (cur != NULL);
5299 if (delete != NULL) {
5300 xmlUnlinkNode(delete);
5301 xmlFreeNode(delete);
5307 * xmlRelaxNGCleanupDoc:
5308 * @ctxt: a Relax-NG parser context
5309 * @doc: an xmldocPtr document pointer
5311 * Cleanup the document from unwanted nodes for parsing, resolve
5312 * Include and externalRef lookups.
5314 * Returns the cleaned up document or NULL in case of error
5317 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt, xmlDocPtr doc) {
5323 root = xmlDocGetRootElement(doc);
5325 if (ctxt->error != NULL)
5326 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5331 xmlRelaxNGCleanupTree(ctxt, root);
5337 * @ctxt: a Relax-NG parser context
5339 * parse a schema definition resource and build an internal
5340 * XML Shema struture which can be used to validate instances.
5341 * *WARNING* this interface is highly subject to change
5343 * Returns the internal XML RelaxNG structure built from the resource or
5344 * NULL in case of error
5347 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt)
5349 xmlRelaxNGPtr ret = NULL;
5353 xmlRelaxNGInitTypes();
5359 * First step is to parse the input document into an DOM/Infoset
5361 if (ctxt->URL != NULL) {
5362 doc = xmlParseFile((const char *) ctxt->URL);
5364 if (ctxt->error != NULL)
5365 ctxt->error(ctxt->userData,
5366 "xmlRelaxNGParse: could not load %s\n", ctxt->URL);
5370 } else if (ctxt->buffer != NULL) {
5371 doc = xmlParseMemory(ctxt->buffer, ctxt->size);
5373 if (ctxt->error != NULL)
5374 ctxt->error(ctxt->userData,
5375 "xmlRelaxNGParse: could not parse schemas\n");
5379 doc->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
5380 ctxt->URL = xmlStrdup(BAD_CAST "in_memory_buffer");
5382 if (ctxt->error != NULL)
5383 ctxt->error(ctxt->userData,
5384 "xmlRelaxNGParse: nothing to parse\n");
5388 ctxt->document = doc;
5391 * Some preprocessing of the document content
5393 doc = xmlRelaxNGCleanupDoc(ctxt, doc);
5395 xmlFreeDoc(ctxt->document);
5396 ctxt->document = NULL;
5401 * Then do the parsing for good
5403 root = xmlDocGetRootElement(doc);
5405 if (ctxt->error != NULL)
5406 ctxt->error(ctxt->userData, "xmlRelaxNGParse: %s is empty\n",
5412 ret = xmlRelaxNGParseDocument(ctxt, root);
5419 * Check the ref/defines links
5422 * try to preprocess interleaves
5424 if (ctxt->interleaves != NULL) {
5425 xmlHashScan(ctxt->interleaves,
5426 (xmlHashScanner)xmlRelaxNGComputeInterleaves, ctxt);
5430 * if there was a parsing error return NULL
5432 if (ctxt->nbErrors > 0) {
5433 xmlRelaxNGFree(ret);
5434 ctxt->document = NULL;
5440 * Transfer the pointer for cleanup at the schema level.
5443 ctxt->document = NULL;
5444 ret->documents = ctxt->documents;
5445 ctxt->documents = NULL;
5447 ret->includes = ctxt->includes;
5448 ctxt->includes = NULL;
5449 ret->defNr = ctxt->defNr;
5450 ret->defTab = ctxt->defTab;
5451 ctxt->defTab = NULL;
5457 * xmlRelaxNGSetParserErrors:
5458 * @ctxt: a Relax-NG validation context
5459 * @err: the error callback
5460 * @warn: the warning callback
5461 * @ctx: contextual data for the callbacks
5463 * Set the callback functions used to handle errors for a validation context
5466 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt,
5467 xmlRelaxNGValidityErrorFunc err,
5468 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
5472 ctxt->warning = warn;
5473 ctxt->userData = ctx;
5475 /************************************************************************
5477 * Dump back a compiled form *
5479 ************************************************************************/
5480 static void xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define);
5483 * xmlRelaxNGDumpDefines:
5484 * @output: the file output
5485 * @defines: a list of define structures
5487 * Dump a RelaxNG structure back
5490 xmlRelaxNGDumpDefines(FILE * output, xmlRelaxNGDefinePtr defines) {
5491 while (defines != NULL) {
5492 xmlRelaxNGDumpDefine(output, defines);
5493 defines = defines->next;
5498 * xmlRelaxNGDumpDefine:
5499 * @output: the file output
5500 * @define: a define structure
5502 * Dump a RelaxNG structure back
5505 xmlRelaxNGDumpDefine(FILE * output, xmlRelaxNGDefinePtr define) {
5508 switch(define->type) {
5509 case XML_RELAXNG_EMPTY:
5510 fprintf(output, "<empty/>\n");
5512 case XML_RELAXNG_NOT_ALLOWED:
5513 fprintf(output, "<notAllowed/>\n");
5515 case XML_RELAXNG_TEXT:
5516 fprintf(output, "<text/>\n");
5518 case XML_RELAXNG_ELEMENT:
5519 fprintf(output, "<element>\n");
5520 if (define->name != NULL) {
5521 fprintf(output, "<name");
5522 if (define->ns != NULL)
5523 fprintf(output, " ns=\"%s\"", define->ns);
5524 fprintf(output, ">%s</name>\n", define->name);
5526 xmlRelaxNGDumpDefines(output, define->attrs);
5527 xmlRelaxNGDumpDefines(output, define->content);
5528 fprintf(output, "</element>\n");
5530 case XML_RELAXNG_LIST:
5531 fprintf(output, "<list>\n");
5532 xmlRelaxNGDumpDefines(output, define->content);
5533 fprintf(output, "</list>\n");
5535 case XML_RELAXNG_ONEORMORE:
5536 fprintf(output, "<oneOrMore>\n");
5537 xmlRelaxNGDumpDefines(output, define->content);
5538 fprintf(output, "</oneOrMore>\n");
5540 case XML_RELAXNG_ZEROORMORE:
5541 fprintf(output, "<zeroOrMore>\n");
5542 xmlRelaxNGDumpDefines(output, define->content);
5543 fprintf(output, "</zeroOrMore>\n");
5545 case XML_RELAXNG_CHOICE:
5546 fprintf(output, "<choice>\n");
5547 xmlRelaxNGDumpDefines(output, define->content);
5548 fprintf(output, "</choice>\n");
5550 case XML_RELAXNG_GROUP:
5551 fprintf(output, "<group>\n");
5552 xmlRelaxNGDumpDefines(output, define->content);
5553 fprintf(output, "</group>\n");
5555 case XML_RELAXNG_INTERLEAVE:
5556 fprintf(output, "<interleave>\n");
5557 xmlRelaxNGDumpDefines(output, define->content);
5558 fprintf(output, "</interleave>\n");
5560 case XML_RELAXNG_OPTIONAL:
5561 fprintf(output, "<optional>\n");
5562 xmlRelaxNGDumpDefines(output, define->content);
5563 fprintf(output, "</optional>\n");
5565 case XML_RELAXNG_ATTRIBUTE:
5566 fprintf(output, "<attribute>\n");
5567 xmlRelaxNGDumpDefines(output, define->content);
5568 fprintf(output, "</attribute>\n");
5570 case XML_RELAXNG_DEF:
5571 fprintf(output, "<define");
5572 if (define->name != NULL)
5573 fprintf(output, " name=\"%s\"", define->name);
5574 fprintf(output, ">\n");
5575 xmlRelaxNGDumpDefines(output, define->content);
5576 fprintf(output, "</define>\n");
5578 case XML_RELAXNG_REF:
5579 fprintf(output, "<ref");
5580 if (define->name != NULL)
5581 fprintf(output, " name=\"%s\"", define->name);
5582 fprintf(output, ">\n");
5583 xmlRelaxNGDumpDefines(output, define->content);
5584 fprintf(output, "</ref>\n");
5586 case XML_RELAXNG_PARENTREF:
5587 fprintf(output, "<parentRef");
5588 if (define->name != NULL)
5589 fprintf(output, " name=\"%s\"", define->name);
5590 fprintf(output, ">\n");
5591 xmlRelaxNGDumpDefines(output, define->content);
5592 fprintf(output, "</parentRef>\n");
5594 case XML_RELAXNG_EXTERNALREF:
5595 fprintf(output, "<externalRef>");
5596 xmlRelaxNGDumpDefines(output, define->content);
5597 fprintf(output, "</externalRef>\n");
5599 case XML_RELAXNG_DATATYPE:
5600 case XML_RELAXNG_VALUE:
5603 case XML_RELAXNG_START:
5604 case XML_RELAXNG_EXCEPT:
5605 case XML_RELAXNG_PARAM:
5608 case XML_RELAXNG_NOOP:
5609 xmlRelaxNGDumpDefines(output, define->content);
5615 * xmlRelaxNGDumpGrammar:
5616 * @output: the file output
5617 * @grammar: a grammar structure
5618 * @top: is this a top grammar
5620 * Dump a RelaxNG structure back
5623 xmlRelaxNGDumpGrammar(FILE * output, xmlRelaxNGGrammarPtr grammar, int top)
5625 if (grammar == NULL)
5628 fprintf(output, "<grammar");
5631 " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
5632 switch(grammar->combine) {
5633 case XML_RELAXNG_COMBINE_UNDEFINED:
5635 case XML_RELAXNG_COMBINE_CHOICE:
5636 fprintf(output, " combine=\"choice\"");
5638 case XML_RELAXNG_COMBINE_INTERLEAVE:
5639 fprintf(output, " combine=\"interleave\"");
5642 fprintf(output, " <!-- invalid combine value -->");
5644 fprintf(output, ">\n");
5645 if (grammar->start == NULL) {
5646 fprintf(output, " <!-- grammar had no start -->");
5648 fprintf(output, "<start>\n");
5649 xmlRelaxNGDumpDefine(output, grammar->start);
5650 fprintf(output, "</start>\n");
5652 /* TODO ? Dump the defines ? */
5653 fprintf(output, "</grammar>\n");
5658 * @output: the file output
5659 * @schema: a schema structure
5661 * Dump a RelaxNG structure back
5664 xmlRelaxNGDump(FILE * output, xmlRelaxNGPtr schema)
5666 if (schema == NULL) {
5667 fprintf(output, "RelaxNG empty or failed to compile\n");
5670 fprintf(output, "RelaxNG: ");
5671 if (schema->doc == NULL) {
5672 fprintf(output, "no document\n");
5673 } else if (schema->doc->URL != NULL) {
5674 fprintf(output, "%s\n", schema->doc->URL);
5676 fprintf(output, "\n");
5678 if (schema->topgrammar == NULL) {
5679 fprintf(output, "RelaxNG has no top grammar\n");
5682 xmlRelaxNGDumpGrammar(output, schema->topgrammar, 1);
5686 * xmlRelaxNGDumpTree:
5687 * @output: the file output
5688 * @schema: a schema structure
5690 * Dump the transformed RelaxNG tree.
5693 xmlRelaxNGDumpTree(FILE * output, xmlRelaxNGPtr schema)
5695 if (schema == NULL) {
5696 fprintf(output, "RelaxNG empty or failed to compile\n");
5699 if (schema->doc == NULL) {
5700 fprintf(output, "no document\n");
5702 xmlDocDump(output, schema->doc);
5706 /************************************************************************
5708 * Validation implementation *
5710 ************************************************************************/
5711 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
5712 xmlRelaxNGDefinePtr define);
5713 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
5714 xmlRelaxNGDefinePtr define);
5717 * xmlRelaxNGSkipIgnored:
5718 * @ctxt: a schema validation context
5719 * @node: the top node.
5721 * Skip ignorable nodes in that context
5723 * Returns the new sibling or NULL in case of error.
5726 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED,
5729 * TODO complete and handle entities
5731 while ((node != NULL) &&
5732 ((node->type == XML_COMMENT_NODE) ||
5733 (node->type == XML_PI_NODE) ||
5734 ((node->type == XML_TEXT_NODE) &&
5735 (IS_BLANK_NODE(node))))) {
5742 * xmlRelaxNGNormalize:
5743 * @ctxt: a schema validation context
5744 * @str: the string to normalize
5746 * Implements the normalizeWhiteSpace( s ) function from
5747 * section 6.2.9 of the spec
5749 * Returns the new string or NULL in case of error.
5752 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *str) {
5760 while (*tmp != 0) tmp++;
5763 ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
5767 VALID_ERROR("xmlRelaxNGNormalize: out of memory\n");
5769 xmlGenericError(xmlGenericErrorContext,
5770 "xmlRelaxNGNormalize: out of memory\n");
5775 while (IS_BLANK(*str)) str++;
5777 if (IS_BLANK(*str)) {
5778 while (IS_BLANK(*str)) str++;
5790 * xmlRelaxNGValidateDatatype:
5791 * @ctxt: a Relax-NG validation context
5792 * @value: the string value
5793 * @type: the datatype definition
5795 * Validate the given value against the dataype
5797 * Returns 0 if the validation succeeded or an error code.
5800 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt, const xmlChar *value,
5801 xmlRelaxNGDefinePtr define) {
5803 xmlRelaxNGTypeLibraryPtr lib;
5805 if ((define == NULL) || (define->data == NULL)) {
5808 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
5809 if (lib->check != NULL)
5810 ret = lib->check(lib->data, define->name, value);
5815 VALID_ERROR2("Internal: failed to validate type %s\n", define->name);
5817 } else if (ret == 1) {
5821 VALID_ERROR3("Type %s doesn't allow value %s\n", define->name, value);
5825 if ((ret == 0) && (define->content != NULL)) {
5826 const xmlChar *oldvalue, *oldendvalue;
5828 oldvalue = ctxt->state->value;
5829 oldendvalue = ctxt->state->endvalue;
5830 ctxt->state->value = (xmlChar *) value;
5831 ctxt->state->endvalue = NULL;
5832 ret = xmlRelaxNGValidateValue(ctxt, define->content);
5833 ctxt->state->value = (xmlChar *) oldvalue;
5834 ctxt->state->endvalue = (xmlChar *) oldendvalue;
5840 * xmlRelaxNGNextValue:
5841 * @ctxt: a Relax-NG validation context
5843 * Skip to the next value when validating within a list
5845 * Returns 0 if the operation succeeded or an error code.
5848 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt) {
5851 cur = ctxt->state->value;
5852 if ((cur == NULL) || (ctxt->state->endvalue == NULL)) {
5853 ctxt->state->value = NULL;
5854 ctxt->state->endvalue = NULL;
5857 while (*cur != 0) cur++;
5858 while ((cur != ctxt->state->endvalue) && (*cur == 0)) cur++;
5859 if (cur == ctxt->state->endvalue)
5860 ctxt->state->value = NULL;
5862 ctxt->state->value = cur;
5867 * xmlRelaxNGValidateValueList:
5868 * @ctxt: a Relax-NG validation context
5869 * @defines: the list of definitions to verify
5871 * Validate the given set of definitions for the current value
5873 * Returns 0 if the validation succeeded or an error code.
5876 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt,
5877 xmlRelaxNGDefinePtr defines) {
5880 while (defines != NULL) {
5881 ret = xmlRelaxNGValidateValue(ctxt, defines);
5884 defines = defines->next;
5890 * xmlRelaxNGValidateValue:
5891 * @ctxt: a Relax-NG validation context
5892 * @define: the definition to verify
5894 * Validate the given definition for the current value
5896 * Returns 0 if the validation succeeded or an error code.
5899 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
5900 xmlRelaxNGDefinePtr define) {
5901 int ret = 0, oldflags;
5904 value = ctxt->state->value;
5905 switch (define->type) {
5906 case XML_RELAXNG_EMPTY: {
5907 if ((value != NULL) && (value[0] != 0)) {
5910 while (IS_BLANK(value[idx]))
5912 if (value[idx] != 0)
5917 case XML_RELAXNG_TEXT:
5919 case XML_RELAXNG_VALUE: {
5920 if (!xmlStrEqual(value, define->value)) {
5921 if (define->name != NULL) {
5922 xmlRelaxNGTypeLibraryPtr lib;
5924 lib = (xmlRelaxNGTypeLibraryPtr) define->data;
5925 if ((lib != NULL) && (lib->comp != NULL))
5926 ret = lib->comp(lib->data, define->name, value,
5932 VALID_ERROR2("Internal: failed to compare type %s\n",
5935 } else if (ret == 1) {
5941 xmlChar *nval, *nvalue;
5944 * TODO: trivial optimizations are possible by
5945 * computing at compile-time
5947 nval = xmlRelaxNGNormalize(ctxt, define->value);
5948 nvalue = xmlRelaxNGNormalize(ctxt, value);
5950 if ((nval == NULL) || (nvalue == NULL) ||
5951 (!xmlStrEqual(nval, nvalue)))
5960 xmlRelaxNGNextValue(ctxt);
5963 case XML_RELAXNG_DATATYPE: {
5964 ret = xmlRelaxNGValidateDatatype(ctxt, value, define);
5966 xmlRelaxNGNextValue(ctxt);
5970 case XML_RELAXNG_CHOICE: {
5971 xmlRelaxNGDefinePtr list = define->content;
5974 oldflags = ctxt->flags;
5975 ctxt->flags |= FLAGS_IGNORABLE;
5977 oldvalue = ctxt->state->value;
5978 while (list != NULL) {
5979 ret = xmlRelaxNGValidateValue(ctxt, list);
5983 ctxt->state->value = oldvalue;
5986 ctxt->flags = oldflags;
5988 xmlRelaxNGNextValue(ctxt);
5991 case XML_RELAXNG_LIST: {
5992 xmlRelaxNGDefinePtr list = define->content;
5993 xmlChar *oldvalue, *oldend, *val, *cur;
5998 oldvalue = ctxt->state->value;
5999 oldend = ctxt->state->endvalue;
6001 val = xmlStrdup(oldvalue);
6003 val = xmlStrdup(BAD_CAST "");
6007 VALID_ERROR("Internal: no state\n");
6012 if (IS_BLANK(*cur)) {
6018 while (IS_BLANK(*cur))
6024 xmlGenericError(xmlGenericErrorContext,
6025 "list value: '%s' found %d items\n", oldvalue, nb_values);
6028 ctxt->state->endvalue = cur;
6030 while ((*cur == 0) && (cur != ctxt->state->endvalue)) cur++;
6032 ctxt->state->value = cur;
6034 while (list != NULL) {
6035 if (ctxt->state->value == ctxt->state->endvalue)
6036 ctxt->state->value = NULL;
6037 ret = xmlRelaxNGValidateValue(ctxt, list);
6040 xmlGenericError(xmlGenericErrorContext,
6041 "Failed to validate value: '%s' with %d rule\n",
6042 ctxt->state->value, nb_values);
6052 if ((ret == 0) && (ctxt->state->value != NULL) &&
6053 (ctxt->state->value != ctxt->state->endvalue)) {
6055 VALID_ERROR2("Extra data in list: %s\n", ctxt->state->value);
6059 ctxt->state->value = oldvalue;
6060 ctxt->state->endvalue = oldend;
6063 case XML_RELAXNG_ONEORMORE:
6064 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6068 /* no break on purpose */
6069 case XML_RELAXNG_ZEROORMORE: {
6070 xmlChar *cur, *temp;
6072 oldflags = ctxt->flags;
6073 ctxt->flags |= FLAGS_IGNORABLE;
6074 cur = ctxt->state->value;
6076 while ((cur != NULL) && (cur != ctxt->state->endvalue) &&
6079 ret = xmlRelaxNGValidateValueList(ctxt, define->content);
6081 ctxt->state->value = temp;
6085 cur = ctxt->state->value;
6087 ctxt->flags = oldflags;
6090 case XML_RELAXNG_EXCEPT: {
6091 xmlRelaxNGDefinePtr list;
6093 list = define->content;
6094 while (list != NULL) {
6095 ret = xmlRelaxNGValidateValue(ctxt, list);
6105 case XML_RELAXNG_GROUP: {
6106 xmlRelaxNGDefinePtr list;
6108 list = define->content;
6109 while (list != NULL) {
6110 ret = xmlRelaxNGValidateValue(ctxt, list);
6128 * xmlRelaxNGValidateValueContent:
6129 * @ctxt: a Relax-NG validation context
6130 * @defines: the list of definitions to verify
6132 * Validate the given definitions for the current value
6134 * Returns 0 if the validation succeeded or an error code.
6137 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt,
6138 xmlRelaxNGDefinePtr defines) {
6141 while (defines != NULL) {
6142 ret = xmlRelaxNGValidateValue(ctxt, defines);
6145 defines = defines->next;
6151 * xmlRelaxNGAttributeMatch:
6152 * @ctxt: a Relax-NG validation context
6153 * @define: the definition to check
6154 * @prop: the attribute
6156 * Check if the attribute matches the definition nameClass
6158 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
6161 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt,
6162 xmlRelaxNGDefinePtr define,
6166 if (define->name != NULL) {
6167 if (!xmlStrEqual(define->name, prop->name))
6170 if (define->ns != NULL) {
6171 if (define->ns[0] == 0) {
6172 if (prop->ns != NULL)
6175 if ((prop->ns == NULL) ||
6176 (!xmlStrEqual(define->ns, prop->ns->href)))
6180 if (define->nameClass == NULL)
6182 define = define->nameClass;
6183 if (define->type == XML_RELAXNG_EXCEPT) {
6184 xmlRelaxNGDefinePtr list;
6186 list = define->content;
6187 while (list != NULL) {
6188 ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
6202 * xmlRelaxNGValidateAttribute:
6203 * @ctxt: a Relax-NG validation context
6204 * @define: the definition to verify
6206 * Validate the given attribute definition for that node
6208 * Returns 0 if the validation succeeded or an error code.
6211 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt,
6212 xmlRelaxNGDefinePtr define) {
6214 xmlChar *value, *oldvalue;
6215 xmlAttrPtr prop = NULL, tmp;
6217 if (ctxt->state->nbAttrLeft <= 0)
6219 if (define->name != NULL) {
6220 for (i = 0;i < ctxt->state->nbAttrs;i++) {
6221 tmp = ctxt->state->attrs[i];
6222 if ((tmp != NULL) && (xmlStrEqual(define->name, tmp->name))) {
6223 if ((((define->ns == NULL) || (define->ns[0] == 0)) &&
6224 (tmp->ns == NULL)) ||
6225 ((tmp->ns != NULL) &&
6226 (xmlStrEqual(define->ns, tmp->ns->href)))) {
6233 value = xmlNodeListGetString(prop->doc, prop->children, 1);
6234 oldvalue = ctxt->state->value;
6235 ctxt->state->value = value;
6236 ctxt->state->endvalue = NULL;
6237 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
6238 if (ctxt->state->value != NULL)
6239 value = ctxt->state->value;
6242 ctxt->state->value = oldvalue;
6245 * flag the attribute as processed
6247 ctxt->state->attrs[i] = NULL;
6248 ctxt->state->nbAttrLeft--;
6254 xmlGenericError(xmlGenericErrorContext,
6255 "xmlRelaxNGValidateAttribute(%s): %d\n", define->name, ret);
6258 for (i = 0;i < ctxt->state->nbAttrs;i++) {
6259 tmp = ctxt->state->attrs[i];
6260 if ((tmp != NULL) &&
6261 (xmlRelaxNGAttributeMatch(ctxt, define, tmp) == 1)) {
6267 value = xmlNodeListGetString(prop->doc, prop->children, 1);
6268 oldvalue = ctxt->state->value;
6269 ctxt->state->value = value;
6270 ret = xmlRelaxNGValidateValueContent(ctxt, define->content);
6271 if (ctxt->state->value != NULL)
6272 value = ctxt->state->value;
6275 ctxt->state->value = oldvalue;
6278 * flag the attribute as processed
6280 ctxt->state->attrs[i] = NULL;
6281 ctxt->state->nbAttrLeft--;
6287 if (define->ns != NULL) {
6288 xmlGenericError(xmlGenericErrorContext,
6289 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
6292 xmlGenericError(xmlGenericErrorContext,
6293 "xmlRelaxNGValidateAttribute(anyName): %d\n",
6303 * xmlRelaxNGValidateAttributeList:
6304 * @ctxt: a Relax-NG validation context
6305 * @define: the list of definition to verify
6307 * Validate the given node against the list of attribute definitions
6309 * Returns 0 if the validation succeeded or an error code.
6312 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
6313 xmlRelaxNGDefinePtr defines) {
6315 while (defines != NULL) {
6316 if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
6318 defines = defines->next;
6324 * xmlRelaxNGNodeMatchesList:
6326 * @list: a NULL terminated array of definitions
6328 * Check if a node can be matched by one of the definitions
6330 * Returns 1 if matches 0 otherwise
6333 xmlRelaxNGNodeMatchesList(xmlNodePtr node, xmlRelaxNGDefinePtr *list) {
6334 xmlRelaxNGDefinePtr cur;
6337 if ((node == NULL) || (list == NULL))
6341 while (cur != NULL) {
6342 if ((node->type == XML_ELEMENT_NODE) &&
6343 (cur->type == XML_RELAXNG_ELEMENT)) {
6344 if (cur->name == NULL) {
6345 if ((node->ns != NULL) &&
6346 (xmlStrEqual(node->ns->href, cur->ns)))
6348 } else if (xmlStrEqual(cur->name, node->name)) {
6349 if ((cur->ns == NULL) || (cur->ns[0] == 0)) {
6350 if (node->ns == NULL)
6353 if ((node->ns != NULL) &&
6354 (xmlStrEqual(node->ns->href, cur->ns)))
6358 } else if ((node->type == XML_TEXT_NODE) &&
6359 (cur->type == XML_RELAXNG_TEXT)) {
6368 * xmlRelaxNGValidateInterleave:
6369 * @ctxt: a Relax-NG validation context
6370 * @define: the definition to verify
6372 * Validate an interleave definition for a node.
6374 * Returns 0 if the validation succeeded or an error code.
6377 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt,
6378 xmlRelaxNGDefinePtr define) {
6379 int ret = 0, i, nbgroups, left;
6380 xmlRelaxNGPartitionPtr partitions;
6381 xmlRelaxNGInterleaveGroupPtr group = NULL;
6382 xmlNodePtr cur, start, last = NULL, lastchg = NULL, lastelem;
6383 xmlNodePtr *list = NULL, *lasts = NULL;
6385 if (define->data != NULL) {
6386 partitions = (xmlRelaxNGPartitionPtr) define->data;
6387 nbgroups = partitions->nbgroups;
6391 VALID_ERROR("Internal: interleave block has no data\n");
6396 * Build arrays to store the first and last node of the chain
6397 * pertaining to each group
6399 list = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
6402 VALID_ERROR("Internal: out of memory in interleave check\n");
6405 memset(list, 0, nbgroups * sizeof(xmlNodePtr));
6406 lasts = (xmlNodePtr *) xmlMalloc(nbgroups * sizeof(xmlNodePtr));
6407 if (lasts == NULL) {
6409 VALID_ERROR("Internal: out of memory in interleave check\n");
6412 memset(lasts, 0, nbgroups * sizeof(xmlNodePtr));
6415 * Walk the sequence of children finding the right group and
6416 * sorting them in sequences.
6418 cur = ctxt->state->seq;
6419 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
6421 while (cur != NULL) {
6422 ctxt->state->seq = cur;
6423 for (i = 0;i < nbgroups;i++) {
6424 group = partitions->groups[i];
6427 if (xmlRelaxNGNodeMatchesList(cur, group->defs))
6431 * We break as soon as an element not matched is found
6433 if (i >= nbgroups) {
6436 if (lasts[i] != NULL) {
6437 lasts[i]->next = cur;
6443 if (cur->next != NULL)
6444 lastchg = cur->next;
6447 cur = xmlRelaxNGSkipIgnored(ctxt, cur->next);
6451 VALID_ERROR("Invalid sequence in interleave\n");
6456 for (i = 0;i < nbgroups;i++) {
6457 group = partitions->groups[i];
6458 if (lasts[i] != NULL) {
6459 last = lasts[i]->next;
6460 lasts[i]->next = NULL;
6462 ctxt->state->seq = list[i];
6463 ret = xmlRelaxNGValidateDefinition(ctxt, group->rule);
6466 cur = ctxt->state->seq;
6467 cur = xmlRelaxNGSkipIgnored(ctxt, cur);
6470 VALID_ERROR2("Extra element %s in interleave\n", cur->name);
6474 if (lasts[i] != NULL) {
6475 lasts[i]->next = last;
6478 ctxt->state->seq = lastelem;
6481 VALID_ERROR("Invalid sequence in interleave\n");
6488 * builds the next links chain from the prev one
6491 while (cur != NULL) {
6492 if ((cur == start) || (cur->prev == NULL))
6494 cur->prev->next = cur;
6504 * xmlRelaxNGValidateElementContent:
6505 * @ctxt: a Relax-NG validation context
6506 * @define: the list of definition to verify
6508 * Validate the given node content against the (list) of definitions
6510 * Returns 0 if the validation succeeded or an error code.
6513 xmlRelaxNGValidateElementContent(xmlRelaxNGValidCtxtPtr ctxt,
6514 xmlRelaxNGDefinePtr defines) {
6517 if (ctxt->state == NULL) {
6519 VALID_ERROR("Internal: no state\n");
6522 while (defines != NULL) {
6523 res = xmlRelaxNGValidateDefinition(ctxt, defines);
6526 defines = defines->next;
6533 * xmlRelaxNGElementMatch:
6534 * @ctxt: a Relax-NG validation context
6535 * @define: the definition to check
6536 * @elem: the element
6538 * Check if the element matches the definition nameClass
6540 * Returns 1 if the element matches, 0 if no, or -1 in case of error
6543 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt,
6544 xmlRelaxNGDefinePtr define,
6548 if (define->name != NULL) {
6549 if (!xmlStrEqual(elem->name, define->name)) {
6551 VALID_ERROR3("Expecting element %s, got %s\n",
6552 define->name, elem->name);
6556 if ((define->ns != NULL) && (define->ns[0] != 0)) {
6557 if (elem->ns == NULL) {
6559 VALID_ERROR2("Expecting a namespace for element %s\n",
6562 } else if (!xmlStrEqual(elem->ns->href, define->ns)) {
6564 VALID_ERROR3("Expecting element %s has wrong namespace: expecting %s\n",
6565 elem->name, define->ns);
6568 } else if ((elem->ns != NULL) && (define->ns != NULL) &&
6569 (define->name == NULL)) {
6571 VALID_ERROR2("Expecting no namespace for element %s\n",
6574 } else if ((elem->ns != NULL) && (define->name != NULL)) {
6576 VALID_ERROR2("Expecting no namespace for element %s\n",
6581 if (define->nameClass == NULL)
6584 define = define->nameClass;
6585 if (define->type == XML_RELAXNG_EXCEPT) {
6586 xmlRelaxNGDefinePtr list;
6587 oldflags = ctxt->flags;
6588 ctxt->flags |= FLAGS_IGNORABLE;
6590 list = define->content;
6591 while (list != NULL) {
6592 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
6594 ctxt->flags = oldflags;
6598 ctxt->flags = oldflags;
6604 ctxt->flags = oldflags;
6605 } else if (define->type == XML_RELAXNG_CHOICE) {
6606 xmlRelaxNGDefinePtr list;
6607 oldflags = ctxt->flags;
6608 ctxt->flags |= FLAGS_IGNORABLE;
6610 list = define->nameClass;
6611 while (list != NULL) {
6612 ret = xmlRelaxNGElementMatch(ctxt, list, elem);
6614 ctxt->flags = oldflags;
6618 ctxt->flags = oldflags;
6624 ctxt->flags = oldflags;
6633 * xmlRelaxNGValidateDefinition:
6634 * @ctxt: a Relax-NG validation context
6635 * @define: the definition to verify
6637 * Validate the current node against the definition
6639 * Returns 0 if the validation succeeded or an error code.
6642 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
6643 xmlRelaxNGDefinePtr define) {
6645 int ret = 0, i, tmp, oldflags;
6646 xmlRelaxNGValidStatePtr oldstate, state;
6648 if (define == NULL) {
6650 VALID_ERROR("internal error: define == NULL\n");
6653 if (ctxt->state != NULL) {
6654 node = ctxt->state->seq;
6659 for (i = 0;i < ctxt->depth;i++)
6660 xmlGenericError(xmlGenericErrorContext, " ");
6661 xmlGenericError(xmlGenericErrorContext,
6662 "Start validating %s ", xmlRelaxNGDefName(define));
6663 if (define->name != NULL)
6664 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
6665 if ((node != NULL) && (node->name != NULL))
6666 xmlGenericError(xmlGenericErrorContext, "on %s\n", node->name);
6668 xmlGenericError(xmlGenericErrorContext, "\n");
6671 switch (define->type) {
6672 case XML_RELAXNG_EMPTY:
6673 node = xmlRelaxNGSkipIgnored(ctxt, node);
6676 VALID_ERROR("Expecting an empty element\n");
6682 case XML_RELAXNG_NOT_ALLOWED:
6685 case XML_RELAXNG_TEXT:
6692 while ((node != NULL) &&
6693 ((node->type == XML_TEXT_NODE) ||
6694 (node->type == XML_COMMENT_NODE) ||
6695 (node->type == XML_PI_NODE) ||
6696 (node->type == XML_CDATA_SECTION_NODE)))
6699 if (node == ctxt->state->seq) {
6701 VALID_ERROR("Expecting text content\n");
6705 ctxt->state->seq = node;
6707 case XML_RELAXNG_ELEMENT:
6708 node = xmlRelaxNGSkipIgnored(ctxt, node);
6711 VALID_ERROR("Expecting an element, got empty\n");
6715 if (node->type != XML_ELEMENT_NODE) {
6717 VALID_ERROR2("Expecting an element got %d type\n", node->type);
6722 * This node was already validated successfully against
6725 if (node->_private == define) {
6726 ctxt->state->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
6730 ret = xmlRelaxNGElementMatch(ctxt, define, node);
6737 state = xmlRelaxNGNewValidState(ctxt, node);
6738 if (state == NULL) {
6743 oldstate = ctxt->state;
6744 ctxt->state = state;
6745 if (define->attrs != NULL) {
6746 tmp = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
6750 xmlGenericError(xmlGenericErrorContext,
6751 "E: Element %s failed to validate attributes\n",
6756 if (define->content != NULL) {
6757 tmp = xmlRelaxNGValidateElementContent(ctxt, define->content);
6761 xmlGenericError(xmlGenericErrorContext,
6762 "E: Element %s failed to validate element content\n",
6767 state = ctxt->state;
6768 if (state->seq != NULL) {
6769 state->seq = xmlRelaxNGSkipIgnored(ctxt, state->seq);
6770 if (state->seq != NULL) {
6772 VALID_ERROR3("Extra content for element %s: %s\n",
6773 node->name, state->seq->name);
6776 xmlGenericError(xmlGenericErrorContext,
6777 "E: Element %s has extra content: %s\n",
6778 node->name, state->seq->name);
6782 for (i = 0;i < state->nbAttrs;i++) {
6783 if (state->attrs[i] != NULL) {
6785 VALID_ERROR3("Invalid attribute %s for element %s\n",
6786 state->attrs[i]->name, node->name);
6790 ctxt->state = oldstate;
6791 xmlRelaxNGFreeValidState(state);
6792 if (oldstate != NULL)
6793 oldstate->seq = xmlRelaxNGSkipIgnored(ctxt, node->next);
6795 node->_private = define;
6799 xmlGenericError(xmlGenericErrorContext,
6800 "xmlRelaxNGValidateDefinition(): validated %s : %d",
6802 if (oldstate == NULL)
6803 xmlGenericError(xmlGenericErrorContext, ": no state\n");
6804 else if (oldstate->seq == NULL)
6805 xmlGenericError(xmlGenericErrorContext, ": done\n");
6806 else if (oldstate->seq->type == XML_ELEMENT_NODE)
6807 xmlGenericError(xmlGenericErrorContext, ": next elem %s\n",
6808 oldstate->seq->name);
6810 xmlGenericError(xmlGenericErrorContext, ": next %s %d\n",
6811 oldstate->seq->name, oldstate->seq->type);
6814 case XML_RELAXNG_OPTIONAL:
6815 oldflags = ctxt->flags;
6816 ctxt->flags |= FLAGS_IGNORABLE;
6817 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
6818 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6820 xmlRelaxNGFreeValidState(ctxt->state);
6821 ctxt->state = oldstate;
6825 xmlRelaxNGFreeValidState(oldstate);
6826 ctxt->flags = oldflags;
6829 case XML_RELAXNG_ONEORMORE:
6830 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6834 /* no break on purpose */
6835 case XML_RELAXNG_ZEROORMORE: {
6836 oldflags = ctxt->flags;
6837 ctxt->flags |= FLAGS_IGNORABLE;
6838 while (ctxt->state->nbAttrLeft != 0) {
6839 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
6840 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6842 xmlRelaxNGFreeValidState(ctxt->state);
6843 ctxt->state = oldstate;
6846 xmlRelaxNGFreeValidState(oldstate);
6850 * There is no attribute left to be consumed,
6851 * we can check the closure by looking at ctxt->state->seq
6853 xmlNodePtr cur, temp;
6855 cur = ctxt->state->seq;
6857 while ((cur != NULL) && (temp != cur)) {
6859 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
6860 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6862 xmlRelaxNGFreeValidState(ctxt->state);
6863 ctxt->state = oldstate;
6866 xmlRelaxNGFreeValidState(oldstate);
6867 cur = ctxt->state->seq;
6870 ctxt->flags = oldflags;
6874 case XML_RELAXNG_CHOICE: {
6875 xmlRelaxNGDefinePtr list = define->content;
6878 oldflags = ctxt->flags;
6879 ctxt->flags |= FLAGS_IGNORABLE;
6881 while (list != NULL) {
6882 oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);
6883 ret = xmlRelaxNGValidateDefinition(ctxt, list);
6885 if (xmlRelaxNGEqualValidState(ctxt, ctxt->state, oldstate)){
6887 * if that pattern was nullable flag it but try
6888 * to make more progresses
6892 xmlRelaxNGFreeValidState(oldstate);
6896 xmlRelaxNGFreeValidState(ctxt->state);
6897 ctxt->state = oldstate;
6900 ctxt->flags = oldflags;
6905 case XML_RELAXNG_DEF:
6906 case XML_RELAXNG_GROUP: {
6907 xmlRelaxNGDefinePtr list = define->content;
6909 while (list != NULL) {
6910 ret = xmlRelaxNGValidateDefinition(ctxt, list);
6917 case XML_RELAXNG_INTERLEAVE:
6918 ret = xmlRelaxNGValidateInterleave(ctxt, define);
6920 case XML_RELAXNG_ATTRIBUTE:
6921 ret = xmlRelaxNGValidateAttribute(ctxt, define);
6923 case XML_RELAXNG_NOOP:
6924 case XML_RELAXNG_REF:
6925 case XML_RELAXNG_PARENTREF:
6926 case XML_RELAXNG_EXTERNALREF:
6927 ret = xmlRelaxNGValidateDefinition(ctxt, define->content);
6929 case XML_RELAXNG_DATATYPE: {
6931 xmlChar *content = NULL;
6934 while (child != NULL) {
6935 if (child->type == XML_ELEMENT_NODE) {
6937 VALID_ERROR2("Element %s has child elements\n",
6938 node->parent->name);
6941 } else if ((child->type == XML_TEXT_NODE) ||
6942 (child->type == XML_CDATA_SECTION_NODE)) {
6943 content = xmlStrcat(content, child->content);
6945 /* TODO: handle entities ... */
6946 child = child->next;
6949 if (content != NULL)
6953 if (content == NULL) {
6954 content = xmlStrdup(BAD_CAST "");
6955 if (content == NULL) {
6957 VALID_ERROR("Allocation failure\n");
6962 ret = xmlRelaxNGValidateDatatype(ctxt, content, define);
6965 VALID_ERROR2("internal error validating %s\n", define->name);
6966 } else if (ret == 0) {
6967 ctxt->state->seq = NULL;
6969 if (content != NULL)
6973 case XML_RELAXNG_VALUE: {
6974 xmlChar *content = NULL;
6979 while (child != NULL) {
6980 if (child->type == XML_ELEMENT_NODE) {
6982 VALID_ERROR2("Element %s has child elements\n",
6983 node->parent->name);
6986 } else if ((child->type == XML_TEXT_NODE) ||
6987 (child->type == XML_CDATA_SECTION_NODE)) {
6988 content = xmlStrcat(content, child->content);
6990 /* TODO: handle entities ... */
6991 child = child->next;
6994 if (content != NULL)
6998 if (content == NULL) {
6999 content = xmlStrdup(BAD_CAST "");
7000 if (content == NULL) {
7002 VALID_ERROR("Allocation failure\n");
7007 oldvalue = ctxt->state->value;
7008 ctxt->state->value = content;
7009 ret = xmlRelaxNGValidateValue(ctxt, define);
7010 ctxt->state->value = oldvalue;
7013 if (define->name != NULL) {
7014 VALID_ERROR2("error validating value %s\n", define->name);
7016 VALID_ERROR("error validating value\n");
7018 } else if (ret == 0) {
7019 ctxt->state->seq = NULL;
7021 if (content != NULL)
7025 case XML_RELAXNG_LIST: {
7028 xmlChar *oldvalue, *oldendvalue;
7032 * Make sure it's only text nodes
7037 while (child != NULL) {
7038 if (child->type == XML_ELEMENT_NODE) {
7040 VALID_ERROR2("Element %s has child elements\n",
7041 node->parent->name);
7044 } else if ((child->type == XML_TEXT_NODE) ||
7045 (child->type == XML_CDATA_SECTION_NODE)) {
7046 content = xmlStrcat(content, child->content);
7048 /* TODO: handle entities ... */
7049 child = child->next;
7052 if (content != NULL)
7056 if (content == NULL) {
7057 content = xmlStrdup(BAD_CAST "");
7058 if (content == NULL) {
7060 VALID_ERROR("Allocation failure\n");
7065 len = xmlStrlen(content);
7066 oldvalue = ctxt->state->value;
7067 oldendvalue = ctxt->state->endvalue;
7068 ctxt->state->value = content;
7069 ctxt->state->endvalue = content + len;
7070 ret = xmlRelaxNGValidateValue(ctxt, define);
7071 ctxt->state->value = oldvalue;
7072 ctxt->state->endvalue = oldendvalue;
7075 VALID_ERROR("error validating list\n");
7076 } else if ((ret == 0) && (node != NULL)) {
7077 ctxt->state->seq = node->next;
7079 if (content != NULL)
7083 case XML_RELAXNG_START:
7084 case XML_RELAXNG_EXCEPT:
7085 case XML_RELAXNG_PARAM:
7092 for (i = 0;i < ctxt->depth;i++)
7093 xmlGenericError(xmlGenericErrorContext, " ");
7094 xmlGenericError(xmlGenericErrorContext,
7095 "Validating %s ", xmlRelaxNGDefName(define));
7096 if (define->name != NULL)
7097 xmlGenericError(xmlGenericErrorContext, "%s ", define->name);
7099 xmlGenericError(xmlGenericErrorContext, "suceeded\n");
7101 xmlGenericError(xmlGenericErrorContext, "failed\n");
7107 * xmlRelaxNGValidateDocument:
7108 * @ctxt: a Relax-NG validation context
7109 * @doc: the document
7111 * Validate the given document
7113 * Returns 0 if the validation succeeded or an error code.
7116 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
7118 xmlRelaxNGPtr schema;
7119 xmlRelaxNGGrammarPtr grammar;
7120 xmlRelaxNGValidStatePtr state;
7122 if ((ctxt == NULL) || (ctxt->schema == NULL) || (doc == NULL))
7125 schema = ctxt->schema;
7126 grammar = schema->topgrammar;
7127 if (grammar == NULL) {
7129 VALID_ERROR("No top grammar defined\n");
7132 state = xmlRelaxNGNewValidState(ctxt, NULL);
7133 ctxt->state = state;
7134 ret = xmlRelaxNGValidateDefinition(ctxt, grammar->start);
7135 state = ctxt->state;
7136 if ((state != NULL) && (state->seq != NULL)) {
7140 node = xmlRelaxNGSkipIgnored(ctxt, node);
7143 VALID_ERROR("extra data on the document\n");
7147 xmlRelaxNGFreeValidState(state);
7152 /************************************************************************
7154 * Validation interfaces *
7156 ************************************************************************/
7158 * xmlRelaxNGNewValidCtxt:
7159 * @schema: a precompiled XML RelaxNGs
7161 * Create an XML RelaxNGs validation context based on the given schema
7163 * Returns the validation context or NULL in case of error
7165 xmlRelaxNGValidCtxtPtr
7166 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema) {
7167 xmlRelaxNGValidCtxtPtr ret;
7169 ret = (xmlRelaxNGValidCtxtPtr) xmlMalloc(sizeof(xmlRelaxNGValidCtxt));
7171 xmlGenericError(xmlGenericErrorContext,
7172 "Failed to allocate new schama validation context\n");
7175 memset(ret, 0, sizeof(xmlRelaxNGValidCtxt));
7176 ret->schema = schema;
7177 ret->error = xmlGenericError;
7178 ret->userData = xmlGenericErrorContext;
7183 * xmlRelaxNGFreeValidCtxt:
7184 * @ctxt: the schema validation context
7186 * Free the resources associated to the schema validation context
7189 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt) {
7196 * xmlRelaxNGSetValidErrors:
7197 * @ctxt: a Relax-NG validation context
7198 * @err: the error function
7199 * @warn: the warning function
7200 * @ctx: the functions context
7202 * Set the error and warning callback informations
7205 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt,
7206 xmlRelaxNGValidityErrorFunc err,
7207 xmlRelaxNGValidityWarningFunc warn, void *ctx) {
7211 ctxt->warning = warn;
7212 ctxt->userData = ctx;
7216 * xmlRelaxNGValidateDoc:
7217 * @ctxt: a Relax-NG validation context
7218 * @doc: a parsed document tree
7220 * Validate a document tree in memory.
7222 * Returns 0 if the document is valid, a positive error code
7223 * number otherwise and -1 in case of internal or API error.
7226 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt, xmlDocPtr doc) {
7229 if ((ctxt == NULL) || (doc == NULL))
7234 ret = xmlRelaxNGValidateDocument(ctxt, doc);
7236 * TODO: build error codes
7243 #endif /* LIBXML_SCHEMAS_ENABLED */