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>
11 * - add support for DTD compatibility spec
12 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
13 * - report better mem allocations pbms at runtime and abort immediately.
19 #ifdef LIBXML_SCHEMAS_ENABLED
24 #include <libxml/xmlmemory.h>
25 #include <libxml/parser.h>
26 #include <libxml/parserInternals.h>
27 #include <libxml/hash.h>
28 #include <libxml/uri.h>
30 #include <libxml/relaxng.h>
32 #include <libxml/xmlschemastypes.h>
33 #include <libxml/xmlautomata.h>
34 #include <libxml/xmlregexp.h>
35 #include <libxml/xmlschemastypes.h>
37 #include "private/error.h"
38 #include "private/regexp.h"
39 #include "private/string.h"
42 * The Relax-NG namespace
44 static const xmlChar
*xmlRelaxNGNs
= (const xmlChar
*)
45 "http://relaxng.org/ns/structure/1.0";
47 #define IS_RELAXNG(node, typ) \
48 ((node != NULL) && (node->ns != NULL) && \
49 (node->type == XML_ELEMENT_NODE) && \
50 (xmlStrEqual(node->name, (const xmlChar *) typ)) && \
51 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
57 #define DEBUG_GRAMMAR 1
59 #define DEBUG_CONTENT 1
65 #define DEBUG_INTERLEAVE 1
69 #define DEBUG_INCLUDE 1
73 #define DEBUG_COMPILE 1
75 #define DEBUG_PROGRESSIVE 1
81 xmlGenericError(xmlGenericErrorContext, \
82 "Unimplemented block at %s:%d\n", \
85 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema
;
86 typedef xmlRelaxNGSchema
*xmlRelaxNGSchemaPtr
;
88 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine
;
89 typedef xmlRelaxNGDefine
*xmlRelaxNGDefinePtr
;
91 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument
;
92 typedef xmlRelaxNGDocument
*xmlRelaxNGDocumentPtr
;
94 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude
;
95 typedef xmlRelaxNGInclude
*xmlRelaxNGIncludePtr
;
98 XML_RELAXNG_COMBINE_UNDEFINED
= 0, /* undefined */
99 XML_RELAXNG_COMBINE_CHOICE
, /* choice */
100 XML_RELAXNG_COMBINE_INTERLEAVE
/* interleave */
104 XML_RELAXNG_CONTENT_ERROR
= -1,
105 XML_RELAXNG_CONTENT_EMPTY
= 0,
106 XML_RELAXNG_CONTENT_SIMPLE
,
107 XML_RELAXNG_CONTENT_COMPLEX
108 } xmlRelaxNGContentType
;
110 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar
;
111 typedef xmlRelaxNGGrammar
*xmlRelaxNGGrammarPtr
;
113 struct _xmlRelaxNGGrammar
{
114 xmlRelaxNGGrammarPtr parent
; /* the parent grammar if any */
115 xmlRelaxNGGrammarPtr children
; /* the children grammar if any */
116 xmlRelaxNGGrammarPtr next
; /* the next grammar if any */
117 xmlRelaxNGDefinePtr start
; /* <start> content */
118 xmlRelaxNGCombine combine
; /* the default combine value */
119 xmlRelaxNGDefinePtr startList
; /* list of <start> definitions */
120 xmlHashTablePtr defs
; /* define* */
121 xmlHashTablePtr refs
; /* references */
126 XML_RELAXNG_NOOP
= -1, /* a no operation from simplification */
127 XML_RELAXNG_EMPTY
= 0, /* an empty pattern */
128 XML_RELAXNG_NOT_ALLOWED
, /* not allowed top */
129 XML_RELAXNG_EXCEPT
, /* except present in nameclass defs */
130 XML_RELAXNG_TEXT
, /* textual content */
131 XML_RELAXNG_ELEMENT
, /* an element */
132 XML_RELAXNG_DATATYPE
, /* external data type definition */
133 XML_RELAXNG_PARAM
, /* external data type parameter */
134 XML_RELAXNG_VALUE
, /* value from an external data type definition */
135 XML_RELAXNG_LIST
, /* a list of patterns */
136 XML_RELAXNG_ATTRIBUTE
, /* an attribute following a pattern */
137 XML_RELAXNG_DEF
, /* a definition */
138 XML_RELAXNG_REF
, /* reference to a definition */
139 XML_RELAXNG_EXTERNALREF
, /* reference to an external def */
140 XML_RELAXNG_PARENTREF
, /* reference to a def in the parent grammar */
141 XML_RELAXNG_OPTIONAL
, /* optional patterns */
142 XML_RELAXNG_ZEROORMORE
, /* zero or more non empty patterns */
143 XML_RELAXNG_ONEORMORE
, /* one or more non empty patterns */
144 XML_RELAXNG_CHOICE
, /* a choice between non empty patterns */
145 XML_RELAXNG_GROUP
, /* a pair/group of non empty patterns */
146 XML_RELAXNG_INTERLEAVE
, /* interleaving choice of non-empty patterns */
147 XML_RELAXNG_START
/* Used to keep track of starts on grammars */
150 #define IS_NULLABLE (1 << 0)
151 #define IS_NOT_NULLABLE (1 << 1)
152 #define IS_INDETERMINIST (1 << 2)
153 #define IS_MIXED (1 << 3)
154 #define IS_TRIABLE (1 << 4)
155 #define IS_PROCESSED (1 << 5)
156 #define IS_COMPILABLE (1 << 6)
157 #define IS_NOT_COMPILABLE (1 << 7)
158 #define IS_EXTERNAL_REF (1 << 8)
160 struct _xmlRelaxNGDefine
{
161 xmlRelaxNGType type
; /* the type of definition */
162 xmlNodePtr node
; /* the node in the source */
163 xmlChar
*name
; /* the element local name if present */
164 xmlChar
*ns
; /* the namespace local name if present */
165 xmlChar
*value
; /* value when available */
166 void *data
; /* data lib or specific pointer */
167 xmlRelaxNGDefinePtr content
; /* the expected content */
168 xmlRelaxNGDefinePtr parent
; /* the parent definition, if any */
169 xmlRelaxNGDefinePtr next
; /* list within grouping sequences */
170 xmlRelaxNGDefinePtr attrs
; /* list of attributes for elements */
171 xmlRelaxNGDefinePtr nameClass
; /* the nameClass definition if any */
172 xmlRelaxNGDefinePtr nextHash
; /* next define in defs/refs hash tables */
173 short depth
; /* used for the cycle detection */
174 short dflags
; /* define related flags */
175 xmlRegexpPtr contModel
; /* a compiled content model if available */
181 * A RelaxNGs definition
184 void *_private
; /* unused by the library for users or bindings */
185 xmlRelaxNGGrammarPtr topgrammar
;
188 int idref
; /* requires idref checking */
190 xmlHashTablePtr defs
; /* define */
191 xmlHashTablePtr refs
; /* references */
192 xmlRelaxNGDocumentPtr documents
; /* all the documents loaded */
193 xmlRelaxNGIncludePtr includes
; /* all the includes loaded */
194 int defNr
; /* number of defines used */
195 xmlRelaxNGDefinePtr
*defTab
; /* pointer to the allocated definitions */
199 #define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
200 #define XML_RELAXNG_IN_ONEORMORE (1 << 1)
201 #define XML_RELAXNG_IN_LIST (1 << 2)
202 #define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
203 #define XML_RELAXNG_IN_START (1 << 4)
204 #define XML_RELAXNG_IN_OOMGROUP (1 << 5)
205 #define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
206 #define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
207 #define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
208 #define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
210 struct _xmlRelaxNGParserCtxt
{
211 void *userData
; /* user specific data block */
212 xmlRelaxNGValidityErrorFunc error
; /* the callback in case of errors */
213 xmlRelaxNGValidityWarningFunc warning
; /* the callback in case of warning */
214 xmlStructuredErrorFunc serror
;
215 xmlRelaxNGValidErr err
;
217 xmlRelaxNGPtr schema
; /* The schema in use */
218 xmlRelaxNGGrammarPtr grammar
; /* the current grammar */
219 xmlRelaxNGGrammarPtr parentgrammar
; /* the parent grammar */
220 int flags
; /* parser flags */
221 int nbErrors
; /* number of errors at parse time */
222 int nbWarnings
; /* number of warnings at parse time */
223 const xmlChar
*define
; /* the current define scope */
224 xmlRelaxNGDefinePtr def
; /* the current define */
227 xmlHashTablePtr interleaves
; /* keep track of all the interleaves */
229 xmlRelaxNGDocumentPtr documents
; /* all the documents loaded */
230 xmlRelaxNGIncludePtr includes
; /* all the includes loaded */
234 int defNr
; /* number of defines used */
235 int defMax
; /* number of defines allocated */
236 xmlRelaxNGDefinePtr
*defTab
; /* pointer to the allocated definitions */
241 /* the document stack */
242 xmlRelaxNGDocumentPtr doc
; /* Current parsed external ref */
243 int docNr
; /* Depth of the parsing stack */
244 int docMax
; /* Max depth of the parsing stack */
245 xmlRelaxNGDocumentPtr
*docTab
; /* array of docs */
247 /* the include stack */
248 xmlRelaxNGIncludePtr inc
; /* Current parsed include */
249 int incNr
; /* Depth of the include parsing stack */
250 int incMax
; /* Max depth of the parsing stack */
251 xmlRelaxNGIncludePtr
*incTab
; /* array of incs */
253 int idref
; /* requires idref checking */
255 /* used to compile content models */
256 xmlAutomataPtr am
; /* the automata */
257 xmlAutomataStatePtr state
; /* used to build the automata */
259 int crng
; /* compact syntax and other flags */
260 int freedoc
; /* need to free the document */
263 #define FLAGS_IGNORABLE 1
264 #define FLAGS_NEGATIVE 2
265 #define FLAGS_MIXED_CONTENT 4
266 #define FLAGS_NOERROR 8
269 * xmlRelaxNGInterleaveGroup:
271 * A RelaxNGs partition set associated to lists of definitions
273 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup
;
274 typedef xmlRelaxNGInterleaveGroup
*xmlRelaxNGInterleaveGroupPtr
;
275 struct _xmlRelaxNGInterleaveGroup
{
276 xmlRelaxNGDefinePtr rule
; /* the rule to satisfy */
277 xmlRelaxNGDefinePtr
*defs
; /* the array of element definitions */
278 xmlRelaxNGDefinePtr
*attrs
; /* the array of attributes definitions */
281 #define IS_DETERMINIST 1
282 #define IS_NEEDCHECK 2
285 * xmlRelaxNGPartitions:
287 * A RelaxNGs partition associated to an interleave group
289 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition
;
290 typedef xmlRelaxNGPartition
*xmlRelaxNGPartitionPtr
;
291 struct _xmlRelaxNGPartition
{
292 int nbgroups
; /* number of groups in the partitions */
293 xmlHashTablePtr triage
; /* hash table used to direct nodes to the
294 * right group when possible */
295 int flags
; /* determinist ? */
296 xmlRelaxNGInterleaveGroupPtr
*groups
;
300 * xmlRelaxNGValidState:
302 * A RelaxNGs validation state
305 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState
;
306 typedef xmlRelaxNGValidState
*xmlRelaxNGValidStatePtr
;
307 struct _xmlRelaxNGValidState
{
308 xmlNodePtr node
; /* the current node */
309 xmlNodePtr seq
; /* the sequence of children left to validate */
310 int nbAttrs
; /* the number of attributes */
311 int maxAttrs
; /* the size of attrs */
312 int nbAttrLeft
; /* the number of attributes left to validate */
313 xmlChar
*value
; /* the value when operating on string */
314 xmlChar
*endvalue
; /* the end value when operating on string */
315 xmlAttrPtr
*attrs
; /* the array of attributes */
321 * A RelaxNGs container for validation state
323 typedef struct _xmlRelaxNGStates xmlRelaxNGStates
;
324 typedef xmlRelaxNGStates
*xmlRelaxNGStatesPtr
;
325 struct _xmlRelaxNGStates
{
326 int nbState
; /* the number of states */
327 int maxState
; /* the size of the array */
328 xmlRelaxNGValidStatePtr
*tabState
;
331 #define ERROR_IS_DUP 1
334 * xmlRelaxNGValidError:
336 * A RelaxNGs validation error
338 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError
;
339 typedef xmlRelaxNGValidError
*xmlRelaxNGValidErrorPtr
;
340 struct _xmlRelaxNGValidError
{
341 xmlRelaxNGValidErr err
; /* the error number */
342 int flags
; /* flags */
343 xmlNodePtr node
; /* the current node */
344 xmlNodePtr seq
; /* the current child */
345 const xmlChar
*arg1
; /* first arg */
346 const xmlChar
*arg2
; /* second arg */
350 * xmlRelaxNGValidCtxt:
352 * A RelaxNGs validation context
355 struct _xmlRelaxNGValidCtxt
{
356 void *userData
; /* user specific data block */
357 xmlRelaxNGValidityErrorFunc error
; /* the callback in case of errors */
358 xmlRelaxNGValidityWarningFunc warning
; /* the callback in case of warning */
359 xmlStructuredErrorFunc serror
;
360 int nbErrors
; /* number of errors in validation */
362 xmlRelaxNGPtr schema
; /* The schema in use */
363 xmlDocPtr doc
; /* the document being validated */
364 int flags
; /* validation flags */
365 int depth
; /* validation depth */
366 int idref
; /* requires idref checking */
367 int errNo
; /* the first error found */
370 * Errors accumulated in branches may have to be stacked to be
371 * provided back when it's sure they affect validation.
373 xmlRelaxNGValidErrorPtr err
; /* Last error */
374 int errNr
; /* Depth of the error stack */
375 int errMax
; /* Max depth of the error stack */
376 xmlRelaxNGValidErrorPtr errTab
; /* stack of errors */
378 xmlRelaxNGValidStatePtr state
; /* the current validation state */
379 xmlRelaxNGStatesPtr states
; /* the accumulated state list */
381 xmlRelaxNGStatesPtr freeState
; /* the pool of free valid states */
384 xmlRelaxNGStatesPtr
*freeStates
; /* the pool of free state groups */
387 * This is used for "progressive" validation
389 xmlRegExecCtxtPtr elem
; /* the current element regexp */
390 int elemNr
; /* the number of element validated */
391 int elemMax
; /* the max depth of elements */
392 xmlRegExecCtxtPtr
*elemTab
; /* the stack of regexp runtime */
393 int pstate
; /* progressive state */
394 xmlNodePtr pnode
; /* the current node */
395 xmlRelaxNGDefinePtr pdef
; /* the non-streamable definition */
396 int perr
; /* signal error in content model
397 * outside the regexp */
403 * Structure associated to a RelaxNGs document element
405 struct _xmlRelaxNGInclude
{
406 xmlRelaxNGIncludePtr next
; /* keep a chain of includes */
407 xmlChar
*href
; /* the normalized href value */
408 xmlDocPtr doc
; /* the associated XML document */
409 xmlRelaxNGDefinePtr content
; /* the definitions */
410 xmlRelaxNGPtr schema
; /* the schema */
414 * xmlRelaxNGDocument:
416 * Structure associated to a RelaxNGs document element
418 struct _xmlRelaxNGDocument
{
419 xmlRelaxNGDocumentPtr next
; /* keep a chain of documents */
420 xmlChar
*href
; /* the normalized href value */
421 xmlDocPtr doc
; /* the associated XML document */
422 xmlRelaxNGDefinePtr content
; /* the definitions */
423 xmlRelaxNGPtr schema
; /* the schema */
424 int externalRef
; /* 1 if an external ref */
428 /************************************************************************
430 * Some factorized error routines *
432 ************************************************************************/
436 * @ctxt: an Relax-NG parser context
437 * @extra: extra information
439 * Handle a redefinition of attribute error
442 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt
, const char *extra
)
444 xmlStructuredErrorFunc schannel
= NULL
;
445 xmlGenericErrorFunc channel
= NULL
;
449 if (ctxt
->serror
!= NULL
)
450 schannel
= ctxt
->serror
;
452 channel
= ctxt
->error
;
453 data
= ctxt
->userData
;
457 __xmlRaiseError(schannel
, channel
, data
,
458 NULL
, NULL
, XML_FROM_RELAXNGP
,
459 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, extra
,
461 "Memory allocation failed : %s\n", extra
);
463 __xmlRaiseError(schannel
, channel
, data
,
464 NULL
, NULL
, XML_FROM_RELAXNGP
,
465 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, NULL
,
466 NULL
, NULL
, 0, 0, "Memory allocation failed\n");
471 * @ctxt: a Relax-NG validation context
472 * @extra: extra information
474 * Handle a redefinition of attribute error
477 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt
, const char *extra
)
479 xmlStructuredErrorFunc schannel
= NULL
;
480 xmlGenericErrorFunc channel
= NULL
;
484 if (ctxt
->serror
!= NULL
)
485 schannel
= ctxt
->serror
;
487 channel
= ctxt
->error
;
488 data
= ctxt
->userData
;
492 __xmlRaiseError(schannel
, channel
, data
,
493 NULL
, NULL
, XML_FROM_RELAXNGV
,
494 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, extra
,
496 "Memory allocation failed : %s\n", extra
);
498 __xmlRaiseError(schannel
, channel
, data
,
499 NULL
, NULL
, XML_FROM_RELAXNGV
,
500 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, NULL
,
501 NULL
, NULL
, 0, 0, "Memory allocation failed\n");
506 * @ctxt: a Relax-NG parser context
507 * @node: the node raising the error
508 * @error: the error code
513 * Handle a Relax NG Parsing error
515 static void LIBXML_ATTR_FORMAT(4,0)
516 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
, int error
,
517 const char *msg
, const xmlChar
* str1
, const xmlChar
* str2
)
519 xmlStructuredErrorFunc schannel
= NULL
;
520 xmlGenericErrorFunc channel
= NULL
;
524 if (ctxt
->serror
!= NULL
)
525 schannel
= ctxt
->serror
;
527 channel
= ctxt
->error
;
528 data
= ctxt
->userData
;
531 __xmlRaiseError(schannel
, channel
, data
,
532 NULL
, node
, XML_FROM_RELAXNGP
,
533 error
, XML_ERR_ERROR
, NULL
, 0,
534 (const char *) str1
, (const char *) str2
, NULL
, 0, 0,
540 * @ctxt: a Relax-NG validation context
541 * @node: the node raising the error
542 * @error: the error code
547 * Handle a Relax NG Validation error
549 static void LIBXML_ATTR_FORMAT(4,0)
550 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt
, xmlNodePtr node
, int error
,
551 const char *msg
, const xmlChar
* str1
, const xmlChar
* str2
)
553 xmlStructuredErrorFunc schannel
= NULL
;
554 xmlGenericErrorFunc channel
= NULL
;
558 if (ctxt
->serror
!= NULL
)
559 schannel
= ctxt
->serror
;
561 channel
= ctxt
->error
;
562 data
= ctxt
->userData
;
565 __xmlRaiseError(schannel
, channel
, data
,
566 NULL
, node
, XML_FROM_RELAXNGV
,
567 error
, XML_ERR_ERROR
, NULL
, 0,
568 (const char *) str1
, (const char *) str2
, NULL
, 0, 0,
572 /************************************************************************
574 * Preliminary type checking interfaces *
576 ************************************************************************/
579 * xmlRelaxNGTypeHave:
580 * @data: data needed for the library
581 * @type: the type name
582 * @value: the value to check
584 * Function provided by a type library to check if a type is exported
586 * Returns 1 if yes, 0 if no and -1 in case of error.
588 typedef int (*xmlRelaxNGTypeHave
) (void *data
, const xmlChar
* type
);
591 * xmlRelaxNGTypeCheck:
592 * @data: data needed for the library
593 * @type: the type name
594 * @value: the value to check
595 * @result: place to store the result if needed
597 * Function provided by a type library to check if a value match a type
599 * Returns 1 if yes, 0 if no and -1 in case of error.
601 typedef int (*xmlRelaxNGTypeCheck
) (void *data
, const xmlChar
* type
,
602 const xmlChar
* value
, void **result
,
606 * xmlRelaxNGFacetCheck:
607 * @data: data needed for the library
608 * @type: the type name
609 * @facet: the facet name
610 * @val: the facet value
611 * @strval: the string value
612 * @value: the value to check
614 * Function provided by a type library to check a value facet
616 * Returns 1 if yes, 0 if no and -1 in case of error.
618 typedef int (*xmlRelaxNGFacetCheck
) (void *data
, const xmlChar
* type
,
619 const xmlChar
* facet
,
621 const xmlChar
* strval
, void *value
);
624 * xmlRelaxNGTypeFree:
625 * @data: data needed for the library
626 * @result: the value to free
628 * Function provided by a type library to free a returned result
630 typedef void (*xmlRelaxNGTypeFree
) (void *data
, void *result
);
633 * xmlRelaxNGTypeCompare:
634 * @data: data needed for the library
635 * @type: the type name
636 * @value1: the first value
637 * @value2: the second value
639 * Function provided by a type library to compare two values accordingly
642 * Returns 1 if yes, 0 if no and -1 in case of error.
644 typedef int (*xmlRelaxNGTypeCompare
) (void *data
, const xmlChar
* type
,
645 const xmlChar
* value1
,
648 const xmlChar
* value2
,
650 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary
;
651 typedef xmlRelaxNGTypeLibrary
*xmlRelaxNGTypeLibraryPtr
;
652 struct _xmlRelaxNGTypeLibrary
{
653 const xmlChar
*namespace; /* the datatypeLibrary value */
654 void *data
; /* data needed for the library */
655 xmlRelaxNGTypeHave have
; /* the export function */
656 xmlRelaxNGTypeCheck check
; /* the checking function */
657 xmlRelaxNGTypeCompare comp
; /* the compare function */
658 xmlRelaxNGFacetCheck facet
; /* the facet check function */
659 xmlRelaxNGTypeFree freef
; /* the freeing function */
662 /************************************************************************
664 * Allocation functions *
666 ************************************************************************/
667 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar
);
668 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define
);
669 static void xmlRelaxNGNormExtSpace(xmlChar
* value
);
670 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema
);
671 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
673 xmlRelaxNGValidStatePtr state1
,
674 xmlRelaxNGValidStatePtr state2
);
675 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt
,
676 xmlRelaxNGValidStatePtr state
);
679 * xmlRelaxNGFreeDocument:
680 * @docu: a document structure
682 * Deallocate a RelaxNG document structure.
685 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu
)
690 if (docu
->href
!= NULL
)
692 if (docu
->doc
!= NULL
)
693 xmlFreeDoc(docu
->doc
);
694 if (docu
->schema
!= NULL
)
695 xmlRelaxNGFreeInnerSchema(docu
->schema
);
700 * xmlRelaxNGFreeDocumentList:
701 * @docu: a list of document structure
703 * Deallocate a RelaxNG document structures.
706 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu
)
708 xmlRelaxNGDocumentPtr next
;
710 while (docu
!= NULL
) {
712 xmlRelaxNGFreeDocument(docu
);
718 * xmlRelaxNGFreeInclude:
719 * @incl: a include structure
721 * Deallocate a RelaxNG include structure.
724 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl
)
729 if (incl
->href
!= NULL
)
731 if (incl
->doc
!= NULL
)
732 xmlFreeDoc(incl
->doc
);
733 if (incl
->schema
!= NULL
)
734 xmlRelaxNGFree(incl
->schema
);
739 * xmlRelaxNGFreeIncludeList:
740 * @incl: a include structure list
742 * Deallocate a RelaxNG include structure.
745 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl
)
747 xmlRelaxNGIncludePtr next
;
749 while (incl
!= NULL
) {
751 xmlRelaxNGFreeInclude(incl
);
757 * xmlRelaxNGNewRelaxNG:
758 * @ctxt: a Relax-NG validation context (optional)
760 * Allocate a new RelaxNG structure.
762 * Returns the newly allocated structure or NULL in case or error
765 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt
)
769 ret
= (xmlRelaxNGPtr
) xmlMalloc(sizeof(xmlRelaxNG
));
771 xmlRngPErrMemory(ctxt
, NULL
);
774 memset(ret
, 0, sizeof(xmlRelaxNG
));
780 * xmlRelaxNGFreeInnerSchema:
781 * @schema: a schema structure
783 * Deallocate a RelaxNG schema structure.
786 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema
)
791 if (schema
->doc
!= NULL
)
792 xmlFreeDoc(schema
->doc
);
793 if (schema
->defTab
!= NULL
) {
796 for (i
= 0; i
< schema
->defNr
; i
++)
797 xmlRelaxNGFreeDefine(schema
->defTab
[i
]);
798 xmlFree(schema
->defTab
);
806 * @schema: a schema structure
808 * Deallocate a RelaxNG structure.
811 xmlRelaxNGFree(xmlRelaxNGPtr schema
)
816 if (schema
->topgrammar
!= NULL
)
817 xmlRelaxNGFreeGrammar(schema
->topgrammar
);
818 if (schema
->doc
!= NULL
)
819 xmlFreeDoc(schema
->doc
);
820 if (schema
->documents
!= NULL
)
821 xmlRelaxNGFreeDocumentList(schema
->documents
);
822 if (schema
->includes
!= NULL
)
823 xmlRelaxNGFreeIncludeList(schema
->includes
);
824 if (schema
->defTab
!= NULL
) {
827 for (i
= 0; i
< schema
->defNr
; i
++)
828 xmlRelaxNGFreeDefine(schema
->defTab
[i
]);
829 xmlFree(schema
->defTab
);
836 * xmlRelaxNGNewGrammar:
837 * @ctxt: a Relax-NG validation context (optional)
839 * Allocate a new RelaxNG grammar.
841 * Returns the newly allocated structure or NULL in case or error
843 static xmlRelaxNGGrammarPtr
844 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt
)
846 xmlRelaxNGGrammarPtr ret
;
848 ret
= (xmlRelaxNGGrammarPtr
) xmlMalloc(sizeof(xmlRelaxNGGrammar
));
850 xmlRngPErrMemory(ctxt
, NULL
);
853 memset(ret
, 0, sizeof(xmlRelaxNGGrammar
));
859 * xmlRelaxNGFreeGrammar:
860 * @grammar: a grammar structure
862 * Deallocate a RelaxNG grammar structure.
865 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar
)
870 if (grammar
->children
!= NULL
) {
871 xmlRelaxNGFreeGrammar(grammar
->children
);
873 if (grammar
->next
!= NULL
) {
874 xmlRelaxNGFreeGrammar(grammar
->next
);
876 if (grammar
->refs
!= NULL
) {
877 xmlHashFree(grammar
->refs
, NULL
);
879 if (grammar
->defs
!= NULL
) {
880 xmlHashFree(grammar
->defs
, NULL
);
887 * xmlRelaxNGNewDefine:
888 * @ctxt: a Relax-NG validation context
889 * @node: the node in the input document.
891 * Allocate a new RelaxNG define.
893 * Returns the newly allocated structure or NULL in case or error
895 static xmlRelaxNGDefinePtr
896 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
898 xmlRelaxNGDefinePtr ret
;
900 if (ctxt
->defMax
== 0) {
903 ctxt
->defTab
= (xmlRelaxNGDefinePtr
*)
904 xmlMalloc(ctxt
->defMax
* sizeof(xmlRelaxNGDefinePtr
));
905 if (ctxt
->defTab
== NULL
) {
906 xmlRngPErrMemory(ctxt
, "allocating define\n");
909 } else if (ctxt
->defMax
<= ctxt
->defNr
) {
910 xmlRelaxNGDefinePtr
*tmp
;
913 tmp
= (xmlRelaxNGDefinePtr
*) xmlRealloc(ctxt
->defTab
,
916 (xmlRelaxNGDefinePtr
));
918 xmlRngPErrMemory(ctxt
, "allocating define\n");
923 ret
= (xmlRelaxNGDefinePtr
) xmlMalloc(sizeof(xmlRelaxNGDefine
));
925 xmlRngPErrMemory(ctxt
, "allocating define\n");
928 memset(ret
, 0, sizeof(xmlRelaxNGDefine
));
929 ctxt
->defTab
[ctxt
->defNr
++] = ret
;
936 * xmlRelaxNGFreePartition:
937 * @partitions: a partition set structure
939 * Deallocate RelaxNG partition set structures.
942 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions
)
944 xmlRelaxNGInterleaveGroupPtr group
;
947 if (partitions
!= NULL
) {
948 if (partitions
->groups
!= NULL
) {
949 for (j
= 0; j
< partitions
->nbgroups
; j
++) {
950 group
= partitions
->groups
[j
];
952 if (group
->defs
!= NULL
)
953 xmlFree(group
->defs
);
954 if (group
->attrs
!= NULL
)
955 xmlFree(group
->attrs
);
959 xmlFree(partitions
->groups
);
961 if (partitions
->triage
!= NULL
) {
962 xmlHashFree(partitions
->triage
, NULL
);
969 * xmlRelaxNGFreeDefine:
970 * @define: a define structure
972 * Deallocate a RelaxNG define structure.
975 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define
)
980 if ((define
->type
== XML_RELAXNG_VALUE
) && (define
->attrs
!= NULL
)) {
981 xmlRelaxNGTypeLibraryPtr lib
;
983 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
984 if ((lib
!= NULL
) && (lib
->freef
!= NULL
))
985 lib
->freef(lib
->data
, (void *) define
->attrs
);
987 if ((define
->data
!= NULL
) && (define
->type
== XML_RELAXNG_INTERLEAVE
))
988 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr
) define
->data
);
989 if ((define
->data
!= NULL
) && (define
->type
== XML_RELAXNG_CHOICE
))
990 xmlHashFree((xmlHashTablePtr
) define
->data
, NULL
);
991 if (define
->name
!= NULL
)
992 xmlFree(define
->name
);
993 if (define
->ns
!= NULL
)
995 if (define
->value
!= NULL
)
996 xmlFree(define
->value
);
997 if (define
->contModel
!= NULL
)
998 xmlRegFreeRegexp(define
->contModel
);
1003 * xmlRelaxNGNewStates:
1004 * @ctxt: a Relax-NG validation context
1005 * @size: the default size for the container
1007 * Allocate a new RelaxNG validation state container
1009 * Returns the newly allocated structure or NULL in case or error
1011 static xmlRelaxNGStatesPtr
1012 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt
, int size
)
1014 xmlRelaxNGStatesPtr ret
;
1016 if ((ctxt
!= NULL
) &&
1017 (ctxt
->freeStates
!= NULL
) && (ctxt
->freeStatesNr
> 0)) {
1018 ctxt
->freeStatesNr
--;
1019 ret
= ctxt
->freeStates
[ctxt
->freeStatesNr
];
1026 ret
= (xmlRelaxNGStatesPtr
) xmlMalloc(sizeof(xmlRelaxNGStates
) +
1029 sizeof(xmlRelaxNGValidStatePtr
));
1031 xmlRngVErrMemory(ctxt
, "allocating states\n");
1035 ret
->maxState
= size
;
1036 ret
->tabState
= (xmlRelaxNGValidStatePtr
*) xmlMalloc((size
) *
1038 (xmlRelaxNGValidStatePtr
));
1039 if (ret
->tabState
== NULL
) {
1040 xmlRngVErrMemory(ctxt
, "allocating states\n");
1048 * xmlRelaxNGAddStateUniq:
1049 * @ctxt: a Relax-NG validation context
1050 * @states: the states container
1051 * @state: the validation state
1053 * Add a RelaxNG validation state to the container without checking
1056 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1059 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt
,
1060 xmlRelaxNGStatesPtr states
,
1061 xmlRelaxNGValidStatePtr state
)
1063 if (state
== NULL
) {
1066 if (states
->nbState
>= states
->maxState
) {
1067 xmlRelaxNGValidStatePtr
*tmp
;
1070 size
= states
->maxState
* 2;
1071 tmp
= (xmlRelaxNGValidStatePtr
*) xmlRealloc(states
->tabState
,
1074 (xmlRelaxNGValidStatePtr
));
1076 xmlRngVErrMemory(ctxt
, "adding states\n");
1079 states
->tabState
= tmp
;
1080 states
->maxState
= size
;
1082 states
->tabState
[states
->nbState
++] = state
;
1087 * xmlRelaxNGAddState:
1088 * @ctxt: a Relax-NG validation context
1089 * @states: the states container
1090 * @state: the validation state
1092 * Add a RelaxNG validation state to the container
1094 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1097 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt
,
1098 xmlRelaxNGStatesPtr states
,
1099 xmlRelaxNGValidStatePtr state
)
1103 if (state
== NULL
|| states
== NULL
) {
1106 if (states
->nbState
>= states
->maxState
) {
1107 xmlRelaxNGValidStatePtr
*tmp
;
1110 size
= states
->maxState
* 2;
1111 tmp
= (xmlRelaxNGValidStatePtr
*) xmlRealloc(states
->tabState
,
1114 (xmlRelaxNGValidStatePtr
));
1116 xmlRngVErrMemory(ctxt
, "adding states\n");
1119 states
->tabState
= tmp
;
1120 states
->maxState
= size
;
1122 for (i
= 0; i
< states
->nbState
; i
++) {
1123 if (xmlRelaxNGEqualValidState(ctxt
, state
, states
->tabState
[i
])) {
1124 xmlRelaxNGFreeValidState(ctxt
, state
);
1128 states
->tabState
[states
->nbState
++] = state
;
1133 * xmlRelaxNGFreeStates:
1134 * @ctxt: a Relax-NG validation context
1135 * @states: the container
1137 * Free a RelaxNG validation state container
1140 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt
,
1141 xmlRelaxNGStatesPtr states
)
1145 if ((ctxt
!= NULL
) && (ctxt
->freeStates
== NULL
)) {
1146 ctxt
->freeStatesMax
= 40;
1147 ctxt
->freeStatesNr
= 0;
1148 ctxt
->freeStates
= (xmlRelaxNGStatesPtr
*)
1149 xmlMalloc(ctxt
->freeStatesMax
* sizeof(xmlRelaxNGStatesPtr
));
1150 if (ctxt
->freeStates
== NULL
) {
1151 xmlRngVErrMemory(ctxt
, "storing states\n");
1153 } else if ((ctxt
!= NULL
)
1154 && (ctxt
->freeStatesNr
>= ctxt
->freeStatesMax
)) {
1155 xmlRelaxNGStatesPtr
*tmp
;
1157 tmp
= (xmlRelaxNGStatesPtr
*) xmlRealloc(ctxt
->freeStates
,
1158 2 * ctxt
->freeStatesMax
*
1160 (xmlRelaxNGStatesPtr
));
1162 xmlRngVErrMemory(ctxt
, "storing states\n");
1163 xmlFree(states
->tabState
);
1167 ctxt
->freeStates
= tmp
;
1168 ctxt
->freeStatesMax
*= 2;
1170 if ((ctxt
== NULL
) || (ctxt
->freeStates
== NULL
)) {
1171 xmlFree(states
->tabState
);
1174 ctxt
->freeStates
[ctxt
->freeStatesNr
++] = states
;
1179 * xmlRelaxNGNewValidState:
1180 * @ctxt: a Relax-NG validation context
1181 * @node: the current node or NULL for the document
1183 * Allocate a new RelaxNG validation state
1185 * Returns the newly allocated structure or NULL in case or error
1187 static xmlRelaxNGValidStatePtr
1188 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt
, xmlNodePtr node
)
1190 xmlRelaxNGValidStatePtr ret
;
1192 xmlAttrPtr attrs
[MAX_ATTR
];
1194 xmlNodePtr root
= NULL
;
1197 root
= xmlDocGetRootElement(ctxt
->doc
);
1201 attr
= node
->properties
;
1202 while (attr
!= NULL
) {
1203 if (nbAttrs
< MAX_ATTR
)
1204 attrs
[nbAttrs
++] = attr
;
1210 if ((ctxt
->freeState
!= NULL
) && (ctxt
->freeState
->nbState
> 0)) {
1211 ctxt
->freeState
->nbState
--;
1212 ret
= ctxt
->freeState
->tabState
[ctxt
->freeState
->nbState
];
1215 (xmlRelaxNGValidStatePtr
)
1216 xmlMalloc(sizeof(xmlRelaxNGValidState
));
1218 xmlRngVErrMemory(ctxt
, "allocating states\n");
1221 memset(ret
, 0, sizeof(xmlRelaxNGValidState
));
1224 ret
->endvalue
= NULL
;
1226 ret
->node
= (xmlNodePtr
) ctxt
->doc
;
1230 ret
->seq
= node
->children
;
1234 if (ret
->attrs
== NULL
) {
1238 ret
->maxAttrs
= nbAttrs
;
1239 ret
->attrs
= (xmlAttrPtr
*) xmlMalloc(ret
->maxAttrs
*
1240 sizeof(xmlAttrPtr
));
1241 if (ret
->attrs
== NULL
) {
1242 xmlRngVErrMemory(ctxt
, "allocating states\n");
1245 } else if (ret
->maxAttrs
< nbAttrs
) {
1248 tmp
= (xmlAttrPtr
*) xmlRealloc(ret
->attrs
, nbAttrs
*
1249 sizeof(xmlAttrPtr
));
1251 xmlRngVErrMemory(ctxt
, "allocating states\n");
1255 ret
->maxAttrs
= nbAttrs
;
1257 ret
->nbAttrs
= nbAttrs
;
1258 if (nbAttrs
< MAX_ATTR
) {
1259 memcpy(ret
->attrs
, attrs
, sizeof(xmlAttrPtr
) * nbAttrs
);
1261 attr
= node
->properties
;
1263 while (attr
!= NULL
) {
1264 ret
->attrs
[nbAttrs
++] = attr
;
1269 ret
->nbAttrLeft
= ret
->nbAttrs
;
1274 * xmlRelaxNGCopyValidState:
1275 * @ctxt: a Relax-NG validation context
1276 * @state: a validation state
1278 * Copy the validation state
1280 * Returns the newly allocated structure or NULL in case or error
1282 static xmlRelaxNGValidStatePtr
1283 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt
,
1284 xmlRelaxNGValidStatePtr state
)
1286 xmlRelaxNGValidStatePtr ret
;
1287 unsigned int maxAttrs
;
1292 if ((ctxt
->freeState
!= NULL
) && (ctxt
->freeState
->nbState
> 0)) {
1293 ctxt
->freeState
->nbState
--;
1294 ret
= ctxt
->freeState
->tabState
[ctxt
->freeState
->nbState
];
1297 (xmlRelaxNGValidStatePtr
)
1298 xmlMalloc(sizeof(xmlRelaxNGValidState
));
1300 xmlRngVErrMemory(ctxt
, "allocating states\n");
1303 memset(ret
, 0, sizeof(xmlRelaxNGValidState
));
1306 maxAttrs
= ret
->maxAttrs
;
1307 memcpy(ret
, state
, sizeof(xmlRelaxNGValidState
));
1309 ret
->maxAttrs
= maxAttrs
;
1310 if (state
->nbAttrs
> 0) {
1311 if (ret
->attrs
== NULL
) {
1312 ret
->maxAttrs
= state
->maxAttrs
;
1313 ret
->attrs
= (xmlAttrPtr
*) xmlMalloc(ret
->maxAttrs
*
1314 sizeof(xmlAttrPtr
));
1315 if (ret
->attrs
== NULL
) {
1316 xmlRngVErrMemory(ctxt
, "allocating states\n");
1320 } else if (ret
->maxAttrs
< state
->nbAttrs
) {
1323 tmp
= (xmlAttrPtr
*) xmlRealloc(ret
->attrs
, state
->maxAttrs
*
1324 sizeof(xmlAttrPtr
));
1326 xmlRngVErrMemory(ctxt
, "allocating states\n");
1330 ret
->maxAttrs
= state
->maxAttrs
;
1333 memcpy(ret
->attrs
, state
->attrs
,
1334 state
->nbAttrs
* sizeof(xmlAttrPtr
));
1340 * xmlRelaxNGEqualValidState:
1341 * @ctxt: a Relax-NG validation context
1342 * @state1: a validation state
1343 * @state2: a validation state
1345 * Compare the validation states for equality
1347 * Returns 1 if equal, 0 otherwise
1350 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
1351 xmlRelaxNGValidStatePtr state1
,
1352 xmlRelaxNGValidStatePtr state2
)
1356 if ((state1
== NULL
) || (state2
== NULL
))
1358 if (state1
== state2
)
1360 if (state1
->node
!= state2
->node
)
1362 if (state1
->seq
!= state2
->seq
)
1364 if (state1
->nbAttrLeft
!= state2
->nbAttrLeft
)
1366 if (state1
->nbAttrs
!= state2
->nbAttrs
)
1368 if (state1
->endvalue
!= state2
->endvalue
)
1370 if ((state1
->value
!= state2
->value
) &&
1371 (!xmlStrEqual(state1
->value
, state2
->value
)))
1373 for (i
= 0; i
< state1
->nbAttrs
; i
++) {
1374 if (state1
->attrs
[i
] != state2
->attrs
[i
])
1381 * xmlRelaxNGFreeValidState:
1382 * @state: a validation state structure
1384 * Deallocate a RelaxNG validation state structure.
1387 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt
,
1388 xmlRelaxNGValidStatePtr state
)
1393 if ((ctxt
!= NULL
) && (ctxt
->freeState
== NULL
)) {
1394 ctxt
->freeState
= xmlRelaxNGNewStates(ctxt
, 40);
1396 if ((ctxt
== NULL
) || (ctxt
->freeState
== NULL
)) {
1397 if (state
->attrs
!= NULL
)
1398 xmlFree(state
->attrs
);
1401 xmlRelaxNGAddStatesUniq(ctxt
, ctxt
->freeState
, state
);
1405 /************************************************************************
1407 * Semi internal functions *
1409 ************************************************************************/
1412 * xmlRelaxParserSetFlag:
1413 * @ctxt: a RelaxNG parser context
1414 * @flags: a set of flags values
1416 * Semi private function used to pass information to a parser context
1417 * which are a combination of xmlRelaxNGParserFlag .
1419 * Returns 0 if success and -1 in case of error
1422 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt
, int flags
)
1424 if (ctxt
== NULL
) return(-1);
1425 if (flags
& XML_RELAXNGP_FREE_DOC
) {
1426 ctxt
->crng
|= XML_RELAXNGP_FREE_DOC
;
1427 flags
-= XML_RELAXNGP_FREE_DOC
;
1429 if (flags
& XML_RELAXNGP_CRNG
) {
1430 ctxt
->crng
|= XML_RELAXNGP_CRNG
;
1431 flags
-= XML_RELAXNGP_CRNG
;
1433 if (flags
!= 0) return(-1);
1437 /************************************************************************
1439 * Document functions *
1441 ************************************************************************/
1442 static xmlDocPtr
xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
,
1446 * xmlRelaxNGIncludePush:
1447 * @ctxt: the parser context
1448 * @value: the element doc
1450 * Pushes a new include on top of the include stack
1452 * Returns 0 in case of error, the index in the stack otherwise
1455 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt
,
1456 xmlRelaxNGIncludePtr value
)
1458 if (ctxt
->incTab
== NULL
) {
1462 (xmlRelaxNGIncludePtr
*) xmlMalloc(ctxt
->incMax
*
1463 sizeof(ctxt
->incTab
[0]));
1464 if (ctxt
->incTab
== NULL
) {
1465 xmlRngPErrMemory(ctxt
, "allocating include\n");
1469 if (ctxt
->incNr
>= ctxt
->incMax
) {
1472 (xmlRelaxNGIncludePtr
*) xmlRealloc(ctxt
->incTab
,
1474 sizeof(ctxt
->incTab
[0]));
1475 if (ctxt
->incTab
== NULL
) {
1476 xmlRngPErrMemory(ctxt
, "allocating include\n");
1480 ctxt
->incTab
[ctxt
->incNr
] = value
;
1482 return (ctxt
->incNr
++);
1486 * xmlRelaxNGIncludePop:
1487 * @ctxt: the parser context
1489 * Pops the top include from the include stack
1491 * Returns the include just removed
1493 static xmlRelaxNGIncludePtr
1494 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt
)
1496 xmlRelaxNGIncludePtr ret
;
1498 if (ctxt
->incNr
<= 0)
1501 if (ctxt
->incNr
> 0)
1502 ctxt
->inc
= ctxt
->incTab
[ctxt
->incNr
- 1];
1505 ret
= ctxt
->incTab
[ctxt
->incNr
];
1506 ctxt
->incTab
[ctxt
->incNr
] = NULL
;
1511 * xmlRelaxNGRemoveRedefine:
1512 * @ctxt: the parser context
1513 * @URL: the normalized URL
1514 * @target: the included target
1515 * @name: the define name to eliminate
1517 * Applies the elimination algorithm of 4.7
1519 * Returns 0 in case of error, 1 in case of success.
1522 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt
,
1523 const xmlChar
* URL ATTRIBUTE_UNUSED
,
1524 xmlNodePtr target
, const xmlChar
* name
)
1527 xmlNodePtr tmp
, tmp2
;
1530 #ifdef DEBUG_INCLUDE
1532 xmlGenericError(xmlGenericErrorContext
,
1533 "Elimination of <include> start from %s\n", URL
);
1535 xmlGenericError(xmlGenericErrorContext
,
1536 "Elimination of <include> define %s from %s\n",
1540 while (tmp
!= NULL
) {
1542 if ((name
== NULL
) && (IS_RELAXNG(tmp
, "start"))) {
1546 } else if ((name
!= NULL
) && (IS_RELAXNG(tmp
, "define"))) {
1547 name2
= xmlGetProp(tmp
, BAD_CAST
"name");
1548 xmlRelaxNGNormExtSpace(name2
);
1549 if (name2
!= NULL
) {
1550 if (xmlStrEqual(name
, name2
)) {
1557 } else if (IS_RELAXNG(tmp
, "include")) {
1558 xmlChar
*href
= NULL
;
1559 xmlRelaxNGDocumentPtr inc
= tmp
->psvi
;
1561 if ((inc
!= NULL
) && (inc
->doc
!= NULL
) &&
1562 (inc
->doc
->children
!= NULL
)) {
1565 (inc
->doc
->children
->name
, BAD_CAST
"grammar")) {
1566 #ifdef DEBUG_INCLUDE
1567 href
= xmlGetProp(tmp
, BAD_CAST
"href");
1569 if (xmlRelaxNGRemoveRedefine(ctxt
, href
,
1570 xmlDocGetRootElement(inc
->doc
)->children
,
1574 #ifdef DEBUG_INCLUDE
1580 if (xmlRelaxNGRemoveRedefine(ctxt
, URL
, tmp
->children
, name
) == 1) {
1590 * xmlRelaxNGLoadInclude:
1591 * @ctxt: the parser context
1592 * @URL: the normalized URL
1593 * @node: the include node.
1594 * @ns: the namespace passed from the context.
1596 * First lookup if the document is already loaded into the parser context,
1597 * check against recursion. If not found the resource is loaded and
1598 * the content is preprocessed before being returned back to the caller.
1600 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1602 static xmlRelaxNGIncludePtr
1603 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt
, const xmlChar
* URL
,
1604 xmlNodePtr node
, const xmlChar
* ns
)
1606 xmlRelaxNGIncludePtr ret
= NULL
;
1609 xmlNodePtr root
, cur
;
1611 #ifdef DEBUG_INCLUDE
1612 xmlGenericError(xmlGenericErrorContext
,
1613 "xmlRelaxNGLoadInclude(%s)\n", URL
);
1617 * check against recursion in the stack
1619 for (i
= 0; i
< ctxt
->incNr
; i
++) {
1620 if (xmlStrEqual(ctxt
->incTab
[i
]->href
, URL
)) {
1621 xmlRngPErr(ctxt
, NULL
, XML_RNGP_INCLUDE_RECURSE
,
1622 "Detected an Include recursion for %s\n", URL
,
1631 doc
= xmlReadFile((const char *) URL
,NULL
,0);
1633 xmlRngPErr(ctxt
, node
, XML_RNGP_PARSE_ERROR
,
1634 "xmlRelaxNG: could not load %s\n", URL
, NULL
);
1637 #ifdef DEBUG_INCLUDE
1638 xmlGenericError(xmlGenericErrorContext
, "Parsed %s Okay\n", URL
);
1642 * Allocate the document structures and register it first.
1644 ret
= (xmlRelaxNGIncludePtr
) xmlMalloc(sizeof(xmlRelaxNGInclude
));
1646 xmlRngPErrMemory(ctxt
, "allocating include\n");
1650 memset(ret
, 0, sizeof(xmlRelaxNGInclude
));
1652 ret
->href
= xmlStrdup(URL
);
1653 ret
->next
= ctxt
->includes
;
1654 ctxt
->includes
= ret
;
1657 * transmit the ns if needed
1660 root
= xmlDocGetRootElement(doc
);
1662 if (xmlHasProp(root
, BAD_CAST
"ns") == NULL
) {
1663 xmlSetProp(root
, BAD_CAST
"ns", ns
);
1669 * push it on the stack
1671 xmlRelaxNGIncludePush(ctxt
, ret
);
1674 * Some preprocessing of the document content, this include recursing
1675 * in the include stack.
1677 #ifdef DEBUG_INCLUDE
1678 xmlGenericError(xmlGenericErrorContext
, "cleanup of %s\n", URL
);
1681 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
1688 * Pop up the include from the stack
1690 xmlRelaxNGIncludePop(ctxt
);
1692 #ifdef DEBUG_INCLUDE
1693 xmlGenericError(xmlGenericErrorContext
, "Checking of %s\n", URL
);
1696 * Check that the top element is a grammar
1698 root
= xmlDocGetRootElement(doc
);
1700 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY
,
1701 "xmlRelaxNG: included document is empty %s\n", URL
,
1705 if (!IS_RELAXNG(root
, "grammar")) {
1706 xmlRngPErr(ctxt
, node
, XML_RNGP_GRAMMAR_MISSING
,
1707 "xmlRelaxNG: included document %s root is not a grammar\n",
1713 * Elimination of redefined rules in the include.
1715 cur
= node
->children
;
1716 while (cur
!= NULL
) {
1717 if (IS_RELAXNG(cur
, "start")) {
1721 xmlRelaxNGRemoveRedefine(ctxt
, URL
, root
->children
, NULL
);
1723 xmlRngPErr(ctxt
, node
, XML_RNGP_START_MISSING
,
1724 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1727 } else if (IS_RELAXNG(cur
, "define")) {
1730 name
= xmlGetProp(cur
, BAD_CAST
"name");
1732 xmlRngPErr(ctxt
, node
, XML_RNGP_NAME_MISSING
,
1733 "xmlRelaxNG: include %s has define without name\n",
1738 xmlRelaxNGNormExtSpace(name
);
1739 found
= xmlRelaxNGRemoveRedefine(ctxt
, URL
,
1740 root
->children
, name
);
1742 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_MISSING
,
1743 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1749 if (IS_RELAXNG(cur
, "div") && cur
->children
!= NULL
) {
1750 cur
= cur
->children
;
1752 if (cur
->next
!= NULL
) {
1755 while (cur
->parent
!= node
&& cur
->parent
->next
== NULL
) {
1758 cur
= cur
->parent
!= node
? cur
->parent
->next
: NULL
;
1768 * xmlRelaxNGValidErrorPush:
1769 * @ctxt: the validation context
1770 * @err: the error code
1771 * @arg1: the first string argument
1772 * @arg2: the second string argument
1773 * @dup: arg need to be duplicated
1775 * Pushes a new error on top of the error stack
1777 * Returns 0 in case of error, the index in the stack otherwise
1780 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt
,
1781 xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
1782 const xmlChar
* arg2
, int dup
)
1784 xmlRelaxNGValidErrorPtr cur
;
1787 xmlGenericError(xmlGenericErrorContext
,
1788 "Pushing error %d at %d on stack\n", err
, ctxt
->errNr
);
1790 if (ctxt
->errTab
== NULL
) {
1794 (xmlRelaxNGValidErrorPtr
) xmlMalloc(ctxt
->errMax
*
1796 (xmlRelaxNGValidError
));
1797 if (ctxt
->errTab
== NULL
) {
1798 xmlRngVErrMemory(ctxt
, "pushing error\n");
1803 if (ctxt
->errNr
>= ctxt
->errMax
) {
1806 (xmlRelaxNGValidErrorPtr
) xmlRealloc(ctxt
->errTab
,
1809 (xmlRelaxNGValidError
));
1810 if (ctxt
->errTab
== NULL
) {
1811 xmlRngVErrMemory(ctxt
, "pushing error\n");
1814 ctxt
->err
= &ctxt
->errTab
[ctxt
->errNr
- 1];
1816 if ((ctxt
->err
!= NULL
) && (ctxt
->state
!= NULL
) &&
1817 (ctxt
->err
->node
== ctxt
->state
->node
) && (ctxt
->err
->err
== err
))
1818 return (ctxt
->errNr
);
1819 cur
= &ctxt
->errTab
[ctxt
->errNr
];
1822 cur
->arg1
= xmlStrdup(arg1
);
1823 cur
->arg2
= xmlStrdup(arg2
);
1824 cur
->flags
= ERROR_IS_DUP
;
1830 if (ctxt
->state
!= NULL
) {
1831 cur
->node
= ctxt
->state
->node
;
1832 cur
->seq
= ctxt
->state
->seq
;
1838 return (ctxt
->errNr
++);
1842 * xmlRelaxNGValidErrorPop:
1843 * @ctxt: the validation context
1845 * Pops the top error from the error stack
1848 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt
)
1850 xmlRelaxNGValidErrorPtr cur
;
1852 if (ctxt
->errNr
<= 0) {
1857 if (ctxt
->errNr
> 0)
1858 ctxt
->err
= &ctxt
->errTab
[ctxt
->errNr
- 1];
1861 cur
= &ctxt
->errTab
[ctxt
->errNr
];
1862 if (cur
->flags
& ERROR_IS_DUP
) {
1863 if (cur
->arg1
!= NULL
)
1864 xmlFree((xmlChar
*) cur
->arg1
);
1866 if (cur
->arg2
!= NULL
)
1867 xmlFree((xmlChar
*) cur
->arg2
);
1874 * xmlRelaxNGDocumentPush:
1875 * @ctxt: the parser context
1876 * @value: the element doc
1878 * Pushes a new doc on top of the doc stack
1880 * Returns 0 in case of error, the index in the stack otherwise
1883 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt
,
1884 xmlRelaxNGDocumentPtr value
)
1886 if (ctxt
->docTab
== NULL
) {
1890 (xmlRelaxNGDocumentPtr
*) xmlMalloc(ctxt
->docMax
*
1891 sizeof(ctxt
->docTab
[0]));
1892 if (ctxt
->docTab
== NULL
) {
1893 xmlRngPErrMemory(ctxt
, "adding document\n");
1897 if (ctxt
->docNr
>= ctxt
->docMax
) {
1900 (xmlRelaxNGDocumentPtr
*) xmlRealloc(ctxt
->docTab
,
1902 sizeof(ctxt
->docTab
[0]));
1903 if (ctxt
->docTab
== NULL
) {
1904 xmlRngPErrMemory(ctxt
, "adding document\n");
1908 ctxt
->docTab
[ctxt
->docNr
] = value
;
1910 return (ctxt
->docNr
++);
1914 * xmlRelaxNGDocumentPop:
1915 * @ctxt: the parser context
1917 * Pops the top doc from the doc stack
1919 * Returns the doc just removed
1921 static xmlRelaxNGDocumentPtr
1922 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt
)
1924 xmlRelaxNGDocumentPtr ret
;
1926 if (ctxt
->docNr
<= 0)
1929 if (ctxt
->docNr
> 0)
1930 ctxt
->doc
= ctxt
->docTab
[ctxt
->docNr
- 1];
1933 ret
= ctxt
->docTab
[ctxt
->docNr
];
1934 ctxt
->docTab
[ctxt
->docNr
] = NULL
;
1939 * xmlRelaxNGLoadExternalRef:
1940 * @ctxt: the parser context
1941 * @URL: the normalized URL
1942 * @ns: the inherited ns if any
1944 * First lookup if the document is already loaded into the parser context,
1945 * check against recursion. If not found the resource is loaded and
1946 * the content is preprocessed before being returned back to the caller.
1948 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1950 static xmlRelaxNGDocumentPtr
1951 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt
,
1952 const xmlChar
* URL
, const xmlChar
* ns
)
1954 xmlRelaxNGDocumentPtr ret
= NULL
;
1960 * check against recursion in the stack
1962 for (i
= 0; i
< ctxt
->docNr
; i
++) {
1963 if (xmlStrEqual(ctxt
->docTab
[i
]->href
, URL
)) {
1964 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EXTERNALREF_RECURSE
,
1965 "Detected an externalRef recursion for %s\n", URL
,
1974 doc
= xmlReadFile((const char *) URL
,NULL
,0);
1976 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
1977 "xmlRelaxNG: could not load %s\n", URL
, NULL
);
1982 * Allocate the document structures and register it first.
1984 ret
= (xmlRelaxNGDocumentPtr
) xmlMalloc(sizeof(xmlRelaxNGDocument
));
1986 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_ERR_NO_MEMORY
,
1987 "xmlRelaxNG: allocate memory for doc %s\n", URL
, NULL
);
1991 memset(ret
, 0, sizeof(xmlRelaxNGDocument
));
1993 ret
->href
= xmlStrdup(URL
);
1994 ret
->next
= ctxt
->documents
;
1995 ret
->externalRef
= 1;
1996 ctxt
->documents
= ret
;
1999 * transmit the ns if needed
2002 root
= xmlDocGetRootElement(doc
);
2004 if (xmlHasProp(root
, BAD_CAST
"ns") == NULL
) {
2005 xmlSetProp(root
, BAD_CAST
"ns", ns
);
2011 * push it on the stack and register it in the hash table
2013 xmlRelaxNGDocumentPush(ctxt
, ret
);
2016 * Some preprocessing of the document content
2018 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
2024 xmlRelaxNGDocumentPop(ctxt
);
2029 /************************************************************************
2033 ************************************************************************/
2035 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2036 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2037 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2038 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2039 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
2042 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def
)
2046 switch (def
->type
) {
2047 case XML_RELAXNG_EMPTY
:
2049 case XML_RELAXNG_NOT_ALLOWED
:
2050 return ("notAllowed");
2051 case XML_RELAXNG_EXCEPT
:
2053 case XML_RELAXNG_TEXT
:
2055 case XML_RELAXNG_ELEMENT
:
2057 case XML_RELAXNG_DATATYPE
:
2058 return ("datatype");
2059 case XML_RELAXNG_VALUE
:
2061 case XML_RELAXNG_LIST
:
2063 case XML_RELAXNG_ATTRIBUTE
:
2064 return ("attribute");
2065 case XML_RELAXNG_DEF
:
2067 case XML_RELAXNG_REF
:
2069 case XML_RELAXNG_EXTERNALREF
:
2070 return ("externalRef");
2071 case XML_RELAXNG_PARENTREF
:
2072 return ("parentRef");
2073 case XML_RELAXNG_OPTIONAL
:
2074 return ("optional");
2075 case XML_RELAXNG_ZEROORMORE
:
2076 return ("zeroOrMore");
2077 case XML_RELAXNG_ONEORMORE
:
2078 return ("oneOrMore");
2079 case XML_RELAXNG_CHOICE
:
2081 case XML_RELAXNG_GROUP
:
2083 case XML_RELAXNG_INTERLEAVE
:
2084 return ("interleave");
2085 case XML_RELAXNG_START
:
2087 case XML_RELAXNG_NOOP
:
2089 case XML_RELAXNG_PARAM
:
2096 * xmlRelaxNGGetErrorString:
2097 * @err: the error code
2098 * @arg1: the first string argument
2099 * @arg2: the second string argument
2101 * computes a formatted error string for the given error code and args
2103 * Returns the error string, it must be deallocated by the caller
2106 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
2107 const xmlChar
* arg2
)
2119 case XML_RELAXNG_OK
:
2121 case XML_RELAXNG_ERR_MEMORY
:
2122 return (xmlCharStrdup("out of memory\n"));
2123 case XML_RELAXNG_ERR_TYPE
:
2124 snprintf(msg
, 1000, "failed to validate type %s\n", arg1
);
2126 case XML_RELAXNG_ERR_TYPEVAL
:
2127 snprintf(msg
, 1000, "Type %s doesn't allow value '%s'\n", arg1
,
2130 case XML_RELAXNG_ERR_DUPID
:
2131 snprintf(msg
, 1000, "ID %s redefined\n", arg1
);
2133 case XML_RELAXNG_ERR_TYPECMP
:
2134 snprintf(msg
, 1000, "failed to compare type %s\n", arg1
);
2136 case XML_RELAXNG_ERR_NOSTATE
:
2137 return (xmlCharStrdup("Internal error: no state\n"));
2138 case XML_RELAXNG_ERR_NODEFINE
:
2139 return (xmlCharStrdup("Internal error: no define\n"));
2140 case XML_RELAXNG_ERR_INTERNAL
:
2141 snprintf(msg
, 1000, "Internal error: %s\n", arg1
);
2143 case XML_RELAXNG_ERR_LISTEXTRA
:
2144 snprintf(msg
, 1000, "Extra data in list: %s\n", arg1
);
2146 case XML_RELAXNG_ERR_INTERNODATA
:
2147 return (xmlCharStrdup
2148 ("Internal: interleave block has no data\n"));
2149 case XML_RELAXNG_ERR_INTERSEQ
:
2150 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2151 case XML_RELAXNG_ERR_INTEREXTRA
:
2152 snprintf(msg
, 1000, "Extra element %s in interleave\n", arg1
);
2154 case XML_RELAXNG_ERR_ELEMNAME
:
2155 snprintf(msg
, 1000, "Expecting element %s, got %s\n", arg1
,
2158 case XML_RELAXNG_ERR_ELEMNONS
:
2159 snprintf(msg
, 1000, "Expecting a namespace for element %s\n",
2162 case XML_RELAXNG_ERR_ELEMWRONGNS
:
2164 "Element %s has wrong namespace: expecting %s\n", arg1
,
2167 case XML_RELAXNG_ERR_ELEMWRONG
:
2168 snprintf(msg
, 1000, "Did not expect element %s there\n", arg1
);
2170 case XML_RELAXNG_ERR_TEXTWRONG
:
2172 "Did not expect text in element %s content\n", arg1
);
2174 case XML_RELAXNG_ERR_ELEMEXTRANS
:
2175 snprintf(msg
, 1000, "Expecting no namespace for element %s\n",
2178 case XML_RELAXNG_ERR_ELEMNOTEMPTY
:
2179 snprintf(msg
, 1000, "Expecting element %s to be empty\n", arg1
);
2181 case XML_RELAXNG_ERR_NOELEM
:
2182 snprintf(msg
, 1000, "Expecting an element %s, got nothing\n",
2185 case XML_RELAXNG_ERR_NOTELEM
:
2186 return (xmlCharStrdup("Expecting an element got text\n"));
2187 case XML_RELAXNG_ERR_ATTRVALID
:
2188 snprintf(msg
, 1000, "Element %s failed to validate attributes\n",
2191 case XML_RELAXNG_ERR_CONTENTVALID
:
2192 snprintf(msg
, 1000, "Element %s failed to validate content\n",
2195 case XML_RELAXNG_ERR_EXTRACONTENT
:
2196 snprintf(msg
, 1000, "Element %s has extra content: %s\n",
2199 case XML_RELAXNG_ERR_INVALIDATTR
:
2200 snprintf(msg
, 1000, "Invalid attribute %s for element %s\n",
2203 case XML_RELAXNG_ERR_LACKDATA
:
2204 snprintf(msg
, 1000, "Datatype element %s contains no data\n",
2207 case XML_RELAXNG_ERR_DATAELEM
:
2208 snprintf(msg
, 1000, "Datatype element %s has child elements\n",
2211 case XML_RELAXNG_ERR_VALELEM
:
2212 snprintf(msg
, 1000, "Value element %s has child elements\n",
2215 case XML_RELAXNG_ERR_LISTELEM
:
2216 snprintf(msg
, 1000, "List element %s has child elements\n",
2219 case XML_RELAXNG_ERR_DATATYPE
:
2220 snprintf(msg
, 1000, "Error validating datatype %s\n", arg1
);
2222 case XML_RELAXNG_ERR_VALUE
:
2223 snprintf(msg
, 1000, "Error validating value %s\n", arg1
);
2225 case XML_RELAXNG_ERR_LIST
:
2226 return (xmlCharStrdup("Error validating list\n"));
2227 case XML_RELAXNG_ERR_NOGRAMMAR
:
2228 return (xmlCharStrdup("No top grammar defined\n"));
2229 case XML_RELAXNG_ERR_EXTRADATA
:
2230 return (xmlCharStrdup("Extra data in the document\n"));
2232 return (xmlCharStrdup("Unknown error !\n"));
2235 snprintf(msg
, 1000, "Unknown error code %d\n", err
);
2238 result
= xmlCharStrdup(msg
);
2239 return (xmlEscapeFormatString(&result
));
2243 * xmlRelaxNGShowValidError:
2244 * @ctxt: the validation context
2245 * @err: the error number
2247 * @child: the node child generating the problem.
2248 * @arg1: the first argument
2249 * @arg2: the second argument
2251 * Show a validation error.
2254 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt
,
2255 xmlRelaxNGValidErr err
, xmlNodePtr node
,
2256 xmlNodePtr child
, const xmlChar
* arg1
,
2257 const xmlChar
* arg2
)
2261 if (ctxt
->flags
& FLAGS_NOERROR
)
2265 xmlGenericError(xmlGenericErrorContext
, "Show error %d\n", err
);
2267 msg
= xmlRelaxNGGetErrorString(err
, arg1
, arg2
);
2271 if (ctxt
->errNo
== XML_RELAXNG_OK
)
2273 xmlRngVErr(ctxt
, (child
== NULL
? node
: child
), err
,
2274 (const char *) msg
, arg1
, arg2
);
2279 * xmlRelaxNGPopErrors:
2280 * @ctxt: the validation context
2281 * @level: the error level in the stack
2283 * pop and discard all errors until the given level is reached
2286 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt
, int level
)
2289 xmlRelaxNGValidErrorPtr err
;
2292 xmlGenericError(xmlGenericErrorContext
,
2293 "Pop errors till level %d\n", level
);
2295 for (i
= level
; i
< ctxt
->errNr
; i
++) {
2296 err
= &ctxt
->errTab
[i
];
2297 if (err
->flags
& ERROR_IS_DUP
) {
2298 if (err
->arg1
!= NULL
)
2299 xmlFree((xmlChar
*) err
->arg1
);
2301 if (err
->arg2
!= NULL
)
2302 xmlFree((xmlChar
*) err
->arg2
);
2307 ctxt
->errNr
= level
;
2308 if (ctxt
->errNr
<= 0)
2313 * xmlRelaxNGDumpValidError:
2314 * @ctxt: the validation context
2316 * Show all validation error over a given index.
2319 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt
)
2322 xmlRelaxNGValidErrorPtr err
, dup
;
2325 xmlGenericError(xmlGenericErrorContext
,
2326 "Dumping error stack %d errors\n", ctxt
->errNr
);
2328 for (i
= 0, k
= 0; i
< ctxt
->errNr
; i
++) {
2329 err
= &ctxt
->errTab
[i
];
2330 if (k
< MAX_ERROR
) {
2331 for (j
= 0; j
< i
; j
++) {
2332 dup
= &ctxt
->errTab
[j
];
2333 if ((err
->err
== dup
->err
) && (err
->node
== dup
->node
) &&
2334 (xmlStrEqual(err
->arg1
, dup
->arg1
)) &&
2335 (xmlStrEqual(err
->arg2
, dup
->arg2
))) {
2339 xmlRelaxNGShowValidError(ctxt
, err
->err
, err
->node
, err
->seq
,
2340 err
->arg1
, err
->arg2
);
2344 if (err
->flags
& ERROR_IS_DUP
) {
2345 if (err
->arg1
!= NULL
)
2346 xmlFree((xmlChar
*) err
->arg1
);
2348 if (err
->arg2
!= NULL
)
2349 xmlFree((xmlChar
*) err
->arg2
);
2358 * xmlRelaxNGAddValidError:
2359 * @ctxt: the validation context
2360 * @err: the error number
2361 * @arg1: the first argument
2362 * @arg2: the second argument
2363 * @dup: need to dup the args
2365 * Register a validation error, either generating it if it's sure
2366 * or stacking it for later handling if unsure.
2369 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt
,
2370 xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
2371 const xmlChar
* arg2
, int dup
)
2375 if (ctxt
->flags
& FLAGS_NOERROR
)
2379 xmlGenericError(xmlGenericErrorContext
, "Adding error %d\n", err
);
2382 * generate the error directly
2384 if (((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) ||
2385 (ctxt
->flags
& FLAGS_NEGATIVE
)) {
2386 xmlNodePtr node
, seq
;
2389 * Flush first any stacked error which might be the
2390 * real cause of the problem.
2392 if (ctxt
->errNr
!= 0)
2393 xmlRelaxNGDumpValidError(ctxt
);
2394 if (ctxt
->state
!= NULL
) {
2395 node
= ctxt
->state
->node
;
2396 seq
= ctxt
->state
->seq
;
2400 if ((node
== NULL
) && (seq
== NULL
)) {
2403 xmlRelaxNGShowValidError(ctxt
, err
, node
, seq
, arg1
, arg2
);
2406 * Stack the error for later processing if needed
2409 xmlRelaxNGValidErrorPush(ctxt
, err
, arg1
, arg2
, dup
);
2414 /************************************************************************
2416 * Type library hooks *
2418 ************************************************************************/
2419 static xmlChar
*xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
,
2420 const xmlChar
* str
);
2423 * xmlRelaxNGSchemaTypeHave:
2424 * @data: data needed for the library
2425 * @type: the type name
2427 * Check if the given type is provided by
2428 * the W3C XMLSchema Datatype library.
2430 * Returns 1 if yes, 0 if no and -1 in case of error.
2433 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED
, const xmlChar
* type
)
2435 xmlSchemaTypePtr typ
;
2439 typ
= xmlSchemaGetPredefinedType(type
,
2441 "http://www.w3.org/2001/XMLSchema");
2448 * xmlRelaxNGSchemaTypeCheck:
2449 * @data: data needed for the library
2450 * @type: the type name
2451 * @value: the value to check
2454 * Check if the given type and value are validated by
2455 * the W3C XMLSchema Datatype library.
2457 * Returns 1 if yes, 0 if no and -1 in case of error.
2460 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED
,
2461 const xmlChar
* type
,
2462 const xmlChar
* value
,
2463 void **result
, xmlNodePtr node
)
2465 xmlSchemaTypePtr typ
;
2468 if ((type
== NULL
) || (value
== NULL
))
2470 typ
= xmlSchemaGetPredefinedType(type
,
2472 "http://www.w3.org/2001/XMLSchema");
2475 ret
= xmlSchemaValPredefTypeNode(typ
, value
,
2476 (xmlSchemaValPtr
*) result
, node
);
2477 if (ret
== 2) /* special ID error code */
2487 * xmlRelaxNGSchemaFacetCheck:
2488 * @data: data needed for the library
2489 * @type: the type name
2490 * @facet: the facet name
2491 * @val: the facet value
2492 * @strval: the string value
2493 * @value: the value to check
2495 * Function provided by a type library to check a value facet
2497 * Returns 1 if yes, 0 if no and -1 in case of error.
2500 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED
,
2501 const xmlChar
* type
, const xmlChar
* facetname
,
2502 const xmlChar
* val
, const xmlChar
* strval
,
2505 xmlSchemaFacetPtr facet
;
2506 xmlSchemaTypePtr typ
;
2509 if ((type
== NULL
) || (strval
== NULL
))
2511 typ
= xmlSchemaGetPredefinedType(type
,
2513 "http://www.w3.org/2001/XMLSchema");
2517 facet
= xmlSchemaNewFacet();
2521 if (xmlStrEqual(facetname
, BAD_CAST
"minInclusive")) {
2522 facet
->type
= XML_SCHEMA_FACET_MININCLUSIVE
;
2523 } else if (xmlStrEqual(facetname
, BAD_CAST
"minExclusive")) {
2524 facet
->type
= XML_SCHEMA_FACET_MINEXCLUSIVE
;
2525 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxInclusive")) {
2526 facet
->type
= XML_SCHEMA_FACET_MAXINCLUSIVE
;
2527 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxExclusive")) {
2528 facet
->type
= XML_SCHEMA_FACET_MAXEXCLUSIVE
;
2529 } else if (xmlStrEqual(facetname
, BAD_CAST
"totalDigits")) {
2530 facet
->type
= XML_SCHEMA_FACET_TOTALDIGITS
;
2531 } else if (xmlStrEqual(facetname
, BAD_CAST
"fractionDigits")) {
2532 facet
->type
= XML_SCHEMA_FACET_FRACTIONDIGITS
;
2533 } else if (xmlStrEqual(facetname
, BAD_CAST
"pattern")) {
2534 facet
->type
= XML_SCHEMA_FACET_PATTERN
;
2535 } else if (xmlStrEqual(facetname
, BAD_CAST
"enumeration")) {
2536 facet
->type
= XML_SCHEMA_FACET_ENUMERATION
;
2537 } else if (xmlStrEqual(facetname
, BAD_CAST
"whiteSpace")) {
2538 facet
->type
= XML_SCHEMA_FACET_WHITESPACE
;
2539 } else if (xmlStrEqual(facetname
, BAD_CAST
"length")) {
2540 facet
->type
= XML_SCHEMA_FACET_LENGTH
;
2541 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxLength")) {
2542 facet
->type
= XML_SCHEMA_FACET_MAXLENGTH
;
2543 } else if (xmlStrEqual(facetname
, BAD_CAST
"minLength")) {
2544 facet
->type
= XML_SCHEMA_FACET_MINLENGTH
;
2546 xmlSchemaFreeFacet(facet
);
2550 ret
= xmlSchemaCheckFacet(facet
, typ
, NULL
, type
);
2552 xmlSchemaFreeFacet(facet
);
2555 ret
= xmlSchemaValidateFacet(typ
, facet
, strval
, value
);
2556 xmlSchemaFreeFacet(facet
);
2563 * xmlRelaxNGSchemaFreeValue:
2564 * @data: data needed for the library
2565 * @value: the value to free
2567 * Function provided by a type library to free a Schemas value
2569 * Returns 1 if yes, 0 if no and -1 in case of error.
2572 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED
, void *value
)
2574 xmlSchemaFreeValue(value
);
2578 * xmlRelaxNGSchemaTypeCompare:
2579 * @data: data needed for the library
2580 * @type: the type name
2581 * @value1: the first value
2582 * @value2: the second value
2584 * Compare two values for equality accordingly a type from the W3C XMLSchema
2587 * Returns 1 if equal, 0 if no and -1 in case of error.
2590 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED
,
2591 const xmlChar
* type
,
2592 const xmlChar
* value1
,
2595 const xmlChar
* value2
, xmlNodePtr ctxt2
)
2598 xmlSchemaTypePtr typ
;
2599 xmlSchemaValPtr res1
= NULL
, res2
= NULL
;
2601 if ((type
== NULL
) || (value1
== NULL
) || (value2
== NULL
))
2603 typ
= xmlSchemaGetPredefinedType(type
,
2605 "http://www.w3.org/2001/XMLSchema");
2608 if (comp1
== NULL
) {
2609 ret
= xmlSchemaValPredefTypeNode(typ
, value1
, &res1
, ctxt1
);
2615 res1
= (xmlSchemaValPtr
) comp1
;
2617 ret
= xmlSchemaValPredefTypeNode(typ
, value2
, &res2
, ctxt2
);
2619 if (res1
!= (xmlSchemaValPtr
) comp1
)
2620 xmlSchemaFreeValue(res1
);
2623 ret
= xmlSchemaCompareValues(res1
, res2
);
2624 if (res1
!= (xmlSchemaValPtr
) comp1
)
2625 xmlSchemaFreeValue(res1
);
2626 xmlSchemaFreeValue(res2
);
2635 * xmlRelaxNGDefaultTypeHave:
2636 * @data: data needed for the library
2637 * @type: the type name
2639 * Check if the given type is provided by
2640 * the default datatype library.
2642 * Returns 1 if yes, 0 if no and -1 in case of error.
2645 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED
,
2646 const xmlChar
* type
)
2650 if (xmlStrEqual(type
, BAD_CAST
"string"))
2652 if (xmlStrEqual(type
, BAD_CAST
"token"))
2658 * xmlRelaxNGDefaultTypeCheck:
2659 * @data: data needed for the library
2660 * @type: the type name
2661 * @value: the value to check
2664 * Check if the given type and value are validated by
2665 * the default datatype library.
2667 * Returns 1 if yes, 0 if no and -1 in case of error.
2670 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED
,
2671 const xmlChar
* type ATTRIBUTE_UNUSED
,
2672 const xmlChar
* value ATTRIBUTE_UNUSED
,
2673 void **result ATTRIBUTE_UNUSED
,
2674 xmlNodePtr node ATTRIBUTE_UNUSED
)
2678 if (xmlStrEqual(type
, BAD_CAST
"string"))
2680 if (xmlStrEqual(type
, BAD_CAST
"token")) {
2688 * xmlRelaxNGDefaultTypeCompare:
2689 * @data: data needed for the library
2690 * @type: the type name
2691 * @value1: the first value
2692 * @value2: the second value
2694 * Compare two values accordingly a type from the default
2697 * Returns 1 if yes, 0 if no and -1 in case of error.
2700 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED
,
2701 const xmlChar
* type
,
2702 const xmlChar
* value1
,
2703 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED
,
2704 void *comp1 ATTRIBUTE_UNUSED
,
2705 const xmlChar
* value2
,
2706 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED
)
2710 if (xmlStrEqual(type
, BAD_CAST
"string")) {
2711 ret
= xmlStrEqual(value1
, value2
);
2712 } else if (xmlStrEqual(type
, BAD_CAST
"token")) {
2713 if (!xmlStrEqual(value1
, value2
)) {
2714 xmlChar
*nval
, *nvalue
;
2717 * TODO: trivial optimizations are possible by
2718 * computing at compile-time
2720 nval
= xmlRelaxNGNormalize(NULL
, value1
);
2721 nvalue
= xmlRelaxNGNormalize(NULL
, value2
);
2723 if ((nval
== NULL
) || (nvalue
== NULL
))
2725 else if (xmlStrEqual(nval
, nvalue
))
2739 static int xmlRelaxNGTypeInitialized
= 0;
2740 static xmlHashTablePtr xmlRelaxNGRegisteredTypes
= NULL
;
2743 * xmlRelaxNGFreeTypeLibrary:
2744 * @lib: the type library structure
2745 * @namespace: the URI bound to the library
2747 * Free the structure associated to the type library
2750 xmlRelaxNGFreeTypeLibrary(void *payload
,
2751 const xmlChar
* namespace ATTRIBUTE_UNUSED
)
2753 xmlRelaxNGTypeLibraryPtr lib
= (xmlRelaxNGTypeLibraryPtr
) payload
;
2756 if (lib
->namespace != NULL
)
2757 xmlFree((xmlChar
*) lib
->namespace);
2762 * xmlRelaxNGRegisterTypeLibrary:
2763 * @namespace: the URI bound to the library
2764 * @data: data associated to the library
2765 * @have: the provide function
2766 * @check: the checking function
2767 * @comp: the comparison function
2769 * Register a new type library
2771 * Returns 0 in case of success and -1 in case of error.
2774 xmlRelaxNGRegisterTypeLibrary(const xmlChar
* namespace, void *data
,
2775 xmlRelaxNGTypeHave have
,
2776 xmlRelaxNGTypeCheck check
,
2777 xmlRelaxNGTypeCompare comp
,
2778 xmlRelaxNGFacetCheck facet
,
2779 xmlRelaxNGTypeFree freef
)
2781 xmlRelaxNGTypeLibraryPtr lib
;
2784 if ((xmlRelaxNGRegisteredTypes
== NULL
) || (namespace == NULL
) ||
2785 (check
== NULL
) || (comp
== NULL
))
2787 if (xmlHashLookup(xmlRelaxNGRegisteredTypes
, namespace) != NULL
) {
2788 xmlGenericError(xmlGenericErrorContext
,
2789 "Relax-NG types library '%s' already registered\n",
2794 (xmlRelaxNGTypeLibraryPtr
)
2795 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary
));
2797 xmlRngVErrMemory(NULL
, "adding types library\n");
2800 memset(lib
, 0, sizeof(xmlRelaxNGTypeLibrary
));
2801 lib
->namespace = xmlStrdup(namespace);
2808 ret
= xmlHashAddEntry(xmlRelaxNGRegisteredTypes
, namespace, lib
);
2810 xmlGenericError(xmlGenericErrorContext
,
2811 "Relax-NG types library failed to register '%s'\n",
2813 xmlRelaxNGFreeTypeLibrary(lib
, namespace);
2820 * xmlRelaxNGInitTypes:
2822 * Initialize the default type libraries.
2824 * Returns 0 in case of success and -1 in case of error.
2827 xmlRelaxNGInitTypes(void)
2829 if (xmlRelaxNGTypeInitialized
!= 0)
2831 xmlRelaxNGRegisteredTypes
= xmlHashCreate(10);
2832 if (xmlRelaxNGRegisteredTypes
== NULL
) {
2833 xmlGenericError(xmlGenericErrorContext
,
2834 "Failed to allocate sh table for Relax-NG types\n");
2837 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2838 "http://www.w3.org/2001/XMLSchema-datatypes",
2839 NULL
, xmlRelaxNGSchemaTypeHave
,
2840 xmlRelaxNGSchemaTypeCheck
,
2841 xmlRelaxNGSchemaTypeCompare
,
2842 xmlRelaxNGSchemaFacetCheck
,
2843 xmlRelaxNGSchemaFreeValue
);
2844 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs
, NULL
,
2845 xmlRelaxNGDefaultTypeHave
,
2846 xmlRelaxNGDefaultTypeCheck
,
2847 xmlRelaxNGDefaultTypeCompare
, NULL
,
2849 xmlRelaxNGTypeInitialized
= 1;
2854 * xmlRelaxNGCleanupTypes:
2856 * DEPRECATED: This function will be made private. Call xmlCleanupParser
2857 * to free global state but see the warnings there. xmlCleanupParser
2858 * should be only called once at program exit. In most cases, you don't
2859 * have call cleanup functions at all.
2861 * Cleanup the default Schemas type library associated to RelaxNG
2864 xmlRelaxNGCleanupTypes(void)
2866 xmlSchemaCleanupTypes();
2867 if (xmlRelaxNGTypeInitialized
== 0)
2869 xmlHashFree(xmlRelaxNGRegisteredTypes
, xmlRelaxNGFreeTypeLibrary
);
2870 xmlRelaxNGTypeInitialized
= 0;
2873 /************************************************************************
2875 * Compiling element content into regexp *
2877 * Sometime the element content can be compiled into a pure regexp, *
2878 * This allows a faster execution and streamability at that level *
2880 ************************************************************************/
2882 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt
,
2883 xmlRelaxNGDefinePtr def
);
2886 * xmlRelaxNGIsCompilable:
2887 * @define: the definition to check
2889 * Check if a definition is nullable.
2891 * Returns 1 if yes, 0 if no and -1 in case of error
2894 xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def
)
2901 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
2902 (def
->dflags
& IS_COMPILABLE
))
2904 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
2905 (def
->dflags
& IS_NOT_COMPILABLE
))
2907 switch (def
->type
) {
2908 case XML_RELAXNG_NOOP
:
2909 ret
= xmlRelaxNGIsCompilable(def
->content
);
2911 case XML_RELAXNG_TEXT
:
2912 case XML_RELAXNG_EMPTY
:
2915 case XML_RELAXNG_ELEMENT
:
2917 * Check if the element content is compilable
2919 if (((def
->dflags
& IS_NOT_COMPILABLE
) == 0) &&
2920 ((def
->dflags
& IS_COMPILABLE
) == 0)) {
2921 xmlRelaxNGDefinePtr list
;
2923 list
= def
->content
;
2924 while (list
!= NULL
) {
2925 ret
= xmlRelaxNGIsCompilable(list
);
2931 * Because the routine is recursive, we must guard against
2932 * discovering both COMPILABLE and NOT_COMPILABLE
2935 def
->dflags
&= ~IS_COMPILABLE
;
2936 def
->dflags
|= IS_NOT_COMPILABLE
;
2938 if ((ret
== 1) && !(def
->dflags
&= IS_NOT_COMPILABLE
))
2939 def
->dflags
|= IS_COMPILABLE
;
2940 #ifdef DEBUG_COMPILE
2942 xmlGenericError(xmlGenericErrorContext
,
2943 "element content for %s is compilable\n",
2945 } else if (ret
== 0) {
2946 xmlGenericError(xmlGenericErrorContext
,
2947 "element content for %s is not compilable\n",
2950 xmlGenericError(xmlGenericErrorContext
,
2951 "Problem in RelaxNGIsCompilable for element %s\n",
2957 * All elements return a compilable status unless they
2958 * are generic like anyName
2960 if ((def
->nameClass
!= NULL
) || (def
->name
== NULL
))
2965 case XML_RELAXNG_REF
:
2966 case XML_RELAXNG_EXTERNALREF
:
2967 case XML_RELAXNG_PARENTREF
:
2968 if (def
->depth
== -20) {
2971 xmlRelaxNGDefinePtr list
;
2974 list
= def
->content
;
2975 while (list
!= NULL
) {
2976 ret
= xmlRelaxNGIsCompilable(list
);
2983 case XML_RELAXNG_START
:
2984 case XML_RELAXNG_OPTIONAL
:
2985 case XML_RELAXNG_ZEROORMORE
:
2986 case XML_RELAXNG_ONEORMORE
:
2987 case XML_RELAXNG_CHOICE
:
2988 case XML_RELAXNG_GROUP
:
2989 case XML_RELAXNG_DEF
:{
2990 xmlRelaxNGDefinePtr list
;
2992 list
= def
->content
;
2993 while (list
!= NULL
) {
2994 ret
= xmlRelaxNGIsCompilable(list
);
3001 case XML_RELAXNG_EXCEPT
:
3002 case XML_RELAXNG_ATTRIBUTE
:
3003 case XML_RELAXNG_INTERLEAVE
:
3004 case XML_RELAXNG_DATATYPE
:
3005 case XML_RELAXNG_LIST
:
3006 case XML_RELAXNG_PARAM
:
3007 case XML_RELAXNG_VALUE
:
3008 case XML_RELAXNG_NOT_ALLOWED
:
3013 def
->dflags
|= IS_NOT_COMPILABLE
;
3015 def
->dflags
|= IS_COMPILABLE
;
3016 #ifdef DEBUG_COMPILE
3018 xmlGenericError(xmlGenericErrorContext
,
3019 "RelaxNGIsCompilable %s : true\n",
3020 xmlRelaxNGDefName(def
));
3021 } else if (ret
== 0) {
3022 xmlGenericError(xmlGenericErrorContext
,
3023 "RelaxNGIsCompilable %s : false\n",
3024 xmlRelaxNGDefName(def
));
3026 xmlGenericError(xmlGenericErrorContext
,
3027 "Problem in RelaxNGIsCompilable %s\n",
3028 xmlRelaxNGDefName(def
));
3035 * xmlRelaxNGCompile:
3036 * ctxt: the RelaxNG parser context
3037 * @define: the definition tree to compile
3039 * Compile the set of definitions, it works recursively, till the
3040 * element boundaries, where it tries to compile the content if possible
3042 * Returns 0 if success and -1 in case of error
3045 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt
, xmlRelaxNGDefinePtr def
)
3048 xmlRelaxNGDefinePtr list
;
3050 if ((ctxt
== NULL
) || (def
== NULL
))
3053 switch (def
->type
) {
3054 case XML_RELAXNG_START
:
3055 if ((xmlRelaxNGIsCompilable(def
) == 1) && (def
->depth
!= -25)) {
3056 xmlAutomataPtr oldam
= ctxt
->am
;
3057 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3061 list
= def
->content
;
3062 ctxt
->am
= xmlNewAutomata();
3063 if (ctxt
->am
== NULL
)
3067 * assume identical strings but not same pointer are different
3068 * atoms, needed for non-determinism detection
3069 * That way if 2 elements with the same name are in a choice
3070 * branch the automata is found non-deterministic and
3071 * we fallback to the normal validation which does the right
3072 * thing of exploring both choices.
3074 xmlAutomataSetFlags(ctxt
->am
, 1);
3076 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
3077 while (list
!= NULL
) {
3078 xmlRelaxNGCompile(ctxt
, list
);
3081 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
3082 if (xmlAutomataIsDeterminist(ctxt
->am
))
3083 def
->contModel
= xmlAutomataCompile(ctxt
->am
);
3085 xmlFreeAutomata(ctxt
->am
);
3086 ctxt
->state
= oldstate
;
3090 case XML_RELAXNG_ELEMENT
:
3091 if ((ctxt
->am
!= NULL
) && (def
->name
!= NULL
)) {
3092 ctxt
->state
= xmlAutomataNewTransition2(ctxt
->am
,
3097 if ((def
->dflags
& IS_COMPILABLE
) && (def
->depth
!= -25)) {
3098 xmlAutomataPtr oldam
= ctxt
->am
;
3099 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3103 list
= def
->content
;
3104 ctxt
->am
= xmlNewAutomata();
3105 if (ctxt
->am
== NULL
)
3107 xmlAutomataSetFlags(ctxt
->am
, 1);
3108 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
3109 while (list
!= NULL
) {
3110 xmlRelaxNGCompile(ctxt
, list
);
3113 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
3114 def
->contModel
= xmlAutomataCompile(ctxt
->am
);
3115 if (!xmlRegexpIsDeterminist(def
->contModel
)) {
3116 #ifdef DEBUG_COMPILE
3117 xmlGenericError(xmlGenericErrorContext
,
3118 "Content model not determinist %s\n",
3122 * we can only use the automata if it is determinist
3124 xmlRegFreeRegexp(def
->contModel
);
3125 def
->contModel
= NULL
;
3127 xmlFreeAutomata(ctxt
->am
);
3128 ctxt
->state
= oldstate
;
3131 xmlAutomataPtr oldam
= ctxt
->am
;
3134 * we can't build the content model for this element content
3135 * but it still might be possible to build it for some of its
3136 * children, recurse.
3138 ret
= xmlRelaxNGTryCompile(ctxt
, def
);
3142 case XML_RELAXNG_NOOP
:
3143 ret
= xmlRelaxNGCompile(ctxt
, def
->content
);
3145 case XML_RELAXNG_OPTIONAL
:{
3146 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3148 list
= def
->content
;
3149 while (list
!= NULL
) {
3150 xmlRelaxNGCompile(ctxt
, list
);
3153 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
3156 case XML_RELAXNG_ZEROORMORE
:{
3157 xmlAutomataStatePtr oldstate
;
3160 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3161 oldstate
= ctxt
->state
;
3162 list
= def
->content
;
3163 while (list
!= NULL
) {
3164 xmlRelaxNGCompile(ctxt
, list
);
3167 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldstate
);
3169 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3172 case XML_RELAXNG_ONEORMORE
:{
3173 xmlAutomataStatePtr oldstate
;
3175 list
= def
->content
;
3176 while (list
!= NULL
) {
3177 xmlRelaxNGCompile(ctxt
, list
);
3180 oldstate
= ctxt
->state
;
3181 list
= def
->content
;
3182 while (list
!= NULL
) {
3183 xmlRelaxNGCompile(ctxt
, list
);
3186 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldstate
);
3188 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3191 case XML_RELAXNG_CHOICE
:{
3192 xmlAutomataStatePtr target
= NULL
;
3193 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3195 list
= def
->content
;
3196 while (list
!= NULL
) {
3197 ctxt
->state
= oldstate
;
3198 ret
= xmlRelaxNGCompile(ctxt
, list
);
3202 target
= ctxt
->state
;
3204 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
,
3209 ctxt
->state
= target
;
3213 case XML_RELAXNG_REF
:
3214 case XML_RELAXNG_EXTERNALREF
:
3215 case XML_RELAXNG_PARENTREF
:
3216 case XML_RELAXNG_GROUP
:
3217 case XML_RELAXNG_DEF
:
3218 list
= def
->content
;
3219 while (list
!= NULL
) {
3220 ret
= xmlRelaxNGCompile(ctxt
, list
);
3226 case XML_RELAXNG_TEXT
:{
3227 xmlAutomataStatePtr oldstate
;
3230 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3231 oldstate
= ctxt
->state
;
3232 xmlRelaxNGCompile(ctxt
, def
->content
);
3233 xmlAutomataNewTransition(ctxt
->am
, ctxt
->state
,
3234 ctxt
->state
, BAD_CAST
"#text",
3237 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3240 case XML_RELAXNG_EMPTY
:
3242 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3244 case XML_RELAXNG_EXCEPT
:
3245 case XML_RELAXNG_ATTRIBUTE
:
3246 case XML_RELAXNG_INTERLEAVE
:
3247 case XML_RELAXNG_NOT_ALLOWED
:
3248 case XML_RELAXNG_DATATYPE
:
3249 case XML_RELAXNG_LIST
:
3250 case XML_RELAXNG_PARAM
:
3251 case XML_RELAXNG_VALUE
:
3252 /* This should not happen and generate an internal error */
3253 fprintf(stderr
, "RNG internal error trying to compile %s\n",
3254 xmlRelaxNGDefName(def
));
3261 * xmlRelaxNGTryCompile:
3262 * ctxt: the RelaxNG parser context
3263 * @define: the definition tree to compile
3265 * Try to compile the set of definitions, it works recursively,
3266 * possibly ignoring parts which cannot be compiled.
3268 * Returns 0 if success and -1 in case of error
3271 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt
, xmlRelaxNGDefinePtr def
)
3274 xmlRelaxNGDefinePtr list
;
3276 if ((ctxt
== NULL
) || (def
== NULL
))
3279 if ((def
->type
== XML_RELAXNG_START
) ||
3280 (def
->type
== XML_RELAXNG_ELEMENT
)) {
3281 ret
= xmlRelaxNGIsCompilable(def
);
3282 if ((def
->dflags
& IS_COMPILABLE
) && (def
->depth
!= -25)) {
3284 ret
= xmlRelaxNGCompile(ctxt
, def
);
3285 #ifdef DEBUG_PROGRESSIVE
3287 if (def
->type
== XML_RELAXNG_START
)
3288 xmlGenericError(xmlGenericErrorContext
,
3289 "compiled the start\n");
3291 xmlGenericError(xmlGenericErrorContext
,
3292 "compiled element %s\n", def
->name
);
3294 if (def
->type
== XML_RELAXNG_START
)
3295 xmlGenericError(xmlGenericErrorContext
,
3296 "failed to compile the start\n");
3298 xmlGenericError(xmlGenericErrorContext
,
3299 "failed to compile element %s\n",
3306 switch (def
->type
) {
3307 case XML_RELAXNG_NOOP
:
3308 ret
= xmlRelaxNGTryCompile(ctxt
, def
->content
);
3310 case XML_RELAXNG_TEXT
:
3311 case XML_RELAXNG_DATATYPE
:
3312 case XML_RELAXNG_LIST
:
3313 case XML_RELAXNG_PARAM
:
3314 case XML_RELAXNG_VALUE
:
3315 case XML_RELAXNG_EMPTY
:
3316 case XML_RELAXNG_ELEMENT
:
3319 case XML_RELAXNG_OPTIONAL
:
3320 case XML_RELAXNG_ZEROORMORE
:
3321 case XML_RELAXNG_ONEORMORE
:
3322 case XML_RELAXNG_CHOICE
:
3323 case XML_RELAXNG_GROUP
:
3324 case XML_RELAXNG_DEF
:
3325 case XML_RELAXNG_START
:
3326 case XML_RELAXNG_REF
:
3327 case XML_RELAXNG_EXTERNALREF
:
3328 case XML_RELAXNG_PARENTREF
:
3329 list
= def
->content
;
3330 while (list
!= NULL
) {
3331 ret
= xmlRelaxNGTryCompile(ctxt
, list
);
3337 case XML_RELAXNG_EXCEPT
:
3338 case XML_RELAXNG_ATTRIBUTE
:
3339 case XML_RELAXNG_INTERLEAVE
:
3340 case XML_RELAXNG_NOT_ALLOWED
:
3347 /************************************************************************
3349 * Parsing functions *
3351 ************************************************************************/
3353 static xmlRelaxNGDefinePtr
xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3354 ctxt
, xmlNodePtr node
);
3355 static xmlRelaxNGDefinePtr
xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3356 ctxt
, xmlNodePtr node
);
3357 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3358 ctxt
, xmlNodePtr nodes
,
3360 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3361 ctxt
, xmlNodePtr node
);
3362 static xmlRelaxNGPtr
xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
,
3364 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
3366 static xmlRelaxNGDefinePtr
xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3367 ctxt
, xmlNodePtr node
,
3370 static xmlRelaxNGGrammarPtr
xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3371 ctxt
, xmlNodePtr nodes
);
3372 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
3373 xmlRelaxNGDefinePtr define
,
3377 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3380 * xmlRelaxNGIsNullable:
3381 * @define: the definition to verify
3383 * Check if a definition is nullable.
3385 * Returns 1 if yes, 0 if no and -1 in case of error
3388 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define
)
3395 if (define
->dflags
& IS_NULLABLE
)
3397 if (define
->dflags
& IS_NOT_NULLABLE
)
3399 switch (define
->type
) {
3400 case XML_RELAXNG_EMPTY
:
3401 case XML_RELAXNG_TEXT
:
3404 case XML_RELAXNG_NOOP
:
3405 case XML_RELAXNG_DEF
:
3406 case XML_RELAXNG_REF
:
3407 case XML_RELAXNG_EXTERNALREF
:
3408 case XML_RELAXNG_PARENTREF
:
3409 case XML_RELAXNG_ONEORMORE
:
3410 ret
= xmlRelaxNGIsNullable(define
->content
);
3412 case XML_RELAXNG_EXCEPT
:
3413 case XML_RELAXNG_NOT_ALLOWED
:
3414 case XML_RELAXNG_ELEMENT
:
3415 case XML_RELAXNG_DATATYPE
:
3416 case XML_RELAXNG_PARAM
:
3417 case XML_RELAXNG_VALUE
:
3418 case XML_RELAXNG_LIST
:
3419 case XML_RELAXNG_ATTRIBUTE
:
3422 case XML_RELAXNG_CHOICE
:{
3423 xmlRelaxNGDefinePtr list
= define
->content
;
3425 while (list
!= NULL
) {
3426 ret
= xmlRelaxNGIsNullable(list
);
3434 case XML_RELAXNG_START
:
3435 case XML_RELAXNG_INTERLEAVE
:
3436 case XML_RELAXNG_GROUP
:{
3437 xmlRelaxNGDefinePtr list
= define
->content
;
3439 while (list
!= NULL
) {
3440 ret
= xmlRelaxNGIsNullable(list
);
3452 define
->dflags
|= IS_NOT_NULLABLE
;
3454 define
->dflags
|= IS_NULLABLE
;
3459 * xmlRelaxNGIsBlank:
3462 * Check if a string is ignorable c.f. 4.2. Whitespace
3464 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3467 xmlRelaxNGIsBlank(xmlChar
* str
)
3472 if (!(IS_BLANK_CH(*str
)))
3480 * xmlRelaxNGGetDataTypeLibrary:
3481 * @ctxt: a Relax-NG parser context
3482 * @node: the current data or value element
3484 * Applies algorithm from 4.3. datatypeLibrary attribute
3486 * Returns the datatypeLibrary value or NULL if not found
3489 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
3492 xmlChar
*ret
, *escape
;
3497 if ((IS_RELAXNG(node
, "data")) || (IS_RELAXNG(node
, "value"))) {
3498 ret
= xmlGetProp(node
, BAD_CAST
"datatypeLibrary");
3504 escape
= xmlURIEscapeStr(ret
, BAD_CAST
":/#?");
3505 if (escape
== NULL
) {
3512 node
= node
->parent
;
3513 while ((node
!= NULL
) && (node
->type
== XML_ELEMENT_NODE
)) {
3514 ret
= xmlGetProp(node
, BAD_CAST
"datatypeLibrary");
3520 escape
= xmlURIEscapeStr(ret
, BAD_CAST
":/#?");
3521 if (escape
== NULL
) {
3527 node
= node
->parent
;
3533 * xmlRelaxNGParseValue:
3534 * @ctxt: a Relax-NG parser context
3535 * @node: the data node.
3537 * parse the content of a RelaxNG value node.
3539 * Returns the definition pointer or NULL in case of error
3541 static xmlRelaxNGDefinePtr
3542 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
3544 xmlRelaxNGDefinePtr def
= NULL
;
3545 xmlRelaxNGTypeLibraryPtr lib
= NULL
;
3550 def
= xmlRelaxNGNewDefine(ctxt
, node
);
3553 def
->type
= XML_RELAXNG_VALUE
;
3555 type
= xmlGetProp(node
, BAD_CAST
"type");
3557 xmlRelaxNGNormExtSpace(type
);
3558 if (xmlValidateNCName(type
, 0)) {
3559 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_VALUE
,
3560 "value type '%s' is not an NCName\n", type
, NULL
);
3562 library
= xmlRelaxNGGetDataTypeLibrary(ctxt
, node
);
3563 if (library
== NULL
)
3565 xmlStrdup(BAD_CAST
"http://relaxng.org/ns/structure/1.0");
3570 lib
= (xmlRelaxNGTypeLibraryPtr
)
3571 xmlHashLookup(xmlRelaxNGRegisteredTypes
, library
);
3573 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_TYPE_LIB
,
3574 "Use of unregistered type library '%s'\n", library
,
3579 if (lib
->have
== NULL
) {
3580 xmlRngPErr(ctxt
, node
, XML_RNGP_ERROR_TYPE_LIB
,
3581 "Internal error with type library '%s': no 'have'\n",
3584 success
= lib
->have(lib
->data
, def
->name
);
3586 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_NOT_FOUND
,
3587 "Error type '%s' is not exported by type library '%s'\n",
3588 def
->name
, library
);
3593 if (node
->children
== NULL
) {
3594 def
->value
= xmlStrdup(BAD_CAST
"");
3595 } else if (((node
->children
->type
!= XML_TEXT_NODE
) &&
3596 (node
->children
->type
!= XML_CDATA_SECTION_NODE
)) ||
3597 (node
->children
->next
!= NULL
)) {
3598 xmlRngPErr(ctxt
, node
, XML_RNGP_TEXT_EXPECTED
,
3599 "Expecting a single text value for <value>content\n",
3601 } else if (def
!= NULL
) {
3602 def
->value
= xmlNodeGetContent(node
);
3603 if (def
->value
== NULL
) {
3604 xmlRngPErr(ctxt
, node
, XML_RNGP_VALUE_NO_CONTENT
,
3605 "Element <value> has no content\n", NULL
, NULL
);
3606 } else if ((lib
!= NULL
) && (lib
->check
!= NULL
) && (success
== 1)) {
3610 lib
->check(lib
->data
, def
->name
, def
->value
, &val
, node
);
3612 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_VALUE
,
3613 "Value '%s' is not acceptable for type '%s'\n",
3614 def
->value
, def
->name
);
3625 * xmlRelaxNGParseData:
3626 * @ctxt: a Relax-NG parser context
3627 * @node: the data node.
3629 * parse the content of a RelaxNG data node.
3631 * Returns the definition pointer or NULL in case of error
3633 static xmlRelaxNGDefinePtr
3634 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
3636 xmlRelaxNGDefinePtr def
= NULL
, except
;
3637 xmlRelaxNGDefinePtr param
, lastparam
= NULL
;
3638 xmlRelaxNGTypeLibraryPtr lib
;
3644 type
= xmlGetProp(node
, BAD_CAST
"type");
3646 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_MISSING
, "data has no type\n", NULL
,
3650 xmlRelaxNGNormExtSpace(type
);
3651 if (xmlValidateNCName(type
, 0)) {
3652 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_VALUE
,
3653 "data type '%s' is not an NCName\n", type
, NULL
);
3655 library
= xmlRelaxNGGetDataTypeLibrary(ctxt
, node
);
3656 if (library
== NULL
)
3658 xmlStrdup(BAD_CAST
"http://relaxng.org/ns/structure/1.0");
3660 def
= xmlRelaxNGNewDefine(ctxt
, node
);
3666 def
->type
= XML_RELAXNG_DATATYPE
;
3670 lib
= (xmlRelaxNGTypeLibraryPtr
)
3671 xmlHashLookup(xmlRelaxNGRegisteredTypes
, library
);
3673 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_TYPE_LIB
,
3674 "Use of unregistered type library '%s'\n", library
,
3679 if (lib
->have
== NULL
) {
3680 xmlRngPErr(ctxt
, node
, XML_RNGP_ERROR_TYPE_LIB
,
3681 "Internal error with type library '%s': no 'have'\n",
3684 tmp
= lib
->have(lib
->data
, def
->name
);
3686 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_NOT_FOUND
,
3687 "Error type '%s' is not exported by type library '%s'\n",
3688 def
->name
, library
);
3693 "http://www.w3.org/2001/XMLSchema-datatypes"))
3694 && ((xmlStrEqual(def
->name
, BAD_CAST
"IDREF"))
3695 || (xmlStrEqual(def
->name
, BAD_CAST
"IDREFS")))) {
3700 content
= node
->children
;
3703 * Handle optional params
3705 while (content
!= NULL
) {
3706 if (!xmlStrEqual(content
->name
, BAD_CAST
"param"))
3708 if (xmlStrEqual(library
,
3709 BAD_CAST
"http://relaxng.org/ns/structure/1.0")) {
3710 xmlRngPErr(ctxt
, node
, XML_RNGP_PARAM_FORBIDDEN
,
3711 "Type library '%s' does not allow type parameters\n",
3713 content
= content
->next
;
3714 while ((content
!= NULL
) &&
3715 (xmlStrEqual(content
->name
, BAD_CAST
"param")))
3716 content
= content
->next
;
3718 param
= xmlRelaxNGNewDefine(ctxt
, node
);
3719 if (param
!= NULL
) {
3720 param
->type
= XML_RELAXNG_PARAM
;
3721 param
->name
= xmlGetProp(content
, BAD_CAST
"name");
3722 if (param
->name
== NULL
) {
3723 xmlRngPErr(ctxt
, node
, XML_RNGP_PARAM_NAME_MISSING
,
3724 "param has no name\n", NULL
, NULL
);
3726 param
->value
= xmlNodeGetContent(content
);
3727 if (lastparam
== NULL
) {
3728 def
->attrs
= lastparam
= param
;
3730 lastparam
->next
= param
;
3736 content
= content
->next
;
3740 * Handle optional except
3742 if ((content
!= NULL
)
3743 && (xmlStrEqual(content
->name
, BAD_CAST
"except"))) {
3745 xmlRelaxNGDefinePtr tmp2
, last
= NULL
;
3747 except
= xmlRelaxNGNewDefine(ctxt
, node
);
3748 if (except
== NULL
) {
3751 except
->type
= XML_RELAXNG_EXCEPT
;
3752 child
= content
->children
;
3753 def
->content
= except
;
3754 if (child
== NULL
) {
3755 xmlRngPErr(ctxt
, content
, XML_RNGP_EXCEPT_NO_CONTENT
,
3756 "except has no content\n", NULL
, NULL
);
3758 while (child
!= NULL
) {
3759 tmp2
= xmlRelaxNGParsePattern(ctxt
, child
);
3762 except
->content
= last
= tmp2
;
3768 child
= child
->next
;
3770 content
= content
->next
;
3773 * Check there is no unhandled data
3775 if (content
!= NULL
) {
3776 xmlRngPErr(ctxt
, content
, XML_RNGP_DATA_CONTENT
,
3777 "Element data has unexpected content %s\n",
3778 content
->name
, NULL
);
3784 static const xmlChar
*invalidName
= BAD_CAST
"\1";
3787 * xmlRelaxNGCompareNameClasses:
3788 * @defs1: the first element/attribute defs
3789 * @defs2: the second element/attribute defs
3790 * @name: the restriction on the name
3791 * @ns: the restriction on the namespace
3793 * Compare the 2 lists of element definitions. The comparison is
3794 * that if both lists do not accept the same QNames, it returns 1
3795 * If the 2 lists can accept the same QName the comparison returns 0
3797 * Returns 1 distinct, 0 if equal
3800 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1
,
3801 xmlRelaxNGDefinePtr def2
)
3806 xmlRelaxNGValidCtxt ctxt
;
3808 memset(&ctxt
, 0, sizeof(xmlRelaxNGValidCtxt
));
3810 ctxt
.flags
= FLAGS_IGNORABLE
| FLAGS_NOERROR
;
3812 if ((def1
->type
== XML_RELAXNG_ELEMENT
) ||
3813 (def1
->type
== XML_RELAXNG_ATTRIBUTE
)) {
3814 if (def2
->type
== XML_RELAXNG_TEXT
)
3816 if (def1
->name
!= NULL
) {
3817 node
.name
= def1
->name
;
3819 node
.name
= invalidName
;
3821 if (def1
->ns
!= NULL
) {
3822 if (def1
->ns
[0] == 0) {
3831 if (xmlRelaxNGElementMatch(&ctxt
, def2
, &node
)) {
3832 if (def1
->nameClass
!= NULL
) {
3833 ret
= xmlRelaxNGCompareNameClasses(def1
->nameClass
, def2
);
3840 } else if (def1
->type
== XML_RELAXNG_TEXT
) {
3841 if (def2
->type
== XML_RELAXNG_TEXT
)
3844 } else if (def1
->type
== XML_RELAXNG_EXCEPT
) {
3845 ret
= xmlRelaxNGCompareNameClasses(def1
->content
, def2
);
3855 if ((def2
->type
== XML_RELAXNG_ELEMENT
) ||
3856 (def2
->type
== XML_RELAXNG_ATTRIBUTE
)) {
3857 if (def2
->name
!= NULL
) {
3858 node
.name
= def2
->name
;
3860 node
.name
= invalidName
;
3863 if (def2
->ns
!= NULL
) {
3864 if (def2
->ns
[0] == 0) {
3870 ns
.href
= invalidName
;
3872 if (xmlRelaxNGElementMatch(&ctxt
, def1
, &node
)) {
3873 if (def2
->nameClass
!= NULL
) {
3874 ret
= xmlRelaxNGCompareNameClasses(def2
->nameClass
, def1
);
3889 * xmlRelaxNGCompareElemDefLists:
3890 * @ctxt: a Relax-NG parser context
3891 * @defs1: the first list of element/attribute defs
3892 * @defs2: the second list of element/attribute defs
3894 * Compare the 2 lists of element or attribute definitions. The comparison
3895 * is that if both lists do not accept the same QNames, it returns 1
3896 * If the 2 lists can accept the same QName the comparison returns 0
3898 * Returns 1 distinct, 0 if equal
3901 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3902 ATTRIBUTE_UNUSED
, xmlRelaxNGDefinePtr
* def1
,
3903 xmlRelaxNGDefinePtr
* def2
)
3905 xmlRelaxNGDefinePtr
*basedef2
= def2
;
3907 if ((def1
== NULL
) || (def2
== NULL
))
3909 if ((*def1
== NULL
) || (*def2
== NULL
))
3911 while (*def1
!= NULL
) {
3912 while ((*def2
) != NULL
) {
3913 if (xmlRelaxNGCompareNameClasses(*def1
, *def2
) == 0)
3924 * xmlRelaxNGGenerateAttributes:
3925 * @ctxt: a Relax-NG parser context
3926 * @def: the definition definition
3928 * Check if the definition can only generate attributes
3930 * Returns 1 if yes, 0 if no and -1 in case of error.
3933 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt
,
3934 xmlRelaxNGDefinePtr def
)
3936 xmlRelaxNGDefinePtr parent
, cur
, tmp
;
3939 * Don't run that check in case of error. Infinite recursion
3942 if (ctxt
->nbErrors
!= 0)
3947 while (cur
!= NULL
) {
3948 if ((cur
->type
== XML_RELAXNG_ELEMENT
) ||
3949 (cur
->type
== XML_RELAXNG_TEXT
) ||
3950 (cur
->type
== XML_RELAXNG_DATATYPE
) ||
3951 (cur
->type
== XML_RELAXNG_PARAM
) ||
3952 (cur
->type
== XML_RELAXNG_LIST
) ||
3953 (cur
->type
== XML_RELAXNG_VALUE
) ||
3954 (cur
->type
== XML_RELAXNG_EMPTY
))
3956 if ((cur
->type
== XML_RELAXNG_CHOICE
) ||
3957 (cur
->type
== XML_RELAXNG_INTERLEAVE
) ||
3958 (cur
->type
== XML_RELAXNG_GROUP
) ||
3959 (cur
->type
== XML_RELAXNG_ONEORMORE
) ||
3960 (cur
->type
== XML_RELAXNG_ZEROORMORE
) ||
3961 (cur
->type
== XML_RELAXNG_OPTIONAL
) ||
3962 (cur
->type
== XML_RELAXNG_PARENTREF
) ||
3963 (cur
->type
== XML_RELAXNG_EXTERNALREF
) ||
3964 (cur
->type
== XML_RELAXNG_REF
) ||
3965 (cur
->type
== XML_RELAXNG_DEF
)) {
3966 if (cur
->content
!= NULL
) {
3970 while (tmp
!= NULL
) {
3971 tmp
->parent
= parent
;
3979 if (cur
->next
!= NULL
) {
3989 if (cur
->next
!= NULL
) {
3993 } while (cur
!= NULL
);
3999 * xmlRelaxNGGetElements:
4000 * @ctxt: a Relax-NG parser context
4001 * @def: the definition definition
4002 * @eora: gather elements (0), attributes (1) or elements and text (2)
4004 * Compute the list of top elements a definition can generate
4006 * Returns a list of elements or NULL if none was found.
4008 static xmlRelaxNGDefinePtr
*
4009 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt
,
4010 xmlRelaxNGDefinePtr def
, int eora
)
4012 xmlRelaxNGDefinePtr
*ret
= NULL
, parent
, cur
, tmp
;
4017 * Don't run that check in case of error. Infinite recursion
4020 if (ctxt
->nbErrors
!= 0)
4025 while (cur
!= NULL
) {
4026 if (((eora
== 0) && ((cur
->type
== XML_RELAXNG_ELEMENT
) ||
4027 (cur
->type
== XML_RELAXNG_TEXT
))) ||
4028 ((eora
== 1) && (cur
->type
== XML_RELAXNG_ATTRIBUTE
)) ||
4029 ((eora
== 2) && ((cur
->type
== XML_RELAXNG_DATATYPE
) ||
4030 (cur
->type
== XML_RELAXNG_ELEMENT
) ||
4031 (cur
->type
== XML_RELAXNG_LIST
) ||
4032 (cur
->type
== XML_RELAXNG_TEXT
) ||
4033 (cur
->type
== XML_RELAXNG_VALUE
)))) {
4036 ret
= (xmlRelaxNGDefinePtr
*)
4037 xmlMalloc((max
+ 1) * sizeof(xmlRelaxNGDefinePtr
));
4039 xmlRngPErrMemory(ctxt
, "getting element list\n");
4042 } else if (max
<= len
) {
4043 xmlRelaxNGDefinePtr
*temp
;
4046 temp
= xmlRealloc(ret
,
4047 (max
+ 1) * sizeof(xmlRelaxNGDefinePtr
));
4049 xmlRngPErrMemory(ctxt
, "getting element list\n");
4057 } else if ((cur
->type
== XML_RELAXNG_CHOICE
) ||
4058 (cur
->type
== XML_RELAXNG_INTERLEAVE
) ||
4059 (cur
->type
== XML_RELAXNG_GROUP
) ||
4060 (cur
->type
== XML_RELAXNG_ONEORMORE
) ||
4061 (cur
->type
== XML_RELAXNG_ZEROORMORE
) ||
4062 (cur
->type
== XML_RELAXNG_OPTIONAL
) ||
4063 (cur
->type
== XML_RELAXNG_PARENTREF
) ||
4064 (cur
->type
== XML_RELAXNG_REF
) ||
4065 (cur
->type
== XML_RELAXNG_DEF
) ||
4066 (cur
->type
== XML_RELAXNG_EXTERNALREF
)) {
4068 * Don't go within elements or attributes or string values.
4069 * Just gather the element top list
4071 if (cur
->content
!= NULL
) {
4075 while (tmp
!= NULL
) {
4076 tmp
->parent
= parent
;
4084 if (cur
->next
!= NULL
) {
4094 if (cur
->next
!= NULL
) {
4098 } while (cur
!= NULL
);
4104 * xmlRelaxNGCheckChoiceDeterminism:
4105 * @ctxt: a Relax-NG parser context
4106 * @def: the choice definition
4108 * Also used to find indeterministic pattern in choice
4111 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt
,
4112 xmlRelaxNGDefinePtr def
)
4114 xmlRelaxNGDefinePtr
**list
;
4115 xmlRelaxNGDefinePtr cur
;
4116 int nbchild
= 0, i
, j
, ret
;
4117 int is_nullable
= 0;
4118 int is_indeterminist
= 0;
4119 xmlHashTablePtr triage
= NULL
;
4122 if ((def
== NULL
) || (def
->type
!= XML_RELAXNG_CHOICE
))
4125 if (def
->dflags
& IS_PROCESSED
)
4129 * Don't run that check in case of error. Infinite recursion
4132 if (ctxt
->nbErrors
!= 0)
4135 is_nullable
= xmlRelaxNGIsNullable(def
);
4138 while (cur
!= NULL
) {
4143 list
= (xmlRelaxNGDefinePtr
**) xmlMalloc(nbchild
*
4144 sizeof(xmlRelaxNGDefinePtr
4147 xmlRngPErrMemory(ctxt
, "building choice\n");
4152 * a bit strong but safe
4154 if (is_nullable
== 0) {
4155 triage
= xmlHashCreate(10);
4160 while (cur
!= NULL
) {
4161 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 0);
4162 if ((list
[i
] == NULL
) || (list
[i
][0] == NULL
)) {
4164 } else if (is_triable
== 1) {
4165 xmlRelaxNGDefinePtr
*tmp
;
4169 while ((*tmp
!= NULL
) && (is_triable
== 1)) {
4170 if ((*tmp
)->type
== XML_RELAXNG_TEXT
) {
4171 res
= xmlHashAddEntry2(triage
,
4172 BAD_CAST
"#text", NULL
,
4176 } else if (((*tmp
)->type
== XML_RELAXNG_ELEMENT
) &&
4177 ((*tmp
)->name
!= NULL
)) {
4178 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4179 res
= xmlHashAddEntry2(triage
,
4183 res
= xmlHashAddEntry2(triage
,
4184 (*tmp
)->name
, (*tmp
)->ns
,
4188 } else if ((*tmp
)->type
== XML_RELAXNG_ELEMENT
) {
4189 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4190 res
= xmlHashAddEntry2(triage
,
4191 BAD_CAST
"#any", NULL
,
4194 res
= xmlHashAddEntry2(triage
,
4195 BAD_CAST
"#any", (*tmp
)->ns
,
4209 for (i
= 0; i
< nbchild
; i
++) {
4210 if (list
[i
] == NULL
)
4212 for (j
= 0; j
< i
; j
++) {
4213 if (list
[j
] == NULL
)
4215 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, list
[i
], list
[j
]);
4217 is_indeterminist
= 1;
4221 for (i
= 0; i
< nbchild
; i
++) {
4222 if (list
[i
] != NULL
)
4227 if (is_indeterminist
) {
4228 def
->dflags
|= IS_INDETERMINIST
;
4230 if (is_triable
== 1) {
4231 def
->dflags
|= IS_TRIABLE
;
4233 } else if (triage
!= NULL
) {
4234 xmlHashFree(triage
, NULL
);
4236 def
->dflags
|= IS_PROCESSED
;
4240 * xmlRelaxNGCheckGroupAttrs:
4241 * @ctxt: a Relax-NG parser context
4242 * @def: the group definition
4244 * Detects violations of rule 7.3
4247 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt
,
4248 xmlRelaxNGDefinePtr def
)
4250 xmlRelaxNGDefinePtr
**list
;
4251 xmlRelaxNGDefinePtr cur
;
4252 int nbchild
= 0, i
, j
, ret
;
4254 if ((def
== NULL
) ||
4255 ((def
->type
!= XML_RELAXNG_GROUP
) &&
4256 (def
->type
!= XML_RELAXNG_ELEMENT
)))
4259 if (def
->dflags
& IS_PROCESSED
)
4263 * Don't run that check in case of error. Infinite recursion
4266 if (ctxt
->nbErrors
!= 0)
4270 while (cur
!= NULL
) {
4275 while (cur
!= NULL
) {
4280 list
= (xmlRelaxNGDefinePtr
**) xmlMalloc(nbchild
*
4281 sizeof(xmlRelaxNGDefinePtr
4284 xmlRngPErrMemory(ctxt
, "building group\n");
4289 while (cur
!= NULL
) {
4290 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 1);
4295 while (cur
!= NULL
) {
4296 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 1);
4301 for (i
= 0; i
< nbchild
; i
++) {
4302 if (list
[i
] == NULL
)
4304 for (j
= 0; j
< i
; j
++) {
4305 if (list
[j
] == NULL
)
4307 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, list
[i
], list
[j
]);
4309 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_GROUP_ATTR_CONFLICT
,
4310 "Attributes conflicts in group\n", NULL
, NULL
);
4314 for (i
= 0; i
< nbchild
; i
++) {
4315 if (list
[i
] != NULL
)
4320 def
->dflags
|= IS_PROCESSED
;
4324 * xmlRelaxNGComputeInterleaves:
4325 * @def: the interleave definition
4326 * @ctxt: a Relax-NG parser context
4327 * @name: the definition name
4329 * A lot of work for preprocessing interleave definitions
4330 * is potentially needed to get a decent execution speed at runtime
4331 * - trying to get a total order on the element nodes generated
4332 * by the interleaves, order the list of interleave definitions
4333 * following that order.
4334 * - if <text/> is used to handle mixed content, it is better to
4335 * flag this in the define and simplify the runtime checking
4339 xmlRelaxNGComputeInterleaves(void *payload
, void *data
,
4340 const xmlChar
* name ATTRIBUTE_UNUSED
)
4342 xmlRelaxNGDefinePtr def
= (xmlRelaxNGDefinePtr
) payload
;
4343 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
4344 xmlRelaxNGDefinePtr cur
, *tmp
;
4346 xmlRelaxNGPartitionPtr partitions
= NULL
;
4347 xmlRelaxNGInterleaveGroupPtr
*groups
= NULL
;
4348 xmlRelaxNGInterleaveGroupPtr group
;
4353 int is_determinist
= 1;
4356 * Don't run that check in case of error. Infinite recursion
4359 if (ctxt
->nbErrors
!= 0)
4362 #ifdef DEBUG_INTERLEAVE
4363 xmlGenericError(xmlGenericErrorContext
,
4364 "xmlRelaxNGComputeInterleaves(%s)\n", name
);
4367 while (cur
!= NULL
) {
4372 #ifdef DEBUG_INTERLEAVE
4373 xmlGenericError(xmlGenericErrorContext
, " %d child\n", nbchild
);
4375 groups
= (xmlRelaxNGInterleaveGroupPtr
*)
4376 xmlMalloc(nbchild
* sizeof(xmlRelaxNGInterleaveGroupPtr
));
4380 while (cur
!= NULL
) {
4381 groups
[nbgroups
] = (xmlRelaxNGInterleaveGroupPtr
)
4382 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup
));
4383 if (groups
[nbgroups
] == NULL
)
4385 if (cur
->type
== XML_RELAXNG_TEXT
)
4387 groups
[nbgroups
]->rule
= cur
;
4388 groups
[nbgroups
]->defs
= xmlRelaxNGGetElements(ctxt
, cur
, 2);
4389 groups
[nbgroups
]->attrs
= xmlRelaxNGGetElements(ctxt
, cur
, 1);
4393 #ifdef DEBUG_INTERLEAVE
4394 xmlGenericError(xmlGenericErrorContext
, " %d groups\n", nbgroups
);
4398 * Let's check that all rules makes a partitions according to 7.4
4400 partitions
= (xmlRelaxNGPartitionPtr
)
4401 xmlMalloc(sizeof(xmlRelaxNGPartition
));
4402 if (partitions
== NULL
)
4404 memset(partitions
, 0, sizeof(xmlRelaxNGPartition
));
4405 partitions
->nbgroups
= nbgroups
;
4406 partitions
->triage
= xmlHashCreate(nbgroups
);
4407 for (i
= 0; i
< nbgroups
; i
++) {
4409 for (j
= i
+ 1; j
< nbgroups
; j
++) {
4410 if (groups
[j
] == NULL
)
4413 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, group
->defs
,
4416 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_ELEM_TEXT_CONFLICT
,
4417 "Element or text conflicts in interleave\n",
4420 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, group
->attrs
,
4423 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_ATTR_CONFLICT
,
4424 "Attributes conflicts in interleave\n", NULL
,
4429 if ((tmp
!= NULL
) && (*tmp
!= NULL
)) {
4430 while (*tmp
!= NULL
) {
4431 if ((*tmp
)->type
== XML_RELAXNG_TEXT
) {
4432 res
= xmlHashAddEntry2(partitions
->triage
,
4433 BAD_CAST
"#text", NULL
,
4434 (void *) (ptrdiff_t) (i
+ 1));
4436 is_determinist
= -1;
4437 } else if (((*tmp
)->type
== XML_RELAXNG_ELEMENT
) &&
4438 ((*tmp
)->name
!= NULL
)) {
4439 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4440 res
= xmlHashAddEntry2(partitions
->triage
,
4442 (void *) (ptrdiff_t) (i
+ 1));
4444 res
= xmlHashAddEntry2(partitions
->triage
,
4445 (*tmp
)->name
, (*tmp
)->ns
,
4446 (void *) (ptrdiff_t) (i
+ 1));
4448 is_determinist
= -1;
4449 } else if ((*tmp
)->type
== XML_RELAXNG_ELEMENT
) {
4450 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4451 res
= xmlHashAddEntry2(partitions
->triage
,
4452 BAD_CAST
"#any", NULL
,
4453 (void *) (ptrdiff_t) (i
+ 1));
4455 res
= xmlHashAddEntry2(partitions
->triage
,
4456 BAD_CAST
"#any", (*tmp
)->ns
,
4457 (void *) (ptrdiff_t) (i
+ 1));
4458 if ((*tmp
)->nameClass
!= NULL
)
4461 is_determinist
= -1;
4463 is_determinist
= -1;
4471 partitions
->groups
= groups
;
4474 * and save the partition list back in the def
4476 def
->data
= partitions
;
4478 def
->dflags
|= IS_MIXED
;
4479 if (is_determinist
== 1)
4480 partitions
->flags
= IS_DETERMINIST
;
4481 if (is_determinist
== 2)
4482 partitions
->flags
= IS_DETERMINIST
| IS_NEEDCHECK
;
4486 xmlRngPErrMemory(ctxt
, "in interleave computation\n");
4487 if (groups
!= NULL
) {
4488 for (i
= 0; i
< nbgroups
; i
++)
4489 if (groups
[i
] != NULL
) {
4490 if (groups
[i
]->defs
!= NULL
)
4491 xmlFree(groups
[i
]->defs
);
4496 xmlRelaxNGFreePartition(partitions
);
4500 * xmlRelaxNGParseInterleave:
4501 * @ctxt: a Relax-NG parser context
4502 * @node: the data node.
4504 * parse the content of a RelaxNG interleave node.
4506 * Returns the definition pointer or NULL in case of error
4508 static xmlRelaxNGDefinePtr
4509 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4511 xmlRelaxNGDefinePtr def
= NULL
;
4512 xmlRelaxNGDefinePtr last
= NULL
, cur
;
4515 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4519 def
->type
= XML_RELAXNG_INTERLEAVE
;
4521 if (ctxt
->interleaves
== NULL
)
4522 ctxt
->interleaves
= xmlHashCreate(10);
4523 if (ctxt
->interleaves
== NULL
) {
4524 xmlRngPErrMemory(ctxt
, "create interleaves\n");
4528 snprintf(name
, 32, "interleave%d", ctxt
->nbInterleaves
++);
4529 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST name
, def
) < 0) {
4530 xmlRngPErr(ctxt
, node
, XML_RNGP_INTERLEAVE_ADD
,
4531 "Failed to add %s to hash table\n",
4532 (const xmlChar
*) name
, NULL
);
4535 child
= node
->children
;
4536 if (child
== NULL
) {
4537 xmlRngPErr(ctxt
, node
, XML_RNGP_INTERLEAVE_NO_CONTENT
,
4538 "Element interleave is empty\n", NULL
, NULL
);
4540 while (child
!= NULL
) {
4541 if (IS_RELAXNG(child
, "element")) {
4542 cur
= xmlRelaxNGParseElement(ctxt
, child
);
4544 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
4549 def
->content
= last
= cur
;
4555 child
= child
->next
;
4562 * xmlRelaxNGParseInclude:
4563 * @ctxt: a Relax-NG parser context
4564 * @node: the include node
4566 * Integrate the content of an include node in the current grammar
4568 * Returns 0 in case of success or -1 in case of error
4571 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4573 xmlRelaxNGIncludePtr incl
;
4579 xmlRngPErr(ctxt
, node
, XML_RNGP_INCLUDE_EMPTY
,
4580 "Include node has no data\n", NULL
, NULL
);
4583 root
= xmlDocGetRootElement(incl
->doc
);
4585 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY
, "Include document is empty\n",
4589 if (!xmlStrEqual(root
->name
, BAD_CAST
"grammar")) {
4590 xmlRngPErr(ctxt
, node
, XML_RNGP_GRAMMAR_MISSING
,
4591 "Include document root is not a grammar\n", NULL
, NULL
);
4596 * Merge the definition from both the include and the internal list
4598 if (root
->children
!= NULL
) {
4599 tmp
= xmlRelaxNGParseGrammarContent(ctxt
, root
->children
);
4603 if (node
->children
!= NULL
) {
4604 tmp
= xmlRelaxNGParseGrammarContent(ctxt
, node
->children
);
4612 * xmlRelaxNGParseDefine:
4613 * @ctxt: a Relax-NG parser context
4614 * @node: the define node
4616 * parse the content of a RelaxNG define element node.
4618 * Returns 0 in case of success or -1 in case of error
4621 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4625 xmlRelaxNGDefinePtr def
;
4626 const xmlChar
*olddefine
;
4628 name
= xmlGetProp(node
, BAD_CAST
"name");
4630 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_NAME_MISSING
,
4631 "define has no name\n", NULL
, NULL
);
4633 xmlRelaxNGNormExtSpace(name
);
4634 if (xmlValidateNCName(name
, 0)) {
4635 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_DEFINE_NAME
,
4636 "define name '%s' is not an NCName\n", name
, NULL
);
4638 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4643 def
->type
= XML_RELAXNG_DEF
;
4645 if (node
->children
== NULL
) {
4646 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_EMPTY
,
4647 "define has no children\n", NULL
, NULL
);
4649 olddefine
= ctxt
->define
;
4650 ctxt
->define
= name
;
4652 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4653 ctxt
->define
= olddefine
;
4655 if (ctxt
->grammar
->defs
== NULL
)
4656 ctxt
->grammar
->defs
= xmlHashCreate(10);
4657 if (ctxt
->grammar
->defs
== NULL
) {
4658 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_CREATE_FAILED
,
4659 "Could not create definition hash\n", NULL
, NULL
);
4662 tmp
= xmlHashAddEntry(ctxt
->grammar
->defs
, name
, def
);
4664 xmlRelaxNGDefinePtr prev
;
4666 prev
= xmlHashLookup(ctxt
->grammar
->defs
, name
);
4668 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_CREATE_FAILED
,
4669 "Internal error on define aggregation of %s\n",
4673 while (prev
->nextHash
!= NULL
)
4674 prev
= prev
->nextHash
;
4675 prev
->nextHash
= def
;
4684 * xmlRelaxNGParseImportRef:
4685 * @payload: the parser context
4686 * @data: the current grammar
4687 * @name: the reference name
4689 * Import import one references into the current grammar
4692 xmlRelaxNGParseImportRef(void *payload
, void *data
, const xmlChar
*name
) {
4693 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
4694 xmlRelaxNGDefinePtr def
= (xmlRelaxNGDefinePtr
) payload
;
4697 def
->dflags
|= IS_EXTERNAL_REF
;
4699 tmp
= xmlHashAddEntry(ctxt
->grammar
->refs
, name
, def
);
4701 xmlRelaxNGDefinePtr prev
;
4703 prev
= (xmlRelaxNGDefinePtr
)
4704 xmlHashLookup(ctxt
->grammar
->refs
, def
->name
);
4706 if (def
->name
!= NULL
) {
4707 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4708 "Error refs definitions '%s'\n",
4711 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4712 "Error refs definitions\n",
4716 def
->nextHash
= prev
->nextHash
;
4717 prev
->nextHash
= def
;
4723 * xmlRelaxNGParseImportRefs:
4724 * @ctxt: the parser context
4725 * @grammar: the sub grammar
4727 * Import references from the subgrammar into the current grammar
4729 * Returns 0 in case of success, -1 in case of failure
4732 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt
,
4733 xmlRelaxNGGrammarPtr grammar
) {
4734 if ((ctxt
== NULL
) || (grammar
== NULL
) || (ctxt
->grammar
== NULL
))
4736 if (grammar
->refs
== NULL
)
4738 if (ctxt
->grammar
->refs
== NULL
)
4739 ctxt
->grammar
->refs
= xmlHashCreate(10);
4740 if (ctxt
->grammar
->refs
== NULL
) {
4741 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4742 "Could not create references hash\n", NULL
, NULL
);
4745 xmlHashScan(grammar
->refs
, xmlRelaxNGParseImportRef
, ctxt
);
4750 * xmlRelaxNGProcessExternalRef:
4751 * @ctxt: the parser context
4752 * @node: the externalRef node
4754 * Process and compile an externalRef node
4756 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4758 static xmlRelaxNGDefinePtr
4759 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4761 xmlRelaxNGDocumentPtr docu
;
4762 xmlNodePtr root
, tmp
;
4764 int newNs
= 0, oldflags
;
4765 xmlRelaxNGDefinePtr def
;
4769 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4772 def
->type
= XML_RELAXNG_EXTERNALREF
;
4774 if (docu
->content
== NULL
) {
4776 * Then do the parsing for good
4778 root
= xmlDocGetRootElement(docu
->doc
);
4780 xmlRngPErr(ctxt
, node
, XML_RNGP_EXTERNALREF_EMTPY
,
4781 "xmlRelaxNGParse: %s is empty\n", ctxt
->URL
,
4786 * ns transmission rules
4788 ns
= xmlGetProp(root
, BAD_CAST
"ns");
4791 while ((tmp
!= NULL
) && (tmp
->type
== XML_ELEMENT_NODE
)) {
4792 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
4799 xmlSetProp(root
, BAD_CAST
"ns", ns
);
4808 * Parsing to get a precompiled schemas.
4810 oldflags
= ctxt
->flags
;
4811 ctxt
->flags
|= XML_RELAXNG_IN_EXTERNALREF
;
4812 docu
->schema
= xmlRelaxNGParseDocument(ctxt
, root
);
4813 ctxt
->flags
= oldflags
;
4814 if ((docu
->schema
!= NULL
) &&
4815 (docu
->schema
->topgrammar
!= NULL
)) {
4816 docu
->content
= docu
->schema
->topgrammar
->start
;
4817 if (docu
->schema
->topgrammar
->refs
)
4818 xmlRelaxNGParseImportRefs(ctxt
, docu
->schema
->topgrammar
);
4822 * the externalRef may be reused in a different ns context
4825 xmlUnsetProp(root
, BAD_CAST
"ns");
4828 def
->content
= docu
->content
;
4836 * xmlRelaxNGParsePattern:
4837 * @ctxt: a Relax-NG parser context
4838 * @node: the pattern node.
4840 * parse the content of a RelaxNG pattern node.
4842 * Returns the definition pointer or NULL in case of error or if no
4843 * pattern is generated.
4845 static xmlRelaxNGDefinePtr
4846 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4848 xmlRelaxNGDefinePtr def
= NULL
;
4853 if (IS_RELAXNG(node
, "element")) {
4854 def
= xmlRelaxNGParseElement(ctxt
, node
);
4855 } else if (IS_RELAXNG(node
, "attribute")) {
4856 def
= xmlRelaxNGParseAttribute(ctxt
, node
);
4857 } else if (IS_RELAXNG(node
, "empty")) {
4858 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4861 def
->type
= XML_RELAXNG_EMPTY
;
4862 if (node
->children
!= NULL
) {
4863 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_NOT_EMPTY
,
4864 "empty: had a child node\n", NULL
, NULL
);
4866 } else if (IS_RELAXNG(node
, "text")) {
4867 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4870 def
->type
= XML_RELAXNG_TEXT
;
4871 if (node
->children
!= NULL
) {
4872 xmlRngPErr(ctxt
, node
, XML_RNGP_TEXT_HAS_CHILD
,
4873 "text: had a child node\n", NULL
, NULL
);
4875 } else if (IS_RELAXNG(node
, "zeroOrMore")) {
4876 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4879 def
->type
= XML_RELAXNG_ZEROORMORE
;
4880 if (node
->children
== NULL
) {
4881 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4882 "Element %s is empty\n", node
->name
, NULL
);
4885 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4887 } else if (IS_RELAXNG(node
, "oneOrMore")) {
4888 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4891 def
->type
= XML_RELAXNG_ONEORMORE
;
4892 if (node
->children
== NULL
) {
4893 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4894 "Element %s is empty\n", node
->name
, NULL
);
4897 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4899 } else if (IS_RELAXNG(node
, "optional")) {
4900 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4903 def
->type
= XML_RELAXNG_OPTIONAL
;
4904 if (node
->children
== NULL
) {
4905 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4906 "Element %s is empty\n", node
->name
, NULL
);
4909 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4911 } else if (IS_RELAXNG(node
, "choice")) {
4912 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4915 def
->type
= XML_RELAXNG_CHOICE
;
4916 if (node
->children
== NULL
) {
4917 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4918 "Element %s is empty\n", node
->name
, NULL
);
4921 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4923 } else if (IS_RELAXNG(node
, "group")) {
4924 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4927 def
->type
= XML_RELAXNG_GROUP
;
4928 if (node
->children
== NULL
) {
4929 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4930 "Element %s is empty\n", node
->name
, NULL
);
4933 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4935 } else if (IS_RELAXNG(node
, "ref")) {
4936 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4939 def
->type
= XML_RELAXNG_REF
;
4940 def
->name
= xmlGetProp(node
, BAD_CAST
"name");
4941 if (def
->name
== NULL
) {
4942 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NO_NAME
, "ref has no name\n",
4945 xmlRelaxNGNormExtSpace(def
->name
);
4946 if (xmlValidateNCName(def
->name
, 0)) {
4947 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NAME_INVALID
,
4948 "ref name '%s' is not an NCName\n", def
->name
,
4952 if (node
->children
!= NULL
) {
4953 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NOT_EMPTY
, "ref is not empty\n",
4956 if (ctxt
->grammar
->refs
== NULL
)
4957 ctxt
->grammar
->refs
= xmlHashCreate(10);
4958 if (ctxt
->grammar
->refs
== NULL
) {
4959 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4960 "Could not create references hash\n", NULL
, NULL
);
4965 tmp
= xmlHashAddEntry(ctxt
->grammar
->refs
, def
->name
, def
);
4967 xmlRelaxNGDefinePtr prev
;
4969 prev
= (xmlRelaxNGDefinePtr
)
4970 xmlHashLookup(ctxt
->grammar
->refs
, def
->name
);
4972 if (def
->name
!= NULL
) {
4973 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4974 "Error refs definitions '%s'\n",
4977 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4978 "Error refs definitions\n",
4983 def
->nextHash
= prev
->nextHash
;
4984 prev
->nextHash
= def
;
4988 } else if (IS_RELAXNG(node
, "data")) {
4989 def
= xmlRelaxNGParseData(ctxt
, node
);
4990 } else if (IS_RELAXNG(node
, "value")) {
4991 def
= xmlRelaxNGParseValue(ctxt
, node
);
4992 } else if (IS_RELAXNG(node
, "list")) {
4993 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4996 def
->type
= XML_RELAXNG_LIST
;
4997 if (node
->children
== NULL
) {
4998 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4999 "Element %s is empty\n", node
->name
, NULL
);
5002 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
5004 } else if (IS_RELAXNG(node
, "interleave")) {
5005 def
= xmlRelaxNGParseInterleave(ctxt
, node
);
5006 } else if (IS_RELAXNG(node
, "externalRef")) {
5007 def
= xmlRelaxNGProcessExternalRef(ctxt
, node
);
5008 } else if (IS_RELAXNG(node
, "notAllowed")) {
5009 def
= xmlRelaxNGNewDefine(ctxt
, node
);
5012 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
5013 if (node
->children
!= NULL
) {
5014 xmlRngPErr(ctxt
, node
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
5015 "xmlRelaxNGParse: notAllowed element is not empty\n",
5018 } else if (IS_RELAXNG(node
, "grammar")) {
5019 xmlRelaxNGGrammarPtr grammar
, old
;
5020 xmlRelaxNGGrammarPtr oldparent
;
5022 #ifdef DEBUG_GRAMMAR
5023 xmlGenericError(xmlGenericErrorContext
,
5024 "Found <grammar> pattern\n");
5027 oldparent
= ctxt
->parentgrammar
;
5028 old
= ctxt
->grammar
;
5029 ctxt
->parentgrammar
= old
;
5030 grammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
5032 ctxt
->grammar
= old
;
5033 ctxt
->parentgrammar
= oldparent
;
5035 if (grammar
!= NULL
) {
5036 grammar
->next
= old
->next
;
5037 old
->next
= grammar
;
5041 if (grammar
!= NULL
)
5042 def
= grammar
->start
;
5045 } else if (IS_RELAXNG(node
, "parentRef")) {
5046 if (ctxt
->parentgrammar
== NULL
) {
5047 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NO_PARENT
,
5048 "Use of parentRef without a parent grammar\n", NULL
,
5052 def
= xmlRelaxNGNewDefine(ctxt
, node
);
5055 def
->type
= XML_RELAXNG_PARENTREF
;
5056 def
->name
= xmlGetProp(node
, BAD_CAST
"name");
5057 if (def
->name
== NULL
) {
5058 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NO_NAME
,
5059 "parentRef has no name\n", NULL
, NULL
);
5061 xmlRelaxNGNormExtSpace(def
->name
);
5062 if (xmlValidateNCName(def
->name
, 0)) {
5063 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NAME_INVALID
,
5064 "parentRef name '%s' is not an NCName\n",
5068 if (node
->children
!= NULL
) {
5069 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NOT_EMPTY
,
5070 "parentRef is not empty\n", NULL
, NULL
);
5072 if (ctxt
->parentgrammar
->refs
== NULL
)
5073 ctxt
->parentgrammar
->refs
= xmlHashCreate(10);
5074 if (ctxt
->parentgrammar
->refs
== NULL
) {
5075 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_CREATE_FAILED
,
5076 "Could not create references hash\n", NULL
, NULL
);
5078 } else if (def
->name
!= NULL
) {
5082 xmlHashAddEntry(ctxt
->parentgrammar
->refs
, def
->name
, def
);
5084 xmlRelaxNGDefinePtr prev
;
5086 prev
= (xmlRelaxNGDefinePtr
)
5087 xmlHashLookup(ctxt
->parentgrammar
->refs
, def
->name
);
5089 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_CREATE_FAILED
,
5090 "Internal error parentRef definitions '%s'\n",
5094 def
->nextHash
= prev
->nextHash
;
5095 prev
->nextHash
= def
;
5099 } else if (IS_RELAXNG(node
, "mixed")) {
5100 if (node
->children
== NULL
) {
5101 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
, "Mixed is empty\n",
5105 def
= xmlRelaxNGParseInterleave(ctxt
, node
);
5107 xmlRelaxNGDefinePtr tmp
;
5109 if ((def
->content
!= NULL
) && (def
->content
->next
!= NULL
)) {
5110 tmp
= xmlRelaxNGNewDefine(ctxt
, node
);
5112 tmp
->type
= XML_RELAXNG_GROUP
;
5113 tmp
->content
= def
->content
;
5118 tmp
= xmlRelaxNGNewDefine(ctxt
, node
);
5121 tmp
->type
= XML_RELAXNG_TEXT
;
5122 tmp
->next
= def
->content
;
5127 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_CONSTRUCT
,
5128 "Unexpected node %s is not a pattern\n", node
->name
,
5136 * xmlRelaxNGParseAttribute:
5137 * @ctxt: a Relax-NG parser context
5138 * @node: the element node
5140 * parse the content of a RelaxNG attribute node.
5142 * Returns the definition pointer or NULL in case of error.
5144 static xmlRelaxNGDefinePtr
5145 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5147 xmlRelaxNGDefinePtr ret
, cur
;
5151 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5154 ret
->type
= XML_RELAXNG_ATTRIBUTE
;
5155 ret
->parent
= ctxt
->def
;
5156 child
= node
->children
;
5157 if (child
== NULL
) {
5158 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_EMPTY
,
5159 "xmlRelaxNGParseattribute: attribute has no children\n",
5163 old_flags
= ctxt
->flags
;
5164 ctxt
->flags
|= XML_RELAXNG_IN_ATTRIBUTE
;
5165 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5167 child
= child
->next
;
5169 if (child
!= NULL
) {
5170 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5172 switch (cur
->type
) {
5173 case XML_RELAXNG_EMPTY
:
5174 case XML_RELAXNG_NOT_ALLOWED
:
5175 case XML_RELAXNG_TEXT
:
5176 case XML_RELAXNG_ELEMENT
:
5177 case XML_RELAXNG_DATATYPE
:
5178 case XML_RELAXNG_VALUE
:
5179 case XML_RELAXNG_LIST
:
5180 case XML_RELAXNG_REF
:
5181 case XML_RELAXNG_PARENTREF
:
5182 case XML_RELAXNG_EXTERNALREF
:
5183 case XML_RELAXNG_DEF
:
5184 case XML_RELAXNG_ONEORMORE
:
5185 case XML_RELAXNG_ZEROORMORE
:
5186 case XML_RELAXNG_OPTIONAL
:
5187 case XML_RELAXNG_CHOICE
:
5188 case XML_RELAXNG_GROUP
:
5189 case XML_RELAXNG_INTERLEAVE
:
5190 case XML_RELAXNG_ATTRIBUTE
:
5194 case XML_RELAXNG_START
:
5195 case XML_RELAXNG_PARAM
:
5196 case XML_RELAXNG_EXCEPT
:
5197 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_CONTENT
,
5198 "attribute has invalid content\n", NULL
,
5201 case XML_RELAXNG_NOOP
:
5202 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_NOOP
,
5203 "RNG Internal error, noop found in attribute\n",
5208 child
= child
->next
;
5210 if (child
!= NULL
) {
5211 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_CHILDREN
,
5212 "attribute has multiple children\n", NULL
, NULL
);
5214 ctxt
->flags
= old_flags
;
5219 * xmlRelaxNGParseExceptNameClass:
5220 * @ctxt: a Relax-NG parser context
5221 * @node: the except node
5222 * @attr: 1 if within an attribute, 0 if within an element
5224 * parse the content of a RelaxNG nameClass node.
5226 * Returns the definition pointer or NULL in case of error.
5228 static xmlRelaxNGDefinePtr
5229 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt
,
5230 xmlNodePtr node
, int attr
)
5232 xmlRelaxNGDefinePtr ret
, cur
, last
= NULL
;
5235 if (!IS_RELAXNG(node
, "except")) {
5236 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_MISSING
,
5237 "Expecting an except node\n", NULL
, NULL
);
5240 if (node
->next
!= NULL
) {
5241 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_MULTIPLE
,
5242 "exceptNameClass allows only a single except node\n",
5245 if (node
->children
== NULL
) {
5246 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_EMPTY
, "except has no content\n",
5251 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5254 ret
->type
= XML_RELAXNG_EXCEPT
;
5255 child
= node
->children
;
5256 while (child
!= NULL
) {
5257 cur
= xmlRelaxNGNewDefine(ctxt
, child
);
5261 cur
->type
= XML_RELAXNG_ATTRIBUTE
;
5263 cur
->type
= XML_RELAXNG_ELEMENT
;
5265 if (xmlRelaxNGParseNameClass(ctxt
, child
, cur
) != NULL
) {
5273 child
= child
->next
;
5280 * xmlRelaxNGParseNameClass:
5281 * @ctxt: a Relax-NG parser context
5282 * @node: the nameClass node
5283 * @def: the current definition
5285 * parse the content of a RelaxNG nameClass node.
5287 * Returns the definition pointer or NULL in case of error.
5289 static xmlRelaxNGDefinePtr
5290 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
,
5291 xmlRelaxNGDefinePtr def
)
5293 xmlRelaxNGDefinePtr ret
, tmp
;
5297 if ((IS_RELAXNG(node
, "name")) || (IS_RELAXNG(node
, "anyName")) ||
5298 (IS_RELAXNG(node
, "nsName"))) {
5299 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
5300 (def
->type
!= XML_RELAXNG_ATTRIBUTE
)) {
5301 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5305 if (ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
)
5306 ret
->type
= XML_RELAXNG_ATTRIBUTE
;
5308 ret
->type
= XML_RELAXNG_ELEMENT
;
5311 if (IS_RELAXNG(node
, "name")) {
5312 val
= xmlNodeGetContent(node
);
5313 xmlRelaxNGNormExtSpace(val
);
5314 if (xmlValidateNCName(val
, 0)) {
5315 if (node
->parent
!= NULL
)
5316 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NAME
,
5317 "Element %s name '%s' is not an NCName\n",
5318 node
->parent
->name
, val
);
5320 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NAME
,
5321 "name '%s' is not an NCName\n",
5325 val
= xmlGetProp(node
, BAD_CAST
"ns");
5327 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5329 (xmlStrEqual(val
, BAD_CAST
"http://www.w3.org/2000/xmlns"))) {
5330 xmlRngPErr(ctxt
, node
, XML_RNGP_XML_NS
,
5331 "Attribute with namespace '%s' is not allowed\n",
5334 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5336 (val
[0] == 0) && (xmlStrEqual(ret
->name
, BAD_CAST
"xmlns"))) {
5337 xmlRngPErr(ctxt
, node
, XML_RNGP_XMLNS_NAME
,
5338 "Attribute with QName 'xmlns' is not allowed\n",
5341 } else if (IS_RELAXNG(node
, "anyName")) {
5344 if (node
->children
!= NULL
) {
5346 xmlRelaxNGParseExceptNameClass(ctxt
, node
->children
,
5348 XML_RELAXNG_ATTRIBUTE
));
5350 } else if (IS_RELAXNG(node
, "nsName")) {
5352 ret
->ns
= xmlGetProp(node
, BAD_CAST
"ns");
5353 if (ret
->ns
== NULL
) {
5354 xmlRngPErr(ctxt
, node
, XML_RNGP_NSNAME_NO_NS
,
5355 "nsName has no ns attribute\n", NULL
, NULL
);
5357 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5358 (ret
->ns
!= NULL
) &&
5360 (ret
->ns
, BAD_CAST
"http://www.w3.org/2000/xmlns"))) {
5361 xmlRngPErr(ctxt
, node
, XML_RNGP_XML_NS
,
5362 "Attribute with namespace '%s' is not allowed\n",
5365 if (node
->children
!= NULL
) {
5367 xmlRelaxNGParseExceptNameClass(ctxt
, node
->children
,
5369 XML_RELAXNG_ATTRIBUTE
));
5371 } else if (IS_RELAXNG(node
, "choice")) {
5373 xmlRelaxNGDefinePtr last
= NULL
;
5375 if (def
->type
== XML_RELAXNG_CHOICE
) {
5378 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5382 ret
->type
= XML_RELAXNG_CHOICE
;
5385 if (node
->children
== NULL
) {
5386 xmlRngPErr(ctxt
, node
, XML_RNGP_CHOICE_EMPTY
,
5387 "Element choice is empty\n", NULL
, NULL
);
5390 child
= node
->children
;
5391 while (child
!= NULL
) {
5392 tmp
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5401 child
= child
->next
;
5405 xmlRngPErr(ctxt
, node
, XML_RNGP_CHOICE_CONTENT
,
5406 "expecting name, anyName, nsName or choice : got %s\n",
5407 (node
== NULL
? (const xmlChar
*) "nothing" : node
->name
),
5412 if (def
->nameClass
== NULL
) {
5413 def
->nameClass
= ret
;
5415 tmp
= def
->nameClass
;
5416 while (tmp
->next
!= NULL
) {
5426 * xmlRelaxNGParseElement:
5427 * @ctxt: a Relax-NG parser context
5428 * @node: the element node
5430 * parse the content of a RelaxNG element node.
5432 * Returns the definition pointer or NULL in case of error.
5434 static xmlRelaxNGDefinePtr
5435 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5437 xmlRelaxNGDefinePtr ret
, cur
, last
;
5439 const xmlChar
*olddefine
;
5441 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5444 ret
->type
= XML_RELAXNG_ELEMENT
;
5445 ret
->parent
= ctxt
->def
;
5446 child
= node
->children
;
5447 if (child
== NULL
) {
5448 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_EMPTY
,
5449 "xmlRelaxNGParseElement: element has no children\n",
5453 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5455 child
= child
->next
;
5457 if (child
== NULL
) {
5458 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NO_CONTENT
,
5459 "xmlRelaxNGParseElement: element has no content\n",
5463 olddefine
= ctxt
->define
;
5464 ctxt
->define
= NULL
;
5466 while (child
!= NULL
) {
5467 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5470 switch (cur
->type
) {
5471 case XML_RELAXNG_EMPTY
:
5472 case XML_RELAXNG_NOT_ALLOWED
:
5473 case XML_RELAXNG_TEXT
:
5474 case XML_RELAXNG_ELEMENT
:
5475 case XML_RELAXNG_DATATYPE
:
5476 case XML_RELAXNG_VALUE
:
5477 case XML_RELAXNG_LIST
:
5478 case XML_RELAXNG_REF
:
5479 case XML_RELAXNG_PARENTREF
:
5480 case XML_RELAXNG_EXTERNALREF
:
5481 case XML_RELAXNG_DEF
:
5482 case XML_RELAXNG_ZEROORMORE
:
5483 case XML_RELAXNG_ONEORMORE
:
5484 case XML_RELAXNG_OPTIONAL
:
5485 case XML_RELAXNG_CHOICE
:
5486 case XML_RELAXNG_GROUP
:
5487 case XML_RELAXNG_INTERLEAVE
:
5489 ret
->content
= last
= cur
;
5491 if ((last
->type
== XML_RELAXNG_ELEMENT
) &&
5492 (ret
->content
== last
)) {
5493 ret
->content
= xmlRelaxNGNewDefine(ctxt
, node
);
5494 if (ret
->content
!= NULL
) {
5495 ret
->content
->type
= XML_RELAXNG_GROUP
;
5496 ret
->content
->content
= last
;
5498 ret
->content
= last
;
5505 case XML_RELAXNG_ATTRIBUTE
:
5506 cur
->next
= ret
->attrs
;
5509 case XML_RELAXNG_START
:
5510 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5511 "RNG Internal error, start found in element\n",
5514 case XML_RELAXNG_PARAM
:
5515 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5516 "RNG Internal error, param found in element\n",
5519 case XML_RELAXNG_EXCEPT
:
5520 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5521 "RNG Internal error, except found in element\n",
5524 case XML_RELAXNG_NOOP
:
5525 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5526 "RNG Internal error, noop found in element\n",
5531 child
= child
->next
;
5533 ctxt
->define
= olddefine
;
5538 * xmlRelaxNGParsePatterns:
5539 * @ctxt: a Relax-NG parser context
5540 * @nodes: list of nodes
5541 * @group: use an implicit <group> for elements
5543 * parse the content of a RelaxNG start node.
5545 * Returns the definition pointer or NULL in case of error.
5547 static xmlRelaxNGDefinePtr
5548 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
,
5551 xmlRelaxNGDefinePtr def
= NULL
, last
= NULL
, cur
, parent
;
5554 while (nodes
!= NULL
) {
5555 if (IS_RELAXNG(nodes
, "element")) {
5556 cur
= xmlRelaxNGParseElement(ctxt
, nodes
);
5562 if ((group
== 1) && (def
->type
== XML_RELAXNG_ELEMENT
) &&
5564 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5567 def
->type
= XML_RELAXNG_GROUP
;
5568 def
->content
= last
;
5573 cur
->parent
= parent
;
5575 cur
= xmlRelaxNGParsePattern(ctxt
, nodes
);
5585 nodes
= nodes
->next
;
5591 * xmlRelaxNGParseStart:
5592 * @ctxt: a Relax-NG parser context
5593 * @nodes: start children nodes
5595 * parse the content of a RelaxNG start node.
5597 * Returns 0 in case of success, -1 in case of error
5600 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
5603 xmlRelaxNGDefinePtr def
= NULL
, last
;
5605 if (nodes
== NULL
) {
5606 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
, "start has no children\n",
5610 if (IS_RELAXNG(nodes
, "empty")) {
5611 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5614 def
->type
= XML_RELAXNG_EMPTY
;
5615 if (nodes
->children
!= NULL
) {
5616 xmlRngPErr(ctxt
, nodes
, XML_RNGP_EMPTY_CONTENT
,
5617 "element empty is not empty\n", NULL
, NULL
);
5619 } else if (IS_RELAXNG(nodes
, "notAllowed")) {
5620 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5623 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
5624 if (nodes
->children
!= NULL
) {
5625 xmlRngPErr(ctxt
, nodes
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
5626 "element notAllowed is not empty\n", NULL
, NULL
);
5629 def
= xmlRelaxNGParsePatterns(ctxt
, nodes
, 1);
5631 if (ctxt
->grammar
->start
!= NULL
) {
5632 last
= ctxt
->grammar
->start
;
5633 while (last
->next
!= NULL
)
5637 ctxt
->grammar
->start
= def
;
5639 nodes
= nodes
->next
;
5640 if (nodes
!= NULL
) {
5641 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_CONTENT
,
5642 "start more than one children\n", NULL
, NULL
);
5649 * xmlRelaxNGParseGrammarContent:
5650 * @ctxt: a Relax-NG parser context
5651 * @nodes: grammar children nodes
5653 * parse the content of a RelaxNG grammar node.
5655 * Returns 0 in case of success, -1 in case of error
5658 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
5663 if (nodes
== NULL
) {
5664 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_EMPTY
,
5665 "grammar has no children\n", NULL
, NULL
);
5668 while (nodes
!= NULL
) {
5669 if (IS_RELAXNG(nodes
, "start")) {
5670 if (nodes
->children
== NULL
) {
5671 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
,
5672 "start has no children\n", NULL
, NULL
);
5674 tmp
= xmlRelaxNGParseStart(ctxt
, nodes
->children
);
5678 } else if (IS_RELAXNG(nodes
, "define")) {
5679 tmp
= xmlRelaxNGParseDefine(ctxt
, nodes
);
5682 } else if (IS_RELAXNG(nodes
, "include")) {
5683 tmp
= xmlRelaxNGParseInclude(ctxt
, nodes
);
5687 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
5688 "grammar has unexpected child %s\n", nodes
->name
,
5692 nodes
= nodes
->next
;
5698 * xmlRelaxNGCheckReference:
5700 * @ctxt: a Relax-NG parser context
5701 * @name: the name associated to the defines
5703 * Applies the 4.17. combine attribute rule for all the define
5704 * element of a given grammar using the same name.
5707 xmlRelaxNGCheckReference(void *payload
, void *data
, const xmlChar
* name
)
5709 xmlRelaxNGDefinePtr ref
= (xmlRelaxNGDefinePtr
) payload
;
5710 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
5711 xmlRelaxNGGrammarPtr grammar
;
5712 xmlRelaxNGDefinePtr def
, cur
;
5715 * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5717 if (ref
->dflags
& IS_EXTERNAL_REF
)
5720 grammar
= ctxt
->grammar
;
5721 if (grammar
== NULL
) {
5722 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5723 "Internal error: no grammar in CheckReference %s\n",
5727 if (ref
->content
!= NULL
) {
5728 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5729 "Internal error: reference has content in CheckReference %s\n",
5733 if (grammar
->defs
!= NULL
) {
5734 def
= xmlHashLookup(grammar
->defs
, name
);
5737 while (cur
!= NULL
) {
5739 cur
= cur
->nextHash
;
5742 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5743 "Reference %s has no matching definition\n", name
,
5747 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5748 "Reference %s has no matching definition\n", name
,
5754 * xmlRelaxNGCheckCombine:
5755 * @define: the define(s) list
5756 * @ctxt: a Relax-NG parser context
5757 * @name: the name associated to the defines
5759 * Applies the 4.17. combine attribute rule for all the define
5760 * element of a given grammar using the same name.
5763 xmlRelaxNGCheckCombine(void *payload
, void *data
, const xmlChar
* name
)
5765 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) payload
;
5766 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
5768 int choiceOrInterleave
= -1;
5770 xmlRelaxNGDefinePtr cur
, last
, tmp
, tmp2
;
5772 if (define
->nextHash
== NULL
)
5775 while (cur
!= NULL
) {
5776 combine
= xmlGetProp(cur
->node
, BAD_CAST
"combine");
5777 if (combine
!= NULL
) {
5778 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5779 if (choiceOrInterleave
== -1)
5780 choiceOrInterleave
= 1;
5781 else if (choiceOrInterleave
== 0) {
5782 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5783 "Defines for %s use both 'choice' and 'interleave'\n",
5786 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5787 if (choiceOrInterleave
== -1)
5788 choiceOrInterleave
= 0;
5789 else if (choiceOrInterleave
== 1) {
5790 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5791 "Defines for %s use both 'choice' and 'interleave'\n",
5795 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5796 "Defines for %s use unknown combine value '%s''\n",
5804 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_NEED_COMBINE
,
5805 "Some defines for %s needs the combine attribute\n",
5810 cur
= cur
->nextHash
;
5813 xmlGenericError(xmlGenericErrorContext
,
5814 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5815 name
, choiceOrInterleave
);
5817 if (choiceOrInterleave
== -1)
5818 choiceOrInterleave
= 0;
5819 cur
= xmlRelaxNGNewDefine(ctxt
, define
->node
);
5822 if (choiceOrInterleave
== 0)
5823 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5825 cur
->type
= XML_RELAXNG_CHOICE
;
5828 while (tmp
!= NULL
) {
5829 if (tmp
->content
!= NULL
) {
5830 if (tmp
->content
->next
!= NULL
) {
5832 * we need first to create a wrapper.
5834 tmp2
= xmlRelaxNGNewDefine(ctxt
, tmp
->content
->node
);
5837 tmp2
->type
= XML_RELAXNG_GROUP
;
5838 tmp2
->content
= tmp
->content
;
5840 tmp2
= tmp
->content
;
5843 cur
->content
= tmp2
;
5850 tmp
= tmp
->nextHash
;
5852 define
->content
= cur
;
5853 if (choiceOrInterleave
== 0) {
5854 if (ctxt
->interleaves
== NULL
)
5855 ctxt
->interleaves
= xmlHashCreate(10);
5856 if (ctxt
->interleaves
== NULL
) {
5857 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5858 "Failed to create interleaves hash table\n", NULL
,
5863 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5864 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5866 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5867 "Failed to add %s to hash table\n",
5868 (const xmlChar
*) tmpname
, NULL
);
5875 * xmlRelaxNGCombineStart:
5876 * @ctxt: a Relax-NG parser context
5877 * @grammar: the grammar
5879 * Applies the 4.17. combine rule for all the start
5880 * element of a given grammar.
5883 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt
,
5884 xmlRelaxNGGrammarPtr grammar
)
5886 xmlRelaxNGDefinePtr starts
;
5888 int choiceOrInterleave
= -1;
5890 xmlRelaxNGDefinePtr cur
;
5892 starts
= grammar
->start
;
5893 if ((starts
== NULL
) || (starts
->next
== NULL
))
5896 while (cur
!= NULL
) {
5897 if ((cur
->node
== NULL
) || (cur
->node
->parent
== NULL
) ||
5898 (!xmlStrEqual(cur
->node
->parent
->name
, BAD_CAST
"start"))) {
5900 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_MISSING
,
5901 "Internal error: start element not found\n", NULL
,
5904 combine
= xmlGetProp(cur
->node
->parent
, BAD_CAST
"combine");
5907 if (combine
!= NULL
) {
5908 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5909 if (choiceOrInterleave
== -1)
5910 choiceOrInterleave
= 1;
5911 else if (choiceOrInterleave
== 0) {
5912 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5913 "<start> use both 'choice' and 'interleave'\n",
5916 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5917 if (choiceOrInterleave
== -1)
5918 choiceOrInterleave
= 0;
5919 else if (choiceOrInterleave
== 1) {
5920 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5921 "<start> use both 'choice' and 'interleave'\n",
5925 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5926 "<start> uses unknown combine value '%s''\n",
5934 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NEED_COMBINE
,
5935 "Some <start> element miss the combine attribute\n",
5943 xmlGenericError(xmlGenericErrorContext
,
5944 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5945 choiceOrInterleave
);
5947 if (choiceOrInterleave
== -1)
5948 choiceOrInterleave
= 0;
5949 cur
= xmlRelaxNGNewDefine(ctxt
, starts
->node
);
5952 if (choiceOrInterleave
== 0)
5953 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5955 cur
->type
= XML_RELAXNG_CHOICE
;
5956 cur
->content
= grammar
->start
;
5957 grammar
->start
= cur
;
5958 if (choiceOrInterleave
== 0) {
5959 if (ctxt
->interleaves
== NULL
)
5960 ctxt
->interleaves
= xmlHashCreate(10);
5961 if (ctxt
->interleaves
== NULL
) {
5962 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5963 "Failed to create interleaves hash table\n", NULL
,
5968 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5969 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5971 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5972 "Failed to add %s to hash table\n",
5973 (const xmlChar
*) tmpname
, NULL
);
5980 * xmlRelaxNGCheckCycles:
5981 * @ctxt: a Relax-NG parser context
5982 * @nodes: grammar children nodes
5983 * @depth: the counter
5987 * Returns 0 if check passed, and -1 in case of error
5990 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt
,
5991 xmlRelaxNGDefinePtr cur
, int depth
)
5995 while ((ret
== 0) && (cur
!= NULL
)) {
5996 if ((cur
->type
== XML_RELAXNG_REF
) ||
5997 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
5998 if (cur
->depth
== -1) {
6000 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
6002 } else if (depth
== cur
->depth
) {
6003 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_CYCLE
,
6004 "Detected a cycle in %s references\n",
6008 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6009 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
+ 1);
6011 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
6019 * xmlRelaxNGTryUnlink:
6020 * @ctxt: a Relax-NG parser context
6021 * @cur: the definition to unlink
6022 * @parent: the parent definition
6023 * @prev: the previous sibling definition
6025 * Try to unlink a definition. If not possible make it a NOOP
6027 * Returns the new prev definition
6029 static xmlRelaxNGDefinePtr
6030 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
6031 xmlRelaxNGDefinePtr cur
,
6032 xmlRelaxNGDefinePtr parent
, xmlRelaxNGDefinePtr prev
)
6035 prev
->next
= cur
->next
;
6037 if (parent
!= NULL
) {
6038 if (parent
->content
== cur
)
6039 parent
->content
= cur
->next
;
6040 else if (parent
->attrs
== cur
)
6041 parent
->attrs
= cur
->next
;
6042 else if (parent
->nameClass
== cur
)
6043 parent
->nameClass
= cur
->next
;
6045 cur
->type
= XML_RELAXNG_NOOP
;
6053 * xmlRelaxNGSimplify:
6054 * @ctxt: a Relax-NG parser context
6055 * @nodes: grammar children nodes
6057 * Check for simplification of empty and notAllowed
6060 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt
,
6061 xmlRelaxNGDefinePtr cur
, xmlRelaxNGDefinePtr parent
)
6063 xmlRelaxNGDefinePtr prev
= NULL
;
6065 while (cur
!= NULL
) {
6066 if ((cur
->type
== XML_RELAXNG_REF
) ||
6067 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6068 if (cur
->depth
!= -3) {
6070 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6072 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6073 cur
->parent
= parent
;
6074 if ((parent
!= NULL
) &&
6075 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6076 (parent
->type
== XML_RELAXNG_LIST
) ||
6077 (parent
->type
== XML_RELAXNG_GROUP
) ||
6078 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6079 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6080 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6081 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6084 if ((parent
!= NULL
) && (parent
->type
== XML_RELAXNG_CHOICE
)) {
6085 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6088 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6089 cur
->parent
= parent
;
6090 if ((parent
!= NULL
) &&
6091 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6092 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6093 parent
->type
= XML_RELAXNG_EMPTY
;
6096 if ((parent
!= NULL
) &&
6097 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6098 (parent
->type
== XML_RELAXNG_INTERLEAVE
))) {
6099 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6103 cur
->parent
= parent
;
6104 if (cur
->content
!= NULL
)
6105 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6106 if ((cur
->type
!= XML_RELAXNG_VALUE
) && (cur
->attrs
!= NULL
))
6107 xmlRelaxNGSimplify(ctxt
, cur
->attrs
, cur
);
6108 if (cur
->nameClass
!= NULL
)
6109 xmlRelaxNGSimplify(ctxt
, cur
->nameClass
, cur
);
6111 * On Elements, try to move attribute only generating rules on
6114 if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6116 xmlRelaxNGDefinePtr tmp
, pre
;
6118 while (cur
->content
!= NULL
) {
6120 xmlRelaxNGGenerateAttributes(ctxt
, cur
->content
);
6121 if (attronly
== 1) {
6123 * migrate cur->content to attrs
6126 cur
->content
= tmp
->next
;
6127 tmp
->next
= cur
->attrs
;
6131 * cur->content can generate elements or text
6137 while ((pre
!= NULL
) && (pre
->next
!= NULL
)) {
6139 attronly
= xmlRelaxNGGenerateAttributes(ctxt
, tmp
);
6140 if (attronly
== 1) {
6142 * migrate tmp to attrs
6144 pre
->next
= tmp
->next
;
6145 tmp
->next
= cur
->attrs
;
6153 * This may result in a simplification
6155 if ((cur
->type
== XML_RELAXNG_GROUP
) ||
6156 (cur
->type
== XML_RELAXNG_INTERLEAVE
)) {
6157 if (cur
->content
== NULL
)
6158 cur
->type
= XML_RELAXNG_EMPTY
;
6159 else if (cur
->content
->next
== NULL
) {
6160 if ((parent
== NULL
) && (prev
== NULL
)) {
6161 cur
->type
= XML_RELAXNG_NOOP
;
6162 } else if (prev
== NULL
) {
6163 parent
->content
= cur
->content
;
6164 cur
->content
->next
= cur
->next
;
6167 cur
->content
->next
= cur
->next
;
6168 prev
->next
= cur
->content
;
6174 * the current node may have been transformed back
6176 if ((cur
->type
== XML_RELAXNG_EXCEPT
) &&
6177 (cur
->content
!= NULL
) &&
6178 (cur
->content
->type
== XML_RELAXNG_NOT_ALLOWED
)) {
6179 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6180 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6181 if ((parent
!= NULL
) &&
6182 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6183 (parent
->type
== XML_RELAXNG_LIST
) ||
6184 (parent
->type
== XML_RELAXNG_GROUP
) ||
6185 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6186 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6187 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6188 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6191 if ((parent
!= NULL
) &&
6192 (parent
->type
== XML_RELAXNG_CHOICE
)) {
6193 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6196 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6197 if ((parent
!= NULL
) &&
6198 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6199 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6200 parent
->type
= XML_RELAXNG_EMPTY
;
6203 if ((parent
!= NULL
) &&
6204 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6205 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6206 (parent
->type
== XML_RELAXNG_CHOICE
))) {
6207 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6219 * xmlRelaxNGGroupContentType:
6220 * @ct1: the first content type
6221 * @ct2: the second content type
6223 * Try to group 2 content types
6225 * Returns the content type
6227 static xmlRelaxNGContentType
6228 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1
,
6229 xmlRelaxNGContentType ct2
)
6231 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6232 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6233 return (XML_RELAXNG_CONTENT_ERROR
);
6234 if (ct1
== XML_RELAXNG_CONTENT_EMPTY
)
6236 if (ct2
== XML_RELAXNG_CONTENT_EMPTY
)
6238 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) &&
6239 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6240 return (XML_RELAXNG_CONTENT_COMPLEX
);
6241 return (XML_RELAXNG_CONTENT_ERROR
);
6245 * xmlRelaxNGMaxContentType:
6246 * @ct1: the first content type
6247 * @ct2: the second content type
6249 * Compute the max content-type
6251 * Returns the content type
6253 static xmlRelaxNGContentType
6254 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1
,
6255 xmlRelaxNGContentType ct2
)
6257 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6258 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6259 return (XML_RELAXNG_CONTENT_ERROR
);
6260 if ((ct1
== XML_RELAXNG_CONTENT_SIMPLE
) ||
6261 (ct2
== XML_RELAXNG_CONTENT_SIMPLE
))
6262 return (XML_RELAXNG_CONTENT_SIMPLE
);
6263 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) ||
6264 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6265 return (XML_RELAXNG_CONTENT_COMPLEX
);
6266 return (XML_RELAXNG_CONTENT_EMPTY
);
6270 * xmlRelaxNGCheckRules:
6271 * @ctxt: a Relax-NG parser context
6272 * @cur: the current definition
6273 * @flags: some accumulated flags
6274 * @ptype: the parent type
6276 * Check for rules in section 7.1 and 7.2
6278 * Returns the content type of @cur
6280 static xmlRelaxNGContentType
6281 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt
,
6282 xmlRelaxNGDefinePtr cur
, int flags
,
6283 xmlRelaxNGType ptype
)
6286 xmlRelaxNGContentType ret
, tmp
, val
= XML_RELAXNG_CONTENT_EMPTY
;
6288 while (cur
!= NULL
) {
6289 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6290 if ((cur
->type
== XML_RELAXNG_REF
) ||
6291 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6293 * This should actually be caught by list//element(ref) at the
6294 * element boundaries, c.f. Bug #159968 local refs are dropped
6298 if (flags
& XML_RELAXNG_IN_LIST
) {
6299 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_REF
,
6300 "Found forbidden pattern list//ref\n", NULL
,
6304 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6305 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_REF
,
6306 "Found forbidden pattern data/except//ref\n",
6309 if (cur
->content
== NULL
) {
6310 if (cur
->type
== XML_RELAXNG_PARENTREF
)
6311 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6312 "Internal found no define for parent refs\n",
6315 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6316 "Internal found no define for ref %s\n",
6317 (cur
->name
? cur
->name
: BAD_CAST
"null"), NULL
);
6319 if (cur
->depth
> -4) {
6321 ret
= xmlRelaxNGCheckRules(ctxt
, cur
->content
,
6323 cur
->depth
= ret
- 15;
6324 } else if (cur
->depth
== -4) {
6325 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6327 ret
= (xmlRelaxNGContentType
) (cur
->depth
+ 15);
6329 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6331 * The 7.3 Attribute derivation rule for groups is plugged there
6333 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6334 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6335 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ELEM
,
6336 "Found forbidden pattern data/except//element(ref)\n",
6339 if (flags
& XML_RELAXNG_IN_LIST
) {
6340 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ELEM
,
6341 "Found forbidden pattern list//element(ref)\n",
6344 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6345 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6346 "Found forbidden pattern attribute//element(ref)\n",
6349 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6350 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6351 "Found forbidden pattern attribute//element(ref)\n",
6355 * reset since in the simple form elements are only child
6360 xmlRelaxNGCheckRules(ctxt
, cur
->attrs
, nflags
, cur
->type
);
6361 if (ret
!= XML_RELAXNG_CONTENT_EMPTY
) {
6362 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_EMPTY
,
6363 "Element %s attributes have a content type error\n",
6367 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6369 if (ret
== XML_RELAXNG_CONTENT_ERROR
) {
6370 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_ERROR
,
6371 "Element %s has a content type error\n",
6374 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6376 } else if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
6377 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6378 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ATTR
,
6379 "Found forbidden pattern attribute//attribute\n",
6382 if (flags
& XML_RELAXNG_IN_LIST
) {
6383 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ATTR
,
6384 "Found forbidden pattern list//attribute\n",
6387 if (flags
& XML_RELAXNG_IN_OOMGROUP
) {
6388 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_GROUP_ATTR
,
6389 "Found forbidden pattern oneOrMore//group//attribute\n",
6392 if (flags
& XML_RELAXNG_IN_OOMINTERLEAVE
) {
6393 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR
,
6394 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6397 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6398 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ATTR
,
6399 "Found forbidden pattern data/except//attribute\n",
6402 if (flags
& XML_RELAXNG_IN_START
) {
6403 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ATTR
,
6404 "Found forbidden pattern start//attribute\n",
6407 if ((!(flags
& XML_RELAXNG_IN_ONEORMORE
))
6408 && cur
->name
== NULL
6409 /* following is checking alternative name class readiness
6410 in case it went the "choice" route */
6411 && cur
->nameClass
== NULL
) {
6412 if (cur
->ns
== NULL
) {
6413 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ANYNAME_ATTR_ANCESTOR
,
6414 "Found anyName attribute without oneOrMore ancestor\n",
6417 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NSNAME_ATTR_ANCESTOR
,
6418 "Found nsName attribute without oneOrMore ancestor\n",
6422 nflags
= flags
| XML_RELAXNG_IN_ATTRIBUTE
;
6423 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
, cur
->type
);
6424 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6425 } else if ((cur
->type
== XML_RELAXNG_ONEORMORE
) ||
6426 (cur
->type
== XML_RELAXNG_ZEROORMORE
)) {
6427 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6428 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE
,
6429 "Found forbidden pattern data/except//oneOrMore\n",
6432 if (flags
& XML_RELAXNG_IN_START
) {
6433 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ONEMORE
,
6434 "Found forbidden pattern start//oneOrMore\n",
6437 nflags
= flags
| XML_RELAXNG_IN_ONEORMORE
;
6439 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6441 ret
= xmlRelaxNGGroupContentType(ret
, ret
);
6442 } else if (cur
->type
== XML_RELAXNG_LIST
) {
6443 if (flags
& XML_RELAXNG_IN_LIST
) {
6444 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_LIST
,
6445 "Found forbidden pattern list//list\n", NULL
,
6448 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6449 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_LIST
,
6450 "Found forbidden pattern data/except//list\n",
6453 if (flags
& XML_RELAXNG_IN_START
) {
6454 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_LIST
,
6455 "Found forbidden pattern start//list\n", NULL
,
6458 nflags
= flags
| XML_RELAXNG_IN_LIST
;
6460 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6462 } else if (cur
->type
== XML_RELAXNG_GROUP
) {
6463 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6464 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_GROUP
,
6465 "Found forbidden pattern data/except//group\n",
6468 if (flags
& XML_RELAXNG_IN_START
) {
6469 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_GROUP
,
6470 "Found forbidden pattern start//group\n", NULL
,
6473 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6474 nflags
= flags
| XML_RELAXNG_IN_OOMGROUP
;
6478 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6481 * The 7.3 Attribute derivation rule for groups is plugged there
6483 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6484 } else if (cur
->type
== XML_RELAXNG_INTERLEAVE
) {
6485 if (flags
& XML_RELAXNG_IN_LIST
) {
6486 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_INTERLEAVE
,
6487 "Found forbidden pattern list//interleave\n",
6490 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6491 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6492 "Found forbidden pattern data/except//interleave\n",
6495 if (flags
& XML_RELAXNG_IN_START
) {
6496 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6497 "Found forbidden pattern start//interleave\n",
6500 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6501 nflags
= flags
| XML_RELAXNG_IN_OOMINTERLEAVE
;
6505 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6507 } else if (cur
->type
== XML_RELAXNG_EXCEPT
) {
6508 if ((cur
->parent
!= NULL
) &&
6509 (cur
->parent
->type
== XML_RELAXNG_DATATYPE
))
6510 nflags
= flags
| XML_RELAXNG_IN_DATAEXCEPT
;
6514 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6516 } else if (cur
->type
== XML_RELAXNG_DATATYPE
) {
6517 if (flags
& XML_RELAXNG_IN_START
) {
6518 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_DATA
,
6519 "Found forbidden pattern start//data\n", NULL
,
6522 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6523 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6524 } else if (cur
->type
== XML_RELAXNG_VALUE
) {
6525 if (flags
& XML_RELAXNG_IN_START
) {
6526 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_VALUE
,
6527 "Found forbidden pattern start//value\n", NULL
,
6530 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6531 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6532 } else if (cur
->type
== XML_RELAXNG_TEXT
) {
6533 if (flags
& XML_RELAXNG_IN_LIST
) {
6534 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_TEXT
,
6535 "Found forbidden pattern list//text\n", NULL
,
6538 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6539 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_TEXT
,
6540 "Found forbidden pattern data/except//text\n",
6543 if (flags
& XML_RELAXNG_IN_START
) {
6544 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_TEXT
,
6545 "Found forbidden pattern start//text\n", NULL
,
6548 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6549 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6550 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6551 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_EMPTY
,
6552 "Found forbidden pattern data/except//empty\n",
6555 if (flags
& XML_RELAXNG_IN_START
) {
6556 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_EMPTY
,
6557 "Found forbidden pattern start//empty\n", NULL
,
6560 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6561 } else if (cur
->type
== XML_RELAXNG_CHOICE
) {
6562 xmlRelaxNGCheckChoiceDeterminism(ctxt
, cur
);
6564 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6567 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6570 if (ptype
== XML_RELAXNG_GROUP
) {
6571 val
= xmlRelaxNGGroupContentType(val
, ret
);
6572 } else if (ptype
== XML_RELAXNG_INTERLEAVE
) {
6574 * TODO: scan complain that tmp is never used, seems on purpose
6575 * need double-checking
6577 tmp
= xmlRelaxNGGroupContentType(val
, ret
);
6578 if (tmp
!= XML_RELAXNG_CONTENT_ERROR
)
6579 tmp
= xmlRelaxNGMaxContentType(val
, ret
);
6580 } else if (ptype
== XML_RELAXNG_CHOICE
) {
6581 val
= xmlRelaxNGMaxContentType(val
, ret
);
6582 } else if (ptype
== XML_RELAXNG_LIST
) {
6583 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6584 } else if (ptype
== XML_RELAXNG_EXCEPT
) {
6585 if (ret
== XML_RELAXNG_CONTENT_ERROR
)
6586 val
= XML_RELAXNG_CONTENT_ERROR
;
6588 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6590 val
= xmlRelaxNGGroupContentType(val
, ret
);
6598 * xmlRelaxNGParseGrammar:
6599 * @ctxt: a Relax-NG parser context
6600 * @nodes: grammar children nodes
6602 * parse a Relax-NG <grammar> node
6604 * Returns the internal xmlRelaxNGGrammarPtr built or
6605 * NULL in case of error
6607 static xmlRelaxNGGrammarPtr
6608 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
6610 xmlRelaxNGGrammarPtr ret
, tmp
, old
;
6612 #ifdef DEBUG_GRAMMAR
6613 xmlGenericError(xmlGenericErrorContext
, "Parsing a new grammar\n");
6616 ret
= xmlRelaxNGNewGrammar(ctxt
);
6621 * Link the new grammar in the tree
6623 ret
->parent
= ctxt
->grammar
;
6624 if (ctxt
->grammar
!= NULL
) {
6625 tmp
= ctxt
->grammar
->children
;
6627 ctxt
->grammar
->children
= ret
;
6629 while (tmp
->next
!= NULL
)
6635 old
= ctxt
->grammar
;
6636 ctxt
->grammar
= ret
;
6637 xmlRelaxNGParseGrammarContent(ctxt
, nodes
);
6638 ctxt
->grammar
= ret
;
6639 if (ctxt
->grammar
== NULL
) {
6640 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
6641 "Failed to parse <grammar> content\n", NULL
, NULL
);
6642 } else if (ctxt
->grammar
->start
== NULL
) {
6643 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_NO_START
,
6644 "Element <grammar> has no <start>\n", NULL
, NULL
);
6648 * Apply 4.17 merging rules to defines and starts
6650 xmlRelaxNGCombineStart(ctxt
, ret
);
6651 if (ret
->defs
!= NULL
) {
6652 xmlHashScan(ret
->defs
, xmlRelaxNGCheckCombine
, ctxt
);
6656 * link together defines and refs in this grammar
6658 if (ret
->refs
!= NULL
) {
6659 xmlHashScan(ret
->refs
, xmlRelaxNGCheckReference
, ctxt
);
6665 ctxt
->grammar
= old
;
6670 * xmlRelaxNGParseDocument:
6671 * @ctxt: a Relax-NG parser context
6672 * @node: the root node of the RelaxNG schema
6674 * parse a Relax-NG definition resource and build an internal
6675 * xmlRelaxNG structure which can be used to validate instances.
6677 * Returns the internal XML RelaxNG structure built or
6678 * NULL in case of error
6680 static xmlRelaxNGPtr
6681 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6683 xmlRelaxNGPtr schema
= NULL
;
6684 const xmlChar
*olddefine
;
6685 xmlRelaxNGGrammarPtr old
;
6687 if ((ctxt
== NULL
) || (node
== NULL
))
6690 schema
= xmlRelaxNGNewRelaxNG(ctxt
);
6694 olddefine
= ctxt
->define
;
6695 ctxt
->define
= NULL
;
6696 if (IS_RELAXNG(node
, "grammar")) {
6697 schema
->topgrammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
6698 if (schema
->topgrammar
== NULL
) {
6699 xmlRelaxNGFree(schema
);
6703 xmlRelaxNGGrammarPtr tmp
, ret
;
6705 schema
->topgrammar
= ret
= xmlRelaxNGNewGrammar(ctxt
);
6706 if (schema
->topgrammar
== NULL
) {
6707 xmlRelaxNGFree(schema
);
6711 * Link the new grammar in the tree
6713 ret
->parent
= ctxt
->grammar
;
6714 if (ctxt
->grammar
!= NULL
) {
6715 tmp
= ctxt
->grammar
->children
;
6717 ctxt
->grammar
->children
= ret
;
6719 while (tmp
->next
!= NULL
)
6724 old
= ctxt
->grammar
;
6725 ctxt
->grammar
= ret
;
6726 xmlRelaxNGParseStart(ctxt
, node
);
6728 ctxt
->grammar
= old
;
6730 ctxt
->define
= olddefine
;
6731 if (schema
->topgrammar
->start
!= NULL
) {
6732 xmlRelaxNGCheckCycles(ctxt
, schema
->topgrammar
->start
, 0);
6733 if ((ctxt
->flags
& XML_RELAXNG_IN_EXTERNALREF
) == 0) {
6734 xmlRelaxNGSimplify(ctxt
, schema
->topgrammar
->start
, NULL
);
6735 while ((schema
->topgrammar
->start
!= NULL
) &&
6736 (schema
->topgrammar
->start
->type
== XML_RELAXNG_NOOP
) &&
6737 (schema
->topgrammar
->start
->next
!= NULL
))
6738 schema
->topgrammar
->start
=
6739 schema
->topgrammar
->start
->content
;
6740 xmlRelaxNGCheckRules(ctxt
, schema
->topgrammar
->start
,
6741 XML_RELAXNG_IN_START
, XML_RELAXNG_NOOP
);
6746 xmlGenericError(xmlGenericErrorContext
,
6747 "xmlRelaxNGParseDocument() failed\n");
6753 /************************************************************************
6755 * Reading RelaxNGs *
6757 ************************************************************************/
6760 * xmlRelaxNGNewParserCtxt:
6761 * @URL: the location of the schema
6763 * Create an XML RelaxNGs parse context for that file/resource expected
6764 * to contain an XML RelaxNGs file.
6766 * Returns the parser context or NULL in case of error
6768 xmlRelaxNGParserCtxtPtr
6769 xmlRelaxNGNewParserCtxt(const char *URL
)
6771 xmlRelaxNGParserCtxtPtr ret
;
6777 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6779 xmlRngPErrMemory(NULL
, "building parser\n");
6782 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6783 ret
->URL
= xmlStrdup((const xmlChar
*) URL
);
6784 ret
->error
= xmlGenericError
;
6785 ret
->userData
= xmlGenericErrorContext
;
6790 * xmlRelaxNGNewMemParserCtxt:
6791 * @buffer: a pointer to a char array containing the schemas
6792 * @size: the size of the array
6794 * Create an XML RelaxNGs parse context for that memory buffer expected
6795 * to contain an XML RelaxNGs file.
6797 * Returns the parser context or NULL in case of error
6799 xmlRelaxNGParserCtxtPtr
6800 xmlRelaxNGNewMemParserCtxt(const char *buffer
, int size
)
6802 xmlRelaxNGParserCtxtPtr ret
;
6804 if ((buffer
== NULL
) || (size
<= 0))
6808 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6810 xmlRngPErrMemory(NULL
, "building parser\n");
6813 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6814 ret
->buffer
= buffer
;
6816 ret
->error
= xmlGenericError
;
6817 ret
->userData
= xmlGenericErrorContext
;
6822 * xmlRelaxNGNewDocParserCtxt:
6823 * @doc: a preparsed document tree
6825 * Create an XML RelaxNGs parser context for that document.
6826 * Note: since the process of compiling a RelaxNG schemas modifies the
6827 * document, the @doc parameter is duplicated internally.
6829 * Returns the parser context or NULL in case of error
6831 xmlRelaxNGParserCtxtPtr
6832 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc
)
6834 xmlRelaxNGParserCtxtPtr ret
;
6839 copy
= xmlCopyDoc(doc
, 1);
6844 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6846 xmlRngPErrMemory(NULL
, "building parser\n");
6850 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6851 ret
->document
= copy
;
6853 ret
->userData
= xmlGenericErrorContext
;
6858 * xmlRelaxNGFreeParserCtxt:
6859 * @ctxt: the schema parser context
6861 * Free the resources associated to the schema parser context
6864 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt
)
6868 if (ctxt
->URL
!= NULL
)
6870 if (ctxt
->doc
!= NULL
)
6871 xmlRelaxNGFreeDocument(ctxt
->doc
);
6872 if (ctxt
->interleaves
!= NULL
)
6873 xmlHashFree(ctxt
->interleaves
, NULL
);
6874 if (ctxt
->documents
!= NULL
)
6875 xmlRelaxNGFreeDocumentList(ctxt
->documents
);
6876 if (ctxt
->includes
!= NULL
)
6877 xmlRelaxNGFreeIncludeList(ctxt
->includes
);
6878 if (ctxt
->docTab
!= NULL
)
6879 xmlFree(ctxt
->docTab
);
6880 if (ctxt
->incTab
!= NULL
)
6881 xmlFree(ctxt
->incTab
);
6882 if (ctxt
->defTab
!= NULL
) {
6885 for (i
= 0; i
< ctxt
->defNr
; i
++)
6886 xmlRelaxNGFreeDefine(ctxt
->defTab
[i
]);
6887 xmlFree(ctxt
->defTab
);
6889 if ((ctxt
->document
!= NULL
) && (ctxt
->freedoc
))
6890 xmlFreeDoc(ctxt
->document
);
6895 * xmlRelaxNGNormExtSpace:
6898 * Removes the leading and ending spaces of the value
6899 * The string is modified "in situ"
6902 xmlRelaxNGNormExtSpace(xmlChar
* value
)
6904 xmlChar
*start
= value
;
6905 xmlChar
*cur
= value
;
6910 while (IS_BLANK_CH(*cur
))
6914 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6919 while (IS_BLANK_CH(*cur
))
6928 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6934 /* don't try to normalize the inner spaces */
6935 while (IS_BLANK_CH(*cur
))
6947 * xmlRelaxNGCleanupAttributes:
6948 * @ctxt: a Relax-NG parser context
6949 * @node: a Relax-NG node
6951 * Check all the attributes on the given node
6954 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6956 xmlAttrPtr cur
, next
;
6958 cur
= node
->properties
;
6959 while (cur
!= NULL
) {
6961 if ((cur
->ns
== NULL
) ||
6962 (xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
6963 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
6964 if ((!xmlStrEqual(node
->name
, BAD_CAST
"element")) &&
6965 (!xmlStrEqual(node
->name
, BAD_CAST
"attribute")) &&
6966 (!xmlStrEqual(node
->name
, BAD_CAST
"ref")) &&
6967 (!xmlStrEqual(node
->name
, BAD_CAST
"parentRef")) &&
6968 (!xmlStrEqual(node
->name
, BAD_CAST
"param")) &&
6969 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6970 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6971 "Attribute %s is not allowed on %s\n",
6972 cur
->name
, node
->name
);
6974 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"type")) {
6975 if ((!xmlStrEqual(node
->name
, BAD_CAST
"value")) &&
6976 (!xmlStrEqual(node
->name
, BAD_CAST
"data"))) {
6977 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6978 "Attribute %s is not allowed on %s\n",
6979 cur
->name
, node
->name
);
6981 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"href")) {
6982 if ((!xmlStrEqual(node
->name
, BAD_CAST
"externalRef")) &&
6983 (!xmlStrEqual(node
->name
, BAD_CAST
"include"))) {
6984 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6985 "Attribute %s is not allowed on %s\n",
6986 cur
->name
, node
->name
);
6988 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"combine")) {
6989 if ((!xmlStrEqual(node
->name
, BAD_CAST
"start")) &&
6990 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6991 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6992 "Attribute %s is not allowed on %s\n",
6993 cur
->name
, node
->name
);
6995 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"datatypeLibrary")) {
6999 val
= xmlNodeListGetString(node
->doc
, cur
->children
, 1);
7002 uri
= xmlParseURI((const char *) val
);
7004 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_URI
,
7005 "Attribute %s contains invalid URI %s\n",
7008 if (uri
->scheme
== NULL
) {
7009 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_NOT_ABSOLUTE
,
7010 "Attribute %s URI %s is not absolute\n",
7013 if (uri
->fragment
!= NULL
) {
7014 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_FRAGMENT
,
7015 "Attribute %s URI %s has a fragment ID\n",
7023 } else if (!xmlStrEqual(cur
->name
, BAD_CAST
"ns")) {
7024 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_ATTRIBUTE
,
7025 "Unknown attribute %s on %s\n", cur
->name
,
7034 * xmlRelaxNGCleanupTree:
7035 * @ctxt: a Relax-NG parser context
7036 * @root: an xmlNodePtr subtree
7038 * Cleanup the subtree from unwanted nodes for parsing, resolve
7039 * Include and externalRef lookups.
7042 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr root
)
7044 xmlNodePtr cur
, delete;
7048 while (cur
!= NULL
) {
7049 if (delete != NULL
) {
7050 xmlUnlinkNode(delete);
7051 xmlFreeNode(delete);
7054 if (cur
->type
== XML_ELEMENT_NODE
) {
7056 * Simplification 4.1. Annotations
7058 if ((cur
->ns
== NULL
) ||
7059 (!xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
7060 if ((cur
->parent
!= NULL
) &&
7061 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
7062 ((xmlStrEqual(cur
->parent
->name
, BAD_CAST
"name")) ||
7063 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value")) ||
7064 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"param")))) {
7065 xmlRngPErr(ctxt
, cur
, XML_RNGP_FOREIGN_ELEMENT
,
7066 "element %s doesn't allow foreign elements\n",
7067 cur
->parent
->name
, NULL
);
7072 xmlRelaxNGCleanupAttributes(ctxt
, cur
);
7073 if (xmlStrEqual(cur
->name
, BAD_CAST
"externalRef")) {
7074 xmlChar
*href
, *ns
, *base
, *URL
;
7075 xmlRelaxNGDocumentPtr docu
;
7079 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7082 while ((tmp
!= NULL
) &&
7083 (tmp
->type
== XML_ELEMENT_NODE
)) {
7084 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7090 href
= xmlGetProp(cur
, BAD_CAST
"href");
7092 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7093 "xmlRelaxNGParse: externalRef has no href attribute\n",
7100 uri
= xmlParseURI((const char *) href
);
7102 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7103 "Incorrect URI for externalRef %s\n",
7112 if (uri
->fragment
!= NULL
) {
7113 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7114 "Fragment forbidden in URI for externalRef %s\n",
7125 base
= xmlNodeGetBase(cur
->doc
, cur
);
7126 URL
= xmlBuildURI(href
, base
);
7128 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7129 "Failed to compute URL for externalRef %s\n",
7144 docu
= xmlRelaxNGLoadExternalRef(ctxt
, URL
, ns
);
7146 xmlRngPErr(ctxt
, cur
, XML_RNGP_EXTERNAL_REF_FAILURE
,
7147 "Failed to load externalRef %s\n", URL
,
7159 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"include")) {
7160 xmlChar
*href
, *ns
, *base
, *URL
;
7161 xmlRelaxNGIncludePtr incl
;
7164 href
= xmlGetProp(cur
, BAD_CAST
"href");
7166 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7167 "xmlRelaxNGParse: include has no href attribute\n",
7172 base
= xmlNodeGetBase(cur
->doc
, cur
);
7173 URL
= xmlBuildURI(href
, base
);
7175 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7176 "Failed to compute URL for include %s\n",
7189 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7192 while ((tmp
!= NULL
) &&
7193 (tmp
->type
== XML_ELEMENT_NODE
)) {
7194 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7200 incl
= xmlRelaxNGLoadInclude(ctxt
, URL
, cur
, ns
);
7204 xmlRngPErr(ctxt
, cur
, XML_RNGP_INCLUDE_FAILURE
,
7205 "Failed to load include %s\n", URL
,
7213 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"element")) ||
7214 (xmlStrEqual(cur
->name
, BAD_CAST
"attribute")))
7217 xmlNodePtr text
= NULL
;
7220 * Simplification 4.8. name attribute of element
7221 * and attribute elements
7223 name
= xmlGetProp(cur
, BAD_CAST
"name");
7225 if (cur
->children
== NULL
) {
7227 xmlNewChild(cur
, cur
->ns
, BAD_CAST
"name",
7232 node
= xmlNewDocNode(cur
->doc
, cur
->ns
,
7233 BAD_CAST
"name", NULL
);
7235 xmlAddPrevSibling(cur
->children
, node
);
7236 text
= xmlNewDocText(node
->doc
, name
);
7237 xmlAddChild(node
, text
);
7242 xmlRngPErr(ctxt
, cur
, XML_RNGP_CREATE_FAILURE
,
7243 "Failed to create a name %s element\n",
7246 xmlUnsetProp(cur
, BAD_CAST
"name");
7248 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7251 xmlSetProp(text
, BAD_CAST
"ns", ns
);
7252 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7255 } else if (xmlStrEqual(cur
->name
,
7256 BAD_CAST
"attribute")) {
7257 xmlSetProp(text
, BAD_CAST
"ns", BAD_CAST
"");
7260 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"name")) ||
7261 (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) ||
7262 (xmlStrEqual(cur
->name
, BAD_CAST
"value"))) {
7264 * Simplification 4.8. name attribute of element
7265 * and attribute elements
7267 if (xmlHasProp(cur
, BAD_CAST
"ns") == NULL
) {
7272 while ((node
!= NULL
) &&
7273 (node
->type
== XML_ELEMENT_NODE
)) {
7274 ns
= xmlGetProp(node
, BAD_CAST
"ns");
7278 node
= node
->parent
;
7281 xmlSetProp(cur
, BAD_CAST
"ns", BAD_CAST
"");
7283 xmlSetProp(cur
, BAD_CAST
"ns", ns
);
7287 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
7288 xmlChar
*name
, *local
, *prefix
;
7291 * Simplification: 4.10. QNames
7293 name
= xmlNodeGetContent(cur
);
7295 local
= xmlSplitQName2(name
, &prefix
);
7296 if (local
!= NULL
) {
7299 ns
= xmlSearchNs(cur
->doc
, cur
, prefix
);
7301 xmlRngPErr(ctxt
, cur
,
7302 XML_RNGP_PREFIX_UNDEFINED
,
7303 "xmlRelaxNGParse: no namespace for prefix %s\n",
7306 xmlSetProp(cur
, BAD_CAST
"ns",
7308 xmlNodeSetContent(cur
, local
);
7319 if (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) {
7320 if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7321 xmlRngPErr(ctxt
, cur
,
7322 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME
,
7323 "Found nsName/except//nsName forbidden construct\n",
7327 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"except")) &&
7329 int oldflags
= ctxt
->flags
;
7334 if ((cur
->parent
!= NULL
) &&
7336 (cur
->parent
->name
, BAD_CAST
"anyName"))) {
7337 ctxt
->flags
|= XML_RELAXNG_IN_ANYEXCEPT
;
7338 xmlRelaxNGCleanupTree(ctxt
, cur
);
7339 ctxt
->flags
= oldflags
;
7341 } else if ((cur
->parent
!= NULL
) &&
7343 (cur
->parent
->name
, BAD_CAST
"nsName"))) {
7344 ctxt
->flags
|= XML_RELAXNG_IN_NSEXCEPT
;
7345 xmlRelaxNGCleanupTree(ctxt
, cur
);
7346 ctxt
->flags
= oldflags
;
7349 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"anyName")) {
7353 if (ctxt
->flags
& XML_RELAXNG_IN_ANYEXCEPT
) {
7354 xmlRngPErr(ctxt
, cur
,
7355 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME
,
7356 "Found anyName/except//anyName forbidden construct\n",
7358 } else if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7359 xmlRngPErr(ctxt
, cur
,
7360 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME
,
7361 "Found nsName/except//anyName forbidden construct\n",
7366 * This is not an else since "include" is transformed
7369 if (xmlStrEqual(cur
->name
, BAD_CAST
"div")) {
7371 xmlNodePtr child
, ins
, tmp
;
7374 * implements rule 4.11
7377 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7379 child
= cur
->children
;
7381 while (child
!= NULL
) {
7383 if (!xmlHasProp(child
, BAD_CAST
"ns")) {
7384 xmlSetProp(child
, BAD_CAST
"ns", ns
);
7388 xmlUnlinkNode(child
);
7389 ins
= xmlAddNextSibling(ins
, child
);
7395 * Since we are about to delete cur, if its nsDef is non-NULL we
7396 * need to preserve it (it contains the ns definitions for the
7397 * children we just moved). We'll just stick it on to the end
7398 * of cur->parent's list, since it's never going to be re-serialized
7401 if ((cur
->nsDef
!= NULL
) && (cur
->parent
!= NULL
)) {
7402 xmlNsPtr parDef
= (xmlNsPtr
)&cur
->parent
->nsDef
;
7403 while (parDef
->next
!= NULL
)
7404 parDef
= parDef
->next
;
7405 parDef
->next
= cur
->nsDef
;
7414 * Simplification 4.2 whitespaces
7416 else if ((cur
->type
== XML_TEXT_NODE
) ||
7417 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
7418 if (IS_BLANK_NODE(cur
)) {
7419 if ((cur
->parent
!= NULL
) &&
7420 (cur
->parent
->type
== XML_ELEMENT_NODE
)) {
7421 if ((!xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value"))
7424 (cur
->parent
->name
, BAD_CAST
"param")))
7439 if (cur
->children
!= NULL
) {
7440 if ((cur
->children
->type
!= XML_ENTITY_DECL
) &&
7441 (cur
->children
->type
!= XML_ENTITY_REF_NODE
) &&
7442 (cur
->children
->type
!= XML_ENTITY_NODE
)) {
7443 cur
= cur
->children
;
7448 if (cur
->next
!= NULL
) {
7461 if (cur
->next
!= NULL
) {
7465 } while (cur
!= NULL
);
7467 if (delete != NULL
) {
7468 xmlUnlinkNode(delete);
7469 xmlFreeNode(delete);
7475 * xmlRelaxNGCleanupDoc:
7476 * @ctxt: a Relax-NG parser context
7477 * @doc: an xmldocPtr document pointer
7479 * Cleanup the document from unwanted nodes for parsing, resolve
7480 * Include and externalRef lookups.
7482 * Returns the cleaned up document or NULL in case of error
7485 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
, xmlDocPtr doc
)
7492 root
= xmlDocGetRootElement(doc
);
7494 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7498 xmlRelaxNGCleanupTree(ctxt
, root
);
7504 * @ctxt: a Relax-NG parser context
7506 * parse a schema definition resource and build an internal
7507 * XML Schema structure which can be used to validate instances.
7509 * Returns the internal XML RelaxNG structure built from the resource or
7510 * NULL in case of error
7513 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt
)
7515 xmlRelaxNGPtr ret
= NULL
;
7519 xmlRelaxNGInitTypes();
7525 * First step is to parse the input document into an DOM/Infoset
7527 if (ctxt
->URL
!= NULL
) {
7528 doc
= xmlReadFile((const char *) ctxt
->URL
,NULL
,0);
7530 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7531 "xmlRelaxNGParse: could not load %s\n", ctxt
->URL
,
7535 } else if (ctxt
->buffer
!= NULL
) {
7536 doc
= xmlReadMemory(ctxt
->buffer
, ctxt
->size
,NULL
,NULL
,0);
7538 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7539 "xmlRelaxNGParse: could not parse schemas\n", NULL
,
7543 doc
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7544 ctxt
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7545 } else if (ctxt
->document
!= NULL
) {
7546 doc
= ctxt
->document
;
7548 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EMPTY
,
7549 "xmlRelaxNGParse: nothing to parse\n", NULL
, NULL
);
7552 ctxt
->document
= doc
;
7555 * Some preprocessing of the document content
7557 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
7559 xmlFreeDoc(ctxt
->document
);
7560 ctxt
->document
= NULL
;
7565 * Then do the parsing for good
7567 root
= xmlDocGetRootElement(doc
);
7569 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
,
7570 XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7571 (ctxt
->URL
? ctxt
->URL
: BAD_CAST
"schemas"), NULL
);
7573 xmlFreeDoc(ctxt
->document
);
7574 ctxt
->document
= NULL
;
7577 ret
= xmlRelaxNGParseDocument(ctxt
, root
);
7579 xmlFreeDoc(ctxt
->document
);
7580 ctxt
->document
= NULL
;
7585 * Check the ref/defines links
7588 * try to preprocess interleaves
7590 if (ctxt
->interleaves
!= NULL
) {
7591 xmlHashScan(ctxt
->interleaves
, xmlRelaxNGComputeInterleaves
, ctxt
);
7595 * if there was a parsing error return NULL
7597 if (ctxt
->nbErrors
> 0) {
7598 xmlRelaxNGFree(ret
);
7599 ctxt
->document
= NULL
;
7605 * try to compile (parts of) the schemas
7607 if ((ret
->topgrammar
!= NULL
) && (ret
->topgrammar
->start
!= NULL
)) {
7608 if (ret
->topgrammar
->start
->type
!= XML_RELAXNG_START
) {
7609 xmlRelaxNGDefinePtr def
;
7611 def
= xmlRelaxNGNewDefine(ctxt
, NULL
);
7613 def
->type
= XML_RELAXNG_START
;
7614 def
->content
= ret
->topgrammar
->start
;
7615 ret
->topgrammar
->start
= def
;
7618 xmlRelaxNGTryCompile(ctxt
, ret
->topgrammar
->start
);
7622 * Transfer the pointer for cleanup at the schema level.
7625 ctxt
->document
= NULL
;
7626 ret
->documents
= ctxt
->documents
;
7627 ctxt
->documents
= NULL
;
7629 ret
->includes
= ctxt
->includes
;
7630 ctxt
->includes
= NULL
;
7631 ret
->defNr
= ctxt
->defNr
;
7632 ret
->defTab
= ctxt
->defTab
;
7633 ctxt
->defTab
= NULL
;
7634 if (ctxt
->idref
== 1)
7641 * xmlRelaxNGSetParserErrors:
7642 * @ctxt: a Relax-NG validation context
7643 * @err: the error callback
7644 * @warn: the warning callback
7645 * @ctx: contextual data for the callbacks
7647 * Set the callback functions used to handle errors for a validation context
7650 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7651 xmlRelaxNGValidityErrorFunc err
,
7652 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
7657 ctxt
->warning
= warn
;
7658 ctxt
->serror
= NULL
;
7659 ctxt
->userData
= ctx
;
7663 * xmlRelaxNGGetParserErrors:
7664 * @ctxt: a Relax-NG validation context
7665 * @err: the error callback result
7666 * @warn: the warning callback result
7667 * @ctx: contextual data for the callbacks result
7669 * Get the callback information used to handle errors for a validation context
7671 * Returns -1 in case of failure, 0 otherwise.
7674 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7675 xmlRelaxNGValidityErrorFunc
* err
,
7676 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
7683 *warn
= ctxt
->warning
;
7685 *ctx
= ctxt
->userData
;
7690 * xmlRelaxNGSetParserStructuredErrors:
7691 * @ctxt: a Relax-NG parser context
7692 * @serror: the error callback
7693 * @ctx: contextual data for the callbacks
7695 * Set the callback functions used to handle errors for a parsing context
7698 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7699 xmlStructuredErrorFunc serror
,
7704 ctxt
->serror
= serror
;
7706 ctxt
->warning
= NULL
;
7707 ctxt
->userData
= ctx
;
7710 #ifdef LIBXML_OUTPUT_ENABLED
7712 /************************************************************************
7714 * Dump back a compiled form *
7716 ************************************************************************/
7717 static void xmlRelaxNGDumpDefine(FILE * output
,
7718 xmlRelaxNGDefinePtr define
);
7721 * xmlRelaxNGDumpDefines:
7722 * @output: the file output
7723 * @defines: a list of define structures
7725 * Dump a RelaxNG structure back
7728 xmlRelaxNGDumpDefines(FILE * output
, xmlRelaxNGDefinePtr defines
)
7730 while (defines
!= NULL
) {
7731 xmlRelaxNGDumpDefine(output
, defines
);
7732 defines
= defines
->next
;
7737 * xmlRelaxNGDumpDefine:
7738 * @output: the file output
7739 * @define: a define structure
7741 * Dump a RelaxNG structure back
7744 xmlRelaxNGDumpDefine(FILE * output
, xmlRelaxNGDefinePtr define
)
7748 switch (define
->type
) {
7749 case XML_RELAXNG_EMPTY
:
7750 fprintf(output
, "<empty/>\n");
7752 case XML_RELAXNG_NOT_ALLOWED
:
7753 fprintf(output
, "<notAllowed/>\n");
7755 case XML_RELAXNG_TEXT
:
7756 fprintf(output
, "<text/>\n");
7758 case XML_RELAXNG_ELEMENT
:
7759 fprintf(output
, "<element>\n");
7760 if (define
->name
!= NULL
) {
7761 fprintf(output
, "<name");
7762 if (define
->ns
!= NULL
)
7763 fprintf(output
, " ns=\"%s\"", define
->ns
);
7764 fprintf(output
, ">%s</name>\n", define
->name
);
7766 xmlRelaxNGDumpDefines(output
, define
->attrs
);
7767 xmlRelaxNGDumpDefines(output
, define
->content
);
7768 fprintf(output
, "</element>\n");
7770 case XML_RELAXNG_LIST
:
7771 fprintf(output
, "<list>\n");
7772 xmlRelaxNGDumpDefines(output
, define
->content
);
7773 fprintf(output
, "</list>\n");
7775 case XML_RELAXNG_ONEORMORE
:
7776 fprintf(output
, "<oneOrMore>\n");
7777 xmlRelaxNGDumpDefines(output
, define
->content
);
7778 fprintf(output
, "</oneOrMore>\n");
7780 case XML_RELAXNG_ZEROORMORE
:
7781 fprintf(output
, "<zeroOrMore>\n");
7782 xmlRelaxNGDumpDefines(output
, define
->content
);
7783 fprintf(output
, "</zeroOrMore>\n");
7785 case XML_RELAXNG_CHOICE
:
7786 fprintf(output
, "<choice>\n");
7787 xmlRelaxNGDumpDefines(output
, define
->content
);
7788 fprintf(output
, "</choice>\n");
7790 case XML_RELAXNG_GROUP
:
7791 fprintf(output
, "<group>\n");
7792 xmlRelaxNGDumpDefines(output
, define
->content
);
7793 fprintf(output
, "</group>\n");
7795 case XML_RELAXNG_INTERLEAVE
:
7796 fprintf(output
, "<interleave>\n");
7797 xmlRelaxNGDumpDefines(output
, define
->content
);
7798 fprintf(output
, "</interleave>\n");
7800 case XML_RELAXNG_OPTIONAL
:
7801 fprintf(output
, "<optional>\n");
7802 xmlRelaxNGDumpDefines(output
, define
->content
);
7803 fprintf(output
, "</optional>\n");
7805 case XML_RELAXNG_ATTRIBUTE
:
7806 fprintf(output
, "<attribute>\n");
7807 xmlRelaxNGDumpDefines(output
, define
->content
);
7808 fprintf(output
, "</attribute>\n");
7810 case XML_RELAXNG_DEF
:
7811 fprintf(output
, "<define");
7812 if (define
->name
!= NULL
)
7813 fprintf(output
, " name=\"%s\"", define
->name
);
7814 fprintf(output
, ">\n");
7815 xmlRelaxNGDumpDefines(output
, define
->content
);
7816 fprintf(output
, "</define>\n");
7818 case XML_RELAXNG_REF
:
7819 fprintf(output
, "<ref");
7820 if (define
->name
!= NULL
)
7821 fprintf(output
, " name=\"%s\"", define
->name
);
7822 fprintf(output
, ">\n");
7823 xmlRelaxNGDumpDefines(output
, define
->content
);
7824 fprintf(output
, "</ref>\n");
7826 case XML_RELAXNG_PARENTREF
:
7827 fprintf(output
, "<parentRef");
7828 if (define
->name
!= NULL
)
7829 fprintf(output
, " name=\"%s\"", define
->name
);
7830 fprintf(output
, ">\n");
7831 xmlRelaxNGDumpDefines(output
, define
->content
);
7832 fprintf(output
, "</parentRef>\n");
7834 case XML_RELAXNG_EXTERNALREF
:
7835 fprintf(output
, "<externalRef>");
7836 xmlRelaxNGDumpDefines(output
, define
->content
);
7837 fprintf(output
, "</externalRef>\n");
7839 case XML_RELAXNG_DATATYPE
:
7840 case XML_RELAXNG_VALUE
:
7842 case XML_RELAXNG_START
:
7843 case XML_RELAXNG_EXCEPT
:
7844 case XML_RELAXNG_PARAM
:
7846 case XML_RELAXNG_NOOP
:
7847 xmlRelaxNGDumpDefines(output
, define
->content
);
7853 * xmlRelaxNGDumpGrammar:
7854 * @output: the file output
7855 * @grammar: a grammar structure
7856 * @top: is this a top grammar
7858 * Dump a RelaxNG structure back
7861 xmlRelaxNGDumpGrammar(FILE * output
, xmlRelaxNGGrammarPtr grammar
, int top
)
7863 if (grammar
== NULL
)
7866 fprintf(output
, "<grammar");
7868 fprintf(output
, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7869 switch (grammar
->combine
) {
7870 case XML_RELAXNG_COMBINE_UNDEFINED
:
7872 case XML_RELAXNG_COMBINE_CHOICE
:
7873 fprintf(output
, " combine=\"choice\"");
7875 case XML_RELAXNG_COMBINE_INTERLEAVE
:
7876 fprintf(output
, " combine=\"interleave\"");
7879 fprintf(output
, " <!-- invalid combine value -->");
7881 fprintf(output
, ">\n");
7882 if (grammar
->start
== NULL
) {
7883 fprintf(output
, " <!-- grammar had no start -->");
7885 fprintf(output
, "<start>\n");
7886 xmlRelaxNGDumpDefine(output
, grammar
->start
);
7887 fprintf(output
, "</start>\n");
7889 /* TODO ? Dump the defines ? */
7890 fprintf(output
, "</grammar>\n");
7895 * @output: the file output
7896 * @schema: a schema structure
7898 * Dump a RelaxNG structure back
7901 xmlRelaxNGDump(FILE * output
, xmlRelaxNGPtr schema
)
7905 if (schema
== NULL
) {
7906 fprintf(output
, "RelaxNG empty or failed to compile\n");
7909 fprintf(output
, "RelaxNG: ");
7910 if (schema
->doc
== NULL
) {
7911 fprintf(output
, "no document\n");
7912 } else if (schema
->doc
->URL
!= NULL
) {
7913 fprintf(output
, "%s\n", schema
->doc
->URL
);
7915 fprintf(output
, "\n");
7917 if (schema
->topgrammar
== NULL
) {
7918 fprintf(output
, "RelaxNG has no top grammar\n");
7921 xmlRelaxNGDumpGrammar(output
, schema
->topgrammar
, 1);
7925 * xmlRelaxNGDumpTree:
7926 * @output: the file output
7927 * @schema: a schema structure
7929 * Dump the transformed RelaxNG tree.
7932 xmlRelaxNGDumpTree(FILE * output
, xmlRelaxNGPtr schema
)
7936 if (schema
== NULL
) {
7937 fprintf(output
, "RelaxNG empty or failed to compile\n");
7940 if (schema
->doc
== NULL
) {
7941 fprintf(output
, "no document\n");
7943 xmlDocDump(output
, schema
->doc
);
7946 #endif /* LIBXML_OUTPUT_ENABLED */
7948 /************************************************************************
7950 * Validation of compiled content *
7952 ************************************************************************/
7953 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
7954 xmlRelaxNGDefinePtr define
);
7957 * xmlRelaxNGValidateCompiledCallback:
7958 * @exec: the regular expression instance
7959 * @token: the token which matched
7960 * @transdata: callback data, the define for the subelement if available
7961 @ @inputdata: callback data, the Relax NG validation context
7963 * Handle the callback and if needed validate the element children.
7966 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED
,
7967 const xmlChar
* token
,
7968 void *transdata
, void *inputdata
)
7970 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
7971 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
7974 #ifdef DEBUG_COMPILE
7975 xmlGenericError(xmlGenericErrorContext
,
7976 "Compiled callback for: '%s'\n", token
);
7979 fprintf(stderr
, "callback on %s missing context\n", token
);
7982 if (define
== NULL
) {
7983 if (token
[0] == '#')
7985 fprintf(stderr
, "callback on %s missing define\n", token
);
7986 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7987 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7990 if (define
->type
!= XML_RELAXNG_ELEMENT
) {
7991 fprintf(stderr
, "callback on %s define is not element\n", token
);
7992 if (ctxt
->errNo
== XML_RELAXNG_OK
)
7993 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7996 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
);
8002 * xmlRelaxNGValidateCompiledContent:
8003 * @ctxt: the RelaxNG validation context
8004 * @regexp: the regular expression as compiled
8005 * @content: list of children to test against the regexp
8007 * Validate the content model of an element or start using the regexp
8009 * Returns 0 in case of success, -1 in case of error.
8012 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt
,
8013 xmlRegexpPtr regexp
, xmlNodePtr content
)
8015 xmlRegExecCtxtPtr exec
;
8020 if ((ctxt
== NULL
) || (regexp
== NULL
))
8022 oldperr
= ctxt
->perr
;
8023 exec
= xmlRegNewExecCtxt(regexp
,
8024 xmlRelaxNGValidateCompiledCallback
, ctxt
);
8027 while (cur
!= NULL
) {
8028 ctxt
->state
->seq
= cur
;
8029 switch (cur
->type
) {
8031 case XML_CDATA_SECTION_NODE
:
8032 if (xmlIsBlankNode(cur
))
8034 ret
= xmlRegExecPushString(exec
, BAD_CAST
"#text", ctxt
);
8036 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
,
8040 case XML_ELEMENT_NODE
:
8041 if (cur
->ns
!= NULL
) {
8042 ret
= xmlRegExecPushString2(exec
, cur
->name
,
8043 cur
->ns
->href
, ctxt
);
8045 ret
= xmlRegExecPushString(exec
, cur
->name
, ctxt
);
8048 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, cur
->name
);
8057 * Switch to next element
8061 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8064 ctxt
->state
->seq
= NULL
;
8065 } else if (ret
== 0) {
8067 * TODO: get some of the names needed to exit the current state of exec
8069 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8071 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8072 xmlRelaxNGDumpValidError(ctxt
);
8076 xmlRegFreeExecCtxt(exec
);
8078 * There might be content model errors outside of the pure
8079 * regexp validation, e.g. for attribute values.
8081 if ((ret
== 0) && (ctxt
->perr
!= 0)) {
8084 ctxt
->perr
= oldperr
;
8088 /************************************************************************
8090 * Progressive validation of when possible *
8092 ************************************************************************/
8093 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
8094 xmlRelaxNGDefinePtr defines
);
8095 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
,
8097 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
);
8100 * xmlRelaxNGElemPush:
8101 * @ctxt: the validation context
8102 * @exec: the regexp runtime for the new content model
8104 * Push a new regexp for the current node content model on the stack
8106 * Returns 0 in case of success and -1 in case of error.
8109 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt
, xmlRegExecCtxtPtr exec
)
8111 if (ctxt
->elemTab
== NULL
) {
8113 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlMalloc(ctxt
->elemMax
*
8115 (xmlRegExecCtxtPtr
));
8116 if (ctxt
->elemTab
== NULL
) {
8117 xmlRngVErrMemory(ctxt
, "validating\n");
8121 if (ctxt
->elemNr
>= ctxt
->elemMax
) {
8123 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlRealloc(ctxt
->elemTab
,
8126 (xmlRegExecCtxtPtr
));
8127 if (ctxt
->elemTab
== NULL
) {
8128 xmlRngVErrMemory(ctxt
, "validating\n");
8132 ctxt
->elemTab
[ctxt
->elemNr
++] = exec
;
8138 * xmlRelaxNGElemPop:
8139 * @ctxt: the validation context
8141 * Pop the regexp of the current node content model from the stack
8143 * Returns the exec or NULL if empty
8145 static xmlRegExecCtxtPtr
8146 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt
)
8148 xmlRegExecCtxtPtr ret
;
8150 if (ctxt
->elemNr
<= 0)
8153 ret
= ctxt
->elemTab
[ctxt
->elemNr
];
8154 ctxt
->elemTab
[ctxt
->elemNr
] = NULL
;
8155 if (ctxt
->elemNr
> 0)
8156 ctxt
->elem
= ctxt
->elemTab
[ctxt
->elemNr
- 1];
8163 * xmlRelaxNGValidateProgressiveCallback:
8164 * @exec: the regular expression instance
8165 * @token: the token which matched
8166 * @transdata: callback data, the define for the subelement if available
8167 @ @inputdata: callback data, the Relax NG validation context
8169 * Handle the callback and if needed validate the element children.
8170 * some of the in/out information are passed via the context in @inputdata.
8173 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8175 const xmlChar
* token
,
8176 void *transdata
, void *inputdata
)
8178 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
8179 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
8180 xmlRelaxNGValidStatePtr state
, oldstate
;
8182 int ret
= 0, oldflags
;
8184 #ifdef DEBUG_PROGRESSIVE
8185 xmlGenericError(xmlGenericErrorContext
,
8186 "Progressive callback for: '%s'\n", token
);
8189 fprintf(stderr
, "callback on %s missing context\n", token
);
8194 if (define
== NULL
) {
8195 if (token
[0] == '#')
8197 fprintf(stderr
, "callback on %s missing define\n", token
);
8198 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8199 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8203 if ((ctxt
== NULL
) || (define
== NULL
)) {
8204 fprintf(stderr
, "callback on %s missing info\n", token
);
8205 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8206 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8209 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
8210 fprintf(stderr
, "callback on %s define is not element\n", token
);
8211 if (ctxt
->errNo
== XML_RELAXNG_OK
)
8212 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8216 if (node
->type
!= XML_ELEMENT_NODE
) {
8217 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
8218 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8219 xmlRelaxNGDumpValidError(ctxt
);
8223 if (define
->contModel
== NULL
) {
8225 * this node cannot be validated in a streamable fashion
8227 #ifdef DEBUG_PROGRESSIVE
8228 xmlGenericError(xmlGenericErrorContext
,
8229 "Element '%s' validation is not streamable\n",
8233 ctxt
->pdef
= define
;
8236 exec
= xmlRegNewExecCtxt(define
->contModel
,
8237 xmlRelaxNGValidateProgressiveCallback
, ctxt
);
8242 xmlRelaxNGElemPush(ctxt
, exec
);
8245 * Validate the attributes part of the content.
8247 state
= xmlRelaxNGNewValidState(ctxt
, node
);
8248 if (state
== NULL
) {
8252 oldstate
= ctxt
->state
;
8253 ctxt
->state
= state
;
8254 if (define
->attrs
!= NULL
) {
8255 ret
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
8258 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
8261 if (ctxt
->state
!= NULL
) {
8262 ctxt
->state
->seq
= NULL
;
8263 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
8267 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8268 } else if (ctxt
->states
!= NULL
) {
8271 oldflags
= ctxt
->flags
;
8273 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8274 state
= ctxt
->states
->tabState
[i
];
8275 ctxt
->state
= state
;
8276 ctxt
->state
->seq
= NULL
;
8278 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
8285 * validation error, log the message for the "best" one
8287 ctxt
->flags
|= FLAGS_IGNORABLE
;
8288 xmlRelaxNGLogBestError(ctxt
);
8290 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8291 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[i
]);
8293 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
8294 ctxt
->states
= NULL
;
8295 if ((ret
== 0) && (tmp
== -1))
8297 ctxt
->flags
= oldflags
;
8299 if (ctxt
->pstate
== -1) {
8300 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
8301 xmlRelaxNGDumpValidError(ctxt
);
8304 ctxt
->state
= oldstate
;
8308 * xmlRelaxNGValidatePushElement:
8309 * @ctxt: the validation context
8310 * @doc: a document instance
8311 * @elem: an element instance
8313 * Push a new element start on the RelaxNG validation stack.
8315 * returns 1 if no validation problem was found or 0 if validating the
8316 * element requires a full node, and -1 in case of error.
8319 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt
,
8320 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8325 if ((ctxt
== NULL
) || (elem
== NULL
))
8328 #ifdef DEBUG_PROGRESSIVE
8329 xmlGenericError(xmlGenericErrorContext
, "PushElem %s\n", elem
->name
);
8331 if (ctxt
->elem
== 0) {
8332 xmlRelaxNGPtr schema
;
8333 xmlRelaxNGGrammarPtr grammar
;
8334 xmlRegExecCtxtPtr exec
;
8335 xmlRelaxNGDefinePtr define
;
8337 schema
= ctxt
->schema
;
8338 if (schema
== NULL
) {
8339 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8342 grammar
= schema
->topgrammar
;
8343 if ((grammar
== NULL
) || (grammar
->start
== NULL
)) {
8344 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8347 define
= grammar
->start
;
8348 if (define
->contModel
== NULL
) {
8349 ctxt
->pdef
= define
;
8352 exec
= xmlRegNewExecCtxt(define
->contModel
,
8353 xmlRelaxNGValidateProgressiveCallback
,
8358 xmlRelaxNGElemPush(ctxt
, exec
);
8362 if (elem
->ns
!= NULL
) {
8364 xmlRegExecPushString2(ctxt
->elem
, elem
->name
, elem
->ns
->href
,
8367 ret
= xmlRegExecPushString(ctxt
->elem
, elem
->name
, ctxt
);
8370 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, elem
->name
);
8372 if (ctxt
->pstate
== 0)
8374 else if (ctxt
->pstate
< 0)
8379 #ifdef DEBUG_PROGRESSIVE
8381 xmlGenericError(xmlGenericErrorContext
, "PushElem %s failed\n",
8388 * xmlRelaxNGValidatePushCData:
8389 * @ctxt: the RelaxNG validation context
8390 * @data: some character data read
8391 * @len: the length of the data
8393 * check the CData parsed for validation in the current stack
8395 * returns 1 if no validation problem was found or -1 otherwise
8398 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt
,
8399 const xmlChar
* data
, int len ATTRIBUTE_UNUSED
)
8403 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (data
== NULL
))
8406 #ifdef DEBUG_PROGRESSIVE
8407 xmlGenericError(xmlGenericErrorContext
, "CDATA %s %d\n", data
, len
);
8410 while (*data
!= 0) {
8411 if (!IS_BLANK_CH(*data
))
8418 ret
= xmlRegExecPushString(ctxt
->elem
, BAD_CAST
"#text", ctxt
);
8420 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
, BAD_CAST
" TODO ");
8421 #ifdef DEBUG_PROGRESSIVE
8422 xmlGenericError(xmlGenericErrorContext
, "CDATA failed\n");
8431 * xmlRelaxNGValidatePopElement:
8432 * @ctxt: the RelaxNG validation context
8433 * @doc: a document instance
8434 * @elem: an element instance
8436 * Pop the element end from the RelaxNG validation stack.
8438 * returns 1 if no validation problem was found or 0 otherwise
8441 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt
,
8442 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8446 xmlRegExecCtxtPtr exec
;
8448 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (elem
== NULL
))
8450 #ifdef DEBUG_PROGRESSIVE
8451 xmlGenericError(xmlGenericErrorContext
, "PopElem %s\n", elem
->name
);
8454 * verify that we reached a terminal state of the content model.
8456 exec
= xmlRelaxNGElemPop(ctxt
);
8457 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8460 * TODO: get some of the names needed to exit the current state of exec
8462 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8464 } else if (ret
< 0) {
8469 xmlRegFreeExecCtxt(exec
);
8470 #ifdef DEBUG_PROGRESSIVE
8472 xmlGenericError(xmlGenericErrorContext
, "PopElem %s failed\n",
8479 * xmlRelaxNGValidateFullElement:
8480 * @ctxt: the validation context
8481 * @doc: a document instance
8482 * @elem: an element instance
8484 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8485 * 0 and the content of the node has been expanded.
8487 * returns 1 if no validation problem was found or -1 in case of error.
8490 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt
,
8491 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8495 xmlRelaxNGValidStatePtr state
;
8497 if ((ctxt
== NULL
) || (ctxt
->pdef
== NULL
) || (elem
== NULL
))
8499 #ifdef DEBUG_PROGRESSIVE
8500 xmlGenericError(xmlGenericErrorContext
, "FullElem %s\n", elem
->name
);
8502 state
= xmlRelaxNGNewValidState(ctxt
, elem
->parent
);
8503 if (state
== NULL
) {
8507 ctxt
->state
= state
;
8508 ctxt
->errNo
= XML_RELAXNG_OK
;
8509 ret
= xmlRelaxNGValidateDefinition(ctxt
, ctxt
->pdef
);
8510 if ((ret
!= 0) || (ctxt
->errNo
!= XML_RELAXNG_OK
))
8514 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8516 #ifdef DEBUG_PROGRESSIVE
8518 xmlGenericError(xmlGenericErrorContext
, "FullElem %s failed\n",
8524 /************************************************************************
8526 * Generic interpreted validation implementation *
8528 ************************************************************************/
8529 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8530 xmlRelaxNGDefinePtr define
);
8533 * xmlRelaxNGSkipIgnored:
8534 * @ctxt: a schema validation context
8535 * @node: the top node.
8537 * Skip ignorable nodes in that context
8539 * Returns the new sibling or NULL in case of error.
8542 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
8546 * TODO complete and handle entities
8548 while ((node
!= NULL
) &&
8549 ((node
->type
== XML_COMMENT_NODE
) ||
8550 (node
->type
== XML_PI_NODE
) ||
8551 (node
->type
== XML_XINCLUDE_START
) ||
8552 (node
->type
== XML_XINCLUDE_END
) ||
8553 (((node
->type
== XML_TEXT_NODE
) ||
8554 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
8555 ((ctxt
->flags
& FLAGS_MIXED_CONTENT
) ||
8556 (IS_BLANK_NODE(node
)))))) {
8563 * xmlRelaxNGNormalize:
8564 * @ctxt: a schema validation context
8565 * @str: the string to normalize
8567 * Implements the normalizeWhiteSpace( s ) function from
8568 * section 6.2.9 of the spec
8570 * Returns the new string or NULL in case of error.
8573 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
, const xmlChar
* str
)
8586 ret
= (xmlChar
*) xmlMallocAtomic(len
+ 1);
8588 xmlRngVErrMemory(ctxt
, "validating\n");
8592 while (IS_BLANK_CH(*str
))
8595 if (IS_BLANK_CH(*str
)) {
8596 while (IS_BLANK_CH(*str
))
8609 * xmlRelaxNGValidateDatatype:
8610 * @ctxt: a Relax-NG validation context
8611 * @value: the string value
8612 * @type: the datatype definition
8615 * Validate the given value against the datatype
8617 * Returns 0 if the validation succeeded or an error code.
8620 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt
,
8621 const xmlChar
* value
,
8622 xmlRelaxNGDefinePtr define
, xmlNodePtr node
)
8625 xmlRelaxNGTypeLibraryPtr lib
;
8626 void *result
= NULL
;
8627 xmlRelaxNGDefinePtr cur
;
8629 if ((define
== NULL
) || (define
->data
== NULL
)) {
8632 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8633 if (lib
->check
!= NULL
) {
8634 if ((define
->attrs
!= NULL
) &&
8635 (define
->attrs
->type
== XML_RELAXNG_PARAM
)) {
8637 lib
->check(lib
->data
, define
->name
, value
, &result
, node
);
8639 ret
= lib
->check(lib
->data
, define
->name
, value
, NULL
, node
);
8644 VALID_ERR2(XML_RELAXNG_ERR_TYPE
, define
->name
);
8645 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8646 lib
->freef(lib
->data
, result
);
8648 } else if (ret
== 1) {
8650 } else if (ret
== 2) {
8651 VALID_ERR2P(XML_RELAXNG_ERR_DUPID
, value
);
8653 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL
, define
->name
, value
);
8656 cur
= define
->attrs
;
8657 while ((ret
== 0) && (cur
!= NULL
) && (cur
->type
== XML_RELAXNG_PARAM
)) {
8658 if (lib
->facet
!= NULL
) {
8659 tmp
= lib
->facet(lib
->data
, define
->name
, cur
->name
,
8660 cur
->value
, value
, result
);
8666 if ((ret
== 0) && (define
->content
!= NULL
)) {
8667 const xmlChar
*oldvalue
, *oldendvalue
;
8669 oldvalue
= ctxt
->state
->value
;
8670 oldendvalue
= ctxt
->state
->endvalue
;
8671 ctxt
->state
->value
= (xmlChar
*) value
;
8672 ctxt
->state
->endvalue
= NULL
;
8673 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8674 ctxt
->state
->value
= (xmlChar
*) oldvalue
;
8675 ctxt
->state
->endvalue
= (xmlChar
*) oldendvalue
;
8677 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8678 lib
->freef(lib
->data
, result
);
8683 * xmlRelaxNGNextValue:
8684 * @ctxt: a Relax-NG validation context
8686 * Skip to the next value when validating within a list
8688 * Returns 0 if the operation succeeded or an error code.
8691 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt
)
8695 cur
= ctxt
->state
->value
;
8696 if ((cur
== NULL
) || (ctxt
->state
->endvalue
== NULL
)) {
8697 ctxt
->state
->value
= NULL
;
8698 ctxt
->state
->endvalue
= NULL
;
8703 while ((cur
!= ctxt
->state
->endvalue
) && (*cur
== 0))
8705 if (cur
== ctxt
->state
->endvalue
)
8706 ctxt
->state
->value
= NULL
;
8708 ctxt
->state
->value
= cur
;
8713 * xmlRelaxNGValidateValueList:
8714 * @ctxt: a Relax-NG validation context
8715 * @defines: the list of definitions to verify
8717 * Validate the given set of definitions for the current value
8719 * Returns 0 if the validation succeeded or an error code.
8722 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt
,
8723 xmlRelaxNGDefinePtr defines
)
8727 while (defines
!= NULL
) {
8728 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
8731 defines
= defines
->next
;
8737 * xmlRelaxNGValidateValue:
8738 * @ctxt: a Relax-NG validation context
8739 * @define: the definition to verify
8741 * Validate the given definition for the current value
8743 * Returns 0 if the validation succeeded or an error code.
8746 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8747 xmlRelaxNGDefinePtr define
)
8749 int ret
= 0, oldflags
;
8752 value
= ctxt
->state
->value
;
8753 switch (define
->type
) {
8754 case XML_RELAXNG_EMPTY
:{
8755 if ((value
!= NULL
) && (value
[0] != 0)) {
8758 while (IS_BLANK_CH(value
[idx
]))
8760 if (value
[idx
] != 0)
8765 case XML_RELAXNG_TEXT
:
8767 case XML_RELAXNG_VALUE
:{
8768 if (!xmlStrEqual(value
, define
->value
)) {
8769 if (define
->name
!= NULL
) {
8770 xmlRelaxNGTypeLibraryPtr lib
;
8772 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8773 if ((lib
!= NULL
) && (lib
->comp
!= NULL
)) {
8774 ret
= lib
->comp(lib
->data
, define
->name
,
8775 define
->value
, define
->node
,
8776 (void *) define
->attrs
,
8777 value
, ctxt
->state
->node
);
8781 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP
,
8784 } else if (ret
== 1) {
8790 xmlChar
*nval
, *nvalue
;
8793 * TODO: trivial optimizations are possible by
8794 * computing at compile-time
8796 nval
= xmlRelaxNGNormalize(ctxt
, define
->value
);
8797 nvalue
= xmlRelaxNGNormalize(ctxt
, value
);
8799 if ((nval
== NULL
) || (nvalue
== NULL
) ||
8800 (!xmlStrEqual(nval
, nvalue
)))
8809 xmlRelaxNGNextValue(ctxt
);
8812 case XML_RELAXNG_DATATYPE
:{
8813 ret
= xmlRelaxNGValidateDatatype(ctxt
, value
, define
,
8816 xmlRelaxNGNextValue(ctxt
);
8820 case XML_RELAXNG_CHOICE
:{
8821 xmlRelaxNGDefinePtr list
= define
->content
;
8824 oldflags
= ctxt
->flags
;
8825 ctxt
->flags
|= FLAGS_IGNORABLE
;
8827 oldvalue
= ctxt
->state
->value
;
8828 while (list
!= NULL
) {
8829 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8833 ctxt
->state
->value
= oldvalue
;
8836 ctxt
->flags
= oldflags
;
8838 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8839 xmlRelaxNGDumpValidError(ctxt
);
8841 if (ctxt
->errNr
> 0)
8842 xmlRelaxNGPopErrors(ctxt
, 0);
8846 case XML_RELAXNG_LIST
:{
8847 xmlRelaxNGDefinePtr list
= define
->content
;
8848 xmlChar
*oldvalue
, *oldend
, *val
, *cur
;
8854 oldvalue
= ctxt
->state
->value
;
8855 oldend
= ctxt
->state
->endvalue
;
8857 val
= xmlStrdup(oldvalue
);
8859 val
= xmlStrdup(BAD_CAST
"");
8862 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
8867 if (IS_BLANK_CH(*cur
)) {
8873 while (IS_BLANK_CH(*cur
))
8879 xmlGenericError(xmlGenericErrorContext
,
8880 "list value: '%s' found %d items\n",
8881 oldvalue
, nb_values
);
8884 ctxt
->state
->endvalue
= cur
;
8886 while ((*cur
== 0) && (cur
!= ctxt
->state
->endvalue
))
8889 ctxt
->state
->value
= cur
;
8891 while (list
!= NULL
) {
8892 if (ctxt
->state
->value
== ctxt
->state
->endvalue
)
8893 ctxt
->state
->value
= NULL
;
8894 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8897 xmlGenericError(xmlGenericErrorContext
,
8898 "Failed to validate value: '%s' with %d rule\n",
8899 ctxt
->state
->value
, nb_values
);
8909 if ((ret
== 0) && (ctxt
->state
->value
!= NULL
) &&
8910 (ctxt
->state
->value
!= ctxt
->state
->endvalue
)) {
8911 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA
,
8912 ctxt
->state
->value
);
8916 ctxt
->state
->value
= oldvalue
;
8917 ctxt
->state
->endvalue
= oldend
;
8920 case XML_RELAXNG_ONEORMORE
:
8921 ret
= xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8925 /* Falls through. */
8926 case XML_RELAXNG_ZEROORMORE
:{
8927 xmlChar
*cur
, *temp
;
8929 if ((ctxt
->state
->value
== NULL
) ||
8930 (*ctxt
->state
->value
== 0)) {
8934 oldflags
= ctxt
->flags
;
8935 ctxt
->flags
|= FLAGS_IGNORABLE
;
8936 cur
= ctxt
->state
->value
;
8938 while ((cur
!= NULL
) && (cur
!= ctxt
->state
->endvalue
) &&
8942 xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8944 ctxt
->state
->value
= temp
;
8948 cur
= ctxt
->state
->value
;
8950 ctxt
->flags
= oldflags
;
8951 if (ctxt
->errNr
> 0)
8952 xmlRelaxNGPopErrors(ctxt
, 0);
8955 case XML_RELAXNG_OPTIONAL
:{
8958 if ((ctxt
->state
->value
== NULL
) ||
8959 (*ctxt
->state
->value
== 0)) {
8963 oldflags
= ctxt
->flags
;
8964 ctxt
->flags
|= FLAGS_IGNORABLE
;
8965 temp
= ctxt
->state
->value
;
8966 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8967 ctxt
->flags
= oldflags
;
8969 ctxt
->state
->value
= temp
;
8970 if (ctxt
->errNr
> 0)
8971 xmlRelaxNGPopErrors(ctxt
, 0);
8975 if (ctxt
->errNr
> 0)
8976 xmlRelaxNGPopErrors(ctxt
, 0);
8979 case XML_RELAXNG_EXCEPT
:{
8980 xmlRelaxNGDefinePtr list
;
8982 list
= define
->content
;
8983 while (list
!= NULL
) {
8984 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8994 case XML_RELAXNG_DEF
:
8995 case XML_RELAXNG_GROUP
:{
8996 xmlRelaxNGDefinePtr list
;
8998 list
= define
->content
;
8999 while (list
!= NULL
) {
9000 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
9010 case XML_RELAXNG_REF
:
9011 case XML_RELAXNG_PARENTREF
:
9012 if (define
->content
== NULL
) {
9013 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
9016 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
9026 * xmlRelaxNGValidateValueContent:
9027 * @ctxt: a Relax-NG validation context
9028 * @defines: the list of definitions to verify
9030 * Validate the given definitions for the current value
9032 * Returns 0 if the validation succeeded or an error code.
9035 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt
,
9036 xmlRelaxNGDefinePtr defines
)
9040 while (defines
!= NULL
) {
9041 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
9044 defines
= defines
->next
;
9050 * xmlRelaxNGAttributeMatch:
9051 * @ctxt: a Relax-NG validation context
9052 * @define: the definition to check
9053 * @prop: the attribute
9055 * Check if the attribute matches the definition nameClass
9057 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
9060 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt
,
9061 xmlRelaxNGDefinePtr define
, xmlAttrPtr prop
)
9065 if (define
->name
!= NULL
) {
9066 if (!xmlStrEqual(define
->name
, prop
->name
))
9069 if (define
->ns
!= NULL
) {
9070 if (define
->ns
[0] == 0) {
9071 if (prop
->ns
!= NULL
)
9074 if ((prop
->ns
== NULL
) ||
9075 (!xmlStrEqual(define
->ns
, prop
->ns
->href
)))
9079 if (define
->nameClass
== NULL
)
9081 define
= define
->nameClass
;
9082 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9083 xmlRelaxNGDefinePtr list
;
9085 list
= define
->content
;
9086 while (list
!= NULL
) {
9087 ret
= xmlRelaxNGAttributeMatch(ctxt
, list
, prop
);
9094 } else if (define
->type
== XML_RELAXNG_CHOICE
) {
9095 xmlRelaxNGDefinePtr list
;
9097 list
= define
->nameClass
;
9098 while (list
!= NULL
) {
9099 ret
= xmlRelaxNGAttributeMatch(ctxt
, list
, prop
);
9113 * xmlRelaxNGValidateAttribute:
9114 * @ctxt: a Relax-NG validation context
9115 * @define: the definition to verify
9117 * Validate the given attribute definition for that node
9119 * Returns 0 if the validation succeeded or an error code.
9122 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt
,
9123 xmlRelaxNGDefinePtr define
)
9126 xmlChar
*value
, *oldvalue
;
9127 xmlAttrPtr prop
= NULL
, tmp
;
9130 if (ctxt
->state
->nbAttrLeft
<= 0)
9132 if (define
->name
!= NULL
) {
9133 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9134 tmp
= ctxt
->state
->attrs
[i
];
9135 if ((tmp
!= NULL
) && (xmlStrEqual(define
->name
, tmp
->name
))) {
9136 if ((((define
->ns
== NULL
) || (define
->ns
[0] == 0)) &&
9137 (tmp
->ns
== NULL
)) ||
9138 ((tmp
->ns
!= NULL
) &&
9139 (xmlStrEqual(define
->ns
, tmp
->ns
->href
)))) {
9146 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9147 oldvalue
= ctxt
->state
->value
;
9148 oldseq
= ctxt
->state
->seq
;
9149 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9150 ctxt
->state
->value
= value
;
9151 ctxt
->state
->endvalue
= NULL
;
9152 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9153 if (ctxt
->state
->value
!= NULL
)
9154 value
= ctxt
->state
->value
;
9157 ctxt
->state
->value
= oldvalue
;
9158 ctxt
->state
->seq
= oldseq
;
9161 * flag the attribute as processed
9163 ctxt
->state
->attrs
[i
] = NULL
;
9164 ctxt
->state
->nbAttrLeft
--;
9170 xmlGenericError(xmlGenericErrorContext
,
9171 "xmlRelaxNGValidateAttribute(%s): %d\n",
9175 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9176 tmp
= ctxt
->state
->attrs
[i
];
9177 if ((tmp
!= NULL
) &&
9178 (xmlRelaxNGAttributeMatch(ctxt
, define
, tmp
) == 1)) {
9184 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9185 oldvalue
= ctxt
->state
->value
;
9186 oldseq
= ctxt
->state
->seq
;
9187 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9188 ctxt
->state
->value
= value
;
9189 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9190 if (ctxt
->state
->value
!= NULL
)
9191 value
= ctxt
->state
->value
;
9194 ctxt
->state
->value
= oldvalue
;
9195 ctxt
->state
->seq
= oldseq
;
9198 * flag the attribute as processed
9200 ctxt
->state
->attrs
[i
] = NULL
;
9201 ctxt
->state
->nbAttrLeft
--;
9207 if (define
->ns
!= NULL
) {
9208 xmlGenericError(xmlGenericErrorContext
,
9209 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9212 xmlGenericError(xmlGenericErrorContext
,
9213 "xmlRelaxNGValidateAttribute(anyName): %d\n",
9223 * xmlRelaxNGValidateAttributeList:
9224 * @ctxt: a Relax-NG validation context
9225 * @define: the list of definition to verify
9227 * Validate the given node against the list of attribute definitions
9229 * Returns 0 if the validation succeeded or an error code.
9232 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
9233 xmlRelaxNGDefinePtr defines
)
9237 xmlRelaxNGDefinePtr cur
;
9240 while (cur
!= NULL
) {
9241 if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
9242 if (xmlRelaxNGValidateAttribute(ctxt
, cur
) != 0)
9251 while (cur
!= NULL
) {
9252 if (cur
->type
!= XML_RELAXNG_ATTRIBUTE
) {
9253 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9254 res
= xmlRelaxNGValidateDefinition(ctxt
, cur
);
9258 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9261 if (res
== -1) /* continues on -2 */
9271 * xmlRelaxNGNodeMatchesList:
9273 * @list: a NULL terminated array of definitions
9275 * Check if a node can be matched by one of the definitions
9277 * Returns 1 if matches 0 otherwise
9280 xmlRelaxNGNodeMatchesList(xmlNodePtr node
, xmlRelaxNGDefinePtr
* list
)
9282 xmlRelaxNGDefinePtr cur
;
9285 if ((node
== NULL
) || (list
== NULL
))
9289 while (cur
!= NULL
) {
9290 if ((node
->type
== XML_ELEMENT_NODE
) &&
9291 (cur
->type
== XML_RELAXNG_ELEMENT
)) {
9292 tmp
= xmlRelaxNGElementMatch(NULL
, cur
, node
);
9295 } else if (((node
->type
== XML_TEXT_NODE
) ||
9296 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
9297 ((cur
->type
== XML_RELAXNG_DATATYPE
) ||
9298 (cur
->type
== XML_RELAXNG_LIST
) ||
9299 (cur
->type
== XML_RELAXNG_TEXT
) ||
9300 (cur
->type
== XML_RELAXNG_VALUE
))) {
9309 * xmlRelaxNGValidateInterleave:
9310 * @ctxt: a Relax-NG validation context
9311 * @define: the definition to verify
9313 * Validate an interleave definition for a node.
9315 * Returns 0 if the validation succeeded or an error code.
9318 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt
,
9319 xmlRelaxNGDefinePtr define
)
9321 int ret
= 0, i
, nbgroups
;
9322 int errNr
= ctxt
->errNr
;
9325 xmlRelaxNGValidStatePtr oldstate
;
9326 xmlRelaxNGPartitionPtr partitions
;
9327 xmlRelaxNGInterleaveGroupPtr group
= NULL
;
9328 xmlNodePtr cur
, start
, last
= NULL
, lastchg
= NULL
, lastelem
;
9329 xmlNodePtr
*list
= NULL
, *lasts
= NULL
;
9331 if (define
->data
!= NULL
) {
9332 partitions
= (xmlRelaxNGPartitionPtr
) define
->data
;
9333 nbgroups
= partitions
->nbgroups
;
9335 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA
);
9339 * Optimizations for MIXED
9341 oldflags
= ctxt
->flags
;
9342 if (define
->dflags
& IS_MIXED
) {
9343 ctxt
->flags
|= FLAGS_MIXED_CONTENT
;
9344 if (nbgroups
== 2) {
9346 * this is a pure <mixed> case
9348 if (ctxt
->state
!= NULL
)
9349 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9351 if (partitions
->groups
[0]->rule
->type
== XML_RELAXNG_TEXT
)
9352 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9353 partitions
->groups
[1]->
9356 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9357 partitions
->groups
[0]->
9360 if (ctxt
->state
!= NULL
)
9361 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9365 ctxt
->flags
= oldflags
;
9371 * Build arrays to store the first and last node of the chain
9372 * pertaining to each group
9374 list
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9376 xmlRngVErrMemory(ctxt
, "validating\n");
9379 memset(list
, 0, nbgroups
* sizeof(xmlNodePtr
));
9380 lasts
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9381 if (lasts
== NULL
) {
9382 xmlRngVErrMemory(ctxt
, "validating\n");
9385 memset(lasts
, 0, nbgroups
* sizeof(xmlNodePtr
));
9388 * Walk the sequence of children finding the right group and
9389 * sorting them in sequences.
9391 cur
= ctxt
->state
->seq
;
9392 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9394 while (cur
!= NULL
) {
9395 ctxt
->state
->seq
= cur
;
9396 if ((partitions
->triage
!= NULL
) &&
9397 (partitions
->flags
& IS_DETERMINIST
)) {
9400 if ((cur
->type
== XML_TEXT_NODE
) ||
9401 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
9402 tmp
= xmlHashLookup2(partitions
->triage
, BAD_CAST
"#text",
9404 } else if (cur
->type
== XML_ELEMENT_NODE
) {
9405 if (cur
->ns
!= NULL
) {
9406 tmp
= xmlHashLookup2(partitions
->triage
, cur
->name
,
9409 tmp
= xmlHashLookup2(partitions
->triage
,
9414 xmlHashLookup2(partitions
->triage
, cur
->name
,
9418 xmlHashLookup2(partitions
->triage
, BAD_CAST
"#any",
9425 i
= ((ptrdiff_t) tmp
) - 1;
9426 if (partitions
->flags
& IS_NEEDCHECK
) {
9427 group
= partitions
->groups
[i
];
9428 if (!xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9433 for (i
= 0; i
< nbgroups
; i
++) {
9434 group
= partitions
->groups
[i
];
9437 if (xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9442 * We break as soon as an element not matched is found
9444 if (i
>= nbgroups
) {
9447 if (lasts
[i
] != NULL
) {
9448 lasts
[i
]->next
= cur
;
9454 if (cur
->next
!= NULL
)
9455 lastchg
= cur
->next
;
9458 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
->next
);
9461 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9466 oldstate
= ctxt
->state
;
9467 for (i
= 0; i
< nbgroups
; i
++) {
9468 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
, oldstate
);
9469 if (ctxt
->state
== NULL
) {
9473 group
= partitions
->groups
[i
];
9474 if (lasts
[i
] != NULL
) {
9475 last
= lasts
[i
]->next
;
9476 lasts
[i
]->next
= NULL
;
9478 ctxt
->state
->seq
= list
[i
];
9479 ret
= xmlRelaxNGValidateDefinition(ctxt
, group
->rule
);
9482 if (ctxt
->state
!= NULL
) {
9483 cur
= ctxt
->state
->seq
;
9484 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9485 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9486 oldstate
= ctxt
->state
;
9489 /* there's a nasty violation of context-free unambiguities,
9490 since in open-name-class context, interleave in the
9491 production shall finish without caring about anything
9492 else that is OK to follow in that case -- it would
9493 otherwise get marked as "extra content" and would
9494 hence fail the validation, hence this perhaps
9495 dirty attempt to rectify such a situation */
9496 && (define
->parent
->type
!= XML_RELAXNG_DEF
9497 || !xmlStrEqual(define
->parent
->name
,
9498 (const xmlChar
*) "open-name-class"))) {
9499 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9501 ctxt
->state
= oldstate
;
9504 } else if (ctxt
->states
!= NULL
) {
9511 * PBM: what happen if there is attributes checks in the interleaves
9514 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9515 cur
= ctxt
->states
->tabState
[j
]->seq
;
9516 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9519 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9523 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9524 /* try to keep the latest one to mach old heuristic */
9525 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9530 } else if (found
== 0) {
9531 if (lowattr
== -1) {
9532 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9535 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9536 /* try to keep the latest one to mach old heuristic */
9537 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9543 * BIG PBM: here we pick only one restarting point :-(
9545 if (ctxt
->states
->nbState
> 0) {
9546 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9548 oldstate
= ctxt
->states
->tabState
[best
];
9549 ctxt
->states
->tabState
[best
] = NULL
;
9552 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1];
9553 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1] = NULL
;
9554 ctxt
->states
->nbState
--;
9557 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9558 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[j
]);
9560 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
9561 ctxt
->states
= NULL
;
9564 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
,
9565 (const xmlChar
*) "noname");
9567 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9570 ctxt
->state
= oldstate
;
9577 if (lasts
[i
] != NULL
) {
9578 lasts
[i
]->next
= last
;
9581 if (ctxt
->state
!= NULL
)
9582 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
9583 ctxt
->state
= oldstate
;
9584 ctxt
->state
->seq
= lastelem
;
9586 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9592 ctxt
->flags
= oldflags
;
9594 * builds the next links chain from the prev one
9597 while (cur
!= NULL
) {
9598 if ((cur
== start
) || (cur
->prev
== NULL
))
9600 cur
->prev
->next
= cur
;
9604 if (ctxt
->errNr
> errNr
)
9605 xmlRelaxNGPopErrors(ctxt
, errNr
);
9614 * xmlRelaxNGValidateDefinitionList:
9615 * @ctxt: a Relax-NG validation context
9616 * @define: the list of definition to verify
9618 * Validate the given node content against the (list) of definitions
9620 * Returns 0 if the validation succeeded or an error code.
9623 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt
,
9624 xmlRelaxNGDefinePtr defines
)
9629 if (defines
== NULL
) {
9630 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL
,
9631 BAD_CAST
"NULL definition list");
9634 while (defines
!= NULL
) {
9635 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9636 res
= xmlRelaxNGValidateDefinition(ctxt
, defines
);
9640 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9643 if (res
== -1) /* continues on -2 */
9645 defines
= defines
->next
;
9652 * xmlRelaxNGElementMatch:
9653 * @ctxt: a Relax-NG validation context
9654 * @define: the definition to check
9655 * @elem: the element
9657 * Check if the element matches the definition nameClass
9659 * Returns 1 if the element matches, 0 if no, or -1 in case of error
9662 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
9663 xmlRelaxNGDefinePtr define
, xmlNodePtr elem
)
9665 int ret
= 0, oldflags
= 0;
9667 if (define
->name
!= NULL
) {
9668 if (!xmlStrEqual(elem
->name
, define
->name
)) {
9669 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME
, define
->name
, elem
->name
);
9673 if ((define
->ns
!= NULL
) && (define
->ns
[0] != 0)) {
9674 if (elem
->ns
== NULL
) {
9675 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS
, elem
->name
);
9677 } else if (!xmlStrEqual(elem
->ns
->href
, define
->ns
)) {
9678 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS
,
9679 elem
->name
, define
->ns
);
9682 } else if ((elem
->ns
!= NULL
) && (define
->ns
!= NULL
) &&
9683 (define
->name
== NULL
)) {
9684 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, elem
->name
);
9686 } else if ((elem
->ns
!= NULL
) && (define
->name
!= NULL
)) {
9687 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, define
->name
);
9691 if (define
->nameClass
== NULL
)
9694 define
= define
->nameClass
;
9695 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9696 xmlRelaxNGDefinePtr list
;
9699 oldflags
= ctxt
->flags
;
9700 ctxt
->flags
|= FLAGS_IGNORABLE
;
9703 list
= define
->content
;
9704 while (list
!= NULL
) {
9705 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9708 ctxt
->flags
= oldflags
;
9713 ctxt
->flags
= oldflags
;
9720 ctxt
->flags
= oldflags
;
9722 } else if (define
->type
== XML_RELAXNG_CHOICE
) {
9723 xmlRelaxNGDefinePtr list
;
9726 oldflags
= ctxt
->flags
;
9727 ctxt
->flags
|= FLAGS_IGNORABLE
;
9730 list
= define
->nameClass
;
9731 while (list
!= NULL
) {
9732 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9735 ctxt
->flags
= oldflags
;
9740 ctxt
->flags
= oldflags
;
9747 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9748 xmlRelaxNGDumpValidError(ctxt
);
9750 if (ctxt
->errNr
> 0)
9751 xmlRelaxNGPopErrors(ctxt
, 0);
9756 ctxt
->flags
= oldflags
;
9765 * xmlRelaxNGBestState:
9766 * @ctxt: a Relax-NG validation context
9768 * Find the "best" state in the ctxt->states list of states to report
9769 * errors about. I.e. a state with no element left in the child list
9770 * or the one with the less attributes left.
9771 * This is called only if a validation error was detected
9773 * Returns the index of the "best" state or -1 in case of error
9776 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt
)
9778 xmlRelaxNGValidStatePtr state
;
9781 int value
= 1000000;
9783 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9784 (ctxt
->states
->nbState
<= 0))
9787 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9788 state
= ctxt
->states
->tabState
[i
];
9791 if (state
->seq
!= NULL
) {
9792 if ((best
== -1) || (value
> 100000)) {
9797 tmp
= state
->nbAttrLeft
;
9798 if ((best
== -1) || (value
> tmp
)) {
9808 * xmlRelaxNGLogBestError:
9809 * @ctxt: a Relax-NG validation context
9811 * Find the "best" state in the ctxt->states list of states to report
9812 * errors about and log it.
9815 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
)
9819 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9820 (ctxt
->states
->nbState
<= 0))
9823 best
= xmlRelaxNGBestState(ctxt
);
9824 if ((best
>= 0) && (best
< ctxt
->states
->nbState
)) {
9825 ctxt
->state
= ctxt
->states
->tabState
[best
];
9827 xmlRelaxNGValidateElementEnd(ctxt
, 1);
9832 * xmlRelaxNGValidateElementEnd:
9833 * @ctxt: a Relax-NG validation context
9834 * @dolog: indicate that error logging should be done
9836 * Validate the end of the element, implements check that
9837 * there is nothing left not consumed in the element content
9838 * or in the attribute list.
9840 * Returns 0 if the validation succeeded or an error code.
9843 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
, int dolog
)
9846 xmlRelaxNGValidStatePtr state
;
9848 state
= ctxt
->state
;
9849 if (state
->seq
!= NULL
) {
9850 state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, state
->seq
);
9851 if (state
->seq
!= NULL
) {
9853 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT
,
9854 state
->node
->name
, state
->seq
->name
);
9859 for (i
= 0; i
< state
->nbAttrs
; i
++) {
9860 if (state
->attrs
[i
] != NULL
) {
9862 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR
,
9863 state
->attrs
[i
]->name
, state
->node
->name
);
9872 * xmlRelaxNGValidateState:
9873 * @ctxt: a Relax-NG validation context
9874 * @define: the definition to verify
9876 * Validate the current state against the definition
9878 * Returns 0 if the validation succeeded or an error code.
9881 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt
,
9882 xmlRelaxNGDefinePtr define
)
9885 int ret
= 0, i
, tmp
, oldflags
, errNr
;
9886 xmlRelaxNGValidStatePtr oldstate
= NULL
, state
;
9888 if (define
== NULL
) {
9889 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
9893 if (ctxt
->state
!= NULL
) {
9894 node
= ctxt
->state
->seq
;
9899 for (i
= 0; i
< ctxt
->depth
; i
++)
9900 xmlGenericError(xmlGenericErrorContext
, " ");
9901 xmlGenericError(xmlGenericErrorContext
,
9902 "Start validating %s ", xmlRelaxNGDefName(define
));
9903 if (define
->name
!= NULL
)
9904 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
9905 if ((node
!= NULL
) && (node
->name
!= NULL
))
9906 xmlGenericError(xmlGenericErrorContext
, "on %s\n", node
->name
);
9908 xmlGenericError(xmlGenericErrorContext
, "\n");
9911 switch (define
->type
) {
9912 case XML_RELAXNG_EMPTY
:
9915 case XML_RELAXNG_NOT_ALLOWED
:
9918 case XML_RELAXNG_TEXT
:
9919 while ((node
!= NULL
) &&
9920 ((node
->type
== XML_TEXT_NODE
) ||
9921 (node
->type
== XML_COMMENT_NODE
) ||
9922 (node
->type
== XML_PI_NODE
) ||
9923 (node
->type
== XML_CDATA_SECTION_NODE
)))
9925 ctxt
->state
->seq
= node
;
9927 case XML_RELAXNG_ELEMENT
:
9928 errNr
= ctxt
->errNr
;
9929 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
9931 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, define
->name
);
9933 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9934 xmlRelaxNGDumpValidError(ctxt
);
9937 if (node
->type
!= XML_ELEMENT_NODE
) {
9938 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
9940 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9941 xmlRelaxNGDumpValidError(ctxt
);
9945 * This node was already validated successfully against
9948 if (node
->psvi
== define
) {
9949 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
9950 if (ctxt
->errNr
> errNr
)
9951 xmlRelaxNGPopErrors(ctxt
, errNr
);
9952 if (ctxt
->errNr
!= 0) {
9953 while ((ctxt
->err
!= NULL
) &&
9954 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
)
9955 && (xmlStrEqual(ctxt
->err
->arg2
, node
->name
)))
9958 XML_RELAXNG_ERR_ELEMEXTRANS
)
9959 && (xmlStrEqual(ctxt
->err
->arg1
, node
->name
)))
9960 || (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
)
9961 || (ctxt
->err
->err
==
9962 XML_RELAXNG_ERR_NOTELEM
)))
9963 xmlRelaxNGValidErrorPop(ctxt
);
9968 ret
= xmlRelaxNGElementMatch(ctxt
, define
, node
);
9971 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9972 xmlRelaxNGDumpValidError(ctxt
);
9976 if (ctxt
->errNr
!= 0) {
9977 if (ctxt
->errNr
> errNr
)
9978 xmlRelaxNGPopErrors(ctxt
, errNr
);
9979 while ((ctxt
->err
!= NULL
) &&
9980 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
) &&
9981 (xmlStrEqual(ctxt
->err
->arg2
, node
->name
))) ||
9982 ((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMEXTRANS
) &&
9983 (xmlStrEqual(ctxt
->err
->arg1
, node
->name
))) ||
9984 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
) ||
9985 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOTELEM
)))
9986 xmlRelaxNGValidErrorPop(ctxt
);
9988 errNr
= ctxt
->errNr
;
9990 oldflags
= ctxt
->flags
;
9991 if (ctxt
->flags
& FLAGS_MIXED_CONTENT
) {
9992 ctxt
->flags
-= FLAGS_MIXED_CONTENT
;
9994 state
= xmlRelaxNGNewValidState(ctxt
, node
);
9995 if (state
== NULL
) {
9997 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9998 xmlRelaxNGDumpValidError(ctxt
);
10002 oldstate
= ctxt
->state
;
10003 ctxt
->state
= state
;
10004 if (define
->attrs
!= NULL
) {
10005 tmp
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
10008 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
10011 if (define
->contModel
!= NULL
) {
10012 xmlRelaxNGValidStatePtr nstate
, tmpstate
= ctxt
->state
;
10013 xmlRelaxNGStatesPtr tmpstates
= ctxt
->states
;
10016 nstate
= xmlRelaxNGNewValidState(ctxt
, node
);
10017 ctxt
->state
= nstate
;
10018 ctxt
->states
= NULL
;
10020 tmp
= xmlRelaxNGValidateCompiledContent(ctxt
,
10023 nseq
= ctxt
->state
->seq
;
10024 ctxt
->state
= tmpstate
;
10025 ctxt
->states
= tmpstates
;
10026 xmlRelaxNGFreeValidState(ctxt
, nstate
);
10028 #ifdef DEBUG_COMPILE
10029 xmlGenericError(xmlGenericErrorContext
,
10030 "Validating content of '%s' : %d\n",
10031 define
->name
, tmp
);
10036 if (ctxt
->states
!= NULL
) {
10039 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10040 state
= ctxt
->states
->tabState
[i
];
10041 ctxt
->state
= state
;
10042 ctxt
->state
->seq
= nseq
;
10044 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
10051 * validation error, log the message for the "best" one
10053 ctxt
->flags
|= FLAGS_IGNORABLE
;
10054 xmlRelaxNGLogBestError(ctxt
);
10056 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10057 xmlRelaxNGFreeValidState(ctxt
,
10061 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10062 ctxt
->flags
= oldflags
;
10063 ctxt
->states
= NULL
;
10064 if ((ret
== 0) && (tmp
== -1))
10067 state
= ctxt
->state
;
10068 if (ctxt
->state
!= NULL
)
10069 ctxt
->state
->seq
= nseq
;
10071 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
10072 xmlRelaxNGFreeValidState(ctxt
, state
);
10075 if (define
->content
!= NULL
) {
10076 tmp
= xmlRelaxNGValidateDefinitionList(ctxt
,
10081 if (ctxt
->state
== NULL
) {
10082 ctxt
->state
= oldstate
;
10083 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
10085 ctxt
->state
= NULL
;
10087 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
10093 if (ctxt
->states
!= NULL
) {
10096 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10097 state
= ctxt
->states
->tabState
[i
];
10098 ctxt
->state
= state
;
10100 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
10107 * validation error, log the message for the "best" one
10109 ctxt
->flags
|= FLAGS_IGNORABLE
;
10110 xmlRelaxNGLogBestError(ctxt
);
10112 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10113 xmlRelaxNGFreeValidState(ctxt
,
10114 ctxt
->states
->tabState
[i
]);
10115 ctxt
->states
->tabState
[i
] = NULL
;
10117 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10118 ctxt
->flags
= oldflags
;
10119 ctxt
->states
= NULL
;
10120 if ((ret
== 0) && (tmp
== -1))
10123 state
= ctxt
->state
;
10125 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
10126 xmlRelaxNGFreeValidState(ctxt
, state
);
10130 node
->psvi
= define
;
10132 ctxt
->flags
= oldflags
;
10133 ctxt
->state
= oldstate
;
10134 if (oldstate
!= NULL
)
10135 oldstate
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
10137 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10138 xmlRelaxNGDumpValidError(ctxt
);
10146 if (ctxt
->errNr
> errNr
)
10147 xmlRelaxNGPopErrors(ctxt
, errNr
);
10151 xmlGenericError(xmlGenericErrorContext
,
10152 "xmlRelaxNGValidateDefinition(): validated %s : %d",
10154 if (oldstate
== NULL
)
10155 xmlGenericError(xmlGenericErrorContext
, ": no state\n");
10156 else if (oldstate
->seq
== NULL
)
10157 xmlGenericError(xmlGenericErrorContext
, ": done\n");
10158 else if (oldstate
->seq
->type
== XML_ELEMENT_NODE
)
10159 xmlGenericError(xmlGenericErrorContext
, ": next elem %s\n",
10160 oldstate
->seq
->name
);
10162 xmlGenericError(xmlGenericErrorContext
, ": next %s %d\n",
10163 oldstate
->seq
->name
, oldstate
->seq
->type
);
10166 case XML_RELAXNG_OPTIONAL
:{
10167 errNr
= ctxt
->errNr
;
10168 oldflags
= ctxt
->flags
;
10169 ctxt
->flags
|= FLAGS_IGNORABLE
;
10170 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10172 xmlRelaxNGValidateDefinitionList(ctxt
,
10175 if (ctxt
->state
!= NULL
)
10176 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10177 ctxt
->state
= oldstate
;
10178 ctxt
->flags
= oldflags
;
10180 if (ctxt
->errNr
> errNr
)
10181 xmlRelaxNGPopErrors(ctxt
, errNr
);
10184 if (ctxt
->states
!= NULL
) {
10185 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10187 ctxt
->states
= xmlRelaxNGNewStates(ctxt
, 1);
10188 if (ctxt
->states
== NULL
) {
10189 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10190 ctxt
->flags
= oldflags
;
10192 if (ctxt
->errNr
> errNr
)
10193 xmlRelaxNGPopErrors(ctxt
, errNr
);
10196 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10197 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, ctxt
->state
);
10198 ctxt
->state
= NULL
;
10200 ctxt
->flags
= oldflags
;
10202 if (ctxt
->errNr
> errNr
)
10203 xmlRelaxNGPopErrors(ctxt
, errNr
);
10206 case XML_RELAXNG_ONEORMORE
:
10207 errNr
= ctxt
->errNr
;
10208 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10212 if (ctxt
->errNr
> errNr
)
10213 xmlRelaxNGPopErrors(ctxt
, errNr
);
10214 /* Falls through. */
10215 case XML_RELAXNG_ZEROORMORE
:{
10217 xmlRelaxNGStatesPtr states
= NULL
, res
= NULL
;
10220 errNr
= ctxt
->errNr
;
10221 res
= xmlRelaxNGNewStates(ctxt
, 1);
10227 * All the input states are also exit states
10229 if (ctxt
->state
!= NULL
) {
10230 xmlRelaxNGAddStates(ctxt
, res
,
10231 xmlRelaxNGCopyValidState(ctxt
,
10235 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10236 xmlRelaxNGAddStates(ctxt
, res
,
10237 xmlRelaxNGCopyValidState(ctxt
,
10238 ctxt
->states
->tabState
[j
]));
10241 oldflags
= ctxt
->flags
;
10242 ctxt
->flags
|= FLAGS_IGNORABLE
;
10245 base
= res
->nbState
;
10247 if (ctxt
->states
!= NULL
) {
10248 states
= ctxt
->states
;
10249 for (i
= 0; i
< states
->nbState
; i
++) {
10250 ctxt
->state
= states
->tabState
[i
];
10251 ctxt
->states
= NULL
;
10252 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10256 if (ctxt
->state
!= NULL
) {
10257 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10259 ctxt
->state
= NULL
;
10262 } else if (ctxt
->states
!= NULL
) {
10263 for (j
= 0; j
< ctxt
->states
->nbState
;
10266 xmlRelaxNGAddStates(ctxt
, res
,
10267 ctxt
->states
->tabState
[j
]);
10271 xmlRelaxNGFreeStates(ctxt
,
10273 ctxt
->states
= NULL
;
10276 if (ctxt
->state
!= NULL
) {
10277 xmlRelaxNGFreeValidState(ctxt
,
10279 ctxt
->state
= NULL
;
10284 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10288 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10289 ctxt
->state
= NULL
;
10291 base
= res
->nbState
;
10292 if (ctxt
->state
!= NULL
) {
10293 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10295 ctxt
->state
= NULL
;
10298 } else if (ctxt
->states
!= NULL
) {
10299 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10300 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10301 ctxt
->states
->tabState
[j
]);
10305 if (states
== NULL
) {
10306 states
= ctxt
->states
;
10308 xmlRelaxNGFreeStates(ctxt
,
10311 ctxt
->states
= NULL
;
10317 * Collect all the new nodes added at that step
10318 * and make them the new node set
10320 if (res
->nbState
- base
== 1) {
10321 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
,
10326 if (states
== NULL
) {
10327 xmlRelaxNGNewStates(ctxt
,
10328 res
->nbState
- base
);
10329 states
= ctxt
->states
;
10330 if (states
== NULL
) {
10335 states
->nbState
= 0;
10336 for (i
= base
; i
< res
->nbState
; i
++)
10337 xmlRelaxNGAddStates(ctxt
, states
,
10338 xmlRelaxNGCopyValidState
10339 (ctxt
, res
->tabState
[i
]));
10340 ctxt
->states
= states
;
10343 } while (progress
== 1);
10344 if (states
!= NULL
) {
10345 xmlRelaxNGFreeStates(ctxt
, states
);
10347 ctxt
->states
= res
;
10348 ctxt
->flags
= oldflags
;
10351 * errors may have to be propagated back...
10353 if (ctxt
->errNr
> errNr
)
10354 xmlRelaxNGPopErrors(ctxt
, errNr
);
10359 case XML_RELAXNG_CHOICE
:{
10360 xmlRelaxNGDefinePtr list
= NULL
;
10361 xmlRelaxNGStatesPtr states
= NULL
;
10363 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10365 errNr
= ctxt
->errNr
;
10366 if ((define
->dflags
& IS_TRIABLE
) && (define
->data
!= NULL
) &&
10369 * node == NULL can't be optimized since IS_TRIABLE
10370 * doesn't account for choice which may lead to
10373 xmlHashTablePtr triage
=
10374 (xmlHashTablePtr
) define
->data
;
10377 * Something we can optimize cleanly there is only one
10378 * possible branch out !
10380 if ((node
->type
== XML_TEXT_NODE
) ||
10381 (node
->type
== XML_CDATA_SECTION_NODE
)) {
10383 xmlHashLookup2(triage
, BAD_CAST
"#text", NULL
);
10384 } else if (node
->type
== XML_ELEMENT_NODE
) {
10385 if (node
->ns
!= NULL
) {
10386 list
= xmlHashLookup2(triage
, node
->name
,
10390 xmlHashLookup2(triage
, BAD_CAST
"#any",
10394 xmlHashLookup2(triage
, node
->name
, NULL
);
10397 xmlHashLookup2(triage
, BAD_CAST
"#any",
10400 if (list
== NULL
) {
10402 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, node
->name
);
10405 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10411 list
= define
->content
;
10412 oldflags
= ctxt
->flags
;
10413 ctxt
->flags
|= FLAGS_IGNORABLE
;
10415 while (list
!= NULL
) {
10416 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10417 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10419 if (states
== NULL
) {
10420 states
= xmlRelaxNGNewStates(ctxt
, 1);
10422 if (ctxt
->state
!= NULL
) {
10423 xmlRelaxNGAddStates(ctxt
, states
, ctxt
->state
);
10424 } else if (ctxt
->states
!= NULL
) {
10425 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10426 xmlRelaxNGAddStates(ctxt
, states
,
10430 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10431 ctxt
->states
= NULL
;
10434 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10436 ctxt
->state
= oldstate
;
10439 if (states
!= NULL
) {
10440 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10441 ctxt
->states
= states
;
10442 ctxt
->state
= NULL
;
10445 ctxt
->states
= NULL
;
10447 ctxt
->flags
= oldflags
;
10449 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10450 xmlRelaxNGDumpValidError(ctxt
);
10453 if (ctxt
->errNr
> errNr
)
10454 xmlRelaxNGPopErrors(ctxt
, errNr
);
10458 case XML_RELAXNG_DEF
:
10459 case XML_RELAXNG_GROUP
:
10460 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10462 case XML_RELAXNG_INTERLEAVE
:
10463 ret
= xmlRelaxNGValidateInterleave(ctxt
, define
);
10465 case XML_RELAXNG_ATTRIBUTE
:
10466 ret
= xmlRelaxNGValidateAttribute(ctxt
, define
);
10468 case XML_RELAXNG_START
:
10469 case XML_RELAXNG_NOOP
:
10470 case XML_RELAXNG_REF
:
10471 case XML_RELAXNG_EXTERNALREF
:
10472 case XML_RELAXNG_PARENTREF
:
10473 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
->content
);
10475 case XML_RELAXNG_DATATYPE
:{
10477 xmlChar
*content
= NULL
;
10480 while (child
!= NULL
) {
10481 if (child
->type
== XML_ELEMENT_NODE
) {
10482 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM
,
10483 node
->parent
->name
);
10486 } else if ((child
->type
== XML_TEXT_NODE
) ||
10487 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10488 content
= xmlStrcat(content
, child
->content
);
10490 /* TODO: handle entities ... */
10491 child
= child
->next
;
10494 if (content
!= NULL
)
10498 if (content
== NULL
) {
10499 content
= xmlStrdup(BAD_CAST
"");
10500 if (content
== NULL
) {
10501 xmlRngVErrMemory(ctxt
, "validating\n");
10506 ret
= xmlRelaxNGValidateDatatype(ctxt
, content
, define
,
10509 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE
, define
->name
);
10510 } else if (ret
== 0) {
10511 ctxt
->state
->seq
= NULL
;
10513 if (content
!= NULL
)
10517 case XML_RELAXNG_VALUE
:{
10518 xmlChar
*content
= NULL
;
10523 while (child
!= NULL
) {
10524 if (child
->type
== XML_ELEMENT_NODE
) {
10525 VALID_ERR2(XML_RELAXNG_ERR_VALELEM
,
10526 node
->parent
->name
);
10529 } else if ((child
->type
== XML_TEXT_NODE
) ||
10530 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10531 content
= xmlStrcat(content
, child
->content
);
10533 /* TODO: handle entities ... */
10534 child
= child
->next
;
10537 if (content
!= NULL
)
10541 if (content
== NULL
) {
10542 content
= xmlStrdup(BAD_CAST
"");
10543 if (content
== NULL
) {
10544 xmlRngVErrMemory(ctxt
, "validating\n");
10549 oldvalue
= ctxt
->state
->value
;
10550 ctxt
->state
->value
= content
;
10551 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10552 ctxt
->state
->value
= oldvalue
;
10554 VALID_ERR2(XML_RELAXNG_ERR_VALUE
, define
->name
);
10555 } else if (ret
== 0) {
10556 ctxt
->state
->seq
= NULL
;
10558 if (content
!= NULL
)
10562 case XML_RELAXNG_LIST
:{
10565 xmlChar
*oldvalue
, *oldendvalue
;
10569 * Make sure it's only text nodes
10574 while (child
!= NULL
) {
10575 if (child
->type
== XML_ELEMENT_NODE
) {
10576 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM
,
10577 node
->parent
->name
);
10580 } else if ((child
->type
== XML_TEXT_NODE
) ||
10581 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10582 content
= xmlStrcat(content
, child
->content
);
10584 /* TODO: handle entities ... */
10585 child
= child
->next
;
10588 if (content
!= NULL
)
10592 if (content
== NULL
) {
10593 content
= xmlStrdup(BAD_CAST
"");
10594 if (content
== NULL
) {
10595 xmlRngVErrMemory(ctxt
, "validating\n");
10600 len
= xmlStrlen(content
);
10601 oldvalue
= ctxt
->state
->value
;
10602 oldendvalue
= ctxt
->state
->endvalue
;
10603 ctxt
->state
->value
= content
;
10604 ctxt
->state
->endvalue
= content
+ len
;
10605 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10606 ctxt
->state
->value
= oldvalue
;
10607 ctxt
->state
->endvalue
= oldendvalue
;
10609 VALID_ERR(XML_RELAXNG_ERR_LIST
);
10610 } else if ((ret
== 0) && (node
!= NULL
)) {
10611 ctxt
->state
->seq
= node
->next
;
10613 if (content
!= NULL
)
10617 case XML_RELAXNG_EXCEPT
:
10618 case XML_RELAXNG_PARAM
:
10624 for (i
= 0; i
< ctxt
->depth
; i
++)
10625 xmlGenericError(xmlGenericErrorContext
, " ");
10626 xmlGenericError(xmlGenericErrorContext
,
10627 "Validating %s ", xmlRelaxNGDefName(define
));
10628 if (define
->name
!= NULL
)
10629 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
10631 xmlGenericError(xmlGenericErrorContext
, "succeeded\n");
10633 xmlGenericError(xmlGenericErrorContext
, "failed\n");
10639 * xmlRelaxNGValidateDefinition:
10640 * @ctxt: a Relax-NG validation context
10641 * @define: the definition to verify
10643 * Validate the current node lists against the definition
10645 * Returns 0 if the validation succeeded or an error code.
10648 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
10649 xmlRelaxNGDefinePtr define
)
10651 xmlRelaxNGStatesPtr states
, res
;
10652 int i
, j
, k
, ret
, oldflags
;
10655 * We should NOT have both ctxt->state and ctxt->states
10657 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10658 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10659 ctxt
->state
= NULL
;
10662 if ((ctxt
->states
== NULL
) || (ctxt
->states
->nbState
== 1)) {
10663 if (ctxt
->states
!= NULL
) {
10664 ctxt
->state
= ctxt
->states
->tabState
[0];
10665 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10666 ctxt
->states
= NULL
;
10668 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10669 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10670 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10671 ctxt
->state
= NULL
;
10673 if ((ctxt
->states
!= NULL
) && (ctxt
->states
->nbState
== 1)) {
10674 ctxt
->state
= ctxt
->states
->tabState
[0];
10675 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10676 ctxt
->states
= NULL
;
10681 states
= ctxt
->states
;
10682 ctxt
->states
= NULL
;
10685 oldflags
= ctxt
->flags
;
10686 ctxt
->flags
|= FLAGS_IGNORABLE
;
10687 for (i
= 0; i
< states
->nbState
; i
++) {
10688 ctxt
->state
= states
->tabState
[i
];
10689 ctxt
->states
= NULL
;
10690 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10692 * We should NOT have both ctxt->state and ctxt->states
10694 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10695 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10696 ctxt
->state
= NULL
;
10699 if (ctxt
->states
== NULL
) {
10701 /* add the state to the container */
10702 xmlRelaxNGAddStates(ctxt
, res
, ctxt
->state
);
10703 ctxt
->state
= NULL
;
10705 /* add the state directly in states */
10706 states
->tabState
[j
++] = ctxt
->state
;
10707 ctxt
->state
= NULL
;
10711 /* make it the new container and copy other results */
10712 res
= ctxt
->states
;
10713 ctxt
->states
= NULL
;
10714 for (k
= 0; k
< j
; k
++)
10715 xmlRelaxNGAddStates(ctxt
, res
,
10716 states
->tabState
[k
]);
10718 /* add all the new results to res and reff the container */
10719 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10720 xmlRelaxNGAddStates(ctxt
, res
,
10721 ctxt
->states
->tabState
[k
]);
10722 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10723 ctxt
->states
= NULL
;
10727 if (ctxt
->state
!= NULL
) {
10728 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10729 ctxt
->state
= NULL
;
10730 } else if (ctxt
->states
!= NULL
) {
10731 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10732 xmlRelaxNGFreeValidState(ctxt
,
10733 ctxt
->states
->tabState
[k
]);
10734 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10735 ctxt
->states
= NULL
;
10739 ctxt
->flags
= oldflags
;
10741 xmlRelaxNGFreeStates(ctxt
, states
);
10742 ctxt
->states
= res
;
10744 } else if (j
> 1) {
10745 states
->nbState
= j
;
10746 ctxt
->states
= states
;
10748 } else if (j
== 1) {
10749 ctxt
->state
= states
->tabState
[0];
10750 xmlRelaxNGFreeStates(ctxt
, states
);
10754 xmlRelaxNGFreeStates(ctxt
, states
);
10755 if (ctxt
->states
!= NULL
) {
10756 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10757 ctxt
->states
= NULL
;
10760 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10761 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10762 ctxt
->state
= NULL
;
10768 * xmlRelaxNGValidateDocument:
10769 * @ctxt: a Relax-NG validation context
10770 * @doc: the document
10772 * Validate the given document
10774 * Returns 0 if the validation succeeded or an error code.
10777 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
10780 xmlRelaxNGPtr schema
;
10781 xmlRelaxNGGrammarPtr grammar
;
10782 xmlRelaxNGValidStatePtr state
;
10785 if ((ctxt
== NULL
) || (ctxt
->schema
== NULL
) || (doc
== NULL
))
10788 ctxt
->errNo
= XML_RELAXNG_OK
;
10789 schema
= ctxt
->schema
;
10790 grammar
= schema
->topgrammar
;
10791 if (grammar
== NULL
) {
10792 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
10795 state
= xmlRelaxNGNewValidState(ctxt
, NULL
);
10796 ctxt
->state
= state
;
10797 ret
= xmlRelaxNGValidateDefinition(ctxt
, grammar
->start
);
10798 if ((ctxt
->state
!= NULL
) && (state
->seq
!= NULL
)) {
10799 state
= ctxt
->state
;
10801 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10802 if (node
!= NULL
) {
10804 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10808 } else if (ctxt
->states
!= NULL
) {
10812 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10813 state
= ctxt
->states
->tabState
[i
];
10815 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10818 xmlRelaxNGFreeValidState(ctxt
, state
);
10822 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10827 if (ctxt
->state
!= NULL
) {
10828 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10829 ctxt
->state
= NULL
;
10832 xmlRelaxNGDumpValidError(ctxt
);
10834 else if (ctxt
->errNr
!= 0) {
10835 ctxt
->error(ctxt
->userData
,
10836 "%d Extra error messages left on stack !\n",
10838 xmlRelaxNGDumpValidError(ctxt
);
10841 #ifdef LIBXML_VALID_ENABLED
10842 if (ctxt
->idref
== 1) {
10843 xmlValidCtxt vctxt
;
10845 memset(&vctxt
, 0, sizeof(xmlValidCtxt
));
10847 vctxt
.error
= ctxt
->error
;
10848 vctxt
.warning
= ctxt
->warning
;
10849 vctxt
.userData
= ctxt
->userData
;
10851 if (xmlValidateDocumentFinal(&vctxt
, doc
) != 1)
10854 #endif /* LIBXML_VALID_ENABLED */
10855 if ((ret
== 0) && (ctxt
->errNo
!= XML_RELAXNG_OK
))
10862 * xmlRelaxNGCleanPSVI:
10863 * @node: an input element or document
10865 * Call this routine to speed up XPath computation on static documents.
10866 * This stamps all the element nodes with the document order
10867 * Like for line information, the order is kept in the element->content
10868 * field, the value stored is actually - the node number (starting at -1)
10869 * to be able to differentiate from line numbers.
10871 * Returns the number of elements found in the document or -1 in case
10875 xmlRelaxNGCleanPSVI(xmlNodePtr node
) {
10878 if ((node
== NULL
) ||
10879 ((node
->type
!= XML_ELEMENT_NODE
) &&
10880 (node
->type
!= XML_DOCUMENT_NODE
) &&
10881 (node
->type
!= XML_HTML_DOCUMENT_NODE
)))
10883 if (node
->type
== XML_ELEMENT_NODE
)
10886 cur
= node
->children
;
10887 while (cur
!= NULL
) {
10888 if (cur
->type
== XML_ELEMENT_NODE
) {
10890 if (cur
->children
!= NULL
) {
10891 cur
= cur
->children
;
10895 if (cur
->next
!= NULL
) {
10907 if (cur
->next
!= NULL
) {
10911 } while (cur
!= NULL
);
10915 /************************************************************************
10917 * Validation interfaces *
10919 ************************************************************************/
10922 * xmlRelaxNGNewValidCtxt:
10923 * @schema: a precompiled XML RelaxNGs
10925 * Create an XML RelaxNGs validation context based on the given schema
10927 * Returns the validation context or NULL in case of error
10929 xmlRelaxNGValidCtxtPtr
10930 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema
)
10932 xmlRelaxNGValidCtxtPtr ret
;
10934 ret
= (xmlRelaxNGValidCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGValidCtxt
));
10936 xmlRngVErrMemory(NULL
, "building context\n");
10939 memset(ret
, 0, sizeof(xmlRelaxNGValidCtxt
));
10940 ret
->schema
= schema
;
10941 ret
->error
= xmlGenericError
;
10942 ret
->userData
= xmlGenericErrorContext
;
10946 ret
->errTab
= NULL
;
10947 if (schema
!= NULL
)
10948 ret
->idref
= schema
->idref
;
10949 ret
->states
= NULL
;
10950 ret
->freeState
= NULL
;
10951 ret
->freeStates
= NULL
;
10952 ret
->errNo
= XML_RELAXNG_OK
;
10957 * xmlRelaxNGFreeValidCtxt:
10958 * @ctxt: the schema validation context
10960 * Free the resources associated to the schema validation context
10963 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt
)
10969 if (ctxt
->states
!= NULL
)
10970 xmlRelaxNGFreeStates(NULL
, ctxt
->states
);
10971 if (ctxt
->freeState
!= NULL
) {
10972 for (k
= 0; k
< ctxt
->freeState
->nbState
; k
++) {
10973 xmlRelaxNGFreeValidState(NULL
, ctxt
->freeState
->tabState
[k
]);
10975 xmlRelaxNGFreeStates(NULL
, ctxt
->freeState
);
10977 if (ctxt
->freeStates
!= NULL
) {
10978 for (k
= 0; k
< ctxt
->freeStatesNr
; k
++) {
10979 xmlRelaxNGFreeStates(NULL
, ctxt
->freeStates
[k
]);
10981 xmlFree(ctxt
->freeStates
);
10983 if (ctxt
->errTab
!= NULL
)
10984 xmlFree(ctxt
->errTab
);
10985 if (ctxt
->elemTab
!= NULL
) {
10986 xmlRegExecCtxtPtr exec
;
10988 exec
= xmlRelaxNGElemPop(ctxt
);
10989 while (exec
!= NULL
) {
10990 xmlRegFreeExecCtxt(exec
);
10991 exec
= xmlRelaxNGElemPop(ctxt
);
10993 xmlFree(ctxt
->elemTab
);
10999 * xmlRelaxNGSetValidErrors:
11000 * @ctxt: a Relax-NG validation context
11001 * @err: the error function
11002 * @warn: the warning function
11003 * @ctx: the functions context
11005 * Set the error and warning callback information
11008 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
11009 xmlRelaxNGValidityErrorFunc err
,
11010 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
11015 ctxt
->warning
= warn
;
11016 ctxt
->userData
= ctx
;
11017 ctxt
->serror
= NULL
;
11021 * xmlRelaxNGSetValidStructuredErrors:
11022 * @ctxt: a Relax-NG validation context
11023 * @serror: the structured error function
11024 * @ctx: the functions context
11026 * Set the structured error callback
11029 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt
,
11030 xmlStructuredErrorFunc serror
, void *ctx
)
11034 ctxt
->serror
= serror
;
11035 ctxt
->error
= NULL
;
11036 ctxt
->warning
= NULL
;
11037 ctxt
->userData
= ctx
;
11041 * xmlRelaxNGGetValidErrors:
11042 * @ctxt: a Relax-NG validation context
11043 * @err: the error function result
11044 * @warn: the warning function result
11045 * @ctx: the functions context result
11047 * Get the error and warning callback information
11049 * Returns -1 in case of error and 0 otherwise
11052 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
11053 xmlRelaxNGValidityErrorFunc
* err
,
11054 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
11059 *err
= ctxt
->error
;
11061 *warn
= ctxt
->warning
;
11063 *ctx
= ctxt
->userData
;
11068 * xmlRelaxNGValidateDoc:
11069 * @ctxt: a Relax-NG validation context
11070 * @doc: a parsed document tree
11072 * Validate a document tree in memory.
11074 * Returns 0 if the document is valid, a positive error code
11075 * number otherwise and -1 in case of internal or API error.
11078 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
11082 if ((ctxt
== NULL
) || (doc
== NULL
))
11087 ret
= xmlRelaxNGValidateDocument(ctxt
, doc
);
11089 * Remove all left PSVI
11091 xmlRelaxNGCleanPSVI((xmlNodePtr
) doc
);
11094 * TODO: build error codes
11101 #endif /* LIBXML_SCHEMAS_ENABLED */