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
23 #include <libxml/xmlmemory.h>
24 #include <libxml/parser.h>
25 #include <libxml/parserInternals.h>
26 #include <libxml/hash.h>
27 #include <libxml/uri.h>
29 #include <libxml/relaxng.h>
31 #include <libxml/xmlschemastypes.h>
32 #include <libxml/xmlautomata.h>
33 #include <libxml/xmlregexp.h>
34 #include <libxml/xmlschemastypes.h>
37 * The Relax-NG namespace
39 static const xmlChar
*xmlRelaxNGNs
= (const xmlChar
*)
40 "http://relaxng.org/ns/structure/1.0";
42 #define IS_RELAXNG(node, type) \
43 ((node != NULL) && (node->ns != NULL) && \
44 (xmlStrEqual(node->name, (const xmlChar *) type)) && \
45 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
51 #define DEBUG_GRAMMAR 1
53 #define DEBUG_CONTENT 1
59 #define DEBUG_INTERLEAVE 1
63 #define DEBUG_INCLUDE 1
67 #define DEBUG_COMPILE 1
69 #define DEBUG_PROGRESSIVE 1
75 xmlGenericError(xmlGenericErrorContext, \
76 "Unimplemented block at %s:%d\n", \
79 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema
;
80 typedef xmlRelaxNGSchema
*xmlRelaxNGSchemaPtr
;
82 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine
;
83 typedef xmlRelaxNGDefine
*xmlRelaxNGDefinePtr
;
85 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument
;
86 typedef xmlRelaxNGDocument
*xmlRelaxNGDocumentPtr
;
88 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude
;
89 typedef xmlRelaxNGInclude
*xmlRelaxNGIncludePtr
;
92 XML_RELAXNG_COMBINE_UNDEFINED
= 0, /* undefined */
93 XML_RELAXNG_COMBINE_CHOICE
, /* choice */
94 XML_RELAXNG_COMBINE_INTERLEAVE
/* interleave */
98 XML_RELAXNG_CONTENT_ERROR
= -1,
99 XML_RELAXNG_CONTENT_EMPTY
= 0,
100 XML_RELAXNG_CONTENT_SIMPLE
,
101 XML_RELAXNG_CONTENT_COMPLEX
102 } xmlRelaxNGContentType
;
104 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar
;
105 typedef xmlRelaxNGGrammar
*xmlRelaxNGGrammarPtr
;
107 struct _xmlRelaxNGGrammar
{
108 xmlRelaxNGGrammarPtr parent
; /* the parent grammar if any */
109 xmlRelaxNGGrammarPtr children
; /* the children grammar if any */
110 xmlRelaxNGGrammarPtr next
; /* the next grammar if any */
111 xmlRelaxNGDefinePtr start
; /* <start> content */
112 xmlRelaxNGCombine combine
; /* the default combine value */
113 xmlRelaxNGDefinePtr startList
; /* list of <start> definitions */
114 xmlHashTablePtr defs
; /* define* */
115 xmlHashTablePtr refs
; /* references */
120 XML_RELAXNG_NOOP
= -1, /* a no operation from simplification */
121 XML_RELAXNG_EMPTY
= 0, /* an empty pattern */
122 XML_RELAXNG_NOT_ALLOWED
, /* not allowed top */
123 XML_RELAXNG_EXCEPT
, /* except present in nameclass defs */
124 XML_RELAXNG_TEXT
, /* textual content */
125 XML_RELAXNG_ELEMENT
, /* an element */
126 XML_RELAXNG_DATATYPE
, /* extenal data type definition */
127 XML_RELAXNG_PARAM
, /* extenal data type parameter */
128 XML_RELAXNG_VALUE
, /* value from an extenal data type definition */
129 XML_RELAXNG_LIST
, /* a list of patterns */
130 XML_RELAXNG_ATTRIBUTE
, /* an attrbute following a pattern */
131 XML_RELAXNG_DEF
, /* a definition */
132 XML_RELAXNG_REF
, /* reference to a definition */
133 XML_RELAXNG_EXTERNALREF
, /* reference to an external def */
134 XML_RELAXNG_PARENTREF
, /* reference to a def in the parent grammar */
135 XML_RELAXNG_OPTIONAL
, /* optional patterns */
136 XML_RELAXNG_ZEROORMORE
, /* zero or more non empty patterns */
137 XML_RELAXNG_ONEORMORE
, /* one or more non empty patterns */
138 XML_RELAXNG_CHOICE
, /* a choice between non empty patterns */
139 XML_RELAXNG_GROUP
, /* a pair/group of non empty patterns */
140 XML_RELAXNG_INTERLEAVE
, /* interleaving choice of non-empty patterns */
141 XML_RELAXNG_START
/* Used to keep track of starts on grammars */
144 #define IS_NULLABLE (1 << 0)
145 #define IS_NOT_NULLABLE (1 << 1)
146 #define IS_INDETERMINIST (1 << 2)
147 #define IS_MIXED (1 << 3)
148 #define IS_TRIABLE (1 << 4)
149 #define IS_PROCESSED (1 << 5)
150 #define IS_COMPILABLE (1 << 6)
151 #define IS_NOT_COMPILABLE (1 << 7)
152 #define IS_EXTERNAL_REF (1 << 8)
154 struct _xmlRelaxNGDefine
{
155 xmlRelaxNGType type
; /* the type of definition */
156 xmlNodePtr node
; /* the node in the source */
157 xmlChar
*name
; /* the element local name if present */
158 xmlChar
*ns
; /* the namespace local name if present */
159 xmlChar
*value
; /* value when available */
160 void *data
; /* data lib or specific pointer */
161 xmlRelaxNGDefinePtr content
; /* the expected content */
162 xmlRelaxNGDefinePtr parent
; /* the parent definition, if any */
163 xmlRelaxNGDefinePtr next
; /* list within grouping sequences */
164 xmlRelaxNGDefinePtr attrs
; /* list of attributes for elements */
165 xmlRelaxNGDefinePtr nameClass
; /* the nameClass definition if any */
166 xmlRelaxNGDefinePtr nextHash
; /* next define in defs/refs hash tables */
167 short depth
; /* used for the cycle detection */
168 short dflags
; /* define related flags */
169 xmlRegexpPtr contModel
; /* a compiled content model if available */
175 * A RelaxNGs definition
178 void *_private
; /* unused by the library for users or bindings */
179 xmlRelaxNGGrammarPtr topgrammar
;
182 int idref
; /* requires idref checking */
184 xmlHashTablePtr defs
; /* define */
185 xmlHashTablePtr refs
; /* references */
186 xmlRelaxNGDocumentPtr documents
; /* all the documents loaded */
187 xmlRelaxNGIncludePtr includes
; /* all the includes loaded */
188 int defNr
; /* number of defines used */
189 xmlRelaxNGDefinePtr
*defTab
; /* pointer to the allocated definitions */
193 #define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
194 #define XML_RELAXNG_IN_ONEORMORE (1 << 1)
195 #define XML_RELAXNG_IN_LIST (1 << 2)
196 #define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
197 #define XML_RELAXNG_IN_START (1 << 4)
198 #define XML_RELAXNG_IN_OOMGROUP (1 << 5)
199 #define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
200 #define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
201 #define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
202 #define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
204 struct _xmlRelaxNGParserCtxt
{
205 void *userData
; /* user specific data block */
206 xmlRelaxNGValidityErrorFunc error
; /* the callback in case of errors */
207 xmlRelaxNGValidityWarningFunc warning
; /* the callback in case of warning */
208 xmlStructuredErrorFunc serror
;
209 xmlRelaxNGValidErr err
;
211 xmlRelaxNGPtr schema
; /* The schema in use */
212 xmlRelaxNGGrammarPtr grammar
; /* the current grammar */
213 xmlRelaxNGGrammarPtr parentgrammar
; /* the parent grammar */
214 int flags
; /* parser flags */
215 int nbErrors
; /* number of errors at parse time */
216 int nbWarnings
; /* number of warnings at parse time */
217 const xmlChar
*define
; /* the current define scope */
218 xmlRelaxNGDefinePtr def
; /* the current define */
221 xmlHashTablePtr interleaves
; /* keep track of all the interleaves */
223 xmlRelaxNGDocumentPtr documents
; /* all the documents loaded */
224 xmlRelaxNGIncludePtr includes
; /* all the includes loaded */
228 int defNr
; /* number of defines used */
229 int defMax
; /* number of defines aloocated */
230 xmlRelaxNGDefinePtr
*defTab
; /* pointer to the allocated definitions */
235 /* the document stack */
236 xmlRelaxNGDocumentPtr doc
; /* Current parsed external ref */
237 int docNr
; /* Depth of the parsing stack */
238 int docMax
; /* Max depth of the parsing stack */
239 xmlRelaxNGDocumentPtr
*docTab
; /* array of docs */
241 /* the include stack */
242 xmlRelaxNGIncludePtr inc
; /* Current parsed include */
243 int incNr
; /* Depth of the include parsing stack */
244 int incMax
; /* Max depth of the parsing stack */
245 xmlRelaxNGIncludePtr
*incTab
; /* array of incs */
247 int idref
; /* requires idref checking */
249 /* used to compile content models */
250 xmlAutomataPtr am
; /* the automata */
251 xmlAutomataStatePtr state
; /* used to build the automata */
253 int crng
; /* compact syntax and other flags */
254 int freedoc
; /* need to free the document */
257 #define FLAGS_IGNORABLE 1
258 #define FLAGS_NEGATIVE 2
259 #define FLAGS_MIXED_CONTENT 4
260 #define FLAGS_NOERROR 8
263 * xmlRelaxNGInterleaveGroup:
265 * A RelaxNGs partition set associated to lists of definitions
267 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup
;
268 typedef xmlRelaxNGInterleaveGroup
*xmlRelaxNGInterleaveGroupPtr
;
269 struct _xmlRelaxNGInterleaveGroup
{
270 xmlRelaxNGDefinePtr rule
; /* the rule to satisfy */
271 xmlRelaxNGDefinePtr
*defs
; /* the array of element definitions */
272 xmlRelaxNGDefinePtr
*attrs
; /* the array of attributes definitions */
275 #define IS_DETERMINIST 1
276 #define IS_NEEDCHECK 2
279 * xmlRelaxNGPartitions:
281 * A RelaxNGs partition associated to an interleave group
283 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition
;
284 typedef xmlRelaxNGPartition
*xmlRelaxNGPartitionPtr
;
285 struct _xmlRelaxNGPartition
{
286 int nbgroups
; /* number of groups in the partitions */
287 xmlHashTablePtr triage
; /* hash table used to direct nodes to the
288 * right group when possible */
289 int flags
; /* determinist ? */
290 xmlRelaxNGInterleaveGroupPtr
*groups
;
294 * xmlRelaxNGValidState:
296 * A RelaxNGs validation state
299 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState
;
300 typedef xmlRelaxNGValidState
*xmlRelaxNGValidStatePtr
;
301 struct _xmlRelaxNGValidState
{
302 xmlNodePtr node
; /* the current node */
303 xmlNodePtr seq
; /* the sequence of children left to validate */
304 int nbAttrs
; /* the number of attributes */
305 int maxAttrs
; /* the size of attrs */
306 int nbAttrLeft
; /* the number of attributes left to validate */
307 xmlChar
*value
; /* the value when operating on string */
308 xmlChar
*endvalue
; /* the end value when operating on string */
309 xmlAttrPtr
*attrs
; /* the array of attributes */
315 * A RelaxNGs container for validation state
317 typedef struct _xmlRelaxNGStates xmlRelaxNGStates
;
318 typedef xmlRelaxNGStates
*xmlRelaxNGStatesPtr
;
319 struct _xmlRelaxNGStates
{
320 int nbState
; /* the number of states */
321 int maxState
; /* the size of the array */
322 xmlRelaxNGValidStatePtr
*tabState
;
325 #define ERROR_IS_DUP 1
328 * xmlRelaxNGValidError:
330 * A RelaxNGs validation error
332 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError
;
333 typedef xmlRelaxNGValidError
*xmlRelaxNGValidErrorPtr
;
334 struct _xmlRelaxNGValidError
{
335 xmlRelaxNGValidErr err
; /* the error number */
336 int flags
; /* flags */
337 xmlNodePtr node
; /* the current node */
338 xmlNodePtr seq
; /* the current child */
339 const xmlChar
*arg1
; /* first arg */
340 const xmlChar
*arg2
; /* second arg */
344 * xmlRelaxNGValidCtxt:
346 * A RelaxNGs validation context
349 struct _xmlRelaxNGValidCtxt
{
350 void *userData
; /* user specific data block */
351 xmlRelaxNGValidityErrorFunc error
; /* the callback in case of errors */
352 xmlRelaxNGValidityWarningFunc warning
; /* the callback in case of warning */
353 xmlStructuredErrorFunc serror
;
354 int nbErrors
; /* number of errors in validation */
356 xmlRelaxNGPtr schema
; /* The schema in use */
357 xmlDocPtr doc
; /* the document being validated */
358 int flags
; /* validation flags */
359 int depth
; /* validation depth */
360 int idref
; /* requires idref checking */
361 int errNo
; /* the first error found */
364 * Errors accumulated in branches may have to be stacked to be
365 * provided back when it's sure they affect validation.
367 xmlRelaxNGValidErrorPtr err
; /* Last error */
368 int errNr
; /* Depth of the error stack */
369 int errMax
; /* Max depth of the error stack */
370 xmlRelaxNGValidErrorPtr errTab
; /* stack of errors */
372 xmlRelaxNGValidStatePtr state
; /* the current validation state */
373 xmlRelaxNGStatesPtr states
; /* the accumulated state list */
375 xmlRelaxNGStatesPtr freeState
; /* the pool of free valid states */
378 xmlRelaxNGStatesPtr
*freeStates
; /* the pool of free state groups */
381 * This is used for "progressive" validation
383 xmlRegExecCtxtPtr elem
; /* the current element regexp */
384 int elemNr
; /* the number of element validated */
385 int elemMax
; /* the max depth of elements */
386 xmlRegExecCtxtPtr
*elemTab
; /* the stack of regexp runtime */
387 int pstate
; /* progressive state */
388 xmlNodePtr pnode
; /* the current node */
389 xmlRelaxNGDefinePtr pdef
; /* the non-streamable definition */
390 int perr
; /* signal error in content model
391 * outside the regexp */
397 * Structure associated to a RelaxNGs document element
399 struct _xmlRelaxNGInclude
{
400 xmlRelaxNGIncludePtr next
; /* keep a chain of includes */
401 xmlChar
*href
; /* the normalized href value */
402 xmlDocPtr doc
; /* the associated XML document */
403 xmlRelaxNGDefinePtr content
; /* the definitions */
404 xmlRelaxNGPtr schema
; /* the schema */
408 * xmlRelaxNGDocument:
410 * Structure associated to a RelaxNGs document element
412 struct _xmlRelaxNGDocument
{
413 xmlRelaxNGDocumentPtr next
; /* keep a chain of documents */
414 xmlChar
*href
; /* the normalized href value */
415 xmlDocPtr doc
; /* the associated XML document */
416 xmlRelaxNGDefinePtr content
; /* the definitions */
417 xmlRelaxNGPtr schema
; /* the schema */
418 int externalRef
; /* 1 if an external ref */
422 /************************************************************************
424 * Some factorized error routines *
426 ************************************************************************/
430 * @ctxt: an Relax-NG parser context
431 * @extra: extra informations
433 * Handle a redefinition of attribute error
436 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt
, const char *extra
)
438 xmlStructuredErrorFunc schannel
= NULL
;
439 xmlGenericErrorFunc channel
= NULL
;
443 if (ctxt
->serror
!= NULL
)
444 schannel
= ctxt
->serror
;
446 channel
= ctxt
->error
;
447 data
= ctxt
->userData
;
451 __xmlRaiseError(schannel
, channel
, data
,
452 NULL
, NULL
, XML_FROM_RELAXNGP
,
453 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, extra
,
455 "Memory allocation failed : %s\n", extra
);
457 __xmlRaiseError(schannel
, channel
, data
,
458 NULL
, NULL
, XML_FROM_RELAXNGP
,
459 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, NULL
,
460 NULL
, NULL
, 0, 0, "Memory allocation failed\n");
465 * @ctxt: a Relax-NG validation context
466 * @extra: extra informations
468 * Handle a redefinition of attribute error
471 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt
, const char *extra
)
473 xmlStructuredErrorFunc schannel
= NULL
;
474 xmlGenericErrorFunc channel
= NULL
;
478 if (ctxt
->serror
!= NULL
)
479 schannel
= ctxt
->serror
;
481 channel
= ctxt
->error
;
482 data
= ctxt
->userData
;
486 __xmlRaiseError(schannel
, channel
, data
,
487 NULL
, NULL
, XML_FROM_RELAXNGV
,
488 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, extra
,
490 "Memory allocation failed : %s\n", extra
);
492 __xmlRaiseError(schannel
, channel
, data
,
493 NULL
, NULL
, XML_FROM_RELAXNGV
,
494 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, NULL
,
495 NULL
, NULL
, 0, 0, "Memory allocation failed\n");
500 * @ctxt: a Relax-NG parser context
501 * @node: the node raising the error
502 * @error: the error code
507 * Handle a Relax NG Parsing error
510 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
, int error
,
511 const char *msg
, const xmlChar
* str1
, const xmlChar
* str2
)
513 xmlStructuredErrorFunc schannel
= NULL
;
514 xmlGenericErrorFunc channel
= NULL
;
518 if (ctxt
->serror
!= NULL
)
519 schannel
= ctxt
->serror
;
521 channel
= ctxt
->error
;
522 data
= ctxt
->userData
;
525 __xmlRaiseError(schannel
, channel
, data
,
526 NULL
, node
, XML_FROM_RELAXNGP
,
527 error
, XML_ERR_ERROR
, NULL
, 0,
528 (const char *) str1
, (const char *) str2
, NULL
, 0, 0,
534 * @ctxt: a Relax-NG validation context
535 * @node: the node raising the error
536 * @error: the error code
541 * Handle a Relax NG Validation error
544 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt
, xmlNodePtr node
, int error
,
545 const char *msg
, const xmlChar
* str1
, const xmlChar
* str2
)
547 xmlStructuredErrorFunc schannel
= NULL
;
548 xmlGenericErrorFunc channel
= NULL
;
552 if (ctxt
->serror
!= NULL
)
553 schannel
= ctxt
->serror
;
555 channel
= ctxt
->error
;
556 data
= ctxt
->userData
;
559 __xmlRaiseError(schannel
, channel
, data
,
560 NULL
, node
, XML_FROM_RELAXNGV
,
561 error
, XML_ERR_ERROR
, NULL
, 0,
562 (const char *) str1
, (const char *) str2
, NULL
, 0, 0,
566 /************************************************************************
568 * Preliminary type checking interfaces *
570 ************************************************************************/
573 * xmlRelaxNGTypeHave:
574 * @data: data needed for the library
575 * @type: the type name
576 * @value: the value to check
578 * Function provided by a type library to check if a type is exported
580 * Returns 1 if yes, 0 if no and -1 in case of error.
582 typedef int (*xmlRelaxNGTypeHave
) (void *data
, const xmlChar
* type
);
585 * xmlRelaxNGTypeCheck:
586 * @data: data needed for the library
587 * @type: the type name
588 * @value: the value to check
589 * @result: place to store the result if needed
591 * Function provided by a type library to check if a value match a type
593 * Returns 1 if yes, 0 if no and -1 in case of error.
595 typedef int (*xmlRelaxNGTypeCheck
) (void *data
, const xmlChar
* type
,
596 const xmlChar
* value
, void **result
,
600 * xmlRelaxNGFacetCheck:
601 * @data: data needed for the library
602 * @type: the type name
603 * @facet: the facet name
604 * @val: the facet value
605 * @strval: the string value
606 * @value: the value to check
608 * Function provided by a type library to check a value facet
610 * Returns 1 if yes, 0 if no and -1 in case of error.
612 typedef int (*xmlRelaxNGFacetCheck
) (void *data
, const xmlChar
* type
,
613 const xmlChar
* facet
,
615 const xmlChar
* strval
, void *value
);
618 * xmlRelaxNGTypeFree:
619 * @data: data needed for the library
620 * @result: the value to free
622 * Function provided by a type library to free a returned result
624 typedef void (*xmlRelaxNGTypeFree
) (void *data
, void *result
);
627 * xmlRelaxNGTypeCompare:
628 * @data: data needed for the library
629 * @type: the type name
630 * @value1: the first value
631 * @value2: the second value
633 * Function provided by a type library to compare two values accordingly
636 * Returns 1 if yes, 0 if no and -1 in case of error.
638 typedef int (*xmlRelaxNGTypeCompare
) (void *data
, const xmlChar
* type
,
639 const xmlChar
* value1
,
642 const xmlChar
* value2
,
644 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary
;
645 typedef xmlRelaxNGTypeLibrary
*xmlRelaxNGTypeLibraryPtr
;
646 struct _xmlRelaxNGTypeLibrary
{
647 const xmlChar
*namespace; /* the datatypeLibrary value */
648 void *data
; /* data needed for the library */
649 xmlRelaxNGTypeHave have
; /* the export function */
650 xmlRelaxNGTypeCheck check
; /* the checking function */
651 xmlRelaxNGTypeCompare comp
; /* the compare function */
652 xmlRelaxNGFacetCheck facet
; /* the facet check function */
653 xmlRelaxNGTypeFree freef
; /* the freeing function */
656 /************************************************************************
658 * Allocation functions *
660 ************************************************************************/
661 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar
);
662 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define
);
663 static void xmlRelaxNGNormExtSpace(xmlChar
* value
);
664 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema
);
665 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
667 xmlRelaxNGValidStatePtr state1
,
668 xmlRelaxNGValidStatePtr state2
);
669 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt
,
670 xmlRelaxNGValidStatePtr state
);
673 * xmlRelaxNGFreeDocument:
674 * @docu: a document structure
676 * Deallocate a RelaxNG document structure.
679 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu
)
684 if (docu
->href
!= NULL
)
686 if (docu
->doc
!= NULL
)
687 xmlFreeDoc(docu
->doc
);
688 if (docu
->schema
!= NULL
)
689 xmlRelaxNGFreeInnerSchema(docu
->schema
);
694 * xmlRelaxNGFreeDocumentList:
695 * @docu: a list of document structure
697 * Deallocate a RelaxNG document structures.
700 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu
)
702 xmlRelaxNGDocumentPtr next
;
704 while (docu
!= NULL
) {
706 xmlRelaxNGFreeDocument(docu
);
712 * xmlRelaxNGFreeInclude:
713 * @incl: a include structure
715 * Deallocate a RelaxNG include structure.
718 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl
)
723 if (incl
->href
!= NULL
)
725 if (incl
->doc
!= NULL
)
726 xmlFreeDoc(incl
->doc
);
727 if (incl
->schema
!= NULL
)
728 xmlRelaxNGFree(incl
->schema
);
733 * xmlRelaxNGFreeIncludeList:
734 * @incl: a include structure list
736 * Deallocate a RelaxNG include structure.
739 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl
)
741 xmlRelaxNGIncludePtr next
;
743 while (incl
!= NULL
) {
745 xmlRelaxNGFreeInclude(incl
);
751 * xmlRelaxNGNewRelaxNG:
752 * @ctxt: a Relax-NG validation context (optional)
754 * Allocate a new RelaxNG structure.
756 * Returns the newly allocated structure or NULL in case or error
759 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt
)
763 ret
= (xmlRelaxNGPtr
) xmlMalloc(sizeof(xmlRelaxNG
));
765 xmlRngPErrMemory(ctxt
, NULL
);
768 memset(ret
, 0, sizeof(xmlRelaxNG
));
774 * xmlRelaxNGFreeInnerSchema:
775 * @schema: a schema structure
777 * Deallocate a RelaxNG schema structure.
780 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema
)
785 if (schema
->doc
!= NULL
)
786 xmlFreeDoc(schema
->doc
);
787 if (schema
->defTab
!= NULL
) {
790 for (i
= 0; i
< schema
->defNr
; i
++)
791 xmlRelaxNGFreeDefine(schema
->defTab
[i
]);
792 xmlFree(schema
->defTab
);
800 * @schema: a schema structure
802 * Deallocate a RelaxNG structure.
805 xmlRelaxNGFree(xmlRelaxNGPtr schema
)
810 if (schema
->topgrammar
!= NULL
)
811 xmlRelaxNGFreeGrammar(schema
->topgrammar
);
812 if (schema
->doc
!= NULL
)
813 xmlFreeDoc(schema
->doc
);
814 if (schema
->documents
!= NULL
)
815 xmlRelaxNGFreeDocumentList(schema
->documents
);
816 if (schema
->includes
!= NULL
)
817 xmlRelaxNGFreeIncludeList(schema
->includes
);
818 if (schema
->defTab
!= NULL
) {
821 for (i
= 0; i
< schema
->defNr
; i
++)
822 xmlRelaxNGFreeDefine(schema
->defTab
[i
]);
823 xmlFree(schema
->defTab
);
830 * xmlRelaxNGNewGrammar:
831 * @ctxt: a Relax-NG validation context (optional)
833 * Allocate a new RelaxNG grammar.
835 * Returns the newly allocated structure or NULL in case or error
837 static xmlRelaxNGGrammarPtr
838 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt
)
840 xmlRelaxNGGrammarPtr ret
;
842 ret
= (xmlRelaxNGGrammarPtr
) xmlMalloc(sizeof(xmlRelaxNGGrammar
));
844 xmlRngPErrMemory(ctxt
, NULL
);
847 memset(ret
, 0, sizeof(xmlRelaxNGGrammar
));
853 * xmlRelaxNGFreeGrammar:
854 * @grammar: a grammar structure
856 * Deallocate a RelaxNG grammar structure.
859 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar
)
864 if (grammar
->children
!= NULL
) {
865 xmlRelaxNGFreeGrammar(grammar
->children
);
867 if (grammar
->next
!= NULL
) {
868 xmlRelaxNGFreeGrammar(grammar
->next
);
870 if (grammar
->refs
!= NULL
) {
871 xmlHashFree(grammar
->refs
, NULL
);
873 if (grammar
->defs
!= NULL
) {
874 xmlHashFree(grammar
->defs
, NULL
);
881 * xmlRelaxNGNewDefine:
882 * @ctxt: a Relax-NG validation context
883 * @node: the node in the input document.
885 * Allocate a new RelaxNG define.
887 * Returns the newly allocated structure or NULL in case or error
889 static xmlRelaxNGDefinePtr
890 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
892 xmlRelaxNGDefinePtr ret
;
894 if (ctxt
->defMax
== 0) {
897 ctxt
->defTab
= (xmlRelaxNGDefinePtr
*)
898 xmlMalloc(ctxt
->defMax
* sizeof(xmlRelaxNGDefinePtr
));
899 if (ctxt
->defTab
== NULL
) {
900 xmlRngPErrMemory(ctxt
, "allocating define\n");
903 } else if (ctxt
->defMax
<= ctxt
->defNr
) {
904 xmlRelaxNGDefinePtr
*tmp
;
907 tmp
= (xmlRelaxNGDefinePtr
*) xmlRealloc(ctxt
->defTab
,
910 (xmlRelaxNGDefinePtr
));
912 xmlRngPErrMemory(ctxt
, "allocating define\n");
917 ret
= (xmlRelaxNGDefinePtr
) xmlMalloc(sizeof(xmlRelaxNGDefine
));
919 xmlRngPErrMemory(ctxt
, "allocating define\n");
922 memset(ret
, 0, sizeof(xmlRelaxNGDefine
));
923 ctxt
->defTab
[ctxt
->defNr
++] = ret
;
930 * xmlRelaxNGFreePartition:
931 * @partitions: a partition set structure
933 * Deallocate RelaxNG partition set structures.
936 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions
)
938 xmlRelaxNGInterleaveGroupPtr group
;
941 if (partitions
!= NULL
) {
942 if (partitions
->groups
!= NULL
) {
943 for (j
= 0; j
< partitions
->nbgroups
; j
++) {
944 group
= partitions
->groups
[j
];
946 if (group
->defs
!= NULL
)
947 xmlFree(group
->defs
);
948 if (group
->attrs
!= NULL
)
949 xmlFree(group
->attrs
);
953 xmlFree(partitions
->groups
);
955 if (partitions
->triage
!= NULL
) {
956 xmlHashFree(partitions
->triage
, NULL
);
963 * xmlRelaxNGFreeDefine:
964 * @define: a define structure
966 * Deallocate a RelaxNG define structure.
969 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define
)
974 if ((define
->type
== XML_RELAXNG_VALUE
) && (define
->attrs
!= NULL
)) {
975 xmlRelaxNGTypeLibraryPtr lib
;
977 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
978 if ((lib
!= NULL
) && (lib
->freef
!= NULL
))
979 lib
->freef(lib
->data
, (void *) define
->attrs
);
981 if ((define
->data
!= NULL
) && (define
->type
== XML_RELAXNG_INTERLEAVE
))
982 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr
) define
->data
);
983 if ((define
->data
!= NULL
) && (define
->type
== XML_RELAXNG_CHOICE
))
984 xmlHashFree((xmlHashTablePtr
) define
->data
, NULL
);
985 if (define
->name
!= NULL
)
986 xmlFree(define
->name
);
987 if (define
->ns
!= NULL
)
989 if (define
->value
!= NULL
)
990 xmlFree(define
->value
);
991 if (define
->contModel
!= NULL
)
992 xmlRegFreeRegexp(define
->contModel
);
997 * xmlRelaxNGNewStates:
998 * @ctxt: a Relax-NG validation context
999 * @size: the default size for the container
1001 * Allocate a new RelaxNG validation state container
1003 * Returns the newly allocated structure or NULL in case or error
1005 static xmlRelaxNGStatesPtr
1006 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt
, int size
)
1008 xmlRelaxNGStatesPtr ret
;
1010 if ((ctxt
!= NULL
) &&
1011 (ctxt
->freeStates
!= NULL
) && (ctxt
->freeStatesNr
> 0)) {
1012 ctxt
->freeStatesNr
--;
1013 ret
= ctxt
->freeStates
[ctxt
->freeStatesNr
];
1020 ret
= (xmlRelaxNGStatesPtr
) xmlMalloc(sizeof(xmlRelaxNGStates
) +
1023 sizeof(xmlRelaxNGValidStatePtr
));
1025 xmlRngVErrMemory(ctxt
, "allocating states\n");
1029 ret
->maxState
= size
;
1030 ret
->tabState
= (xmlRelaxNGValidStatePtr
*) xmlMalloc((size
) *
1032 (xmlRelaxNGValidStatePtr
));
1033 if (ret
->tabState
== NULL
) {
1034 xmlRngVErrMemory(ctxt
, "allocating states\n");
1042 * xmlRelaxNGAddStateUniq:
1043 * @ctxt: a Relax-NG validation context
1044 * @states: the states container
1045 * @state: the validation state
1047 * Add a RelaxNG validation state to the container without checking
1050 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1053 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt
,
1054 xmlRelaxNGStatesPtr states
,
1055 xmlRelaxNGValidStatePtr state
)
1057 if (state
== NULL
) {
1060 if (states
->nbState
>= states
->maxState
) {
1061 xmlRelaxNGValidStatePtr
*tmp
;
1064 size
= states
->maxState
* 2;
1065 tmp
= (xmlRelaxNGValidStatePtr
*) xmlRealloc(states
->tabState
,
1068 (xmlRelaxNGValidStatePtr
));
1070 xmlRngVErrMemory(ctxt
, "adding states\n");
1073 states
->tabState
= tmp
;
1074 states
->maxState
= size
;
1076 states
->tabState
[states
->nbState
++] = state
;
1081 * xmlRelaxNGAddState:
1082 * @ctxt: a Relax-NG validation context
1083 * @states: the states container
1084 * @state: the validation state
1086 * Add a RelaxNG validation state to the container
1088 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1091 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt
,
1092 xmlRelaxNGStatesPtr states
,
1093 xmlRelaxNGValidStatePtr state
)
1097 if (state
== NULL
) {
1100 if (states
->nbState
>= states
->maxState
) {
1101 xmlRelaxNGValidStatePtr
*tmp
;
1104 size
= states
->maxState
* 2;
1105 tmp
= (xmlRelaxNGValidStatePtr
*) xmlRealloc(states
->tabState
,
1108 (xmlRelaxNGValidStatePtr
));
1110 xmlRngVErrMemory(ctxt
, "adding states\n");
1113 states
->tabState
= tmp
;
1114 states
->maxState
= size
;
1116 for (i
= 0; i
< states
->nbState
; i
++) {
1117 if (xmlRelaxNGEqualValidState(ctxt
, state
, states
->tabState
[i
])) {
1118 xmlRelaxNGFreeValidState(ctxt
, state
);
1122 states
->tabState
[states
->nbState
++] = state
;
1127 * xmlRelaxNGFreeStates:
1128 * @ctxt: a Relax-NG validation context
1129 * @states: teh container
1131 * Free a RelaxNG validation state container
1134 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt
,
1135 xmlRelaxNGStatesPtr states
)
1139 if ((ctxt
!= NULL
) && (ctxt
->freeStates
== NULL
)) {
1140 ctxt
->freeStatesMax
= 40;
1141 ctxt
->freeStatesNr
= 0;
1142 ctxt
->freeStates
= (xmlRelaxNGStatesPtr
*)
1143 xmlMalloc(ctxt
->freeStatesMax
* sizeof(xmlRelaxNGStatesPtr
));
1144 if (ctxt
->freeStates
== NULL
) {
1145 xmlRngVErrMemory(ctxt
, "storing states\n");
1147 } else if ((ctxt
!= NULL
)
1148 && (ctxt
->freeStatesNr
>= ctxt
->freeStatesMax
)) {
1149 xmlRelaxNGStatesPtr
*tmp
;
1151 tmp
= (xmlRelaxNGStatesPtr
*) xmlRealloc(ctxt
->freeStates
,
1152 2 * ctxt
->freeStatesMax
*
1154 (xmlRelaxNGStatesPtr
));
1156 xmlRngVErrMemory(ctxt
, "storing states\n");
1157 xmlFree(states
->tabState
);
1161 ctxt
->freeStates
= tmp
;
1162 ctxt
->freeStatesMax
*= 2;
1164 if ((ctxt
== NULL
) || (ctxt
->freeStates
== NULL
)) {
1165 xmlFree(states
->tabState
);
1168 ctxt
->freeStates
[ctxt
->freeStatesNr
++] = states
;
1173 * xmlRelaxNGNewValidState:
1174 * @ctxt: a Relax-NG validation context
1175 * @node: the current node or NULL for the document
1177 * Allocate a new RelaxNG validation state
1179 * Returns the newly allocated structure or NULL in case or error
1181 static xmlRelaxNGValidStatePtr
1182 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt
, xmlNodePtr node
)
1184 xmlRelaxNGValidStatePtr ret
;
1186 xmlAttrPtr attrs
[MAX_ATTR
];
1188 xmlNodePtr root
= NULL
;
1191 root
= xmlDocGetRootElement(ctxt
->doc
);
1195 attr
= node
->properties
;
1196 while (attr
!= NULL
) {
1197 if (nbAttrs
< MAX_ATTR
)
1198 attrs
[nbAttrs
++] = attr
;
1204 if ((ctxt
->freeState
!= NULL
) && (ctxt
->freeState
->nbState
> 0)) {
1205 ctxt
->freeState
->nbState
--;
1206 ret
= ctxt
->freeState
->tabState
[ctxt
->freeState
->nbState
];
1209 (xmlRelaxNGValidStatePtr
)
1210 xmlMalloc(sizeof(xmlRelaxNGValidState
));
1212 xmlRngVErrMemory(ctxt
, "allocating states\n");
1215 memset(ret
, 0, sizeof(xmlRelaxNGValidState
));
1218 ret
->endvalue
= NULL
;
1220 ret
->node
= (xmlNodePtr
) ctxt
->doc
;
1224 ret
->seq
= node
->children
;
1228 if (ret
->attrs
== NULL
) {
1232 ret
->maxAttrs
= nbAttrs
;
1233 ret
->attrs
= (xmlAttrPtr
*) xmlMalloc(ret
->maxAttrs
*
1234 sizeof(xmlAttrPtr
));
1235 if (ret
->attrs
== NULL
) {
1236 xmlRngVErrMemory(ctxt
, "allocating states\n");
1239 } else if (ret
->maxAttrs
< nbAttrs
) {
1242 tmp
= (xmlAttrPtr
*) xmlRealloc(ret
->attrs
, nbAttrs
*
1243 sizeof(xmlAttrPtr
));
1245 xmlRngVErrMemory(ctxt
, "allocating states\n");
1249 ret
->maxAttrs
= nbAttrs
;
1251 ret
->nbAttrs
= nbAttrs
;
1252 if (nbAttrs
< MAX_ATTR
) {
1253 memcpy(ret
->attrs
, attrs
, sizeof(xmlAttrPtr
) * nbAttrs
);
1255 attr
= node
->properties
;
1257 while (attr
!= NULL
) {
1258 ret
->attrs
[nbAttrs
++] = attr
;
1263 ret
->nbAttrLeft
= ret
->nbAttrs
;
1268 * xmlRelaxNGCopyValidState:
1269 * @ctxt: a Relax-NG validation context
1270 * @state: a validation state
1272 * Copy the validation state
1274 * Returns the newly allocated structure or NULL in case or error
1276 static xmlRelaxNGValidStatePtr
1277 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt
,
1278 xmlRelaxNGValidStatePtr state
)
1280 xmlRelaxNGValidStatePtr ret
;
1281 unsigned int maxAttrs
;
1286 if ((ctxt
->freeState
!= NULL
) && (ctxt
->freeState
->nbState
> 0)) {
1287 ctxt
->freeState
->nbState
--;
1288 ret
= ctxt
->freeState
->tabState
[ctxt
->freeState
->nbState
];
1291 (xmlRelaxNGValidStatePtr
)
1292 xmlMalloc(sizeof(xmlRelaxNGValidState
));
1294 xmlRngVErrMemory(ctxt
, "allocating states\n");
1297 memset(ret
, 0, sizeof(xmlRelaxNGValidState
));
1300 maxAttrs
= ret
->maxAttrs
;
1301 memcpy(ret
, state
, sizeof(xmlRelaxNGValidState
));
1303 ret
->maxAttrs
= maxAttrs
;
1304 if (state
->nbAttrs
> 0) {
1305 if (ret
->attrs
== NULL
) {
1306 ret
->maxAttrs
= state
->maxAttrs
;
1307 ret
->attrs
= (xmlAttrPtr
*) xmlMalloc(ret
->maxAttrs
*
1308 sizeof(xmlAttrPtr
));
1309 if (ret
->attrs
== NULL
) {
1310 xmlRngVErrMemory(ctxt
, "allocating states\n");
1314 } else if (ret
->maxAttrs
< state
->nbAttrs
) {
1317 tmp
= (xmlAttrPtr
*) xmlRealloc(ret
->attrs
, state
->maxAttrs
*
1318 sizeof(xmlAttrPtr
));
1320 xmlRngVErrMemory(ctxt
, "allocating states\n");
1324 ret
->maxAttrs
= state
->maxAttrs
;
1327 memcpy(ret
->attrs
, state
->attrs
,
1328 state
->nbAttrs
* sizeof(xmlAttrPtr
));
1334 * xmlRelaxNGEqualValidState:
1335 * @ctxt: a Relax-NG validation context
1336 * @state1: a validation state
1337 * @state2: a validation state
1339 * Compare the validation states for equality
1341 * Returns 1 if equald, 0 otherwise
1344 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
1345 xmlRelaxNGValidStatePtr state1
,
1346 xmlRelaxNGValidStatePtr state2
)
1350 if ((state1
== NULL
) || (state2
== NULL
))
1352 if (state1
== state2
)
1354 if (state1
->node
!= state2
->node
)
1356 if (state1
->seq
!= state2
->seq
)
1358 if (state1
->nbAttrLeft
!= state2
->nbAttrLeft
)
1360 if (state1
->nbAttrs
!= state2
->nbAttrs
)
1362 if (state1
->endvalue
!= state2
->endvalue
)
1364 if ((state1
->value
!= state2
->value
) &&
1365 (!xmlStrEqual(state1
->value
, state2
->value
)))
1367 for (i
= 0; i
< state1
->nbAttrs
; i
++) {
1368 if (state1
->attrs
[i
] != state2
->attrs
[i
])
1375 * xmlRelaxNGFreeValidState:
1376 * @state: a validation state structure
1378 * Deallocate a RelaxNG validation state structure.
1381 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt
,
1382 xmlRelaxNGValidStatePtr state
)
1387 if ((ctxt
!= NULL
) && (ctxt
->freeState
== NULL
)) {
1388 ctxt
->freeState
= xmlRelaxNGNewStates(ctxt
, 40);
1390 if ((ctxt
== NULL
) || (ctxt
->freeState
== NULL
)) {
1391 if (state
->attrs
!= NULL
)
1392 xmlFree(state
->attrs
);
1395 xmlRelaxNGAddStatesUniq(ctxt
, ctxt
->freeState
, state
);
1399 /************************************************************************
1401 * Semi internal functions *
1403 ************************************************************************/
1406 * xmlRelaxParserSetFlag:
1407 * @ctxt: a RelaxNG parser context
1408 * @flags: a set of flags values
1410 * Semi private function used to pass informations to a parser context
1411 * which are a combination of xmlRelaxNGParserFlag .
1413 * Returns 0 if success and -1 in case of error
1416 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt
, int flags
)
1418 if (ctxt
== NULL
) return(-1);
1419 if (flags
& XML_RELAXNGP_FREE_DOC
) {
1420 ctxt
->crng
|= XML_RELAXNGP_FREE_DOC
;
1421 flags
-= XML_RELAXNGP_FREE_DOC
;
1423 if (flags
& XML_RELAXNGP_CRNG
) {
1424 ctxt
->crng
|= XML_RELAXNGP_CRNG
;
1425 flags
-= XML_RELAXNGP_CRNG
;
1427 if (flags
!= 0) return(-1);
1431 /************************************************************************
1433 * Document functions *
1435 ************************************************************************/
1436 static xmlDocPtr
xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
,
1440 * xmlRelaxNGIncludePush:
1441 * @ctxt: the parser context
1442 * @value: the element doc
1444 * Pushes a new include on top of the include stack
1446 * Returns 0 in case of error, the index in the stack otherwise
1449 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt
,
1450 xmlRelaxNGIncludePtr value
)
1452 if (ctxt
->incTab
== NULL
) {
1456 (xmlRelaxNGIncludePtr
*) xmlMalloc(ctxt
->incMax
*
1457 sizeof(ctxt
->incTab
[0]));
1458 if (ctxt
->incTab
== NULL
) {
1459 xmlRngPErrMemory(ctxt
, "allocating include\n");
1463 if (ctxt
->incNr
>= ctxt
->incMax
) {
1466 (xmlRelaxNGIncludePtr
*) xmlRealloc(ctxt
->incTab
,
1468 sizeof(ctxt
->incTab
[0]));
1469 if (ctxt
->incTab
== NULL
) {
1470 xmlRngPErrMemory(ctxt
, "allocating include\n");
1474 ctxt
->incTab
[ctxt
->incNr
] = value
;
1476 return (ctxt
->incNr
++);
1480 * xmlRelaxNGIncludePop:
1481 * @ctxt: the parser context
1483 * Pops the top include from the include stack
1485 * Returns the include just removed
1487 static xmlRelaxNGIncludePtr
1488 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt
)
1490 xmlRelaxNGIncludePtr ret
;
1492 if (ctxt
->incNr
<= 0)
1495 if (ctxt
->incNr
> 0)
1496 ctxt
->inc
= ctxt
->incTab
[ctxt
->incNr
- 1];
1499 ret
= ctxt
->incTab
[ctxt
->incNr
];
1500 ctxt
->incTab
[ctxt
->incNr
] = NULL
;
1505 * xmlRelaxNGRemoveRedefine:
1506 * @ctxt: the parser context
1507 * @URL: the normalized URL
1508 * @target: the included target
1509 * @name: the define name to eliminate
1511 * Applies the elimination algorithm of 4.7
1513 * Returns 0 in case of error, 1 in case of success.
1516 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt
,
1517 const xmlChar
* URL ATTRIBUTE_UNUSED
,
1518 xmlNodePtr target
, const xmlChar
* name
)
1521 xmlNodePtr tmp
, tmp2
;
1524 #ifdef DEBUG_INCLUDE
1526 xmlGenericError(xmlGenericErrorContext
,
1527 "Elimination of <include> start from %s\n", URL
);
1529 xmlGenericError(xmlGenericErrorContext
,
1530 "Elimination of <include> define %s from %s\n",
1534 while (tmp
!= NULL
) {
1536 if ((name
== NULL
) && (IS_RELAXNG(tmp
, "start"))) {
1540 } else if ((name
!= NULL
) && (IS_RELAXNG(tmp
, "define"))) {
1541 name2
= xmlGetProp(tmp
, BAD_CAST
"name");
1542 xmlRelaxNGNormExtSpace(name2
);
1543 if (name2
!= NULL
) {
1544 if (xmlStrEqual(name
, name2
)) {
1551 } else if (IS_RELAXNG(tmp
, "include")) {
1552 xmlChar
*href
= NULL
;
1553 xmlRelaxNGDocumentPtr inc
= tmp
->psvi
;
1555 if ((inc
!= NULL
) && (inc
->doc
!= NULL
) &&
1556 (inc
->doc
->children
!= NULL
)) {
1559 (inc
->doc
->children
->name
, BAD_CAST
"grammar")) {
1560 #ifdef DEBUG_INCLUDE
1561 href
= xmlGetProp(tmp
, BAD_CAST
"href");
1563 if (xmlRelaxNGRemoveRedefine(ctxt
, href
,
1564 inc
->doc
->children
->
1565 children
, name
) == 1) {
1568 #ifdef DEBUG_INCLUDE
1581 * xmlRelaxNGLoadInclude:
1582 * @ctxt: the parser context
1583 * @URL: the normalized URL
1584 * @node: the include node.
1585 * @ns: the namespace passed from the context.
1587 * First lookup if the document is already loaded into the parser context,
1588 * check against recursion. If not found the resource is loaded and
1589 * the content is preprocessed before being returned back to the caller.
1591 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1593 static xmlRelaxNGIncludePtr
1594 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt
, const xmlChar
* URL
,
1595 xmlNodePtr node
, const xmlChar
* ns
)
1597 xmlRelaxNGIncludePtr ret
= NULL
;
1600 xmlNodePtr root
, cur
;
1602 #ifdef DEBUG_INCLUDE
1603 xmlGenericError(xmlGenericErrorContext
,
1604 "xmlRelaxNGLoadInclude(%s)\n", URL
);
1608 * check against recursion in the stack
1610 for (i
= 0; i
< ctxt
->incNr
; i
++) {
1611 if (xmlStrEqual(ctxt
->incTab
[i
]->href
, URL
)) {
1612 xmlRngPErr(ctxt
, NULL
, XML_RNGP_INCLUDE_RECURSE
,
1613 "Detected an Include recursion for %s\n", URL
,
1622 doc
= xmlReadFile((const char *) URL
,NULL
,0);
1624 xmlRngPErr(ctxt
, node
, XML_RNGP_PARSE_ERROR
,
1625 "xmlRelaxNG: could not load %s\n", URL
, NULL
);
1628 #ifdef DEBUG_INCLUDE
1629 xmlGenericError(xmlGenericErrorContext
, "Parsed %s Okay\n", URL
);
1633 * Allocate the document structures and register it first.
1635 ret
= (xmlRelaxNGIncludePtr
) xmlMalloc(sizeof(xmlRelaxNGInclude
));
1637 xmlRngPErrMemory(ctxt
, "allocating include\n");
1641 memset(ret
, 0, sizeof(xmlRelaxNGInclude
));
1643 ret
->href
= xmlStrdup(URL
);
1644 ret
->next
= ctxt
->includes
;
1645 ctxt
->includes
= ret
;
1648 * transmit the ns if needed
1651 root
= xmlDocGetRootElement(doc
);
1653 if (xmlHasProp(root
, BAD_CAST
"ns") == NULL
) {
1654 xmlSetProp(root
, BAD_CAST
"ns", ns
);
1660 * push it on the stack
1662 xmlRelaxNGIncludePush(ctxt
, ret
);
1665 * Some preprocessing of the document content, this include recursing
1666 * in the include stack.
1668 #ifdef DEBUG_INCLUDE
1669 xmlGenericError(xmlGenericErrorContext
, "cleanup of %s\n", URL
);
1672 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
1679 * Pop up the include from the stack
1681 xmlRelaxNGIncludePop(ctxt
);
1683 #ifdef DEBUG_INCLUDE
1684 xmlGenericError(xmlGenericErrorContext
, "Checking of %s\n", URL
);
1687 * Check that the top element is a grammar
1689 root
= xmlDocGetRootElement(doc
);
1691 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY
,
1692 "xmlRelaxNG: included document is empty %s\n", URL
,
1696 if (!IS_RELAXNG(root
, "grammar")) {
1697 xmlRngPErr(ctxt
, node
, XML_RNGP_GRAMMAR_MISSING
,
1698 "xmlRelaxNG: included document %s root is not a grammar\n",
1704 * Elimination of redefined rules in the include.
1706 cur
= node
->children
;
1707 while (cur
!= NULL
) {
1708 if (IS_RELAXNG(cur
, "start")) {
1712 xmlRelaxNGRemoveRedefine(ctxt
, URL
, root
->children
, NULL
);
1714 xmlRngPErr(ctxt
, node
, XML_RNGP_START_MISSING
,
1715 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1718 } else if (IS_RELAXNG(cur
, "define")) {
1721 name
= xmlGetProp(cur
, BAD_CAST
"name");
1723 xmlRngPErr(ctxt
, node
, XML_RNGP_NAME_MISSING
,
1724 "xmlRelaxNG: include %s has define without name\n",
1729 xmlRelaxNGNormExtSpace(name
);
1730 found
= xmlRelaxNGRemoveRedefine(ctxt
, URL
,
1731 root
->children
, name
);
1733 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_MISSING
,
1734 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1748 * xmlRelaxNGValidErrorPush:
1749 * @ctxt: the validation context
1750 * @err: the error code
1751 * @arg1: the first string argument
1752 * @arg2: the second string argument
1753 * @dup: arg need to be duplicated
1755 * Pushes a new error on top of the error stack
1757 * Returns 0 in case of error, the index in the stack otherwise
1760 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt
,
1761 xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
1762 const xmlChar
* arg2
, int dup
)
1764 xmlRelaxNGValidErrorPtr cur
;
1767 xmlGenericError(xmlGenericErrorContext
,
1768 "Pushing error %d at %d on stack\n", err
, ctxt
->errNr
);
1770 if (ctxt
->errTab
== NULL
) {
1774 (xmlRelaxNGValidErrorPtr
) xmlMalloc(ctxt
->errMax
*
1776 (xmlRelaxNGValidError
));
1777 if (ctxt
->errTab
== NULL
) {
1778 xmlRngVErrMemory(ctxt
, "pushing error\n");
1783 if (ctxt
->errNr
>= ctxt
->errMax
) {
1786 (xmlRelaxNGValidErrorPtr
) xmlRealloc(ctxt
->errTab
,
1789 (xmlRelaxNGValidError
));
1790 if (ctxt
->errTab
== NULL
) {
1791 xmlRngVErrMemory(ctxt
, "pushing error\n");
1794 ctxt
->err
= &ctxt
->errTab
[ctxt
->errNr
- 1];
1796 if ((ctxt
->err
!= NULL
) && (ctxt
->state
!= NULL
) &&
1797 (ctxt
->err
->node
== ctxt
->state
->node
) && (ctxt
->err
->err
== err
))
1798 return (ctxt
->errNr
);
1799 cur
= &ctxt
->errTab
[ctxt
->errNr
];
1802 cur
->arg1
= xmlStrdup(arg1
);
1803 cur
->arg2
= xmlStrdup(arg2
);
1804 cur
->flags
= ERROR_IS_DUP
;
1810 if (ctxt
->state
!= NULL
) {
1811 cur
->node
= ctxt
->state
->node
;
1812 cur
->seq
= ctxt
->state
->seq
;
1818 return (ctxt
->errNr
++);
1822 * xmlRelaxNGValidErrorPop:
1823 * @ctxt: the validation context
1825 * Pops the top error from the error stack
1828 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt
)
1830 xmlRelaxNGValidErrorPtr cur
;
1832 if (ctxt
->errNr
<= 0) {
1837 if (ctxt
->errNr
> 0)
1838 ctxt
->err
= &ctxt
->errTab
[ctxt
->errNr
- 1];
1841 cur
= &ctxt
->errTab
[ctxt
->errNr
];
1842 if (cur
->flags
& ERROR_IS_DUP
) {
1843 if (cur
->arg1
!= NULL
)
1844 xmlFree((xmlChar
*) cur
->arg1
);
1846 if (cur
->arg2
!= NULL
)
1847 xmlFree((xmlChar
*) cur
->arg2
);
1854 * xmlRelaxNGDocumentPush:
1855 * @ctxt: the parser context
1856 * @value: the element doc
1858 * Pushes a new doc on top of the doc stack
1860 * Returns 0 in case of error, the index in the stack otherwise
1863 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt
,
1864 xmlRelaxNGDocumentPtr value
)
1866 if (ctxt
->docTab
== NULL
) {
1870 (xmlRelaxNGDocumentPtr
*) xmlMalloc(ctxt
->docMax
*
1871 sizeof(ctxt
->docTab
[0]));
1872 if (ctxt
->docTab
== NULL
) {
1873 xmlRngPErrMemory(ctxt
, "adding document\n");
1877 if (ctxt
->docNr
>= ctxt
->docMax
) {
1880 (xmlRelaxNGDocumentPtr
*) xmlRealloc(ctxt
->docTab
,
1882 sizeof(ctxt
->docTab
[0]));
1883 if (ctxt
->docTab
== NULL
) {
1884 xmlRngPErrMemory(ctxt
, "adding document\n");
1888 ctxt
->docTab
[ctxt
->docNr
] = value
;
1890 return (ctxt
->docNr
++);
1894 * xmlRelaxNGDocumentPop:
1895 * @ctxt: the parser context
1897 * Pops the top doc from the doc stack
1899 * Returns the doc just removed
1901 static xmlRelaxNGDocumentPtr
1902 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt
)
1904 xmlRelaxNGDocumentPtr ret
;
1906 if (ctxt
->docNr
<= 0)
1909 if (ctxt
->docNr
> 0)
1910 ctxt
->doc
= ctxt
->docTab
[ctxt
->docNr
- 1];
1913 ret
= ctxt
->docTab
[ctxt
->docNr
];
1914 ctxt
->docTab
[ctxt
->docNr
] = NULL
;
1919 * xmlRelaxNGLoadExternalRef:
1920 * @ctxt: the parser context
1921 * @URL: the normalized URL
1922 * @ns: the inherited ns if any
1924 * First lookup if the document is already loaded into the parser context,
1925 * check against recursion. If not found the resource is loaded and
1926 * the content is preprocessed before being returned back to the caller.
1928 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1930 static xmlRelaxNGDocumentPtr
1931 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt
,
1932 const xmlChar
* URL
, const xmlChar
* ns
)
1934 xmlRelaxNGDocumentPtr ret
= NULL
;
1940 * check against recursion in the stack
1942 for (i
= 0; i
< ctxt
->docNr
; i
++) {
1943 if (xmlStrEqual(ctxt
->docTab
[i
]->href
, URL
)) {
1944 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EXTERNALREF_RECURSE
,
1945 "Detected an externalRef recursion for %s\n", URL
,
1954 doc
= xmlReadFile((const char *) URL
,NULL
,0);
1956 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
1957 "xmlRelaxNG: could not load %s\n", URL
, NULL
);
1962 * Allocate the document structures and register it first.
1964 ret
= (xmlRelaxNGDocumentPtr
) xmlMalloc(sizeof(xmlRelaxNGDocument
));
1966 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_ERR_NO_MEMORY
,
1967 "xmlRelaxNG: allocate memory for doc %s\n", URL
, NULL
);
1971 memset(ret
, 0, sizeof(xmlRelaxNGDocument
));
1973 ret
->href
= xmlStrdup(URL
);
1974 ret
->next
= ctxt
->documents
;
1975 ret
->externalRef
= 1;
1976 ctxt
->documents
= ret
;
1979 * transmit the ns if needed
1982 root
= xmlDocGetRootElement(doc
);
1984 if (xmlHasProp(root
, BAD_CAST
"ns") == NULL
) {
1985 xmlSetProp(root
, BAD_CAST
"ns", ns
);
1991 * push it on the stack and register it in the hash table
1993 xmlRelaxNGDocumentPush(ctxt
, ret
);
1996 * Some preprocessing of the document content
1998 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
2004 xmlRelaxNGDocumentPop(ctxt
);
2009 /************************************************************************
2013 ************************************************************************/
2015 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2016 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2017 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2018 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2019 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
2022 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def
)
2026 switch (def
->type
) {
2027 case XML_RELAXNG_EMPTY
:
2029 case XML_RELAXNG_NOT_ALLOWED
:
2030 return ("notAllowed");
2031 case XML_RELAXNG_EXCEPT
:
2033 case XML_RELAXNG_TEXT
:
2035 case XML_RELAXNG_ELEMENT
:
2037 case XML_RELAXNG_DATATYPE
:
2038 return ("datatype");
2039 case XML_RELAXNG_VALUE
:
2041 case XML_RELAXNG_LIST
:
2043 case XML_RELAXNG_ATTRIBUTE
:
2044 return ("attribute");
2045 case XML_RELAXNG_DEF
:
2047 case XML_RELAXNG_REF
:
2049 case XML_RELAXNG_EXTERNALREF
:
2050 return ("externalRef");
2051 case XML_RELAXNG_PARENTREF
:
2052 return ("parentRef");
2053 case XML_RELAXNG_OPTIONAL
:
2054 return ("optional");
2055 case XML_RELAXNG_ZEROORMORE
:
2056 return ("zeroOrMore");
2057 case XML_RELAXNG_ONEORMORE
:
2058 return ("oneOrMore");
2059 case XML_RELAXNG_CHOICE
:
2061 case XML_RELAXNG_GROUP
:
2063 case XML_RELAXNG_INTERLEAVE
:
2064 return ("interleave");
2065 case XML_RELAXNG_START
:
2067 case XML_RELAXNG_NOOP
:
2069 case XML_RELAXNG_PARAM
:
2076 * xmlRelaxNGGetErrorString:
2077 * @err: the error code
2078 * @arg1: the first string argument
2079 * @arg2: the second string argument
2081 * computes a formatted error string for the given error code and args
2083 * Returns the error string, it must be deallocated by the caller
2086 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
2087 const xmlChar
* arg2
)
2098 case XML_RELAXNG_OK
:
2100 case XML_RELAXNG_ERR_MEMORY
:
2101 return (xmlCharStrdup("out of memory\n"));
2102 case XML_RELAXNG_ERR_TYPE
:
2103 snprintf(msg
, 1000, "failed to validate type %s\n", arg1
);
2105 case XML_RELAXNG_ERR_TYPEVAL
:
2106 snprintf(msg
, 1000, "Type %s doesn't allow value '%s'\n", arg1
,
2109 case XML_RELAXNG_ERR_DUPID
:
2110 snprintf(msg
, 1000, "ID %s redefined\n", arg1
);
2112 case XML_RELAXNG_ERR_TYPECMP
:
2113 snprintf(msg
, 1000, "failed to compare type %s\n", arg1
);
2115 case XML_RELAXNG_ERR_NOSTATE
:
2116 return (xmlCharStrdup("Internal error: no state\n"));
2117 case XML_RELAXNG_ERR_NODEFINE
:
2118 return (xmlCharStrdup("Internal error: no define\n"));
2119 case XML_RELAXNG_ERR_INTERNAL
:
2120 snprintf(msg
, 1000, "Internal error: %s\n", arg1
);
2122 case XML_RELAXNG_ERR_LISTEXTRA
:
2123 snprintf(msg
, 1000, "Extra data in list: %s\n", arg1
);
2125 case XML_RELAXNG_ERR_INTERNODATA
:
2126 return (xmlCharStrdup
2127 ("Internal: interleave block has no data\n"));
2128 case XML_RELAXNG_ERR_INTERSEQ
:
2129 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2130 case XML_RELAXNG_ERR_INTEREXTRA
:
2131 snprintf(msg
, 1000, "Extra element %s in interleave\n", arg1
);
2133 case XML_RELAXNG_ERR_ELEMNAME
:
2134 snprintf(msg
, 1000, "Expecting element %s, got %s\n", arg1
,
2137 case XML_RELAXNG_ERR_ELEMNONS
:
2138 snprintf(msg
, 1000, "Expecting a namespace for element %s\n",
2141 case XML_RELAXNG_ERR_ELEMWRONGNS
:
2143 "Element %s has wrong namespace: expecting %s\n", arg1
,
2146 case XML_RELAXNG_ERR_ELEMWRONG
:
2147 snprintf(msg
, 1000, "Did not expect element %s there\n", arg1
);
2149 case XML_RELAXNG_ERR_TEXTWRONG
:
2151 "Did not expect text in element %s content\n", arg1
);
2153 case XML_RELAXNG_ERR_ELEMEXTRANS
:
2154 snprintf(msg
, 1000, "Expecting no namespace for element %s\n",
2157 case XML_RELAXNG_ERR_ELEMNOTEMPTY
:
2158 snprintf(msg
, 1000, "Expecting element %s to be empty\n", arg1
);
2160 case XML_RELAXNG_ERR_NOELEM
:
2161 snprintf(msg
, 1000, "Expecting an element %s, got nothing\n",
2164 case XML_RELAXNG_ERR_NOTELEM
:
2165 return (xmlCharStrdup("Expecting an element got text\n"));
2166 case XML_RELAXNG_ERR_ATTRVALID
:
2167 snprintf(msg
, 1000, "Element %s failed to validate attributes\n",
2170 case XML_RELAXNG_ERR_CONTENTVALID
:
2171 snprintf(msg
, 1000, "Element %s failed to validate content\n",
2174 case XML_RELAXNG_ERR_EXTRACONTENT
:
2175 snprintf(msg
, 1000, "Element %s has extra content: %s\n",
2178 case XML_RELAXNG_ERR_INVALIDATTR
:
2179 snprintf(msg
, 1000, "Invalid attribute %s for element %s\n",
2182 case XML_RELAXNG_ERR_LACKDATA
:
2183 snprintf(msg
, 1000, "Datatype element %s contains no data\n",
2186 case XML_RELAXNG_ERR_DATAELEM
:
2187 snprintf(msg
, 1000, "Datatype element %s has child elements\n",
2190 case XML_RELAXNG_ERR_VALELEM
:
2191 snprintf(msg
, 1000, "Value element %s has child elements\n",
2194 case XML_RELAXNG_ERR_LISTELEM
:
2195 snprintf(msg
, 1000, "List element %s has child elements\n",
2198 case XML_RELAXNG_ERR_DATATYPE
:
2199 snprintf(msg
, 1000, "Error validating datatype %s\n", arg1
);
2201 case XML_RELAXNG_ERR_VALUE
:
2202 snprintf(msg
, 1000, "Error validating value %s\n", arg1
);
2204 case XML_RELAXNG_ERR_LIST
:
2205 return (xmlCharStrdup("Error validating list\n"));
2206 case XML_RELAXNG_ERR_NOGRAMMAR
:
2207 return (xmlCharStrdup("No top grammar defined\n"));
2208 case XML_RELAXNG_ERR_EXTRADATA
:
2209 return (xmlCharStrdup("Extra data in the document\n"));
2211 return (xmlCharStrdup("Unknown error !\n"));
2214 snprintf(msg
, 1000, "Unknown error code %d\n", err
);
2217 return (xmlStrdup((xmlChar
*) msg
));
2221 * xmlRelaxNGShowValidError:
2222 * @ctxt: the validation context
2223 * @err: the error number
2225 * @child: the node child generating the problem.
2226 * @arg1: the first argument
2227 * @arg2: the second argument
2229 * Show a validation error.
2232 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt
,
2233 xmlRelaxNGValidErr err
, xmlNodePtr node
,
2234 xmlNodePtr child
, const xmlChar
* arg1
,
2235 const xmlChar
* arg2
)
2239 if (ctxt
->flags
& FLAGS_NOERROR
)
2243 xmlGenericError(xmlGenericErrorContext
, "Show error %d\n", err
);
2245 msg
= xmlRelaxNGGetErrorString(err
, arg1
, arg2
);
2249 if (ctxt
->errNo
== XML_RELAXNG_OK
)
2251 xmlRngVErr(ctxt
, (child
== NULL
? node
: child
), err
,
2252 (const char *) msg
, arg1
, arg2
);
2257 * xmlRelaxNGPopErrors:
2258 * @ctxt: the validation context
2259 * @level: the error level in the stack
2261 * pop and discard all errors until the given level is reached
2264 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt
, int level
)
2267 xmlRelaxNGValidErrorPtr err
;
2270 xmlGenericError(xmlGenericErrorContext
,
2271 "Pop errors till level %d\n", level
);
2273 for (i
= level
; i
< ctxt
->errNr
; i
++) {
2274 err
= &ctxt
->errTab
[i
];
2275 if (err
->flags
& ERROR_IS_DUP
) {
2276 if (err
->arg1
!= NULL
)
2277 xmlFree((xmlChar
*) err
->arg1
);
2279 if (err
->arg2
!= NULL
)
2280 xmlFree((xmlChar
*) err
->arg2
);
2285 ctxt
->errNr
= level
;
2286 if (ctxt
->errNr
<= 0)
2291 * xmlRelaxNGDumpValidError:
2292 * @ctxt: the validation context
2294 * Show all validation error over a given index.
2297 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt
)
2300 xmlRelaxNGValidErrorPtr err
, dup
;
2303 xmlGenericError(xmlGenericErrorContext
,
2304 "Dumping error stack %d errors\n", ctxt
->errNr
);
2306 for (i
= 0, k
= 0; i
< ctxt
->errNr
; i
++) {
2307 err
= &ctxt
->errTab
[i
];
2308 if (k
< MAX_ERROR
) {
2309 for (j
= 0; j
< i
; j
++) {
2310 dup
= &ctxt
->errTab
[j
];
2311 if ((err
->err
== dup
->err
) && (err
->node
== dup
->node
) &&
2312 (xmlStrEqual(err
->arg1
, dup
->arg1
)) &&
2313 (xmlStrEqual(err
->arg2
, dup
->arg2
))) {
2317 xmlRelaxNGShowValidError(ctxt
, err
->err
, err
->node
, err
->seq
,
2318 err
->arg1
, err
->arg2
);
2322 if (err
->flags
& ERROR_IS_DUP
) {
2323 if (err
->arg1
!= NULL
)
2324 xmlFree((xmlChar
*) err
->arg1
);
2326 if (err
->arg2
!= NULL
)
2327 xmlFree((xmlChar
*) err
->arg2
);
2336 * xmlRelaxNGAddValidError:
2337 * @ctxt: the validation context
2338 * @err: the error number
2339 * @arg1: the first argument
2340 * @arg2: the second argument
2341 * @dup: need to dup the args
2343 * Register a validation error, either generating it if it's sure
2344 * or stacking it for later handling if unsure.
2347 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt
,
2348 xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
2349 const xmlChar
* arg2
, int dup
)
2353 if (ctxt
->flags
& FLAGS_NOERROR
)
2357 xmlGenericError(xmlGenericErrorContext
, "Adding error %d\n", err
);
2360 * generate the error directly
2362 if (((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) ||
2363 (ctxt
->flags
& FLAGS_NEGATIVE
)) {
2364 xmlNodePtr node
, seq
;
2367 * Flush first any stacked error which might be the
2368 * real cause of the problem.
2370 if (ctxt
->errNr
!= 0)
2371 xmlRelaxNGDumpValidError(ctxt
);
2372 if (ctxt
->state
!= NULL
) {
2373 node
= ctxt
->state
->node
;
2374 seq
= ctxt
->state
->seq
;
2378 if ((node
== NULL
) && (seq
== NULL
)) {
2381 xmlRelaxNGShowValidError(ctxt
, err
, node
, seq
, arg1
, arg2
);
2384 * Stack the error for later processing if needed
2387 xmlRelaxNGValidErrorPush(ctxt
, err
, arg1
, arg2
, dup
);
2392 /************************************************************************
2394 * Type library hooks *
2396 ************************************************************************/
2397 static xmlChar
*xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
,
2398 const xmlChar
* str
);
2401 * xmlRelaxNGSchemaTypeHave:
2402 * @data: data needed for the library
2403 * @type: the type name
2405 * Check if the given type is provided by
2406 * the W3C XMLSchema Datatype library.
2408 * Returns 1 if yes, 0 if no and -1 in case of error.
2411 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED
, const xmlChar
* type
)
2413 xmlSchemaTypePtr typ
;
2417 typ
= xmlSchemaGetPredefinedType(type
,
2419 "http://www.w3.org/2001/XMLSchema");
2426 * xmlRelaxNGSchemaTypeCheck:
2427 * @data: data needed for the library
2428 * @type: the type name
2429 * @value: the value to check
2432 * Check if the given type and value are validated by
2433 * the W3C XMLSchema Datatype library.
2435 * Returns 1 if yes, 0 if no and -1 in case of error.
2438 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED
,
2439 const xmlChar
* type
,
2440 const xmlChar
* value
,
2441 void **result
, xmlNodePtr node
)
2443 xmlSchemaTypePtr typ
;
2446 if ((type
== NULL
) || (value
== NULL
))
2448 typ
= xmlSchemaGetPredefinedType(type
,
2450 "http://www.w3.org/2001/XMLSchema");
2453 ret
= xmlSchemaValPredefTypeNode(typ
, value
,
2454 (xmlSchemaValPtr
*) result
, node
);
2455 if (ret
== 2) /* special ID error code */
2465 * xmlRelaxNGSchemaFacetCheck:
2466 * @data: data needed for the library
2467 * @type: the type name
2468 * @facet: the facet name
2469 * @val: the facet value
2470 * @strval: the string value
2471 * @value: the value to check
2473 * Function provided by a type library to check a value facet
2475 * Returns 1 if yes, 0 if no and -1 in case of error.
2478 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED
,
2479 const xmlChar
* type
, const xmlChar
* facetname
,
2480 const xmlChar
* val
, const xmlChar
* strval
,
2483 xmlSchemaFacetPtr facet
;
2484 xmlSchemaTypePtr typ
;
2487 if ((type
== NULL
) || (strval
== NULL
))
2489 typ
= xmlSchemaGetPredefinedType(type
,
2491 "http://www.w3.org/2001/XMLSchema");
2495 facet
= xmlSchemaNewFacet();
2499 if (xmlStrEqual(facetname
, BAD_CAST
"minInclusive")) {
2500 facet
->type
= XML_SCHEMA_FACET_MININCLUSIVE
;
2501 } else if (xmlStrEqual(facetname
, BAD_CAST
"minExclusive")) {
2502 facet
->type
= XML_SCHEMA_FACET_MINEXCLUSIVE
;
2503 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxInclusive")) {
2504 facet
->type
= XML_SCHEMA_FACET_MAXINCLUSIVE
;
2505 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxExclusive")) {
2506 facet
->type
= XML_SCHEMA_FACET_MAXEXCLUSIVE
;
2507 } else if (xmlStrEqual(facetname
, BAD_CAST
"totalDigits")) {
2508 facet
->type
= XML_SCHEMA_FACET_TOTALDIGITS
;
2509 } else if (xmlStrEqual(facetname
, BAD_CAST
"fractionDigits")) {
2510 facet
->type
= XML_SCHEMA_FACET_FRACTIONDIGITS
;
2511 } else if (xmlStrEqual(facetname
, BAD_CAST
"pattern")) {
2512 facet
->type
= XML_SCHEMA_FACET_PATTERN
;
2513 } else if (xmlStrEqual(facetname
, BAD_CAST
"enumeration")) {
2514 facet
->type
= XML_SCHEMA_FACET_ENUMERATION
;
2515 } else if (xmlStrEqual(facetname
, BAD_CAST
"whiteSpace")) {
2516 facet
->type
= XML_SCHEMA_FACET_WHITESPACE
;
2517 } else if (xmlStrEqual(facetname
, BAD_CAST
"length")) {
2518 facet
->type
= XML_SCHEMA_FACET_LENGTH
;
2519 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxLength")) {
2520 facet
->type
= XML_SCHEMA_FACET_MAXLENGTH
;
2521 } else if (xmlStrEqual(facetname
, BAD_CAST
"minLength")) {
2522 facet
->type
= XML_SCHEMA_FACET_MINLENGTH
;
2524 xmlSchemaFreeFacet(facet
);
2528 ret
= xmlSchemaCheckFacet(facet
, typ
, NULL
, type
);
2530 xmlSchemaFreeFacet(facet
);
2533 ret
= xmlSchemaValidateFacet(typ
, facet
, strval
, value
);
2534 xmlSchemaFreeFacet(facet
);
2541 * xmlRelaxNGSchemaFreeValue:
2542 * @data: data needed for the library
2543 * @value: the value to free
2545 * Function provided by a type library to free a Schemas value
2547 * Returns 1 if yes, 0 if no and -1 in case of error.
2550 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED
, void *value
)
2552 xmlSchemaFreeValue(value
);
2556 * xmlRelaxNGSchemaTypeCompare:
2557 * @data: data needed for the library
2558 * @type: the type name
2559 * @value1: the first value
2560 * @value2: the second value
2562 * Compare two values for equality accordingly a type from the W3C XMLSchema
2565 * Returns 1 if equal, 0 if no and -1 in case of error.
2568 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED
,
2569 const xmlChar
* type
,
2570 const xmlChar
* value1
,
2573 const xmlChar
* value2
, xmlNodePtr ctxt2
)
2576 xmlSchemaTypePtr typ
;
2577 xmlSchemaValPtr res1
= NULL
, res2
= NULL
;
2579 if ((type
== NULL
) || (value1
== NULL
) || (value2
== NULL
))
2581 typ
= xmlSchemaGetPredefinedType(type
,
2583 "http://www.w3.org/2001/XMLSchema");
2586 if (comp1
== NULL
) {
2587 ret
= xmlSchemaValPredefTypeNode(typ
, value1
, &res1
, ctxt1
);
2593 res1
= (xmlSchemaValPtr
) comp1
;
2595 ret
= xmlSchemaValPredefTypeNode(typ
, value2
, &res2
, ctxt2
);
2597 if ((comp1
== NULL
) && (res1
!= NULL
))
2598 xmlSchemaFreeValue(res1
);
2604 ret
= xmlSchemaCompareValues(res1
, res2
);
2605 if (res1
!= (xmlSchemaValPtr
) comp1
)
2606 xmlSchemaFreeValue(res1
);
2607 xmlSchemaFreeValue(res2
);
2616 * xmlRelaxNGDefaultTypeHave:
2617 * @data: data needed for the library
2618 * @type: the type name
2620 * Check if the given type is provided by
2621 * the default datatype library.
2623 * Returns 1 if yes, 0 if no and -1 in case of error.
2626 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED
,
2627 const xmlChar
* type
)
2631 if (xmlStrEqual(type
, BAD_CAST
"string"))
2633 if (xmlStrEqual(type
, BAD_CAST
"token"))
2639 * xmlRelaxNGDefaultTypeCheck:
2640 * @data: data needed for the library
2641 * @type: the type name
2642 * @value: the value to check
2645 * Check if the given type and value are validated by
2646 * the default datatype library.
2648 * Returns 1 if yes, 0 if no and -1 in case of error.
2651 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED
,
2652 const xmlChar
* type ATTRIBUTE_UNUSED
,
2653 const xmlChar
* value ATTRIBUTE_UNUSED
,
2654 void **result ATTRIBUTE_UNUSED
,
2655 xmlNodePtr node ATTRIBUTE_UNUSED
)
2659 if (xmlStrEqual(type
, BAD_CAST
"string"))
2661 if (xmlStrEqual(type
, BAD_CAST
"token")) {
2669 * xmlRelaxNGDefaultTypeCompare:
2670 * @data: data needed for the library
2671 * @type: the type name
2672 * @value1: the first value
2673 * @value2: the second value
2675 * Compare two values accordingly a type from the default
2678 * Returns 1 if yes, 0 if no and -1 in case of error.
2681 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED
,
2682 const xmlChar
* type
,
2683 const xmlChar
* value1
,
2684 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED
,
2685 void *comp1 ATTRIBUTE_UNUSED
,
2686 const xmlChar
* value2
,
2687 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED
)
2691 if (xmlStrEqual(type
, BAD_CAST
"string")) {
2692 ret
= xmlStrEqual(value1
, value2
);
2693 } else if (xmlStrEqual(type
, BAD_CAST
"token")) {
2694 if (!xmlStrEqual(value1
, value2
)) {
2695 xmlChar
*nval
, *nvalue
;
2698 * TODO: trivial optimizations are possible by
2699 * computing at compile-time
2701 nval
= xmlRelaxNGNormalize(NULL
, value1
);
2702 nvalue
= xmlRelaxNGNormalize(NULL
, value2
);
2704 if ((nval
== NULL
) || (nvalue
== NULL
))
2706 else if (xmlStrEqual(nval
, nvalue
))
2720 static int xmlRelaxNGTypeInitialized
= 0;
2721 static xmlHashTablePtr xmlRelaxNGRegisteredTypes
= NULL
;
2724 * xmlRelaxNGFreeTypeLibrary:
2725 * @lib: the type library structure
2726 * @namespace: the URI bound to the library
2728 * Free the structure associated to the type library
2731 xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib
,
2732 const xmlChar
* namespace ATTRIBUTE_UNUSED
)
2736 if (lib
->namespace != NULL
)
2737 xmlFree((xmlChar
*) lib
->namespace);
2742 * xmlRelaxNGRegisterTypeLibrary:
2743 * @namespace: the URI bound to the library
2744 * @data: data associated to the library
2745 * @have: the provide function
2746 * @check: the checking function
2747 * @comp: the comparison function
2749 * Register a new type library
2751 * Returns 0 in case of success and -1 in case of error.
2754 xmlRelaxNGRegisterTypeLibrary(const xmlChar
* namespace, void *data
,
2755 xmlRelaxNGTypeHave have
,
2756 xmlRelaxNGTypeCheck check
,
2757 xmlRelaxNGTypeCompare comp
,
2758 xmlRelaxNGFacetCheck facet
,
2759 xmlRelaxNGTypeFree freef
)
2761 xmlRelaxNGTypeLibraryPtr lib
;
2764 if ((xmlRelaxNGRegisteredTypes
== NULL
) || (namespace == NULL
) ||
2765 (check
== NULL
) || (comp
== NULL
))
2767 if (xmlHashLookup(xmlRelaxNGRegisteredTypes
, namespace) != NULL
) {
2768 xmlGenericError(xmlGenericErrorContext
,
2769 "Relax-NG types library '%s' already registered\n",
2774 (xmlRelaxNGTypeLibraryPtr
)
2775 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary
));
2777 xmlRngVErrMemory(NULL
, "adding types library\n");
2780 memset(lib
, 0, sizeof(xmlRelaxNGTypeLibrary
));
2781 lib
->namespace = xmlStrdup(namespace);
2788 ret
= xmlHashAddEntry(xmlRelaxNGRegisteredTypes
, namespace, lib
);
2790 xmlGenericError(xmlGenericErrorContext
,
2791 "Relax-NG types library failed to register '%s'\n",
2793 xmlRelaxNGFreeTypeLibrary(lib
, namespace);
2800 * xmlRelaxNGInitTypes:
2802 * Initilize the default type libraries.
2804 * Returns 0 in case of success and -1 in case of error.
2807 xmlRelaxNGInitTypes(void)
2809 if (xmlRelaxNGTypeInitialized
!= 0)
2811 xmlRelaxNGRegisteredTypes
= xmlHashCreate(10);
2812 if (xmlRelaxNGRegisteredTypes
== NULL
) {
2813 xmlGenericError(xmlGenericErrorContext
,
2814 "Failed to allocate sh table for Relax-NG types\n");
2817 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2818 "http://www.w3.org/2001/XMLSchema-datatypes",
2819 NULL
, xmlRelaxNGSchemaTypeHave
,
2820 xmlRelaxNGSchemaTypeCheck
,
2821 xmlRelaxNGSchemaTypeCompare
,
2822 xmlRelaxNGSchemaFacetCheck
,
2823 xmlRelaxNGSchemaFreeValue
);
2824 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs
, NULL
,
2825 xmlRelaxNGDefaultTypeHave
,
2826 xmlRelaxNGDefaultTypeCheck
,
2827 xmlRelaxNGDefaultTypeCompare
, NULL
,
2829 xmlRelaxNGTypeInitialized
= 1;
2834 * xmlRelaxNGCleanupTypes:
2836 * Cleanup the default Schemas type library associated to RelaxNG
2839 xmlRelaxNGCleanupTypes(void)
2841 xmlSchemaCleanupTypes();
2842 if (xmlRelaxNGTypeInitialized
== 0)
2844 xmlHashFree(xmlRelaxNGRegisteredTypes
, (xmlHashDeallocator
)
2845 xmlRelaxNGFreeTypeLibrary
);
2846 xmlRelaxNGTypeInitialized
= 0;
2849 /************************************************************************
2851 * Compiling element content into regexp *
2853 * Sometime the element content can be compiled into a pure regexp, *
2854 * This allows a faster execution and streamability at that level *
2856 ************************************************************************/
2858 /* from automata.c but not exported */
2859 void xmlAutomataSetFlags(xmlAutomataPtr am
, int flags
);
2862 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt
,
2863 xmlRelaxNGDefinePtr def
);
2866 * xmlRelaxNGIsCompileable:
2867 * @define: the definition to check
2869 * Check if a definition is nullable.
2871 * Returns 1 if yes, 0 if no and -1 in case of error
2874 xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def
)
2881 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
2882 (def
->dflags
& IS_COMPILABLE
))
2884 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
2885 (def
->dflags
& IS_NOT_COMPILABLE
))
2887 switch (def
->type
) {
2888 case XML_RELAXNG_NOOP
:
2889 ret
= xmlRelaxNGIsCompileable(def
->content
);
2891 case XML_RELAXNG_TEXT
:
2892 case XML_RELAXNG_EMPTY
:
2895 case XML_RELAXNG_ELEMENT
:
2897 * Check if the element content is compileable
2899 if (((def
->dflags
& IS_NOT_COMPILABLE
) == 0) &&
2900 ((def
->dflags
& IS_COMPILABLE
) == 0)) {
2901 xmlRelaxNGDefinePtr list
;
2903 list
= def
->content
;
2904 while (list
!= NULL
) {
2905 ret
= xmlRelaxNGIsCompileable(list
);
2911 * Because the routine is recursive, we must guard against
2912 * discovering both COMPILABLE and NOT_COMPILABLE
2915 def
->dflags
&= ~IS_COMPILABLE
;
2916 def
->dflags
|= IS_NOT_COMPILABLE
;
2918 if ((ret
== 1) && !(def
->dflags
&= IS_NOT_COMPILABLE
))
2919 def
->dflags
|= IS_COMPILABLE
;
2920 #ifdef DEBUG_COMPILE
2922 xmlGenericError(xmlGenericErrorContext
,
2923 "element content for %s is compilable\n",
2925 } else if (ret
== 0) {
2926 xmlGenericError(xmlGenericErrorContext
,
2927 "element content for %s is not compilable\n",
2930 xmlGenericError(xmlGenericErrorContext
,
2931 "Problem in RelaxNGIsCompileable for element %s\n",
2937 * All elements return a compileable status unless they
2938 * are generic like anyName
2940 if ((def
->nameClass
!= NULL
) || (def
->name
== NULL
))
2945 case XML_RELAXNG_REF
:
2946 case XML_RELAXNG_EXTERNALREF
:
2947 case XML_RELAXNG_PARENTREF
:
2948 if (def
->depth
== -20) {
2951 xmlRelaxNGDefinePtr list
;
2954 list
= def
->content
;
2955 while (list
!= NULL
) {
2956 ret
= xmlRelaxNGIsCompileable(list
);
2963 case XML_RELAXNG_START
:
2964 case XML_RELAXNG_OPTIONAL
:
2965 case XML_RELAXNG_ZEROORMORE
:
2966 case XML_RELAXNG_ONEORMORE
:
2967 case XML_RELAXNG_CHOICE
:
2968 case XML_RELAXNG_GROUP
:
2969 case XML_RELAXNG_DEF
:{
2970 xmlRelaxNGDefinePtr list
;
2972 list
= def
->content
;
2973 while (list
!= NULL
) {
2974 ret
= xmlRelaxNGIsCompileable(list
);
2981 case XML_RELAXNG_EXCEPT
:
2982 case XML_RELAXNG_ATTRIBUTE
:
2983 case XML_RELAXNG_INTERLEAVE
:
2984 case XML_RELAXNG_DATATYPE
:
2985 case XML_RELAXNG_LIST
:
2986 case XML_RELAXNG_PARAM
:
2987 case XML_RELAXNG_VALUE
:
2988 case XML_RELAXNG_NOT_ALLOWED
:
2993 def
->dflags
|= IS_NOT_COMPILABLE
;
2995 def
->dflags
|= IS_COMPILABLE
;
2996 #ifdef DEBUG_COMPILE
2998 xmlGenericError(xmlGenericErrorContext
,
2999 "RelaxNGIsCompileable %s : true\n",
3000 xmlRelaxNGDefName(def
));
3001 } else if (ret
== 0) {
3002 xmlGenericError(xmlGenericErrorContext
,
3003 "RelaxNGIsCompileable %s : false\n",
3004 xmlRelaxNGDefName(def
));
3006 xmlGenericError(xmlGenericErrorContext
,
3007 "Problem in RelaxNGIsCompileable %s\n",
3008 xmlRelaxNGDefName(def
));
3015 * xmlRelaxNGCompile:
3016 * ctxt: the RelaxNG parser context
3017 * @define: the definition tree to compile
3019 * Compile the set of definitions, it works recursively, till the
3020 * element boundaries, where it tries to compile the content if possible
3022 * Returns 0 if success and -1 in case of error
3025 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt
, xmlRelaxNGDefinePtr def
)
3028 xmlRelaxNGDefinePtr list
;
3030 if ((ctxt
== NULL
) || (def
== NULL
))
3033 switch (def
->type
) {
3034 case XML_RELAXNG_START
:
3035 if ((xmlRelaxNGIsCompileable(def
) == 1) && (def
->depth
!= -25)) {
3036 xmlAutomataPtr oldam
= ctxt
->am
;
3037 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3041 list
= def
->content
;
3042 ctxt
->am
= xmlNewAutomata();
3043 if (ctxt
->am
== NULL
)
3047 * assume identical strings but not same pointer are different
3048 * atoms, needed for non-determinism detection
3049 * That way if 2 elements with the same name are in a choice
3050 * branch the automata is found non-deterministic and
3051 * we fallback to the normal validation which does the right
3052 * thing of exploring both choices.
3054 xmlAutomataSetFlags(ctxt
->am
, 1);
3056 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
3057 while (list
!= NULL
) {
3058 xmlRelaxNGCompile(ctxt
, list
);
3061 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
3062 def
->contModel
= xmlAutomataCompile(ctxt
->am
);
3063 xmlRegexpIsDeterminist(def
->contModel
);
3065 xmlFreeAutomata(ctxt
->am
);
3066 ctxt
->state
= oldstate
;
3070 case XML_RELAXNG_ELEMENT
:
3071 if ((ctxt
->am
!= NULL
) && (def
->name
!= NULL
)) {
3072 ctxt
->state
= xmlAutomataNewTransition2(ctxt
->am
,
3077 if ((def
->dflags
& IS_COMPILABLE
) && (def
->depth
!= -25)) {
3078 xmlAutomataPtr oldam
= ctxt
->am
;
3079 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3083 list
= def
->content
;
3084 ctxt
->am
= xmlNewAutomata();
3085 if (ctxt
->am
== NULL
)
3087 xmlAutomataSetFlags(ctxt
->am
, 1);
3088 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
3089 while (list
!= NULL
) {
3090 xmlRelaxNGCompile(ctxt
, list
);
3093 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
3094 def
->contModel
= xmlAutomataCompile(ctxt
->am
);
3095 if (!xmlRegexpIsDeterminist(def
->contModel
)) {
3096 #ifdef DEBUG_COMPILE
3097 xmlGenericError(xmlGenericErrorContext
,
3098 "Content model not determinist %s\n",
3102 * we can only use the automata if it is determinist
3104 xmlRegFreeRegexp(def
->contModel
);
3105 def
->contModel
= NULL
;
3107 xmlFreeAutomata(ctxt
->am
);
3108 ctxt
->state
= oldstate
;
3111 xmlAutomataPtr oldam
= ctxt
->am
;
3114 * we can't build the content model for this element content
3115 * but it still might be possible to build it for some of its
3116 * children, recurse.
3118 ret
= xmlRelaxNGTryCompile(ctxt
, def
);
3122 case XML_RELAXNG_NOOP
:
3123 ret
= xmlRelaxNGCompile(ctxt
, def
->content
);
3125 case XML_RELAXNG_OPTIONAL
:{
3126 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3128 list
= def
->content
;
3129 while (list
!= NULL
) {
3130 xmlRelaxNGCompile(ctxt
, list
);
3133 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
3136 case XML_RELAXNG_ZEROORMORE
:{
3137 xmlAutomataStatePtr oldstate
;
3140 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3141 oldstate
= ctxt
->state
;
3142 list
= def
->content
;
3143 while (list
!= NULL
) {
3144 xmlRelaxNGCompile(ctxt
, list
);
3147 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldstate
);
3149 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3152 case XML_RELAXNG_ONEORMORE
:{
3153 xmlAutomataStatePtr oldstate
;
3155 list
= def
->content
;
3156 while (list
!= NULL
) {
3157 xmlRelaxNGCompile(ctxt
, list
);
3160 oldstate
= ctxt
->state
;
3161 list
= def
->content
;
3162 while (list
!= NULL
) {
3163 xmlRelaxNGCompile(ctxt
, list
);
3166 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldstate
);
3168 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3171 case XML_RELAXNG_CHOICE
:{
3172 xmlAutomataStatePtr target
= NULL
;
3173 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3175 list
= def
->content
;
3176 while (list
!= NULL
) {
3177 ctxt
->state
= oldstate
;
3178 ret
= xmlRelaxNGCompile(ctxt
, list
);
3182 target
= ctxt
->state
;
3184 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
,
3189 ctxt
->state
= target
;
3193 case XML_RELAXNG_REF
:
3194 case XML_RELAXNG_EXTERNALREF
:
3195 case XML_RELAXNG_PARENTREF
:
3196 case XML_RELAXNG_GROUP
:
3197 case XML_RELAXNG_DEF
:
3198 list
= def
->content
;
3199 while (list
!= NULL
) {
3200 ret
= xmlRelaxNGCompile(ctxt
, list
);
3206 case XML_RELAXNG_TEXT
:{
3207 xmlAutomataStatePtr oldstate
;
3210 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3211 oldstate
= ctxt
->state
;
3212 xmlRelaxNGCompile(ctxt
, def
->content
);
3213 xmlAutomataNewTransition(ctxt
->am
, ctxt
->state
,
3214 ctxt
->state
, BAD_CAST
"#text",
3217 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3220 case XML_RELAXNG_EMPTY
:
3222 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3224 case XML_RELAXNG_EXCEPT
:
3225 case XML_RELAXNG_ATTRIBUTE
:
3226 case XML_RELAXNG_INTERLEAVE
:
3227 case XML_RELAXNG_NOT_ALLOWED
:
3228 case XML_RELAXNG_DATATYPE
:
3229 case XML_RELAXNG_LIST
:
3230 case XML_RELAXNG_PARAM
:
3231 case XML_RELAXNG_VALUE
:
3232 /* This should not happen and generate an internal error */
3233 fprintf(stderr
, "RNG internal error trying to compile %s\n",
3234 xmlRelaxNGDefName(def
));
3241 * xmlRelaxNGTryCompile:
3242 * ctxt: the RelaxNG parser context
3243 * @define: the definition tree to compile
3245 * Try to compile the set of definitions, it works recursively,
3246 * possibly ignoring parts which cannot be compiled.
3248 * Returns 0 if success and -1 in case of error
3251 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt
, xmlRelaxNGDefinePtr def
)
3254 xmlRelaxNGDefinePtr list
;
3256 if ((ctxt
== NULL
) || (def
== NULL
))
3259 if ((def
->type
== XML_RELAXNG_START
) ||
3260 (def
->type
== XML_RELAXNG_ELEMENT
)) {
3261 ret
= xmlRelaxNGIsCompileable(def
);
3262 if ((def
->dflags
& IS_COMPILABLE
) && (def
->depth
!= -25)) {
3264 ret
= xmlRelaxNGCompile(ctxt
, def
);
3265 #ifdef DEBUG_PROGRESSIVE
3267 if (def
->type
== XML_RELAXNG_START
)
3268 xmlGenericError(xmlGenericErrorContext
,
3269 "compiled the start\n");
3271 xmlGenericError(xmlGenericErrorContext
,
3272 "compiled element %s\n", def
->name
);
3274 if (def
->type
== XML_RELAXNG_START
)
3275 xmlGenericError(xmlGenericErrorContext
,
3276 "failed to compile the start\n");
3278 xmlGenericError(xmlGenericErrorContext
,
3279 "failed to compile element %s\n",
3286 switch (def
->type
) {
3287 case XML_RELAXNG_NOOP
:
3288 ret
= xmlRelaxNGTryCompile(ctxt
, def
->content
);
3290 case XML_RELAXNG_TEXT
:
3291 case XML_RELAXNG_DATATYPE
:
3292 case XML_RELAXNG_LIST
:
3293 case XML_RELAXNG_PARAM
:
3294 case XML_RELAXNG_VALUE
:
3295 case XML_RELAXNG_EMPTY
:
3296 case XML_RELAXNG_ELEMENT
:
3299 case XML_RELAXNG_OPTIONAL
:
3300 case XML_RELAXNG_ZEROORMORE
:
3301 case XML_RELAXNG_ONEORMORE
:
3302 case XML_RELAXNG_CHOICE
:
3303 case XML_RELAXNG_GROUP
:
3304 case XML_RELAXNG_DEF
:
3305 case XML_RELAXNG_START
:
3306 case XML_RELAXNG_REF
:
3307 case XML_RELAXNG_EXTERNALREF
:
3308 case XML_RELAXNG_PARENTREF
:
3309 list
= def
->content
;
3310 while (list
!= NULL
) {
3311 ret
= xmlRelaxNGTryCompile(ctxt
, list
);
3317 case XML_RELAXNG_EXCEPT
:
3318 case XML_RELAXNG_ATTRIBUTE
:
3319 case XML_RELAXNG_INTERLEAVE
:
3320 case XML_RELAXNG_NOT_ALLOWED
:
3327 /************************************************************************
3329 * Parsing functions *
3331 ************************************************************************/
3333 static xmlRelaxNGDefinePtr
xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3334 ctxt
, xmlNodePtr node
);
3335 static xmlRelaxNGDefinePtr
xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3336 ctxt
, xmlNodePtr node
);
3337 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3338 ctxt
, xmlNodePtr nodes
,
3340 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3341 ctxt
, xmlNodePtr node
);
3342 static xmlRelaxNGPtr
xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
,
3344 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
3346 static xmlRelaxNGDefinePtr
xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3347 ctxt
, xmlNodePtr node
,
3350 static xmlRelaxNGGrammarPtr
xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3351 ctxt
, xmlNodePtr nodes
);
3352 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
3353 xmlRelaxNGDefinePtr define
,
3357 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3360 * xmlRelaxNGIsNullable:
3361 * @define: the definition to verify
3363 * Check if a definition is nullable.
3365 * Returns 1 if yes, 0 if no and -1 in case of error
3368 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define
)
3375 if (define
->dflags
& IS_NULLABLE
)
3377 if (define
->dflags
& IS_NOT_NULLABLE
)
3379 switch (define
->type
) {
3380 case XML_RELAXNG_EMPTY
:
3381 case XML_RELAXNG_TEXT
:
3384 case XML_RELAXNG_NOOP
:
3385 case XML_RELAXNG_DEF
:
3386 case XML_RELAXNG_REF
:
3387 case XML_RELAXNG_EXTERNALREF
:
3388 case XML_RELAXNG_PARENTREF
:
3389 case XML_RELAXNG_ONEORMORE
:
3390 ret
= xmlRelaxNGIsNullable(define
->content
);
3392 case XML_RELAXNG_EXCEPT
:
3393 case XML_RELAXNG_NOT_ALLOWED
:
3394 case XML_RELAXNG_ELEMENT
:
3395 case XML_RELAXNG_DATATYPE
:
3396 case XML_RELAXNG_PARAM
:
3397 case XML_RELAXNG_VALUE
:
3398 case XML_RELAXNG_LIST
:
3399 case XML_RELAXNG_ATTRIBUTE
:
3402 case XML_RELAXNG_CHOICE
:{
3403 xmlRelaxNGDefinePtr list
= define
->content
;
3405 while (list
!= NULL
) {
3406 ret
= xmlRelaxNGIsNullable(list
);
3414 case XML_RELAXNG_START
:
3415 case XML_RELAXNG_INTERLEAVE
:
3416 case XML_RELAXNG_GROUP
:{
3417 xmlRelaxNGDefinePtr list
= define
->content
;
3419 while (list
!= NULL
) {
3420 ret
= xmlRelaxNGIsNullable(list
);
3432 define
->dflags
|= IS_NOT_NULLABLE
;
3434 define
->dflags
|= IS_NULLABLE
;
3439 * xmlRelaxNGIsBlank:
3442 * Check if a string is ignorable c.f. 4.2. Whitespace
3444 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3447 xmlRelaxNGIsBlank(xmlChar
* str
)
3452 if (!(IS_BLANK_CH(*str
)))
3460 * xmlRelaxNGGetDataTypeLibrary:
3461 * @ctxt: a Relax-NG parser context
3462 * @node: the current data or value element
3464 * Applies algorithm from 4.3. datatypeLibrary attribute
3466 * Returns the datatypeLibary value or NULL if not found
3469 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
3472 xmlChar
*ret
, *escape
;
3477 if ((IS_RELAXNG(node
, "data")) || (IS_RELAXNG(node
, "value"))) {
3478 ret
= xmlGetProp(node
, BAD_CAST
"datatypeLibrary");
3484 escape
= xmlURIEscapeStr(ret
, BAD_CAST
":/#?");
3485 if (escape
== NULL
) {
3492 node
= node
->parent
;
3493 while ((node
!= NULL
) && (node
->type
== XML_ELEMENT_NODE
)) {
3494 ret
= xmlGetProp(node
, BAD_CAST
"datatypeLibrary");
3500 escape
= xmlURIEscapeStr(ret
, BAD_CAST
":/#?");
3501 if (escape
== NULL
) {
3507 node
= node
->parent
;
3513 * xmlRelaxNGParseValue:
3514 * @ctxt: a Relax-NG parser context
3515 * @node: the data node.
3517 * parse the content of a RelaxNG value node.
3519 * Returns the definition pointer or NULL in case of error
3521 static xmlRelaxNGDefinePtr
3522 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
3524 xmlRelaxNGDefinePtr def
= NULL
;
3525 xmlRelaxNGTypeLibraryPtr lib
= NULL
;
3530 def
= xmlRelaxNGNewDefine(ctxt
, node
);
3533 def
->type
= XML_RELAXNG_VALUE
;
3535 type
= xmlGetProp(node
, BAD_CAST
"type");
3537 xmlRelaxNGNormExtSpace(type
);
3538 if (xmlValidateNCName(type
, 0)) {
3539 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_VALUE
,
3540 "value type '%s' is not an NCName\n", type
, NULL
);
3542 library
= xmlRelaxNGGetDataTypeLibrary(ctxt
, node
);
3543 if (library
== NULL
)
3545 xmlStrdup(BAD_CAST
"http://relaxng.org/ns/structure/1.0");
3550 lib
= (xmlRelaxNGTypeLibraryPtr
)
3551 xmlHashLookup(xmlRelaxNGRegisteredTypes
, library
);
3553 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_TYPE_LIB
,
3554 "Use of unregistered type library '%s'\n", library
,
3559 if (lib
->have
== NULL
) {
3560 xmlRngPErr(ctxt
, node
, XML_RNGP_ERROR_TYPE_LIB
,
3561 "Internal error with type library '%s': no 'have'\n",
3564 success
= lib
->have(lib
->data
, def
->name
);
3566 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_NOT_FOUND
,
3567 "Error type '%s' is not exported by type library '%s'\n",
3568 def
->name
, library
);
3573 if (node
->children
== NULL
) {
3574 def
->value
= xmlStrdup(BAD_CAST
"");
3575 } else if (((node
->children
->type
!= XML_TEXT_NODE
) &&
3576 (node
->children
->type
!= XML_CDATA_SECTION_NODE
)) ||
3577 (node
->children
->next
!= NULL
)) {
3578 xmlRngPErr(ctxt
, node
, XML_RNGP_TEXT_EXPECTED
,
3579 "Expecting a single text value for <value>content\n",
3581 } else if (def
!= NULL
) {
3582 def
->value
= xmlNodeGetContent(node
);
3583 if (def
->value
== NULL
) {
3584 xmlRngPErr(ctxt
, node
, XML_RNGP_VALUE_NO_CONTENT
,
3585 "Element <value> has no content\n", NULL
, NULL
);
3586 } else if ((lib
!= NULL
) && (lib
->check
!= NULL
) && (success
== 1)) {
3590 lib
->check(lib
->data
, def
->name
, def
->value
, &val
, node
);
3592 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_VALUE
,
3593 "Value '%s' is not acceptable for type '%s'\n",
3594 def
->value
, def
->name
);
3605 * xmlRelaxNGParseData:
3606 * @ctxt: a Relax-NG parser context
3607 * @node: the data node.
3609 * parse the content of a RelaxNG data node.
3611 * Returns the definition pointer or NULL in case of error
3613 static xmlRelaxNGDefinePtr
3614 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
3616 xmlRelaxNGDefinePtr def
= NULL
, except
;
3617 xmlRelaxNGDefinePtr param
, lastparam
= NULL
;
3618 xmlRelaxNGTypeLibraryPtr lib
;
3624 type
= xmlGetProp(node
, BAD_CAST
"type");
3626 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_MISSING
, "data has no type\n", NULL
,
3630 xmlRelaxNGNormExtSpace(type
);
3631 if (xmlValidateNCName(type
, 0)) {
3632 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_VALUE
,
3633 "data type '%s' is not an NCName\n", type
, NULL
);
3635 library
= xmlRelaxNGGetDataTypeLibrary(ctxt
, node
);
3636 if (library
== NULL
)
3638 xmlStrdup(BAD_CAST
"http://relaxng.org/ns/structure/1.0");
3640 def
= xmlRelaxNGNewDefine(ctxt
, node
);
3645 def
->type
= XML_RELAXNG_DATATYPE
;
3649 lib
= (xmlRelaxNGTypeLibraryPtr
)
3650 xmlHashLookup(xmlRelaxNGRegisteredTypes
, library
);
3652 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_TYPE_LIB
,
3653 "Use of unregistered type library '%s'\n", library
,
3658 if (lib
->have
== NULL
) {
3659 xmlRngPErr(ctxt
, node
, XML_RNGP_ERROR_TYPE_LIB
,
3660 "Internal error with type library '%s': no 'have'\n",
3663 tmp
= lib
->have(lib
->data
, def
->name
);
3665 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_NOT_FOUND
,
3666 "Error type '%s' is not exported by type library '%s'\n",
3667 def
->name
, library
);
3672 "http://www.w3.org/2001/XMLSchema-datatypes"))
3673 && ((xmlStrEqual(def
->name
, BAD_CAST
"IDREF"))
3674 || (xmlStrEqual(def
->name
, BAD_CAST
"IDREFS")))) {
3679 content
= node
->children
;
3682 * Handle optional params
3684 while (content
!= NULL
) {
3685 if (!xmlStrEqual(content
->name
, BAD_CAST
"param"))
3687 if (xmlStrEqual(library
,
3688 BAD_CAST
"http://relaxng.org/ns/structure/1.0")) {
3689 xmlRngPErr(ctxt
, node
, XML_RNGP_PARAM_FORBIDDEN
,
3690 "Type library '%s' does not allow type parameters\n",
3692 content
= content
->next
;
3693 while ((content
!= NULL
) &&
3694 (xmlStrEqual(content
->name
, BAD_CAST
"param")))
3695 content
= content
->next
;
3697 param
= xmlRelaxNGNewDefine(ctxt
, node
);
3698 if (param
!= NULL
) {
3699 param
->type
= XML_RELAXNG_PARAM
;
3700 param
->name
= xmlGetProp(content
, BAD_CAST
"name");
3701 if (param
->name
== NULL
) {
3702 xmlRngPErr(ctxt
, node
, XML_RNGP_PARAM_NAME_MISSING
,
3703 "param has no name\n", NULL
, NULL
);
3705 param
->value
= xmlNodeGetContent(content
);
3706 if (lastparam
== NULL
) {
3707 def
->attrs
= lastparam
= param
;
3709 lastparam
->next
= param
;
3715 content
= content
->next
;
3719 * Handle optional except
3721 if ((content
!= NULL
)
3722 && (xmlStrEqual(content
->name
, BAD_CAST
"except"))) {
3724 xmlRelaxNGDefinePtr tmp2
, last
= NULL
;
3726 except
= xmlRelaxNGNewDefine(ctxt
, node
);
3727 if (except
== NULL
) {
3730 except
->type
= XML_RELAXNG_EXCEPT
;
3731 child
= content
->children
;
3732 def
->content
= except
;
3733 if (child
== NULL
) {
3734 xmlRngPErr(ctxt
, content
, XML_RNGP_EXCEPT_NO_CONTENT
,
3735 "except has no content\n", NULL
, NULL
);
3737 while (child
!= NULL
) {
3738 tmp2
= xmlRelaxNGParsePattern(ctxt
, child
);
3741 except
->content
= last
= tmp2
;
3747 child
= child
->next
;
3749 content
= content
->next
;
3752 * Check there is no unhandled data
3754 if (content
!= NULL
) {
3755 xmlRngPErr(ctxt
, content
, XML_RNGP_DATA_CONTENT
,
3756 "Element data has unexpected content %s\n",
3757 content
->name
, NULL
);
3763 static const xmlChar
*invalidName
= BAD_CAST
"\1";
3766 * xmlRelaxNGCompareNameClasses:
3767 * @defs1: the first element/attribute defs
3768 * @defs2: the second element/attribute defs
3769 * @name: the restriction on the name
3770 * @ns: the restriction on the namespace
3772 * Compare the 2 lists of element definitions. The comparison is
3773 * that if both lists do not accept the same QNames, it returns 1
3774 * If the 2 lists can accept the same QName the comparison returns 0
3776 * Returns 1 disttinct, 0 if equal
3779 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1
,
3780 xmlRelaxNGDefinePtr def2
)
3785 xmlRelaxNGValidCtxt ctxt
;
3787 memset(&ctxt
, 0, sizeof(xmlRelaxNGValidCtxt
));
3789 ctxt
.flags
= FLAGS_IGNORABLE
| FLAGS_NOERROR
;
3791 if ((def1
->type
== XML_RELAXNG_ELEMENT
) ||
3792 (def1
->type
== XML_RELAXNG_ATTRIBUTE
)) {
3793 if (def2
->type
== XML_RELAXNG_TEXT
)
3795 if (def1
->name
!= NULL
) {
3796 node
.name
= def1
->name
;
3798 node
.name
= invalidName
;
3800 if (def1
->ns
!= NULL
) {
3801 if (def1
->ns
[0] == 0) {
3810 if (xmlRelaxNGElementMatch(&ctxt
, def2
, &node
)) {
3811 if (def1
->nameClass
!= NULL
) {
3812 ret
= xmlRelaxNGCompareNameClasses(def1
->nameClass
, def2
);
3819 } else if (def1
->type
== XML_RELAXNG_TEXT
) {
3820 if (def2
->type
== XML_RELAXNG_TEXT
)
3823 } else if (def1
->type
== XML_RELAXNG_EXCEPT
) {
3830 if ((def2
->type
== XML_RELAXNG_ELEMENT
) ||
3831 (def2
->type
== XML_RELAXNG_ATTRIBUTE
)) {
3832 if (def2
->name
!= NULL
) {
3833 node
.name
= def2
->name
;
3835 node
.name
= invalidName
;
3838 if (def2
->ns
!= NULL
) {
3839 if (def2
->ns
[0] == 0) {
3845 ns
.href
= invalidName
;
3847 if (xmlRelaxNGElementMatch(&ctxt
, def1
, &node
)) {
3848 if (def2
->nameClass
!= NULL
) {
3849 ret
= xmlRelaxNGCompareNameClasses(def2
->nameClass
, def1
);
3864 * xmlRelaxNGCompareElemDefLists:
3865 * @ctxt: a Relax-NG parser context
3866 * @defs1: the first list of element/attribute defs
3867 * @defs2: the second list of element/attribute defs
3869 * Compare the 2 lists of element or attribute definitions. The comparison
3870 * is that if both lists do not accept the same QNames, it returns 1
3871 * If the 2 lists can accept the same QName the comparison returns 0
3873 * Returns 1 disttinct, 0 if equal
3876 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3877 ATTRIBUTE_UNUSED
, xmlRelaxNGDefinePtr
* def1
,
3878 xmlRelaxNGDefinePtr
* def2
)
3880 xmlRelaxNGDefinePtr
*basedef2
= def2
;
3882 if ((def1
== NULL
) || (def2
== NULL
))
3884 if ((*def1
== NULL
) || (*def2
== NULL
))
3886 while (*def1
!= NULL
) {
3887 while ((*def2
) != NULL
) {
3888 if (xmlRelaxNGCompareNameClasses(*def1
, *def2
) == 0)
3899 * xmlRelaxNGGenerateAttributes:
3900 * @ctxt: a Relax-NG parser context
3901 * @def: the definition definition
3903 * Check if the definition can only generate attributes
3905 * Returns 1 if yes, 0 if no and -1 in case of error.
3908 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt
,
3909 xmlRelaxNGDefinePtr def
)
3911 xmlRelaxNGDefinePtr parent
, cur
, tmp
;
3914 * Don't run that check in case of error. Infinite recursion
3917 if (ctxt
->nbErrors
!= 0)
3922 while (cur
!= NULL
) {
3923 if ((cur
->type
== XML_RELAXNG_ELEMENT
) ||
3924 (cur
->type
== XML_RELAXNG_TEXT
) ||
3925 (cur
->type
== XML_RELAXNG_DATATYPE
) ||
3926 (cur
->type
== XML_RELAXNG_PARAM
) ||
3927 (cur
->type
== XML_RELAXNG_LIST
) ||
3928 (cur
->type
== XML_RELAXNG_VALUE
) ||
3929 (cur
->type
== XML_RELAXNG_EMPTY
))
3931 if ((cur
->type
== XML_RELAXNG_CHOICE
) ||
3932 (cur
->type
== XML_RELAXNG_INTERLEAVE
) ||
3933 (cur
->type
== XML_RELAXNG_GROUP
) ||
3934 (cur
->type
== XML_RELAXNG_ONEORMORE
) ||
3935 (cur
->type
== XML_RELAXNG_ZEROORMORE
) ||
3936 (cur
->type
== XML_RELAXNG_OPTIONAL
) ||
3937 (cur
->type
== XML_RELAXNG_PARENTREF
) ||
3938 (cur
->type
== XML_RELAXNG_EXTERNALREF
) ||
3939 (cur
->type
== XML_RELAXNG_REF
) ||
3940 (cur
->type
== XML_RELAXNG_DEF
)) {
3941 if (cur
->content
!= NULL
) {
3945 while (tmp
!= NULL
) {
3946 tmp
->parent
= parent
;
3954 if (cur
->next
!= NULL
) {
3964 if (cur
->next
!= NULL
) {
3968 } while (cur
!= NULL
);
3974 * xmlRelaxNGGetElements:
3975 * @ctxt: a Relax-NG parser context
3976 * @def: the definition definition
3977 * @eora: gather elements (0) or attributes (1)
3979 * Compute the list of top elements a definition can generate
3981 * Returns a list of elements or NULL if none was found.
3983 static xmlRelaxNGDefinePtr
*
3984 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt
,
3985 xmlRelaxNGDefinePtr def
, int eora
)
3987 xmlRelaxNGDefinePtr
*ret
= NULL
, parent
, cur
, tmp
;
3992 * Don't run that check in case of error. Infinite recursion
3995 if (ctxt
->nbErrors
!= 0)
4000 while (cur
!= NULL
) {
4001 if (((eora
== 0) && ((cur
->type
== XML_RELAXNG_ELEMENT
) ||
4002 (cur
->type
== XML_RELAXNG_TEXT
))) ||
4003 ((eora
== 1) && (cur
->type
== XML_RELAXNG_ATTRIBUTE
))) {
4006 ret
= (xmlRelaxNGDefinePtr
*)
4007 xmlMalloc((max
+ 1) * sizeof(xmlRelaxNGDefinePtr
));
4009 xmlRngPErrMemory(ctxt
, "getting element list\n");
4012 } else if (max
<= len
) {
4013 xmlRelaxNGDefinePtr
*temp
;
4016 temp
= xmlRealloc(ret
,
4017 (max
+ 1) * sizeof(xmlRelaxNGDefinePtr
));
4019 xmlRngPErrMemory(ctxt
, "getting element list\n");
4027 } else if ((cur
->type
== XML_RELAXNG_CHOICE
) ||
4028 (cur
->type
== XML_RELAXNG_INTERLEAVE
) ||
4029 (cur
->type
== XML_RELAXNG_GROUP
) ||
4030 (cur
->type
== XML_RELAXNG_ONEORMORE
) ||
4031 (cur
->type
== XML_RELAXNG_ZEROORMORE
) ||
4032 (cur
->type
== XML_RELAXNG_OPTIONAL
) ||
4033 (cur
->type
== XML_RELAXNG_PARENTREF
) ||
4034 (cur
->type
== XML_RELAXNG_REF
) ||
4035 (cur
->type
== XML_RELAXNG_DEF
) ||
4036 (cur
->type
== XML_RELAXNG_EXTERNALREF
)) {
4038 * Don't go within elements or attributes or string values.
4039 * Just gather the element top list
4041 if (cur
->content
!= NULL
) {
4045 while (tmp
!= NULL
) {
4046 tmp
->parent
= parent
;
4054 if (cur
->next
!= NULL
) {
4064 if (cur
->next
!= NULL
) {
4068 } while (cur
!= NULL
);
4074 * xmlRelaxNGCheckChoiceDeterminism:
4075 * @ctxt: a Relax-NG parser context
4076 * @def: the choice definition
4078 * Also used to find indeterministic pattern in choice
4081 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt
,
4082 xmlRelaxNGDefinePtr def
)
4084 xmlRelaxNGDefinePtr
**list
;
4085 xmlRelaxNGDefinePtr cur
;
4086 int nbchild
= 0, i
, j
, ret
;
4087 int is_nullable
= 0;
4088 int is_indeterminist
= 0;
4089 xmlHashTablePtr triage
= NULL
;
4092 if ((def
== NULL
) || (def
->type
!= XML_RELAXNG_CHOICE
))
4095 if (def
->dflags
& IS_PROCESSED
)
4099 * Don't run that check in case of error. Infinite recursion
4102 if (ctxt
->nbErrors
!= 0)
4105 is_nullable
= xmlRelaxNGIsNullable(def
);
4108 while (cur
!= NULL
) {
4113 list
= (xmlRelaxNGDefinePtr
**) xmlMalloc(nbchild
*
4114 sizeof(xmlRelaxNGDefinePtr
4117 xmlRngPErrMemory(ctxt
, "building choice\n");
4122 * a bit strong but safe
4124 if (is_nullable
== 0) {
4125 triage
= xmlHashCreate(10);
4130 while (cur
!= NULL
) {
4131 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 0);
4132 if ((list
[i
] == NULL
) || (list
[i
][0] == NULL
)) {
4134 } else if (is_triable
== 1) {
4135 xmlRelaxNGDefinePtr
*tmp
;
4139 while ((*tmp
!= NULL
) && (is_triable
== 1)) {
4140 if ((*tmp
)->type
== XML_RELAXNG_TEXT
) {
4141 res
= xmlHashAddEntry2(triage
,
4142 BAD_CAST
"#text", NULL
,
4146 } else if (((*tmp
)->type
== XML_RELAXNG_ELEMENT
) &&
4147 ((*tmp
)->name
!= NULL
)) {
4148 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4149 res
= xmlHashAddEntry2(triage
,
4153 res
= xmlHashAddEntry2(triage
,
4154 (*tmp
)->name
, (*tmp
)->ns
,
4158 } else if ((*tmp
)->type
== XML_RELAXNG_ELEMENT
) {
4159 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4160 res
= xmlHashAddEntry2(triage
,
4161 BAD_CAST
"#any", NULL
,
4164 res
= xmlHashAddEntry2(triage
,
4165 BAD_CAST
"#any", (*tmp
)->ns
,
4179 for (i
= 0; i
< nbchild
; i
++) {
4180 if (list
[i
] == NULL
)
4182 for (j
= 0; j
< i
; j
++) {
4183 if (list
[j
] == NULL
)
4185 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, list
[i
], list
[j
]);
4187 is_indeterminist
= 1;
4191 for (i
= 0; i
< nbchild
; i
++) {
4192 if (list
[i
] != NULL
)
4197 if (is_indeterminist
) {
4198 def
->dflags
|= IS_INDETERMINIST
;
4200 if (is_triable
== 1) {
4201 def
->dflags
|= IS_TRIABLE
;
4203 } else if (triage
!= NULL
) {
4204 xmlHashFree(triage
, NULL
);
4206 def
->dflags
|= IS_PROCESSED
;
4210 * xmlRelaxNGCheckGroupAttrs:
4211 * @ctxt: a Relax-NG parser context
4212 * @def: the group definition
4214 * Detects violations of rule 7.3
4217 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt
,
4218 xmlRelaxNGDefinePtr def
)
4220 xmlRelaxNGDefinePtr
**list
;
4221 xmlRelaxNGDefinePtr cur
;
4222 int nbchild
= 0, i
, j
, ret
;
4224 if ((def
== NULL
) ||
4225 ((def
->type
!= XML_RELAXNG_GROUP
) &&
4226 (def
->type
!= XML_RELAXNG_ELEMENT
)))
4229 if (def
->dflags
& IS_PROCESSED
)
4233 * Don't run that check in case of error. Infinite recursion
4236 if (ctxt
->nbErrors
!= 0)
4240 while (cur
!= NULL
) {
4245 while (cur
!= NULL
) {
4250 list
= (xmlRelaxNGDefinePtr
**) xmlMalloc(nbchild
*
4251 sizeof(xmlRelaxNGDefinePtr
4254 xmlRngPErrMemory(ctxt
, "building group\n");
4259 while (cur
!= NULL
) {
4260 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 1);
4265 while (cur
!= NULL
) {
4266 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 1);
4271 for (i
= 0; i
< nbchild
; i
++) {
4272 if (list
[i
] == NULL
)
4274 for (j
= 0; j
< i
; j
++) {
4275 if (list
[j
] == NULL
)
4277 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, list
[i
], list
[j
]);
4279 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_GROUP_ATTR_CONFLICT
,
4280 "Attributes conflicts in group\n", NULL
, NULL
);
4284 for (i
= 0; i
< nbchild
; i
++) {
4285 if (list
[i
] != NULL
)
4290 def
->dflags
|= IS_PROCESSED
;
4294 * xmlRelaxNGComputeInterleaves:
4295 * @def: the interleave definition
4296 * @ctxt: a Relax-NG parser context
4297 * @name: the definition name
4299 * A lot of work for preprocessing interleave definitions
4300 * is potentially needed to get a decent execution speed at runtime
4301 * - trying to get a total order on the element nodes generated
4302 * by the interleaves, order the list of interleave definitions
4303 * following that order.
4304 * - if <text/> is used to handle mixed content, it is better to
4305 * flag this in the define and simplify the runtime checking
4309 xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def
,
4310 xmlRelaxNGParserCtxtPtr ctxt
,
4311 xmlChar
* name ATTRIBUTE_UNUSED
)
4313 xmlRelaxNGDefinePtr cur
, *tmp
;
4315 xmlRelaxNGPartitionPtr partitions
= NULL
;
4316 xmlRelaxNGInterleaveGroupPtr
*groups
= NULL
;
4317 xmlRelaxNGInterleaveGroupPtr group
;
4322 int is_determinist
= 1;
4325 * Don't run that check in case of error. Infinite recursion
4328 if (ctxt
->nbErrors
!= 0)
4331 #ifdef DEBUG_INTERLEAVE
4332 xmlGenericError(xmlGenericErrorContext
,
4333 "xmlRelaxNGComputeInterleaves(%s)\n", name
);
4336 while (cur
!= NULL
) {
4341 #ifdef DEBUG_INTERLEAVE
4342 xmlGenericError(xmlGenericErrorContext
, " %d child\n", nbchild
);
4344 groups
= (xmlRelaxNGInterleaveGroupPtr
*)
4345 xmlMalloc(nbchild
* sizeof(xmlRelaxNGInterleaveGroupPtr
));
4349 while (cur
!= NULL
) {
4350 groups
[nbgroups
] = (xmlRelaxNGInterleaveGroupPtr
)
4351 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup
));
4352 if (groups
[nbgroups
] == NULL
)
4354 if (cur
->type
== XML_RELAXNG_TEXT
)
4356 groups
[nbgroups
]->rule
= cur
;
4357 groups
[nbgroups
]->defs
= xmlRelaxNGGetElements(ctxt
, cur
, 0);
4358 groups
[nbgroups
]->attrs
= xmlRelaxNGGetElements(ctxt
, cur
, 1);
4362 #ifdef DEBUG_INTERLEAVE
4363 xmlGenericError(xmlGenericErrorContext
, " %d groups\n", nbgroups
);
4367 * Let's check that all rules makes a partitions according to 7.4
4369 partitions
= (xmlRelaxNGPartitionPtr
)
4370 xmlMalloc(sizeof(xmlRelaxNGPartition
));
4371 if (partitions
== NULL
)
4373 memset(partitions
, 0, sizeof(xmlRelaxNGPartition
));
4374 partitions
->nbgroups
= nbgroups
;
4375 partitions
->triage
= xmlHashCreate(nbgroups
);
4376 for (i
= 0; i
< nbgroups
; i
++) {
4378 for (j
= i
+ 1; j
< nbgroups
; j
++) {
4379 if (groups
[j
] == NULL
)
4382 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, group
->defs
,
4385 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_ELEM_TEXT_CONFLICT
,
4386 "Element or text conflicts in interleave\n",
4389 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, group
->attrs
,
4392 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_ATTR_CONFLICT
,
4393 "Attributes conflicts in interleave\n", NULL
,
4398 if ((tmp
!= NULL
) && (*tmp
!= NULL
)) {
4399 while (*tmp
!= NULL
) {
4400 if ((*tmp
)->type
== XML_RELAXNG_TEXT
) {
4401 res
= xmlHashAddEntry2(partitions
->triage
,
4402 BAD_CAST
"#text", NULL
,
4403 (void *) (long) (i
+ 1));
4405 is_determinist
= -1;
4406 } else if (((*tmp
)->type
== XML_RELAXNG_ELEMENT
) &&
4407 ((*tmp
)->name
!= NULL
)) {
4408 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4409 res
= xmlHashAddEntry2(partitions
->triage
,
4411 (void *) (long) (i
+ 1));
4413 res
= xmlHashAddEntry2(partitions
->triage
,
4414 (*tmp
)->name
, (*tmp
)->ns
,
4415 (void *) (long) (i
+ 1));
4417 is_determinist
= -1;
4418 } else if ((*tmp
)->type
== XML_RELAXNG_ELEMENT
) {
4419 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4420 res
= xmlHashAddEntry2(partitions
->triage
,
4421 BAD_CAST
"#any", NULL
,
4422 (void *) (long) (i
+ 1));
4424 res
= xmlHashAddEntry2(partitions
->triage
,
4425 BAD_CAST
"#any", (*tmp
)->ns
,
4426 (void *) (long) (i
+ 1));
4427 if ((*tmp
)->nameClass
!= NULL
)
4430 is_determinist
= -1;
4432 is_determinist
= -1;
4440 partitions
->groups
= groups
;
4443 * and save the partition list back in the def
4445 def
->data
= partitions
;
4447 def
->dflags
|= IS_MIXED
;
4448 if (is_determinist
== 1)
4449 partitions
->flags
= IS_DETERMINIST
;
4450 if (is_determinist
== 2)
4451 partitions
->flags
= IS_DETERMINIST
| IS_NEEDCHECK
;
4455 xmlRngPErrMemory(ctxt
, "in interleave computation\n");
4456 if (groups
!= NULL
) {
4457 for (i
= 0; i
< nbgroups
; i
++)
4458 if (groups
[i
] != NULL
) {
4459 if (groups
[i
]->defs
!= NULL
)
4460 xmlFree(groups
[i
]->defs
);
4465 xmlRelaxNGFreePartition(partitions
);
4469 * xmlRelaxNGParseInterleave:
4470 * @ctxt: a Relax-NG parser context
4471 * @node: the data node.
4473 * parse the content of a RelaxNG interleave node.
4475 * Returns the definition pointer or NULL in case of error
4477 static xmlRelaxNGDefinePtr
4478 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4480 xmlRelaxNGDefinePtr def
= NULL
;
4481 xmlRelaxNGDefinePtr last
= NULL
, cur
;
4484 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4488 def
->type
= XML_RELAXNG_INTERLEAVE
;
4490 if (ctxt
->interleaves
== NULL
)
4491 ctxt
->interleaves
= xmlHashCreate(10);
4492 if (ctxt
->interleaves
== NULL
) {
4493 xmlRngPErrMemory(ctxt
, "create interleaves\n");
4497 snprintf(name
, 32, "interleave%d", ctxt
->nbInterleaves
++);
4498 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST name
, def
) < 0) {
4499 xmlRngPErr(ctxt
, node
, XML_RNGP_INTERLEAVE_ADD
,
4500 "Failed to add %s to hash table\n",
4501 (const xmlChar
*) name
, NULL
);
4504 child
= node
->children
;
4505 if (child
== NULL
) {
4506 xmlRngPErr(ctxt
, node
, XML_RNGP_INTERLEAVE_NO_CONTENT
,
4507 "Element interleave is empty\n", NULL
, NULL
);
4509 while (child
!= NULL
) {
4510 if (IS_RELAXNG(child
, "element")) {
4511 cur
= xmlRelaxNGParseElement(ctxt
, child
);
4513 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
4518 def
->content
= last
= cur
;
4524 child
= child
->next
;
4531 * xmlRelaxNGParseInclude:
4532 * @ctxt: a Relax-NG parser context
4533 * @node: the include node
4535 * Integrate the content of an include node in the current grammar
4537 * Returns 0 in case of success or -1 in case of error
4540 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4542 xmlRelaxNGIncludePtr incl
;
4548 xmlRngPErr(ctxt
, node
, XML_RNGP_INCLUDE_EMPTY
,
4549 "Include node has no data\n", NULL
, NULL
);
4552 root
= xmlDocGetRootElement(incl
->doc
);
4554 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY
, "Include document is empty\n",
4558 if (!xmlStrEqual(root
->name
, BAD_CAST
"grammar")) {
4559 xmlRngPErr(ctxt
, node
, XML_RNGP_GRAMMAR_MISSING
,
4560 "Include document root is not a grammar\n", NULL
, NULL
);
4565 * Merge the definition from both the include and the internal list
4567 if (root
->children
!= NULL
) {
4568 tmp
= xmlRelaxNGParseGrammarContent(ctxt
, root
->children
);
4572 if (node
->children
!= NULL
) {
4573 tmp
= xmlRelaxNGParseGrammarContent(ctxt
, node
->children
);
4581 * xmlRelaxNGParseDefine:
4582 * @ctxt: a Relax-NG parser context
4583 * @node: the define node
4585 * parse the content of a RelaxNG define element node.
4587 * Returns 0 in case of success or -1 in case of error
4590 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4594 xmlRelaxNGDefinePtr def
;
4595 const xmlChar
*olddefine
;
4597 name
= xmlGetProp(node
, BAD_CAST
"name");
4599 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_NAME_MISSING
,
4600 "define has no name\n", NULL
, NULL
);
4602 xmlRelaxNGNormExtSpace(name
);
4603 if (xmlValidateNCName(name
, 0)) {
4604 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_DEFINE_NAME
,
4605 "define name '%s' is not an NCName\n", name
, NULL
);
4607 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4612 def
->type
= XML_RELAXNG_DEF
;
4614 if (node
->children
== NULL
) {
4615 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_EMPTY
,
4616 "define has no children\n", NULL
, NULL
);
4618 olddefine
= ctxt
->define
;
4619 ctxt
->define
= name
;
4621 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4622 ctxt
->define
= olddefine
;
4624 if (ctxt
->grammar
->defs
== NULL
)
4625 ctxt
->grammar
->defs
= xmlHashCreate(10);
4626 if (ctxt
->grammar
->defs
== NULL
) {
4627 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_CREATE_FAILED
,
4628 "Could not create definition hash\n", NULL
, NULL
);
4631 tmp
= xmlHashAddEntry(ctxt
->grammar
->defs
, name
, def
);
4633 xmlRelaxNGDefinePtr prev
;
4635 prev
= xmlHashLookup(ctxt
->grammar
->defs
, name
);
4637 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_CREATE_FAILED
,
4638 "Internal error on define aggregation of %s\n",
4642 while (prev
->nextHash
!= NULL
)
4643 prev
= prev
->nextHash
;
4644 prev
->nextHash
= def
;
4653 * xmlRelaxNGParseImportRef:
4654 * @payload: the parser context
4655 * @data: the current grammar
4656 * @name: the reference name
4658 * Import import one references into the current grammar
4661 xmlRelaxNGParseImportRef(void *payload
, void *data
, xmlChar
*name
) {
4662 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
4663 xmlRelaxNGDefinePtr def
= (xmlRelaxNGDefinePtr
) payload
;
4666 def
->dflags
|= IS_EXTERNAL_REF
;
4668 tmp
= xmlHashAddEntry(ctxt
->grammar
->refs
, name
, def
);
4670 xmlRelaxNGDefinePtr prev
;
4672 prev
= (xmlRelaxNGDefinePtr
)
4673 xmlHashLookup(ctxt
->grammar
->refs
, def
->name
);
4675 if (def
->name
!= NULL
) {
4676 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4677 "Error refs definitions '%s'\n",
4680 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4681 "Error refs definitions\n",
4685 def
->nextHash
= prev
->nextHash
;
4686 prev
->nextHash
= def
;
4692 * xmlRelaxNGParseImportRefs:
4693 * @ctxt: the parser context
4694 * @grammar: the sub grammar
4696 * Import references from the subgrammar into the current grammar
4698 * Returns 0 in case of success, -1 in case of failure
4701 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt
,
4702 xmlRelaxNGGrammarPtr grammar
) {
4703 if ((ctxt
== NULL
) || (grammar
== NULL
) || (ctxt
->grammar
== NULL
))
4705 if (grammar
->refs
== NULL
)
4707 if (ctxt
->grammar
->refs
== NULL
)
4708 ctxt
->grammar
->refs
= xmlHashCreate(10);
4709 if (ctxt
->grammar
->refs
== NULL
) {
4710 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4711 "Could not create references hash\n", NULL
, NULL
);
4714 xmlHashScan(grammar
->refs
, xmlRelaxNGParseImportRef
, ctxt
);
4719 * xmlRelaxNGProcessExternalRef:
4720 * @ctxt: the parser context
4721 * @node: the externlRef node
4723 * Process and compile an externlRef node
4725 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4727 static xmlRelaxNGDefinePtr
4728 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4730 xmlRelaxNGDocumentPtr docu
;
4731 xmlNodePtr root
, tmp
;
4733 int newNs
= 0, oldflags
;
4734 xmlRelaxNGDefinePtr def
;
4738 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4741 def
->type
= XML_RELAXNG_EXTERNALREF
;
4743 if (docu
->content
== NULL
) {
4745 * Then do the parsing for good
4747 root
= xmlDocGetRootElement(docu
->doc
);
4749 xmlRngPErr(ctxt
, node
, XML_RNGP_EXTERNALREF_EMTPY
,
4750 "xmlRelaxNGParse: %s is empty\n", ctxt
->URL
,
4755 * ns transmission rules
4757 ns
= xmlGetProp(root
, BAD_CAST
"ns");
4760 while ((tmp
!= NULL
) && (tmp
->type
== XML_ELEMENT_NODE
)) {
4761 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
4768 xmlSetProp(root
, BAD_CAST
"ns", ns
);
4777 * Parsing to get a precompiled schemas.
4779 oldflags
= ctxt
->flags
;
4780 ctxt
->flags
|= XML_RELAXNG_IN_EXTERNALREF
;
4781 docu
->schema
= xmlRelaxNGParseDocument(ctxt
, root
);
4782 ctxt
->flags
= oldflags
;
4783 if ((docu
->schema
!= NULL
) &&
4784 (docu
->schema
->topgrammar
!= NULL
)) {
4785 docu
->content
= docu
->schema
->topgrammar
->start
;
4786 if (docu
->schema
->topgrammar
->refs
)
4787 xmlRelaxNGParseImportRefs(ctxt
, docu
->schema
->topgrammar
);
4791 * the externalRef may be reused in a different ns context
4794 xmlUnsetProp(root
, BAD_CAST
"ns");
4797 def
->content
= docu
->content
;
4805 * xmlRelaxNGParsePattern:
4806 * @ctxt: a Relax-NG parser context
4807 * @node: the pattern node.
4809 * parse the content of a RelaxNG pattern node.
4811 * Returns the definition pointer or NULL in case of error or if no
4812 * pattern is generated.
4814 static xmlRelaxNGDefinePtr
4815 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4817 xmlRelaxNGDefinePtr def
= NULL
;
4822 if (IS_RELAXNG(node
, "element")) {
4823 def
= xmlRelaxNGParseElement(ctxt
, node
);
4824 } else if (IS_RELAXNG(node
, "attribute")) {
4825 def
= xmlRelaxNGParseAttribute(ctxt
, node
);
4826 } else if (IS_RELAXNG(node
, "empty")) {
4827 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4830 def
->type
= XML_RELAXNG_EMPTY
;
4831 if (node
->children
!= NULL
) {
4832 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_NOT_EMPTY
,
4833 "empty: had a child node\n", NULL
, NULL
);
4835 } else if (IS_RELAXNG(node
, "text")) {
4836 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4839 def
->type
= XML_RELAXNG_TEXT
;
4840 if (node
->children
!= NULL
) {
4841 xmlRngPErr(ctxt
, node
, XML_RNGP_TEXT_HAS_CHILD
,
4842 "text: had a child node\n", NULL
, NULL
);
4844 } else if (IS_RELAXNG(node
, "zeroOrMore")) {
4845 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4848 def
->type
= XML_RELAXNG_ZEROORMORE
;
4849 if (node
->children
== NULL
) {
4850 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4851 "Element %s is empty\n", node
->name
, NULL
);
4854 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4856 } else if (IS_RELAXNG(node
, "oneOrMore")) {
4857 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4860 def
->type
= XML_RELAXNG_ONEORMORE
;
4861 if (node
->children
== NULL
) {
4862 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4863 "Element %s is empty\n", node
->name
, NULL
);
4866 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4868 } else if (IS_RELAXNG(node
, "optional")) {
4869 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4872 def
->type
= XML_RELAXNG_OPTIONAL
;
4873 if (node
->children
== NULL
) {
4874 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4875 "Element %s is empty\n", node
->name
, NULL
);
4878 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4880 } else if (IS_RELAXNG(node
, "choice")) {
4881 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4884 def
->type
= XML_RELAXNG_CHOICE
;
4885 if (node
->children
== NULL
) {
4886 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4887 "Element %s is empty\n", node
->name
, NULL
);
4890 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4892 } else if (IS_RELAXNG(node
, "group")) {
4893 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4896 def
->type
= XML_RELAXNG_GROUP
;
4897 if (node
->children
== NULL
) {
4898 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4899 "Element %s is empty\n", node
->name
, NULL
);
4902 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4904 } else if (IS_RELAXNG(node
, "ref")) {
4905 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4908 def
->type
= XML_RELAXNG_REF
;
4909 def
->name
= xmlGetProp(node
, BAD_CAST
"name");
4910 if (def
->name
== NULL
) {
4911 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NO_NAME
, "ref has no name\n",
4914 xmlRelaxNGNormExtSpace(def
->name
);
4915 if (xmlValidateNCName(def
->name
, 0)) {
4916 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NAME_INVALID
,
4917 "ref name '%s' is not an NCName\n", def
->name
,
4921 if (node
->children
!= NULL
) {
4922 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NOT_EMPTY
, "ref is not empty\n",
4925 if (ctxt
->grammar
->refs
== NULL
)
4926 ctxt
->grammar
->refs
= xmlHashCreate(10);
4927 if (ctxt
->grammar
->refs
== NULL
) {
4928 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4929 "Could not create references hash\n", NULL
, NULL
);
4934 tmp
= xmlHashAddEntry(ctxt
->grammar
->refs
, def
->name
, def
);
4936 xmlRelaxNGDefinePtr prev
;
4938 prev
= (xmlRelaxNGDefinePtr
)
4939 xmlHashLookup(ctxt
->grammar
->refs
, def
->name
);
4941 if (def
->name
!= NULL
) {
4942 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4943 "Error refs definitions '%s'\n",
4946 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4947 "Error refs definitions\n",
4952 def
->nextHash
= prev
->nextHash
;
4953 prev
->nextHash
= def
;
4957 } else if (IS_RELAXNG(node
, "data")) {
4958 def
= xmlRelaxNGParseData(ctxt
, node
);
4959 } else if (IS_RELAXNG(node
, "value")) {
4960 def
= xmlRelaxNGParseValue(ctxt
, node
);
4961 } else if (IS_RELAXNG(node
, "list")) {
4962 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4965 def
->type
= XML_RELAXNG_LIST
;
4966 if (node
->children
== NULL
) {
4967 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4968 "Element %s is empty\n", node
->name
, NULL
);
4971 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4973 } else if (IS_RELAXNG(node
, "interleave")) {
4974 def
= xmlRelaxNGParseInterleave(ctxt
, node
);
4975 } else if (IS_RELAXNG(node
, "externalRef")) {
4976 def
= xmlRelaxNGProcessExternalRef(ctxt
, node
);
4977 } else if (IS_RELAXNG(node
, "notAllowed")) {
4978 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4981 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
4982 if (node
->children
!= NULL
) {
4983 xmlRngPErr(ctxt
, node
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
4984 "xmlRelaxNGParse: notAllowed element is not empty\n",
4987 } else if (IS_RELAXNG(node
, "grammar")) {
4988 xmlRelaxNGGrammarPtr grammar
, old
;
4989 xmlRelaxNGGrammarPtr oldparent
;
4991 #ifdef DEBUG_GRAMMAR
4992 xmlGenericError(xmlGenericErrorContext
,
4993 "Found <grammar> pattern\n");
4996 oldparent
= ctxt
->parentgrammar
;
4997 old
= ctxt
->grammar
;
4998 ctxt
->parentgrammar
= old
;
4999 grammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
5001 ctxt
->grammar
= old
;
5002 ctxt
->parentgrammar
= oldparent
;
5004 if (grammar
!= NULL
) {
5005 grammar
->next
= old
->next
;
5006 old
->next
= grammar
;
5010 if (grammar
!= NULL
)
5011 def
= grammar
->start
;
5014 } else if (IS_RELAXNG(node
, "parentRef")) {
5015 if (ctxt
->parentgrammar
== NULL
) {
5016 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NO_PARENT
,
5017 "Use of parentRef without a parent grammar\n", NULL
,
5021 def
= xmlRelaxNGNewDefine(ctxt
, node
);
5024 def
->type
= XML_RELAXNG_PARENTREF
;
5025 def
->name
= xmlGetProp(node
, BAD_CAST
"name");
5026 if (def
->name
== NULL
) {
5027 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NO_NAME
,
5028 "parentRef has no name\n", NULL
, NULL
);
5030 xmlRelaxNGNormExtSpace(def
->name
);
5031 if (xmlValidateNCName(def
->name
, 0)) {
5032 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NAME_INVALID
,
5033 "parentRef name '%s' is not an NCName\n",
5037 if (node
->children
!= NULL
) {
5038 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NOT_EMPTY
,
5039 "parentRef is not empty\n", NULL
, NULL
);
5041 if (ctxt
->parentgrammar
->refs
== NULL
)
5042 ctxt
->parentgrammar
->refs
= xmlHashCreate(10);
5043 if (ctxt
->parentgrammar
->refs
== NULL
) {
5044 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_CREATE_FAILED
,
5045 "Could not create references hash\n", NULL
, NULL
);
5047 } else if (def
->name
!= NULL
) {
5051 xmlHashAddEntry(ctxt
->parentgrammar
->refs
, def
->name
, def
);
5053 xmlRelaxNGDefinePtr prev
;
5055 prev
= (xmlRelaxNGDefinePtr
)
5056 xmlHashLookup(ctxt
->parentgrammar
->refs
, def
->name
);
5058 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_CREATE_FAILED
,
5059 "Internal error parentRef definitions '%s'\n",
5063 def
->nextHash
= prev
->nextHash
;
5064 prev
->nextHash
= def
;
5068 } else if (IS_RELAXNG(node
, "mixed")) {
5069 if (node
->children
== NULL
) {
5070 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
, "Mixed is empty\n",
5074 def
= xmlRelaxNGParseInterleave(ctxt
, node
);
5076 xmlRelaxNGDefinePtr tmp
;
5078 if ((def
->content
!= NULL
) && (def
->content
->next
!= NULL
)) {
5079 tmp
= xmlRelaxNGNewDefine(ctxt
, node
);
5081 tmp
->type
= XML_RELAXNG_GROUP
;
5082 tmp
->content
= def
->content
;
5087 tmp
= xmlRelaxNGNewDefine(ctxt
, node
);
5090 tmp
->type
= XML_RELAXNG_TEXT
;
5091 tmp
->next
= def
->content
;
5096 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_CONSTRUCT
,
5097 "Unexpected node %s is not a pattern\n", node
->name
,
5105 * xmlRelaxNGParseAttribute:
5106 * @ctxt: a Relax-NG parser context
5107 * @node: the element node
5109 * parse the content of a RelaxNG attribute node.
5111 * Returns the definition pointer or NULL in case of error.
5113 static xmlRelaxNGDefinePtr
5114 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5116 xmlRelaxNGDefinePtr ret
, cur
;
5120 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5123 ret
->type
= XML_RELAXNG_ATTRIBUTE
;
5124 ret
->parent
= ctxt
->def
;
5125 child
= node
->children
;
5126 if (child
== NULL
) {
5127 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_EMPTY
,
5128 "xmlRelaxNGParseattribute: attribute has no children\n",
5132 old_flags
= ctxt
->flags
;
5133 ctxt
->flags
|= XML_RELAXNG_IN_ATTRIBUTE
;
5134 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5136 child
= child
->next
;
5138 if (child
!= NULL
) {
5139 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5141 switch (cur
->type
) {
5142 case XML_RELAXNG_EMPTY
:
5143 case XML_RELAXNG_NOT_ALLOWED
:
5144 case XML_RELAXNG_TEXT
:
5145 case XML_RELAXNG_ELEMENT
:
5146 case XML_RELAXNG_DATATYPE
:
5147 case XML_RELAXNG_VALUE
:
5148 case XML_RELAXNG_LIST
:
5149 case XML_RELAXNG_REF
:
5150 case XML_RELAXNG_PARENTREF
:
5151 case XML_RELAXNG_EXTERNALREF
:
5152 case XML_RELAXNG_DEF
:
5153 case XML_RELAXNG_ONEORMORE
:
5154 case XML_RELAXNG_ZEROORMORE
:
5155 case XML_RELAXNG_OPTIONAL
:
5156 case XML_RELAXNG_CHOICE
:
5157 case XML_RELAXNG_GROUP
:
5158 case XML_RELAXNG_INTERLEAVE
:
5159 case XML_RELAXNG_ATTRIBUTE
:
5163 case XML_RELAXNG_START
:
5164 case XML_RELAXNG_PARAM
:
5165 case XML_RELAXNG_EXCEPT
:
5166 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_CONTENT
,
5167 "attribute has invalid content\n", NULL
,
5170 case XML_RELAXNG_NOOP
:
5171 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_NOOP
,
5172 "RNG Internal error, noop found in attribute\n",
5177 child
= child
->next
;
5179 if (child
!= NULL
) {
5180 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_CHILDREN
,
5181 "attribute has multiple children\n", NULL
, NULL
);
5183 ctxt
->flags
= old_flags
;
5188 * xmlRelaxNGParseExceptNameClass:
5189 * @ctxt: a Relax-NG parser context
5190 * @node: the except node
5191 * @attr: 1 if within an attribute, 0 if within an element
5193 * parse the content of a RelaxNG nameClass node.
5195 * Returns the definition pointer or NULL in case of error.
5197 static xmlRelaxNGDefinePtr
5198 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt
,
5199 xmlNodePtr node
, int attr
)
5201 xmlRelaxNGDefinePtr ret
, cur
, last
= NULL
;
5204 if (!IS_RELAXNG(node
, "except")) {
5205 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_MISSING
,
5206 "Expecting an except node\n", NULL
, NULL
);
5209 if (node
->next
!= NULL
) {
5210 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_MULTIPLE
,
5211 "exceptNameClass allows only a single except node\n",
5214 if (node
->children
== NULL
) {
5215 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_EMPTY
, "except has no content\n",
5220 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5223 ret
->type
= XML_RELAXNG_EXCEPT
;
5224 child
= node
->children
;
5225 while (child
!= NULL
) {
5226 cur
= xmlRelaxNGNewDefine(ctxt
, child
);
5230 cur
->type
= XML_RELAXNG_ATTRIBUTE
;
5232 cur
->type
= XML_RELAXNG_ELEMENT
;
5234 if (xmlRelaxNGParseNameClass(ctxt
, child
, cur
) != NULL
) {
5242 child
= child
->next
;
5249 * xmlRelaxNGParseNameClass:
5250 * @ctxt: a Relax-NG parser context
5251 * @node: the nameClass node
5252 * @def: the current definition
5254 * parse the content of a RelaxNG nameClass node.
5256 * Returns the definition pointer or NULL in case of error.
5258 static xmlRelaxNGDefinePtr
5259 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
,
5260 xmlRelaxNGDefinePtr def
)
5262 xmlRelaxNGDefinePtr ret
, tmp
;
5266 if ((IS_RELAXNG(node
, "name")) || (IS_RELAXNG(node
, "anyName")) ||
5267 (IS_RELAXNG(node
, "nsName"))) {
5268 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
5269 (def
->type
!= XML_RELAXNG_ATTRIBUTE
)) {
5270 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5274 if (ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
)
5275 ret
->type
= XML_RELAXNG_ATTRIBUTE
;
5277 ret
->type
= XML_RELAXNG_ELEMENT
;
5280 if (IS_RELAXNG(node
, "name")) {
5281 val
= xmlNodeGetContent(node
);
5282 xmlRelaxNGNormExtSpace(val
);
5283 if (xmlValidateNCName(val
, 0)) {
5284 if (node
->parent
!= NULL
)
5285 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NAME
,
5286 "Element %s name '%s' is not an NCName\n",
5287 node
->parent
->name
, val
);
5289 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NAME
,
5290 "name '%s' is not an NCName\n",
5294 val
= xmlGetProp(node
, BAD_CAST
"ns");
5296 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5298 (xmlStrEqual(val
, BAD_CAST
"http://www.w3.org/2000/xmlns"))) {
5299 xmlRngPErr(ctxt
, node
, XML_RNGP_XML_NS
,
5300 "Attribute with namespace '%s' is not allowed\n",
5303 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5305 (val
[0] == 0) && (xmlStrEqual(ret
->name
, BAD_CAST
"xmlns"))) {
5306 xmlRngPErr(ctxt
, node
, XML_RNGP_XMLNS_NAME
,
5307 "Attribute with QName 'xmlns' is not allowed\n",
5310 } else if (IS_RELAXNG(node
, "anyName")) {
5313 if (node
->children
!= NULL
) {
5315 xmlRelaxNGParseExceptNameClass(ctxt
, node
->children
,
5317 XML_RELAXNG_ATTRIBUTE
));
5319 } else if (IS_RELAXNG(node
, "nsName")) {
5321 ret
->ns
= xmlGetProp(node
, BAD_CAST
"ns");
5322 if (ret
->ns
== NULL
) {
5323 xmlRngPErr(ctxt
, node
, XML_RNGP_NSNAME_NO_NS
,
5324 "nsName has no ns attribute\n", NULL
, NULL
);
5326 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5327 (ret
->ns
!= NULL
) &&
5329 (ret
->ns
, 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 (node
->children
!= NULL
) {
5336 xmlRelaxNGParseExceptNameClass(ctxt
, node
->children
,
5338 XML_RELAXNG_ATTRIBUTE
));
5340 } else if (IS_RELAXNG(node
, "choice")) {
5342 xmlRelaxNGDefinePtr last
= NULL
;
5344 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5348 ret
->type
= XML_RELAXNG_CHOICE
;
5350 if (node
->children
== NULL
) {
5351 xmlRngPErr(ctxt
, node
, XML_RNGP_CHOICE_EMPTY
,
5352 "Element choice is empty\n", NULL
, NULL
);
5355 child
= node
->children
;
5356 while (child
!= NULL
) {
5357 tmp
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5360 last
= ret
->nameClass
= tmp
;
5366 child
= child
->next
;
5370 xmlRngPErr(ctxt
, node
, XML_RNGP_CHOICE_CONTENT
,
5371 "expecting name, anyName, nsName or choice : got %s\n",
5372 (node
== NULL
? "nothing" : node
->name
), NULL
);
5376 if (def
->nameClass
== NULL
) {
5377 def
->nameClass
= ret
;
5379 tmp
= def
->nameClass
;
5380 while (tmp
->next
!= NULL
) {
5390 * xmlRelaxNGParseElement:
5391 * @ctxt: a Relax-NG parser context
5392 * @node: the element node
5394 * parse the content of a RelaxNG element node.
5396 * Returns the definition pointer or NULL in case of error.
5398 static xmlRelaxNGDefinePtr
5399 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5401 xmlRelaxNGDefinePtr ret
, cur
, last
;
5403 const xmlChar
*olddefine
;
5405 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5408 ret
->type
= XML_RELAXNG_ELEMENT
;
5409 ret
->parent
= ctxt
->def
;
5410 child
= node
->children
;
5411 if (child
== NULL
) {
5412 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_EMPTY
,
5413 "xmlRelaxNGParseElement: element has no children\n",
5417 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5419 child
= child
->next
;
5421 if (child
== NULL
) {
5422 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NO_CONTENT
,
5423 "xmlRelaxNGParseElement: element has no content\n",
5427 olddefine
= ctxt
->define
;
5428 ctxt
->define
= NULL
;
5430 while (child
!= NULL
) {
5431 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5434 switch (cur
->type
) {
5435 case XML_RELAXNG_EMPTY
:
5436 case XML_RELAXNG_NOT_ALLOWED
:
5437 case XML_RELAXNG_TEXT
:
5438 case XML_RELAXNG_ELEMENT
:
5439 case XML_RELAXNG_DATATYPE
:
5440 case XML_RELAXNG_VALUE
:
5441 case XML_RELAXNG_LIST
:
5442 case XML_RELAXNG_REF
:
5443 case XML_RELAXNG_PARENTREF
:
5444 case XML_RELAXNG_EXTERNALREF
:
5445 case XML_RELAXNG_DEF
:
5446 case XML_RELAXNG_ZEROORMORE
:
5447 case XML_RELAXNG_ONEORMORE
:
5448 case XML_RELAXNG_OPTIONAL
:
5449 case XML_RELAXNG_CHOICE
:
5450 case XML_RELAXNG_GROUP
:
5451 case XML_RELAXNG_INTERLEAVE
:
5453 ret
->content
= last
= cur
;
5455 if ((last
->type
== XML_RELAXNG_ELEMENT
) &&
5456 (ret
->content
== last
)) {
5457 ret
->content
= xmlRelaxNGNewDefine(ctxt
, node
);
5458 if (ret
->content
!= NULL
) {
5459 ret
->content
->type
= XML_RELAXNG_GROUP
;
5460 ret
->content
->content
= last
;
5462 ret
->content
= last
;
5469 case XML_RELAXNG_ATTRIBUTE
:
5470 cur
->next
= ret
->attrs
;
5473 case XML_RELAXNG_START
:
5474 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5475 "RNG Internal error, start found in element\n",
5478 case XML_RELAXNG_PARAM
:
5479 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5480 "RNG Internal error, param found in element\n",
5483 case XML_RELAXNG_EXCEPT
:
5484 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5485 "RNG Internal error, except found in element\n",
5488 case XML_RELAXNG_NOOP
:
5489 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5490 "RNG Internal error, noop found in element\n",
5495 child
= child
->next
;
5497 ctxt
->define
= olddefine
;
5502 * xmlRelaxNGParsePatterns:
5503 * @ctxt: a Relax-NG parser context
5504 * @nodes: list of nodes
5505 * @group: use an implicit <group> for elements
5507 * parse the content of a RelaxNG start node.
5509 * Returns the definition pointer or NULL in case of error.
5511 static xmlRelaxNGDefinePtr
5512 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
,
5515 xmlRelaxNGDefinePtr def
= NULL
, last
= NULL
, cur
, parent
;
5518 while (nodes
!= NULL
) {
5519 if (IS_RELAXNG(nodes
, "element")) {
5520 cur
= xmlRelaxNGParseElement(ctxt
, nodes
);
5524 if ((group
== 1) && (def
->type
== XML_RELAXNG_ELEMENT
) &&
5526 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5527 def
->type
= XML_RELAXNG_GROUP
;
5528 def
->content
= last
;
5533 cur
->parent
= parent
;
5535 cur
= xmlRelaxNGParsePattern(ctxt
, nodes
);
5545 nodes
= nodes
->next
;
5551 * xmlRelaxNGParseStart:
5552 * @ctxt: a Relax-NG parser context
5553 * @nodes: start children nodes
5555 * parse the content of a RelaxNG start node.
5557 * Returns 0 in case of success, -1 in case of error
5560 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
5563 xmlRelaxNGDefinePtr def
= NULL
, last
;
5565 if (nodes
== NULL
) {
5566 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
, "start has no children\n",
5570 if (IS_RELAXNG(nodes
, "empty")) {
5571 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5574 def
->type
= XML_RELAXNG_EMPTY
;
5575 if (nodes
->children
!= NULL
) {
5576 xmlRngPErr(ctxt
, nodes
, XML_RNGP_EMPTY_CONTENT
,
5577 "element empty is not empty\n", NULL
, NULL
);
5579 } else if (IS_RELAXNG(nodes
, "notAllowed")) {
5580 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5583 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
5584 if (nodes
->children
!= NULL
) {
5585 xmlRngPErr(ctxt
, nodes
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
5586 "element notAllowed is not empty\n", NULL
, NULL
);
5589 def
= xmlRelaxNGParsePatterns(ctxt
, nodes
, 1);
5591 if (ctxt
->grammar
->start
!= NULL
) {
5592 last
= ctxt
->grammar
->start
;
5593 while (last
->next
!= NULL
)
5597 ctxt
->grammar
->start
= def
;
5599 nodes
= nodes
->next
;
5600 if (nodes
!= NULL
) {
5601 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_CONTENT
,
5602 "start more than one children\n", NULL
, NULL
);
5609 * xmlRelaxNGParseGrammarContent:
5610 * @ctxt: a Relax-NG parser context
5611 * @nodes: grammar children nodes
5613 * parse the content of a RelaxNG grammar node.
5615 * Returns 0 in case of success, -1 in case of error
5618 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
5623 if (nodes
== NULL
) {
5624 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_EMPTY
,
5625 "grammar has no children\n", NULL
, NULL
);
5628 while (nodes
!= NULL
) {
5629 if (IS_RELAXNG(nodes
, "start")) {
5630 if (nodes
->children
== NULL
) {
5631 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
,
5632 "start has no children\n", NULL
, NULL
);
5634 tmp
= xmlRelaxNGParseStart(ctxt
, nodes
->children
);
5638 } else if (IS_RELAXNG(nodes
, "define")) {
5639 tmp
= xmlRelaxNGParseDefine(ctxt
, nodes
);
5642 } else if (IS_RELAXNG(nodes
, "include")) {
5643 tmp
= xmlRelaxNGParseInclude(ctxt
, nodes
);
5647 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
5648 "grammar has unexpected child %s\n", nodes
->name
,
5652 nodes
= nodes
->next
;
5658 * xmlRelaxNGCheckReference:
5660 * @ctxt: a Relax-NG parser context
5661 * @name: the name associated to the defines
5663 * Applies the 4.17. combine attribute rule for all the define
5664 * element of a given grammar using the same name.
5667 xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref
,
5668 xmlRelaxNGParserCtxtPtr ctxt
,
5669 const xmlChar
* name
)
5671 xmlRelaxNGGrammarPtr grammar
;
5672 xmlRelaxNGDefinePtr def
, cur
;
5675 * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5677 if (ref
->dflags
& IS_EXTERNAL_REF
)
5680 grammar
= ctxt
->grammar
;
5681 if (grammar
== NULL
) {
5682 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5683 "Internal error: no grammar in CheckReference %s\n",
5687 if (ref
->content
!= NULL
) {
5688 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5689 "Internal error: reference has content in CheckReference %s\n",
5693 if (grammar
->defs
!= NULL
) {
5694 def
= xmlHashLookup(grammar
->defs
, name
);
5697 while (cur
!= NULL
) {
5699 cur
= cur
->nextHash
;
5702 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5703 "Reference %s has no matching definition\n", name
,
5707 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5708 "Reference %s has no matching definition\n", name
,
5714 * xmlRelaxNGCheckCombine:
5715 * @define: the define(s) list
5716 * @ctxt: a Relax-NG parser context
5717 * @name: the name associated to the defines
5719 * Applies the 4.17. combine attribute rule for all the define
5720 * element of a given grammar using the same name.
5723 xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define
,
5724 xmlRelaxNGParserCtxtPtr ctxt
, const xmlChar
* name
)
5727 int choiceOrInterleave
= -1;
5729 xmlRelaxNGDefinePtr cur
, last
, tmp
, tmp2
;
5731 if (define
->nextHash
== NULL
)
5734 while (cur
!= NULL
) {
5735 combine
= xmlGetProp(cur
->node
, BAD_CAST
"combine");
5736 if (combine
!= NULL
) {
5737 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5738 if (choiceOrInterleave
== -1)
5739 choiceOrInterleave
= 1;
5740 else if (choiceOrInterleave
== 0) {
5741 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5742 "Defines for %s use both 'choice' and 'interleave'\n",
5745 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5746 if (choiceOrInterleave
== -1)
5747 choiceOrInterleave
= 0;
5748 else if (choiceOrInterleave
== 1) {
5749 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5750 "Defines for %s use both 'choice' and 'interleave'\n",
5754 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5755 "Defines for %s use unknown combine value '%s''\n",
5763 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_NEED_COMBINE
,
5764 "Some defines for %s needs the combine attribute\n",
5769 cur
= cur
->nextHash
;
5772 xmlGenericError(xmlGenericErrorContext
,
5773 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5774 name
, choiceOrInterleave
);
5776 if (choiceOrInterleave
== -1)
5777 choiceOrInterleave
= 0;
5778 cur
= xmlRelaxNGNewDefine(ctxt
, define
->node
);
5781 if (choiceOrInterleave
== 0)
5782 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5784 cur
->type
= XML_RELAXNG_CHOICE
;
5787 while (tmp
!= NULL
) {
5788 if (tmp
->content
!= NULL
) {
5789 if (tmp
->content
->next
!= NULL
) {
5791 * we need first to create a wrapper.
5793 tmp2
= xmlRelaxNGNewDefine(ctxt
, tmp
->content
->node
);
5796 tmp2
->type
= XML_RELAXNG_GROUP
;
5797 tmp2
->content
= tmp
->content
;
5799 tmp2
= tmp
->content
;
5802 cur
->content
= tmp2
;
5809 tmp
= tmp
->nextHash
;
5811 define
->content
= cur
;
5812 if (choiceOrInterleave
== 0) {
5813 if (ctxt
->interleaves
== NULL
)
5814 ctxt
->interleaves
= xmlHashCreate(10);
5815 if (ctxt
->interleaves
== NULL
) {
5816 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5817 "Failed to create interleaves hash table\n", NULL
,
5822 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5823 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5825 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5826 "Failed to add %s to hash table\n",
5827 (const xmlChar
*) tmpname
, NULL
);
5834 * xmlRelaxNGCombineStart:
5835 * @ctxt: a Relax-NG parser context
5836 * @grammar: the grammar
5838 * Applies the 4.17. combine rule for all the start
5839 * element of a given grammar.
5842 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt
,
5843 xmlRelaxNGGrammarPtr grammar
)
5845 xmlRelaxNGDefinePtr starts
;
5847 int choiceOrInterleave
= -1;
5849 xmlRelaxNGDefinePtr cur
;
5851 starts
= grammar
->start
;
5852 if ((starts
== NULL
) || (starts
->next
== NULL
))
5855 while (cur
!= NULL
) {
5856 if ((cur
->node
== NULL
) || (cur
->node
->parent
== NULL
) ||
5857 (!xmlStrEqual(cur
->node
->parent
->name
, BAD_CAST
"start"))) {
5859 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_MISSING
,
5860 "Internal error: start element not found\n", NULL
,
5863 combine
= xmlGetProp(cur
->node
->parent
, BAD_CAST
"combine");
5866 if (combine
!= NULL
) {
5867 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5868 if (choiceOrInterleave
== -1)
5869 choiceOrInterleave
= 1;
5870 else if (choiceOrInterleave
== 0) {
5871 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5872 "<start> use both 'choice' and 'interleave'\n",
5875 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5876 if (choiceOrInterleave
== -1)
5877 choiceOrInterleave
= 0;
5878 else if (choiceOrInterleave
== 1) {
5879 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5880 "<start> use both 'choice' and 'interleave'\n",
5884 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5885 "<start> uses unknown combine value '%s''\n",
5893 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NEED_COMBINE
,
5894 "Some <start> element miss the combine attribute\n",
5902 xmlGenericError(xmlGenericErrorContext
,
5903 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5904 choiceOrInterleave
);
5906 if (choiceOrInterleave
== -1)
5907 choiceOrInterleave
= 0;
5908 cur
= xmlRelaxNGNewDefine(ctxt
, starts
->node
);
5911 if (choiceOrInterleave
== 0)
5912 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5914 cur
->type
= XML_RELAXNG_CHOICE
;
5915 cur
->content
= grammar
->start
;
5916 grammar
->start
= cur
;
5917 if (choiceOrInterleave
== 0) {
5918 if (ctxt
->interleaves
== NULL
)
5919 ctxt
->interleaves
= xmlHashCreate(10);
5920 if (ctxt
->interleaves
== NULL
) {
5921 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5922 "Failed to create interleaves hash table\n", NULL
,
5927 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5928 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5930 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5931 "Failed to add %s to hash table\n",
5932 (const xmlChar
*) tmpname
, NULL
);
5939 * xmlRelaxNGCheckCycles:
5940 * @ctxt: a Relax-NG parser context
5941 * @nodes: grammar children nodes
5942 * @depth: the counter
5946 * Returns 0 if check passed, and -1 in case of error
5949 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt
,
5950 xmlRelaxNGDefinePtr cur
, int depth
)
5954 while ((ret
== 0) && (cur
!= NULL
)) {
5955 if ((cur
->type
== XML_RELAXNG_REF
) ||
5956 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
5957 if (cur
->depth
== -1) {
5959 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
5961 } else if (depth
== cur
->depth
) {
5962 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_CYCLE
,
5963 "Detected a cycle in %s references\n",
5967 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
5968 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
+ 1);
5970 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
5978 * xmlRelaxNGTryUnlink:
5979 * @ctxt: a Relax-NG parser context
5980 * @cur: the definition to unlink
5981 * @parent: the parent definition
5982 * @prev: the previous sibling definition
5984 * Try to unlink a definition. If not possble make it a NOOP
5986 * Returns the new prev definition
5988 static xmlRelaxNGDefinePtr
5989 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
5990 xmlRelaxNGDefinePtr cur
,
5991 xmlRelaxNGDefinePtr parent
, xmlRelaxNGDefinePtr prev
)
5994 prev
->next
= cur
->next
;
5996 if (parent
!= NULL
) {
5997 if (parent
->content
== cur
)
5998 parent
->content
= cur
->next
;
5999 else if (parent
->attrs
== cur
)
6000 parent
->attrs
= cur
->next
;
6001 else if (parent
->nameClass
== cur
)
6002 parent
->nameClass
= cur
->next
;
6004 cur
->type
= XML_RELAXNG_NOOP
;
6012 * xmlRelaxNGSimplify:
6013 * @ctxt: a Relax-NG parser context
6014 * @nodes: grammar children nodes
6016 * Check for simplification of empty and notAllowed
6019 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt
,
6020 xmlRelaxNGDefinePtr cur
, xmlRelaxNGDefinePtr parent
)
6022 xmlRelaxNGDefinePtr prev
= NULL
;
6024 while (cur
!= NULL
) {
6025 if ((cur
->type
== XML_RELAXNG_REF
) ||
6026 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6027 if (cur
->depth
!= -3) {
6029 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6031 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6032 cur
->parent
= parent
;
6033 if ((parent
!= NULL
) &&
6034 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6035 (parent
->type
== XML_RELAXNG_LIST
) ||
6036 (parent
->type
== XML_RELAXNG_GROUP
) ||
6037 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6038 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6039 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6040 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6043 if ((parent
!= NULL
) && (parent
->type
== XML_RELAXNG_CHOICE
)) {
6044 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6047 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6048 cur
->parent
= parent
;
6049 if ((parent
!= NULL
) &&
6050 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6051 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6052 parent
->type
= XML_RELAXNG_EMPTY
;
6055 if ((parent
!= NULL
) &&
6056 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6057 (parent
->type
== XML_RELAXNG_INTERLEAVE
))) {
6058 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6062 cur
->parent
= parent
;
6063 if (cur
->content
!= NULL
)
6064 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6065 if ((cur
->type
!= XML_RELAXNG_VALUE
) && (cur
->attrs
!= NULL
))
6066 xmlRelaxNGSimplify(ctxt
, cur
->attrs
, cur
);
6067 if (cur
->nameClass
!= NULL
)
6068 xmlRelaxNGSimplify(ctxt
, cur
->nameClass
, cur
);
6070 * On Elements, try to move attribute only generating rules on
6073 if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6075 xmlRelaxNGDefinePtr tmp
, pre
;
6077 while (cur
->content
!= NULL
) {
6079 xmlRelaxNGGenerateAttributes(ctxt
, cur
->content
);
6080 if (attronly
== 1) {
6082 * migrate cur->content to attrs
6085 cur
->content
= tmp
->next
;
6086 tmp
->next
= cur
->attrs
;
6090 * cur->content can generate elements or text
6096 while ((pre
!= NULL
) && (pre
->next
!= NULL
)) {
6098 attronly
= xmlRelaxNGGenerateAttributes(ctxt
, tmp
);
6099 if (attronly
== 1) {
6101 * migrate tmp to attrs
6103 pre
->next
= tmp
->next
;
6104 tmp
->next
= cur
->attrs
;
6112 * This may result in a simplification
6114 if ((cur
->type
== XML_RELAXNG_GROUP
) ||
6115 (cur
->type
== XML_RELAXNG_INTERLEAVE
)) {
6116 if (cur
->content
== NULL
)
6117 cur
->type
= XML_RELAXNG_EMPTY
;
6118 else if (cur
->content
->next
== NULL
) {
6119 if ((parent
== NULL
) && (prev
== NULL
)) {
6120 cur
->type
= XML_RELAXNG_NOOP
;
6121 } else if (prev
== NULL
) {
6122 parent
->content
= cur
->content
;
6123 cur
->content
->next
= cur
->next
;
6126 cur
->content
->next
= cur
->next
;
6127 prev
->next
= cur
->content
;
6133 * the current node may have been transformed back
6135 if ((cur
->type
== XML_RELAXNG_EXCEPT
) &&
6136 (cur
->content
!= NULL
) &&
6137 (cur
->content
->type
== XML_RELAXNG_NOT_ALLOWED
)) {
6138 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6139 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6140 if ((parent
!= NULL
) &&
6141 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6142 (parent
->type
== XML_RELAXNG_LIST
) ||
6143 (parent
->type
== XML_RELAXNG_GROUP
) ||
6144 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6145 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6146 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6147 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6150 if ((parent
!= NULL
) &&
6151 (parent
->type
== XML_RELAXNG_CHOICE
)) {
6152 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6155 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6156 if ((parent
!= NULL
) &&
6157 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6158 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6159 parent
->type
= XML_RELAXNG_EMPTY
;
6162 if ((parent
!= NULL
) &&
6163 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6164 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6165 (parent
->type
== XML_RELAXNG_CHOICE
))) {
6166 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6178 * xmlRelaxNGGroupContentType:
6179 * @ct1: the first content type
6180 * @ct2: the second content type
6182 * Try to group 2 content types
6184 * Returns the content type
6186 static xmlRelaxNGContentType
6187 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1
,
6188 xmlRelaxNGContentType ct2
)
6190 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6191 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6192 return (XML_RELAXNG_CONTENT_ERROR
);
6193 if (ct1
== XML_RELAXNG_CONTENT_EMPTY
)
6195 if (ct2
== XML_RELAXNG_CONTENT_EMPTY
)
6197 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) &&
6198 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6199 return (XML_RELAXNG_CONTENT_COMPLEX
);
6200 return (XML_RELAXNG_CONTENT_ERROR
);
6204 * xmlRelaxNGMaxContentType:
6205 * @ct1: the first content type
6206 * @ct2: the second content type
6208 * Compute the max content-type
6210 * Returns the content type
6212 static xmlRelaxNGContentType
6213 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1
,
6214 xmlRelaxNGContentType ct2
)
6216 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6217 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6218 return (XML_RELAXNG_CONTENT_ERROR
);
6219 if ((ct1
== XML_RELAXNG_CONTENT_SIMPLE
) ||
6220 (ct2
== XML_RELAXNG_CONTENT_SIMPLE
))
6221 return (XML_RELAXNG_CONTENT_SIMPLE
);
6222 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) ||
6223 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6224 return (XML_RELAXNG_CONTENT_COMPLEX
);
6225 return (XML_RELAXNG_CONTENT_EMPTY
);
6229 * xmlRelaxNGCheckRules:
6230 * @ctxt: a Relax-NG parser context
6231 * @cur: the current definition
6232 * @flags: some accumulated flags
6233 * @ptype: the parent type
6235 * Check for rules in section 7.1 and 7.2
6237 * Returns the content type of @cur
6239 static xmlRelaxNGContentType
6240 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt
,
6241 xmlRelaxNGDefinePtr cur
, int flags
,
6242 xmlRelaxNGType ptype
)
6245 xmlRelaxNGContentType ret
, tmp
, val
= XML_RELAXNG_CONTENT_EMPTY
;
6247 while (cur
!= NULL
) {
6248 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6249 if ((cur
->type
== XML_RELAXNG_REF
) ||
6250 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6252 * This should actually be caught by list//element(ref) at the
6253 * element boundaries, c.f. Bug #159968 local refs are dropped
6257 if (flags
& XML_RELAXNG_IN_LIST
) {
6258 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_REF
,
6259 "Found forbidden pattern list//ref\n", NULL
,
6263 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6264 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_REF
,
6265 "Found forbidden pattern data/except//ref\n",
6268 if (cur
->content
== NULL
) {
6269 if (cur
->type
== XML_RELAXNG_PARENTREF
)
6270 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6271 "Internal found no define for parent refs\n",
6274 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6275 "Internal found no define for ref %s\n",
6276 (cur
->name
? cur
->name
: BAD_CAST
"null"), NULL
);
6278 if (cur
->depth
> -4) {
6280 ret
= xmlRelaxNGCheckRules(ctxt
, cur
->content
,
6282 cur
->depth
= ret
- 15;
6283 } else if (cur
->depth
== -4) {
6284 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6286 ret
= (xmlRelaxNGContentType
) (cur
->depth
+ 15);
6288 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6290 * The 7.3 Attribute derivation rule for groups is plugged there
6292 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6293 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6294 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ELEM
,
6295 "Found forbidden pattern data/except//element(ref)\n",
6298 if (flags
& XML_RELAXNG_IN_LIST
) {
6299 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ELEM
,
6300 "Found forbidden pattern list//element(ref)\n",
6303 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6304 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6305 "Found forbidden pattern attribute//element(ref)\n",
6308 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6309 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6310 "Found forbidden pattern attribute//element(ref)\n",
6314 * reset since in the simple form elements are only child
6319 xmlRelaxNGCheckRules(ctxt
, cur
->attrs
, nflags
, cur
->type
);
6320 if (ret
!= XML_RELAXNG_CONTENT_EMPTY
) {
6321 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_EMPTY
,
6322 "Element %s attributes have a content type error\n",
6326 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6328 if (ret
== XML_RELAXNG_CONTENT_ERROR
) {
6329 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_ERROR
,
6330 "Element %s has a content type error\n",
6333 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6335 } else if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
6336 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6337 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ATTR
,
6338 "Found forbidden pattern attribute//attribute\n",
6341 if (flags
& XML_RELAXNG_IN_LIST
) {
6342 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ATTR
,
6343 "Found forbidden pattern list//attribute\n",
6346 if (flags
& XML_RELAXNG_IN_OOMGROUP
) {
6347 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_GROUP_ATTR
,
6348 "Found forbidden pattern oneOrMore//group//attribute\n",
6351 if (flags
& XML_RELAXNG_IN_OOMINTERLEAVE
) {
6352 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR
,
6353 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6356 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6357 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ATTR
,
6358 "Found forbidden pattern data/except//attribute\n",
6361 if (flags
& XML_RELAXNG_IN_START
) {
6362 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ATTR
,
6363 "Found forbidden pattern start//attribute\n",
6366 if ((!(flags
& XML_RELAXNG_IN_ONEORMORE
))
6367 && (cur
->name
== NULL
)) {
6368 if (cur
->ns
== NULL
) {
6369 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ANYNAME_ATTR_ANCESTOR
,
6370 "Found anyName attribute without oneOrMore ancestor\n",
6373 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NSNAME_ATTR_ANCESTOR
,
6374 "Found nsName attribute without oneOrMore ancestor\n",
6378 nflags
= flags
| XML_RELAXNG_IN_ATTRIBUTE
;
6379 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
, cur
->type
);
6380 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6381 } else if ((cur
->type
== XML_RELAXNG_ONEORMORE
) ||
6382 (cur
->type
== XML_RELAXNG_ZEROORMORE
)) {
6383 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6384 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE
,
6385 "Found forbidden pattern data/except//oneOrMore\n",
6388 if (flags
& XML_RELAXNG_IN_START
) {
6389 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ONEMORE
,
6390 "Found forbidden pattern start//oneOrMore\n",
6393 nflags
= flags
| XML_RELAXNG_IN_ONEORMORE
;
6395 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6397 ret
= xmlRelaxNGGroupContentType(ret
, ret
);
6398 } else if (cur
->type
== XML_RELAXNG_LIST
) {
6399 if (flags
& XML_RELAXNG_IN_LIST
) {
6400 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_LIST
,
6401 "Found forbidden pattern list//list\n", NULL
,
6404 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6405 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_LIST
,
6406 "Found forbidden pattern data/except//list\n",
6409 if (flags
& XML_RELAXNG_IN_START
) {
6410 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_LIST
,
6411 "Found forbidden pattern start//list\n", NULL
,
6414 nflags
= flags
| XML_RELAXNG_IN_LIST
;
6416 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6418 } else if (cur
->type
== XML_RELAXNG_GROUP
) {
6419 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6420 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_GROUP
,
6421 "Found forbidden pattern data/except//group\n",
6424 if (flags
& XML_RELAXNG_IN_START
) {
6425 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_GROUP
,
6426 "Found forbidden pattern start//group\n", NULL
,
6429 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6430 nflags
= flags
| XML_RELAXNG_IN_OOMGROUP
;
6434 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6437 * The 7.3 Attribute derivation rule for groups is plugged there
6439 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6440 } else if (cur
->type
== XML_RELAXNG_INTERLEAVE
) {
6441 if (flags
& XML_RELAXNG_IN_LIST
) {
6442 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_INTERLEAVE
,
6443 "Found forbidden pattern list//interleave\n",
6446 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6447 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6448 "Found forbidden pattern data/except//interleave\n",
6451 if (flags
& XML_RELAXNG_IN_START
) {
6452 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6453 "Found forbidden pattern start//interleave\n",
6456 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6457 nflags
= flags
| XML_RELAXNG_IN_OOMINTERLEAVE
;
6461 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6463 } else if (cur
->type
== XML_RELAXNG_EXCEPT
) {
6464 if ((cur
->parent
!= NULL
) &&
6465 (cur
->parent
->type
== XML_RELAXNG_DATATYPE
))
6466 nflags
= flags
| XML_RELAXNG_IN_DATAEXCEPT
;
6470 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6472 } else if (cur
->type
== XML_RELAXNG_DATATYPE
) {
6473 if (flags
& XML_RELAXNG_IN_START
) {
6474 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_DATA
,
6475 "Found forbidden pattern start//data\n", NULL
,
6478 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6479 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6480 } else if (cur
->type
== XML_RELAXNG_VALUE
) {
6481 if (flags
& XML_RELAXNG_IN_START
) {
6482 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_VALUE
,
6483 "Found forbidden pattern start//value\n", NULL
,
6486 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6487 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6488 } else if (cur
->type
== XML_RELAXNG_TEXT
) {
6489 if (flags
& XML_RELAXNG_IN_LIST
) {
6490 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_TEXT
,
6491 "Found forbidden pattern list//text\n", NULL
,
6494 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6495 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_TEXT
,
6496 "Found forbidden pattern data/except//text\n",
6499 if (flags
& XML_RELAXNG_IN_START
) {
6500 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_TEXT
,
6501 "Found forbidden pattern start//text\n", NULL
,
6504 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6505 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6506 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6507 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_EMPTY
,
6508 "Found forbidden pattern data/except//empty\n",
6511 if (flags
& XML_RELAXNG_IN_START
) {
6512 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_EMPTY
,
6513 "Found forbidden pattern start//empty\n", NULL
,
6516 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6517 } else if (cur
->type
== XML_RELAXNG_CHOICE
) {
6518 xmlRelaxNGCheckChoiceDeterminism(ctxt
, cur
);
6520 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6523 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6526 if (ptype
== XML_RELAXNG_GROUP
) {
6527 val
= xmlRelaxNGGroupContentType(val
, ret
);
6528 } else if (ptype
== XML_RELAXNG_INTERLEAVE
) {
6530 * TODO: scan complain that tmp is never used, seems on purpose
6531 * need double-checking
6533 tmp
= xmlRelaxNGGroupContentType(val
, ret
);
6534 if (tmp
!= XML_RELAXNG_CONTENT_ERROR
)
6535 tmp
= xmlRelaxNGMaxContentType(val
, ret
);
6536 } else if (ptype
== XML_RELAXNG_CHOICE
) {
6537 val
= xmlRelaxNGMaxContentType(val
, ret
);
6538 } else if (ptype
== XML_RELAXNG_LIST
) {
6539 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6540 } else if (ptype
== XML_RELAXNG_EXCEPT
) {
6541 if (ret
== XML_RELAXNG_CONTENT_ERROR
)
6542 val
= XML_RELAXNG_CONTENT_ERROR
;
6544 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6546 val
= xmlRelaxNGGroupContentType(val
, ret
);
6554 * xmlRelaxNGParseGrammar:
6555 * @ctxt: a Relax-NG parser context
6556 * @nodes: grammar children nodes
6558 * parse a Relax-NG <grammar> node
6560 * Returns the internal xmlRelaxNGGrammarPtr built or
6561 * NULL in case of error
6563 static xmlRelaxNGGrammarPtr
6564 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
6566 xmlRelaxNGGrammarPtr ret
, tmp
, old
;
6568 #ifdef DEBUG_GRAMMAR
6569 xmlGenericError(xmlGenericErrorContext
, "Parsing a new grammar\n");
6572 ret
= xmlRelaxNGNewGrammar(ctxt
);
6577 * Link the new grammar in the tree
6579 ret
->parent
= ctxt
->grammar
;
6580 if (ctxt
->grammar
!= NULL
) {
6581 tmp
= ctxt
->grammar
->children
;
6583 ctxt
->grammar
->children
= ret
;
6585 while (tmp
->next
!= NULL
)
6591 old
= ctxt
->grammar
;
6592 ctxt
->grammar
= ret
;
6593 xmlRelaxNGParseGrammarContent(ctxt
, nodes
);
6594 ctxt
->grammar
= ret
;
6595 if (ctxt
->grammar
== NULL
) {
6596 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
6597 "Failed to parse <grammar> content\n", NULL
, NULL
);
6598 } else if (ctxt
->grammar
->start
== NULL
) {
6599 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_NO_START
,
6600 "Element <grammar> has no <start>\n", NULL
, NULL
);
6604 * Apply 4.17 mergingd rules to defines and starts
6606 xmlRelaxNGCombineStart(ctxt
, ret
);
6607 if (ret
->defs
!= NULL
) {
6608 xmlHashScan(ret
->defs
, (xmlHashScanner
) xmlRelaxNGCheckCombine
,
6613 * link together defines and refs in this grammar
6615 if (ret
->refs
!= NULL
) {
6616 xmlHashScan(ret
->refs
, (xmlHashScanner
) xmlRelaxNGCheckReference
,
6623 ctxt
->grammar
= old
;
6628 * xmlRelaxNGParseDocument:
6629 * @ctxt: a Relax-NG parser context
6630 * @node: the root node of the RelaxNG schema
6632 * parse a Relax-NG definition resource and build an internal
6633 * xmlRelaxNG struture which can be used to validate instances.
6635 * Returns the internal XML RelaxNG structure built or
6636 * NULL in case of error
6638 static xmlRelaxNGPtr
6639 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6641 xmlRelaxNGPtr schema
= NULL
;
6642 const xmlChar
*olddefine
;
6643 xmlRelaxNGGrammarPtr old
;
6645 if ((ctxt
== NULL
) || (node
== NULL
))
6648 schema
= xmlRelaxNGNewRelaxNG(ctxt
);
6652 olddefine
= ctxt
->define
;
6653 ctxt
->define
= NULL
;
6654 if (IS_RELAXNG(node
, "grammar")) {
6655 schema
->topgrammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
6657 xmlRelaxNGGrammarPtr tmp
, ret
;
6659 schema
->topgrammar
= ret
= xmlRelaxNGNewGrammar(ctxt
);
6660 if (schema
->topgrammar
== NULL
) {
6664 * Link the new grammar in the tree
6666 ret
->parent
= ctxt
->grammar
;
6667 if (ctxt
->grammar
!= NULL
) {
6668 tmp
= ctxt
->grammar
->children
;
6670 ctxt
->grammar
->children
= ret
;
6672 while (tmp
->next
!= NULL
)
6677 old
= ctxt
->grammar
;
6678 ctxt
->grammar
= ret
;
6679 xmlRelaxNGParseStart(ctxt
, node
);
6681 ctxt
->grammar
= old
;
6683 ctxt
->define
= olddefine
;
6684 if (schema
->topgrammar
->start
!= NULL
) {
6685 xmlRelaxNGCheckCycles(ctxt
, schema
->topgrammar
->start
, 0);
6686 if ((ctxt
->flags
& XML_RELAXNG_IN_EXTERNALREF
) == 0) {
6687 xmlRelaxNGSimplify(ctxt
, schema
->topgrammar
->start
, NULL
);
6688 while ((schema
->topgrammar
->start
!= NULL
) &&
6689 (schema
->topgrammar
->start
->type
== XML_RELAXNG_NOOP
) &&
6690 (schema
->topgrammar
->start
->next
!= NULL
))
6691 schema
->topgrammar
->start
=
6692 schema
->topgrammar
->start
->content
;
6693 xmlRelaxNGCheckRules(ctxt
, schema
->topgrammar
->start
,
6694 XML_RELAXNG_IN_START
, XML_RELAXNG_NOOP
);
6699 xmlGenericError(xmlGenericErrorContext
,
6700 "xmlRelaxNGParseDocument() failed\n");
6706 /************************************************************************
6708 * Reading RelaxNGs *
6710 ************************************************************************/
6713 * xmlRelaxNGNewParserCtxt:
6714 * @URL: the location of the schema
6716 * Create an XML RelaxNGs parse context for that file/resource expected
6717 * to contain an XML RelaxNGs file.
6719 * Returns the parser context or NULL in case of error
6721 xmlRelaxNGParserCtxtPtr
6722 xmlRelaxNGNewParserCtxt(const char *URL
)
6724 xmlRelaxNGParserCtxtPtr ret
;
6730 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6732 xmlRngPErrMemory(NULL
, "building parser\n");
6735 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6736 ret
->URL
= xmlStrdup((const xmlChar
*) URL
);
6737 ret
->error
= xmlGenericError
;
6738 ret
->userData
= xmlGenericErrorContext
;
6743 * xmlRelaxNGNewMemParserCtxt:
6744 * @buffer: a pointer to a char array containing the schemas
6745 * @size: the size of the array
6747 * Create an XML RelaxNGs parse context for that memory buffer expected
6748 * to contain an XML RelaxNGs file.
6750 * Returns the parser context or NULL in case of error
6752 xmlRelaxNGParserCtxtPtr
6753 xmlRelaxNGNewMemParserCtxt(const char *buffer
, int size
)
6755 xmlRelaxNGParserCtxtPtr ret
;
6757 if ((buffer
== NULL
) || (size
<= 0))
6761 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6763 xmlRngPErrMemory(NULL
, "building parser\n");
6766 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6767 ret
->buffer
= buffer
;
6769 ret
->error
= xmlGenericError
;
6770 ret
->userData
= xmlGenericErrorContext
;
6775 * xmlRelaxNGNewDocParserCtxt:
6776 * @doc: a preparsed document tree
6778 * Create an XML RelaxNGs parser context for that document.
6779 * Note: since the process of compiling a RelaxNG schemas modifies the
6780 * document, the @doc parameter is duplicated internally.
6782 * Returns the parser context or NULL in case of error
6784 xmlRelaxNGParserCtxtPtr
6785 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc
)
6787 xmlRelaxNGParserCtxtPtr ret
;
6792 copy
= xmlCopyDoc(doc
, 1);
6797 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6799 xmlRngPErrMemory(NULL
, "building parser\n");
6802 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6803 ret
->document
= copy
;
6805 ret
->userData
= xmlGenericErrorContext
;
6810 * xmlRelaxNGFreeParserCtxt:
6811 * @ctxt: the schema parser context
6813 * Free the resources associated to the schema parser context
6816 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt
)
6820 if (ctxt
->URL
!= NULL
)
6822 if (ctxt
->doc
!= NULL
)
6823 xmlRelaxNGFreeDocument(ctxt
->doc
);
6824 if (ctxt
->interleaves
!= NULL
)
6825 xmlHashFree(ctxt
->interleaves
, NULL
);
6826 if (ctxt
->documents
!= NULL
)
6827 xmlRelaxNGFreeDocumentList(ctxt
->documents
);
6828 if (ctxt
->includes
!= NULL
)
6829 xmlRelaxNGFreeIncludeList(ctxt
->includes
);
6830 if (ctxt
->docTab
!= NULL
)
6831 xmlFree(ctxt
->docTab
);
6832 if (ctxt
->incTab
!= NULL
)
6833 xmlFree(ctxt
->incTab
);
6834 if (ctxt
->defTab
!= NULL
) {
6837 for (i
= 0; i
< ctxt
->defNr
; i
++)
6838 xmlRelaxNGFreeDefine(ctxt
->defTab
[i
]);
6839 xmlFree(ctxt
->defTab
);
6841 if ((ctxt
->document
!= NULL
) && (ctxt
->freedoc
))
6842 xmlFreeDoc(ctxt
->document
);
6847 * xmlRelaxNGNormExtSpace:
6850 * Removes the leading and ending spaces of the value
6851 * The string is modified "in situ"
6854 xmlRelaxNGNormExtSpace(xmlChar
* value
)
6856 xmlChar
*start
= value
;
6857 xmlChar
*cur
= value
;
6862 while (IS_BLANK_CH(*cur
))
6866 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6871 while (IS_BLANK_CH(*cur
))
6880 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6886 /* don't try to normalize the inner spaces */
6887 while (IS_BLANK_CH(*cur
))
6899 * xmlRelaxNGCleanupAttributes:
6900 * @ctxt: a Relax-NG parser context
6901 * @node: a Relax-NG node
6903 * Check all the attributes on the given node
6906 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6908 xmlAttrPtr cur
, next
;
6910 cur
= node
->properties
;
6911 while (cur
!= NULL
) {
6913 if ((cur
->ns
== NULL
) ||
6914 (xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
6915 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
6916 if ((!xmlStrEqual(node
->name
, BAD_CAST
"element")) &&
6917 (!xmlStrEqual(node
->name
, BAD_CAST
"attribute")) &&
6918 (!xmlStrEqual(node
->name
, BAD_CAST
"ref")) &&
6919 (!xmlStrEqual(node
->name
, BAD_CAST
"parentRef")) &&
6920 (!xmlStrEqual(node
->name
, BAD_CAST
"param")) &&
6921 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6922 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6923 "Attribute %s is not allowed on %s\n",
6924 cur
->name
, node
->name
);
6926 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"type")) {
6927 if ((!xmlStrEqual(node
->name
, BAD_CAST
"value")) &&
6928 (!xmlStrEqual(node
->name
, BAD_CAST
"data"))) {
6929 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6930 "Attribute %s is not allowed on %s\n",
6931 cur
->name
, node
->name
);
6933 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"href")) {
6934 if ((!xmlStrEqual(node
->name
, BAD_CAST
"externalRef")) &&
6935 (!xmlStrEqual(node
->name
, BAD_CAST
"include"))) {
6936 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6937 "Attribute %s is not allowed on %s\n",
6938 cur
->name
, node
->name
);
6940 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"combine")) {
6941 if ((!xmlStrEqual(node
->name
, BAD_CAST
"start")) &&
6942 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6943 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6944 "Attribute %s is not allowed on %s\n",
6945 cur
->name
, node
->name
);
6947 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"datatypeLibrary")) {
6951 val
= xmlNodeListGetString(node
->doc
, cur
->children
, 1);
6954 uri
= xmlParseURI((const char *) val
);
6956 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_URI
,
6957 "Attribute %s contains invalid URI %s\n",
6960 if (uri
->scheme
== NULL
) {
6961 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_NOT_ABSOLUTE
,
6962 "Attribute %s URI %s is not absolute\n",
6965 if (uri
->fragment
!= NULL
) {
6966 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_FRAGMENT
,
6967 "Attribute %s URI %s has a fragment ID\n",
6975 } else if (!xmlStrEqual(cur
->name
, BAD_CAST
"ns")) {
6976 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_ATTRIBUTE
,
6977 "Unknown attribute %s on %s\n", cur
->name
,
6986 * xmlRelaxNGCleanupTree:
6987 * @ctxt: a Relax-NG parser context
6988 * @root: an xmlNodePtr subtree
6990 * Cleanup the subtree from unwanted nodes for parsing, resolve
6991 * Include and externalRef lookups.
6994 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr root
)
6996 xmlNodePtr cur
, delete;
7000 while (cur
!= NULL
) {
7001 if (delete != NULL
) {
7002 xmlUnlinkNode(delete);
7003 xmlFreeNode(delete);
7006 if (cur
->type
== XML_ELEMENT_NODE
) {
7008 * Simplification 4.1. Annotations
7010 if ((cur
->ns
== NULL
) ||
7011 (!xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
7012 if ((cur
->parent
!= NULL
) &&
7013 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
7014 ((xmlStrEqual(cur
->parent
->name
, BAD_CAST
"name")) ||
7015 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value")) ||
7016 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"param")))) {
7017 xmlRngPErr(ctxt
, cur
, XML_RNGP_FOREIGN_ELEMENT
,
7018 "element %s doesn't allow foreign elements\n",
7019 cur
->parent
->name
, NULL
);
7024 xmlRelaxNGCleanupAttributes(ctxt
, cur
);
7025 if (xmlStrEqual(cur
->name
, BAD_CAST
"externalRef")) {
7026 xmlChar
*href
, *ns
, *base
, *URL
;
7027 xmlRelaxNGDocumentPtr docu
;
7031 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7034 while ((tmp
!= NULL
) &&
7035 (tmp
->type
== XML_ELEMENT_NODE
)) {
7036 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7042 href
= xmlGetProp(cur
, BAD_CAST
"href");
7044 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7045 "xmlRelaxNGParse: externalRef has no href attribute\n",
7052 uri
= xmlParseURI((const char *) href
);
7054 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7055 "Incorrect URI for externalRef %s\n",
7064 if (uri
->fragment
!= NULL
) {
7065 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7066 "Fragment forbidden in URI for externalRef %s\n",
7077 base
= xmlNodeGetBase(cur
->doc
, cur
);
7078 URL
= xmlBuildURI(href
, base
);
7080 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7081 "Failed to compute URL for externalRef %s\n",
7096 docu
= xmlRelaxNGLoadExternalRef(ctxt
, URL
, ns
);
7098 xmlRngPErr(ctxt
, cur
, XML_RNGP_EXTERNAL_REF_FAILURE
,
7099 "Failed to load externalRef %s\n", URL
,
7111 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"include")) {
7112 xmlChar
*href
, *ns
, *base
, *URL
;
7113 xmlRelaxNGIncludePtr incl
;
7116 href
= xmlGetProp(cur
, BAD_CAST
"href");
7118 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7119 "xmlRelaxNGParse: include has no href attribute\n",
7124 base
= xmlNodeGetBase(cur
->doc
, cur
);
7125 URL
= xmlBuildURI(href
, base
);
7127 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7128 "Failed to compute URL for include %s\n",
7141 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7144 while ((tmp
!= NULL
) &&
7145 (tmp
->type
== XML_ELEMENT_NODE
)) {
7146 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7152 incl
= xmlRelaxNGLoadInclude(ctxt
, URL
, cur
, ns
);
7156 xmlRngPErr(ctxt
, cur
, XML_RNGP_INCLUDE_FAILURE
,
7157 "Failed to load include %s\n", URL
,
7165 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"element")) ||
7166 (xmlStrEqual(cur
->name
, BAD_CAST
"attribute")))
7169 xmlNodePtr text
= NULL
;
7172 * Simplification 4.8. name attribute of element
7173 * and attribute elements
7175 name
= xmlGetProp(cur
, BAD_CAST
"name");
7177 if (cur
->children
== NULL
) {
7179 xmlNewChild(cur
, cur
->ns
, BAD_CAST
"name",
7184 node
= xmlNewDocNode(cur
->doc
, cur
->ns
,
7185 BAD_CAST
"name", NULL
);
7187 xmlAddPrevSibling(cur
->children
, node
);
7188 text
= xmlNewText(name
);
7189 xmlAddChild(node
, text
);
7194 xmlRngPErr(ctxt
, cur
, XML_RNGP_CREATE_FAILURE
,
7195 "Failed to create a name %s element\n",
7198 xmlUnsetProp(cur
, BAD_CAST
"name");
7200 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7203 xmlSetProp(text
, BAD_CAST
"ns", ns
);
7204 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7207 } else if (xmlStrEqual(cur
->name
,
7208 BAD_CAST
"attribute")) {
7209 xmlSetProp(text
, BAD_CAST
"ns", BAD_CAST
"");
7212 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"name")) ||
7213 (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) ||
7214 (xmlStrEqual(cur
->name
, BAD_CAST
"value"))) {
7216 * Simplification 4.8. name attribute of element
7217 * and attribute elements
7219 if (xmlHasProp(cur
, BAD_CAST
"ns") == NULL
) {
7224 while ((node
!= NULL
) &&
7225 (node
->type
== XML_ELEMENT_NODE
)) {
7226 ns
= xmlGetProp(node
, BAD_CAST
"ns");
7230 node
= node
->parent
;
7233 xmlSetProp(cur
, BAD_CAST
"ns", BAD_CAST
"");
7235 xmlSetProp(cur
, BAD_CAST
"ns", ns
);
7239 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
7240 xmlChar
*name
, *local
, *prefix
;
7243 * Simplification: 4.10. QNames
7245 name
= xmlNodeGetContent(cur
);
7247 local
= xmlSplitQName2(name
, &prefix
);
7248 if (local
!= NULL
) {
7251 ns
= xmlSearchNs(cur
->doc
, cur
, prefix
);
7253 xmlRngPErr(ctxt
, cur
,
7254 XML_RNGP_PREFIX_UNDEFINED
,
7255 "xmlRelaxNGParse: no namespace for prefix %s\n",
7258 xmlSetProp(cur
, BAD_CAST
"ns",
7260 xmlNodeSetContent(cur
, local
);
7271 if (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) {
7272 if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7273 xmlRngPErr(ctxt
, cur
,
7274 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME
,
7275 "Found nsName/except//nsName forbidden construct\n",
7279 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"except")) &&
7281 int oldflags
= ctxt
->flags
;
7286 if ((cur
->parent
!= NULL
) &&
7288 (cur
->parent
->name
, BAD_CAST
"anyName"))) {
7289 ctxt
->flags
|= XML_RELAXNG_IN_ANYEXCEPT
;
7290 xmlRelaxNGCleanupTree(ctxt
, cur
);
7291 ctxt
->flags
= oldflags
;
7293 } else if ((cur
->parent
!= NULL
) &&
7295 (cur
->parent
->name
, BAD_CAST
"nsName"))) {
7296 ctxt
->flags
|= XML_RELAXNG_IN_NSEXCEPT
;
7297 xmlRelaxNGCleanupTree(ctxt
, cur
);
7298 ctxt
->flags
= oldflags
;
7301 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"anyName")) {
7305 if (ctxt
->flags
& XML_RELAXNG_IN_ANYEXCEPT
) {
7306 xmlRngPErr(ctxt
, cur
,
7307 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME
,
7308 "Found anyName/except//anyName forbidden construct\n",
7310 } else if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7311 xmlRngPErr(ctxt
, cur
,
7312 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME
,
7313 "Found nsName/except//anyName forbidden construct\n",
7318 * Thisd is not an else since "include" is transformed
7321 if (xmlStrEqual(cur
->name
, BAD_CAST
"div")) {
7323 xmlNodePtr child
, ins
, tmp
;
7326 * implements rule 4.11
7329 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7331 child
= cur
->children
;
7333 while (child
!= NULL
) {
7335 if (!xmlHasProp(child
, BAD_CAST
"ns")) {
7336 xmlSetProp(child
, BAD_CAST
"ns", ns
);
7340 xmlUnlinkNode(child
);
7341 ins
= xmlAddNextSibling(ins
, child
);
7347 * Since we are about to delete cur, if it's nsDef is non-NULL we
7348 * need to preserve it (it contains the ns definitions for the
7349 * children we just moved). We'll just stick it on to the end
7350 * of cur->parent's list, since it's never going to be re-serialized
7353 if (cur
->nsDef
!= NULL
) {
7354 xmlNsPtr parDef
= (xmlNsPtr
)&cur
->parent
->nsDef
;
7355 while (parDef
->next
!= NULL
)
7356 parDef
= parDef
->next
;
7357 parDef
->next
= cur
->nsDef
;
7366 * Simplification 4.2 whitespaces
7368 else if ((cur
->type
== XML_TEXT_NODE
) ||
7369 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
7370 if (IS_BLANK_NODE(cur
)) {
7371 if (cur
->parent
->type
== XML_ELEMENT_NODE
) {
7372 if ((!xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value"))
7375 (cur
->parent
->name
, BAD_CAST
"param")))
7390 if (cur
->children
!= NULL
) {
7391 if ((cur
->children
->type
!= XML_ENTITY_DECL
) &&
7392 (cur
->children
->type
!= XML_ENTITY_REF_NODE
) &&
7393 (cur
->children
->type
!= XML_ENTITY_NODE
)) {
7394 cur
= cur
->children
;
7399 if (cur
->next
!= NULL
) {
7412 if (cur
->next
!= NULL
) {
7416 } while (cur
!= NULL
);
7418 if (delete != NULL
) {
7419 xmlUnlinkNode(delete);
7420 xmlFreeNode(delete);
7426 * xmlRelaxNGCleanupDoc:
7427 * @ctxt: a Relax-NG parser context
7428 * @doc: an xmldocPtr document pointer
7430 * Cleanup the document from unwanted nodes for parsing, resolve
7431 * Include and externalRef lookups.
7433 * Returns the cleaned up document or NULL in case of error
7436 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
, xmlDocPtr doc
)
7443 root
= xmlDocGetRootElement(doc
);
7445 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7449 xmlRelaxNGCleanupTree(ctxt
, root
);
7455 * @ctxt: a Relax-NG parser context
7457 * parse a schema definition resource and build an internal
7458 * XML Shema struture which can be used to validate instances.
7460 * Returns the internal XML RelaxNG structure built from the resource or
7461 * NULL in case of error
7464 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt
)
7466 xmlRelaxNGPtr ret
= NULL
;
7470 xmlRelaxNGInitTypes();
7476 * First step is to parse the input document into an DOM/Infoset
7478 if (ctxt
->URL
!= NULL
) {
7479 doc
= xmlReadFile((const char *) ctxt
->URL
,NULL
,0);
7481 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7482 "xmlRelaxNGParse: could not load %s\n", ctxt
->URL
,
7486 } else if (ctxt
->buffer
!= NULL
) {
7487 doc
= xmlReadMemory(ctxt
->buffer
, ctxt
->size
,NULL
,NULL
,0);
7489 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7490 "xmlRelaxNGParse: could not parse schemas\n", NULL
,
7494 doc
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7495 ctxt
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7496 } else if (ctxt
->document
!= NULL
) {
7497 doc
= ctxt
->document
;
7499 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EMPTY
,
7500 "xmlRelaxNGParse: nothing to parse\n", NULL
, NULL
);
7503 ctxt
->document
= doc
;
7506 * Some preprocessing of the document content
7508 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
7510 xmlFreeDoc(ctxt
->document
);
7511 ctxt
->document
= NULL
;
7516 * Then do the parsing for good
7518 root
= xmlDocGetRootElement(doc
);
7520 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
,
7521 XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7522 (ctxt
->URL
? ctxt
->URL
: BAD_CAST
"schemas"), NULL
);
7524 xmlFreeDoc(ctxt
->document
);
7525 ctxt
->document
= NULL
;
7528 ret
= xmlRelaxNGParseDocument(ctxt
, root
);
7530 xmlFreeDoc(ctxt
->document
);
7531 ctxt
->document
= NULL
;
7536 * Check the ref/defines links
7539 * try to preprocess interleaves
7541 if (ctxt
->interleaves
!= NULL
) {
7542 xmlHashScan(ctxt
->interleaves
,
7543 (xmlHashScanner
) xmlRelaxNGComputeInterleaves
, ctxt
);
7547 * if there was a parsing error return NULL
7549 if (ctxt
->nbErrors
> 0) {
7550 xmlRelaxNGFree(ret
);
7551 ctxt
->document
= NULL
;
7557 * try to compile (parts of) the schemas
7559 if ((ret
->topgrammar
!= NULL
) && (ret
->topgrammar
->start
!= NULL
)) {
7560 if (ret
->topgrammar
->start
->type
!= XML_RELAXNG_START
) {
7561 xmlRelaxNGDefinePtr def
;
7563 def
= xmlRelaxNGNewDefine(ctxt
, NULL
);
7565 def
->type
= XML_RELAXNG_START
;
7566 def
->content
= ret
->topgrammar
->start
;
7567 ret
->topgrammar
->start
= def
;
7570 xmlRelaxNGTryCompile(ctxt
, ret
->topgrammar
->start
);
7574 * Transfer the pointer for cleanup at the schema level.
7577 ctxt
->document
= NULL
;
7578 ret
->documents
= ctxt
->documents
;
7579 ctxt
->documents
= NULL
;
7581 ret
->includes
= ctxt
->includes
;
7582 ctxt
->includes
= NULL
;
7583 ret
->defNr
= ctxt
->defNr
;
7584 ret
->defTab
= ctxt
->defTab
;
7585 ctxt
->defTab
= NULL
;
7586 if (ctxt
->idref
== 1)
7593 * xmlRelaxNGSetParserErrors:
7594 * @ctxt: a Relax-NG validation context
7595 * @err: the error callback
7596 * @warn: the warning callback
7597 * @ctx: contextual data for the callbacks
7599 * Set the callback functions used to handle errors for a validation context
7602 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7603 xmlRelaxNGValidityErrorFunc err
,
7604 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
7609 ctxt
->warning
= warn
;
7610 ctxt
->serror
= NULL
;
7611 ctxt
->userData
= ctx
;
7615 * xmlRelaxNGGetParserErrors:
7616 * @ctxt: a Relax-NG validation context
7617 * @err: the error callback result
7618 * @warn: the warning callback result
7619 * @ctx: contextual data for the callbacks result
7621 * Get the callback information used to handle errors for a validation context
7623 * Returns -1 in case of failure, 0 otherwise.
7626 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7627 xmlRelaxNGValidityErrorFunc
* err
,
7628 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
7635 *warn
= ctxt
->warning
;
7637 *ctx
= ctxt
->userData
;
7642 * xmlRelaxNGSetParserStructuredErrors:
7643 * @ctxt: a Relax-NG parser context
7644 * @serror: the error callback
7645 * @ctx: contextual data for the callbacks
7647 * Set the callback functions used to handle errors for a parsing context
7650 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7651 xmlStructuredErrorFunc serror
,
7656 ctxt
->serror
= serror
;
7658 ctxt
->warning
= NULL
;
7659 ctxt
->userData
= ctx
;
7662 #ifdef LIBXML_OUTPUT_ENABLED
7664 /************************************************************************
7666 * Dump back a compiled form *
7668 ************************************************************************/
7669 static void xmlRelaxNGDumpDefine(FILE * output
,
7670 xmlRelaxNGDefinePtr define
);
7673 * xmlRelaxNGDumpDefines:
7674 * @output: the file output
7675 * @defines: a list of define structures
7677 * Dump a RelaxNG structure back
7680 xmlRelaxNGDumpDefines(FILE * output
, xmlRelaxNGDefinePtr defines
)
7682 while (defines
!= NULL
) {
7683 xmlRelaxNGDumpDefine(output
, defines
);
7684 defines
= defines
->next
;
7689 * xmlRelaxNGDumpDefine:
7690 * @output: the file output
7691 * @define: a define structure
7693 * Dump a RelaxNG structure back
7696 xmlRelaxNGDumpDefine(FILE * output
, xmlRelaxNGDefinePtr define
)
7700 switch (define
->type
) {
7701 case XML_RELAXNG_EMPTY
:
7702 fprintf(output
, "<empty/>\n");
7704 case XML_RELAXNG_NOT_ALLOWED
:
7705 fprintf(output
, "<notAllowed/>\n");
7707 case XML_RELAXNG_TEXT
:
7708 fprintf(output
, "<text/>\n");
7710 case XML_RELAXNG_ELEMENT
:
7711 fprintf(output
, "<element>\n");
7712 if (define
->name
!= NULL
) {
7713 fprintf(output
, "<name");
7714 if (define
->ns
!= NULL
)
7715 fprintf(output
, " ns=\"%s\"", define
->ns
);
7716 fprintf(output
, ">%s</name>\n", define
->name
);
7718 xmlRelaxNGDumpDefines(output
, define
->attrs
);
7719 xmlRelaxNGDumpDefines(output
, define
->content
);
7720 fprintf(output
, "</element>\n");
7722 case XML_RELAXNG_LIST
:
7723 fprintf(output
, "<list>\n");
7724 xmlRelaxNGDumpDefines(output
, define
->content
);
7725 fprintf(output
, "</list>\n");
7727 case XML_RELAXNG_ONEORMORE
:
7728 fprintf(output
, "<oneOrMore>\n");
7729 xmlRelaxNGDumpDefines(output
, define
->content
);
7730 fprintf(output
, "</oneOrMore>\n");
7732 case XML_RELAXNG_ZEROORMORE
:
7733 fprintf(output
, "<zeroOrMore>\n");
7734 xmlRelaxNGDumpDefines(output
, define
->content
);
7735 fprintf(output
, "</zeroOrMore>\n");
7737 case XML_RELAXNG_CHOICE
:
7738 fprintf(output
, "<choice>\n");
7739 xmlRelaxNGDumpDefines(output
, define
->content
);
7740 fprintf(output
, "</choice>\n");
7742 case XML_RELAXNG_GROUP
:
7743 fprintf(output
, "<group>\n");
7744 xmlRelaxNGDumpDefines(output
, define
->content
);
7745 fprintf(output
, "</group>\n");
7747 case XML_RELAXNG_INTERLEAVE
:
7748 fprintf(output
, "<interleave>\n");
7749 xmlRelaxNGDumpDefines(output
, define
->content
);
7750 fprintf(output
, "</interleave>\n");
7752 case XML_RELAXNG_OPTIONAL
:
7753 fprintf(output
, "<optional>\n");
7754 xmlRelaxNGDumpDefines(output
, define
->content
);
7755 fprintf(output
, "</optional>\n");
7757 case XML_RELAXNG_ATTRIBUTE
:
7758 fprintf(output
, "<attribute>\n");
7759 xmlRelaxNGDumpDefines(output
, define
->content
);
7760 fprintf(output
, "</attribute>\n");
7762 case XML_RELAXNG_DEF
:
7763 fprintf(output
, "<define");
7764 if (define
->name
!= NULL
)
7765 fprintf(output
, " name=\"%s\"", define
->name
);
7766 fprintf(output
, ">\n");
7767 xmlRelaxNGDumpDefines(output
, define
->content
);
7768 fprintf(output
, "</define>\n");
7770 case XML_RELAXNG_REF
:
7771 fprintf(output
, "<ref");
7772 if (define
->name
!= NULL
)
7773 fprintf(output
, " name=\"%s\"", define
->name
);
7774 fprintf(output
, ">\n");
7775 xmlRelaxNGDumpDefines(output
, define
->content
);
7776 fprintf(output
, "</ref>\n");
7778 case XML_RELAXNG_PARENTREF
:
7779 fprintf(output
, "<parentRef");
7780 if (define
->name
!= NULL
)
7781 fprintf(output
, " name=\"%s\"", define
->name
);
7782 fprintf(output
, ">\n");
7783 xmlRelaxNGDumpDefines(output
, define
->content
);
7784 fprintf(output
, "</parentRef>\n");
7786 case XML_RELAXNG_EXTERNALREF
:
7787 fprintf(output
, "<externalRef>");
7788 xmlRelaxNGDumpDefines(output
, define
->content
);
7789 fprintf(output
, "</externalRef>\n");
7791 case XML_RELAXNG_DATATYPE
:
7792 case XML_RELAXNG_VALUE
:
7794 case XML_RELAXNG_START
:
7795 case XML_RELAXNG_EXCEPT
:
7796 case XML_RELAXNG_PARAM
:
7798 case XML_RELAXNG_NOOP
:
7799 xmlRelaxNGDumpDefines(output
, define
->content
);
7805 * xmlRelaxNGDumpGrammar:
7806 * @output: the file output
7807 * @grammar: a grammar structure
7808 * @top: is this a top grammar
7810 * Dump a RelaxNG structure back
7813 xmlRelaxNGDumpGrammar(FILE * output
, xmlRelaxNGGrammarPtr grammar
, int top
)
7815 if (grammar
== NULL
)
7818 fprintf(output
, "<grammar");
7820 fprintf(output
, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7821 switch (grammar
->combine
) {
7822 case XML_RELAXNG_COMBINE_UNDEFINED
:
7824 case XML_RELAXNG_COMBINE_CHOICE
:
7825 fprintf(output
, " combine=\"choice\"");
7827 case XML_RELAXNG_COMBINE_INTERLEAVE
:
7828 fprintf(output
, " combine=\"interleave\"");
7831 fprintf(output
, " <!-- invalid combine value -->");
7833 fprintf(output
, ">\n");
7834 if (grammar
->start
== NULL
) {
7835 fprintf(output
, " <!-- grammar had no start -->");
7837 fprintf(output
, "<start>\n");
7838 xmlRelaxNGDumpDefine(output
, grammar
->start
);
7839 fprintf(output
, "</start>\n");
7841 /* TODO ? Dump the defines ? */
7842 fprintf(output
, "</grammar>\n");
7847 * @output: the file output
7848 * @schema: a schema structure
7850 * Dump a RelaxNG structure back
7853 xmlRelaxNGDump(FILE * output
, xmlRelaxNGPtr schema
)
7857 if (schema
== NULL
) {
7858 fprintf(output
, "RelaxNG empty or failed to compile\n");
7861 fprintf(output
, "RelaxNG: ");
7862 if (schema
->doc
== NULL
) {
7863 fprintf(output
, "no document\n");
7864 } else if (schema
->doc
->URL
!= NULL
) {
7865 fprintf(output
, "%s\n", schema
->doc
->URL
);
7867 fprintf(output
, "\n");
7869 if (schema
->topgrammar
== NULL
) {
7870 fprintf(output
, "RelaxNG has no top grammar\n");
7873 xmlRelaxNGDumpGrammar(output
, schema
->topgrammar
, 1);
7877 * xmlRelaxNGDumpTree:
7878 * @output: the file output
7879 * @schema: a schema structure
7881 * Dump the transformed RelaxNG tree.
7884 xmlRelaxNGDumpTree(FILE * output
, xmlRelaxNGPtr schema
)
7888 if (schema
== NULL
) {
7889 fprintf(output
, "RelaxNG empty or failed to compile\n");
7892 if (schema
->doc
== NULL
) {
7893 fprintf(output
, "no document\n");
7895 xmlDocDump(output
, schema
->doc
);
7898 #endif /* LIBXML_OUTPUT_ENABLED */
7900 /************************************************************************
7902 * Validation of compiled content *
7904 ************************************************************************/
7905 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
7906 xmlRelaxNGDefinePtr define
);
7909 * xmlRelaxNGValidateCompiledCallback:
7910 * @exec: the regular expression instance
7911 * @token: the token which matched
7912 * @transdata: callback data, the define for the subelement if available
7913 @ @inputdata: callback data, the Relax NG validation context
7915 * Handle the callback and if needed validate the element children.
7918 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED
,
7919 const xmlChar
* token
,
7920 void *transdata
, void *inputdata
)
7922 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
7923 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
7926 #ifdef DEBUG_COMPILE
7927 xmlGenericError(xmlGenericErrorContext
,
7928 "Compiled callback for: '%s'\n", token
);
7931 fprintf(stderr
, "callback on %s missing context\n", token
);
7934 if (define
== NULL
) {
7935 if (token
[0] == '#')
7937 fprintf(stderr
, "callback on %s missing define\n", token
);
7938 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7939 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7942 if ((ctxt
== NULL
) || (define
== NULL
)) {
7943 fprintf(stderr
, "callback on %s missing info\n", token
);
7944 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7945 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7947 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
7948 fprintf(stderr
, "callback on %s define is not element\n", token
);
7949 if (ctxt
->errNo
== XML_RELAXNG_OK
)
7950 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7953 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
);
7959 * xmlRelaxNGValidateCompiledContent:
7960 * @ctxt: the RelaxNG validation context
7961 * @regexp: the regular expression as compiled
7962 * @content: list of children to test against the regexp
7964 * Validate the content model of an element or start using the regexp
7966 * Returns 0 in case of success, -1 in case of error.
7969 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt
,
7970 xmlRegexpPtr regexp
, xmlNodePtr content
)
7972 xmlRegExecCtxtPtr exec
;
7977 if ((ctxt
== NULL
) || (regexp
== NULL
))
7979 oldperr
= ctxt
->perr
;
7980 exec
= xmlRegNewExecCtxt(regexp
,
7981 xmlRelaxNGValidateCompiledCallback
, ctxt
);
7984 while (cur
!= NULL
) {
7985 ctxt
->state
->seq
= cur
;
7986 switch (cur
->type
) {
7988 case XML_CDATA_SECTION_NODE
:
7989 if (xmlIsBlankNode(cur
))
7991 ret
= xmlRegExecPushString(exec
, BAD_CAST
"#text", ctxt
);
7993 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
,
7997 case XML_ELEMENT_NODE
:
7998 if (cur
->ns
!= NULL
) {
7999 ret
= xmlRegExecPushString2(exec
, cur
->name
,
8000 cur
->ns
->href
, ctxt
);
8002 ret
= xmlRegExecPushString(exec
, cur
->name
, ctxt
);
8005 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, cur
->name
);
8014 * Switch to next element
8018 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8021 ctxt
->state
->seq
= NULL
;
8022 } else if (ret
== 0) {
8024 * TODO: get some of the names needed to exit the current state of exec
8026 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8028 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8029 xmlRelaxNGDumpValidError(ctxt
);
8033 xmlRegFreeExecCtxt(exec
);
8035 * There might be content model errors outside of the pure
8036 * regexp validation, e.g. for attribute values.
8038 if ((ret
== 0) && (ctxt
->perr
!= 0)) {
8041 ctxt
->perr
= oldperr
;
8045 /************************************************************************
8047 * Progressive validation of when possible *
8049 ************************************************************************/
8050 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
8051 xmlRelaxNGDefinePtr defines
);
8052 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
,
8054 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
);
8057 * xmlRelaxNGElemPush:
8058 * @ctxt: the validation context
8059 * @exec: the regexp runtime for the new content model
8061 * Push a new regexp for the current node content model on the stack
8063 * Returns 0 in case of success and -1 in case of error.
8066 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt
, xmlRegExecCtxtPtr exec
)
8068 if (ctxt
->elemTab
== NULL
) {
8070 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlMalloc(ctxt
->elemMax
*
8072 (xmlRegExecCtxtPtr
));
8073 if (ctxt
->elemTab
== NULL
) {
8074 xmlRngVErrMemory(ctxt
, "validating\n");
8078 if (ctxt
->elemNr
>= ctxt
->elemMax
) {
8080 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlRealloc(ctxt
->elemTab
,
8083 (xmlRegExecCtxtPtr
));
8084 if (ctxt
->elemTab
== NULL
) {
8085 xmlRngVErrMemory(ctxt
, "validating\n");
8089 ctxt
->elemTab
[ctxt
->elemNr
++] = exec
;
8095 * xmlRelaxNGElemPop:
8096 * @ctxt: the validation context
8098 * Pop the regexp of the current node content model from the stack
8100 * Returns the exec or NULL if empty
8102 static xmlRegExecCtxtPtr
8103 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt
)
8105 xmlRegExecCtxtPtr ret
;
8107 if (ctxt
->elemNr
<= 0)
8110 ret
= ctxt
->elemTab
[ctxt
->elemNr
];
8111 ctxt
->elemTab
[ctxt
->elemNr
] = NULL
;
8112 if (ctxt
->elemNr
> 0)
8113 ctxt
->elem
= ctxt
->elemTab
[ctxt
->elemNr
- 1];
8120 * xmlRelaxNGValidateProgressiveCallback:
8121 * @exec: the regular expression instance
8122 * @token: the token which matched
8123 * @transdata: callback data, the define for the subelement if available
8124 @ @inputdata: callback data, the Relax NG validation context
8126 * Handle the callback and if needed validate the element children.
8127 * some of the in/out informations are passed via the context in @inputdata.
8130 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8132 const xmlChar
* token
,
8133 void *transdata
, void *inputdata
)
8135 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
8136 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
8137 xmlRelaxNGValidStatePtr state
, oldstate
;
8139 int ret
= 0, oldflags
;
8141 #ifdef DEBUG_PROGRESSIVE
8142 xmlGenericError(xmlGenericErrorContext
,
8143 "Progressive callback for: '%s'\n", token
);
8146 fprintf(stderr
, "callback on %s missing context\n", token
);
8151 if (define
== NULL
) {
8152 if (token
[0] == '#')
8154 fprintf(stderr
, "callback on %s missing define\n", token
);
8155 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8156 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8160 if ((ctxt
== NULL
) || (define
== NULL
)) {
8161 fprintf(stderr
, "callback on %s missing info\n", token
);
8162 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8163 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8166 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
8167 fprintf(stderr
, "callback on %s define is not element\n", token
);
8168 if (ctxt
->errNo
== XML_RELAXNG_OK
)
8169 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8173 if (node
->type
!= XML_ELEMENT_NODE
) {
8174 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
8175 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8176 xmlRelaxNGDumpValidError(ctxt
);
8180 if (define
->contModel
== NULL
) {
8182 * this node cannot be validated in a streamable fashion
8184 #ifdef DEBUG_PROGRESSIVE
8185 xmlGenericError(xmlGenericErrorContext
,
8186 "Element '%s' validation is not streamable\n",
8190 ctxt
->pdef
= define
;
8193 exec
= xmlRegNewExecCtxt(define
->contModel
,
8194 xmlRelaxNGValidateProgressiveCallback
, ctxt
);
8199 xmlRelaxNGElemPush(ctxt
, exec
);
8202 * Validate the attributes part of the content.
8204 state
= xmlRelaxNGNewValidState(ctxt
, node
);
8205 if (state
== NULL
) {
8209 oldstate
= ctxt
->state
;
8210 ctxt
->state
= state
;
8211 if (define
->attrs
!= NULL
) {
8212 ret
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
8215 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
8218 if (ctxt
->state
!= NULL
) {
8219 ctxt
->state
->seq
= NULL
;
8220 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
8224 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8225 } else if (ctxt
->states
!= NULL
) {
8228 oldflags
= ctxt
->flags
;
8230 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8231 state
= ctxt
->states
->tabState
[i
];
8232 ctxt
->state
= state
;
8233 ctxt
->state
->seq
= NULL
;
8235 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
8242 * validation error, log the message for the "best" one
8244 ctxt
->flags
|= FLAGS_IGNORABLE
;
8245 xmlRelaxNGLogBestError(ctxt
);
8247 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8248 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[i
]);
8250 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
8251 ctxt
->states
= NULL
;
8252 if ((ret
== 0) && (tmp
== -1))
8254 ctxt
->flags
= oldflags
;
8256 if (ctxt
->pstate
== -1) {
8257 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
8258 xmlRelaxNGDumpValidError(ctxt
);
8261 ctxt
->state
= oldstate
;
8265 * xmlRelaxNGValidatePushElement:
8266 * @ctxt: the validation context
8267 * @doc: a document instance
8268 * @elem: an element instance
8270 * Push a new element start on the RelaxNG validation stack.
8272 * returns 1 if no validation problem was found or 0 if validating the
8273 * element requires a full node, and -1 in case of error.
8276 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt
,
8277 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8282 if ((ctxt
== NULL
) || (elem
== NULL
))
8285 #ifdef DEBUG_PROGRESSIVE
8286 xmlGenericError(xmlGenericErrorContext
, "PushElem %s\n", elem
->name
);
8288 if (ctxt
->elem
== 0) {
8289 xmlRelaxNGPtr schema
;
8290 xmlRelaxNGGrammarPtr grammar
;
8291 xmlRegExecCtxtPtr exec
;
8292 xmlRelaxNGDefinePtr define
;
8294 schema
= ctxt
->schema
;
8295 if (schema
== NULL
) {
8296 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8299 grammar
= schema
->topgrammar
;
8300 if ((grammar
== NULL
) || (grammar
->start
== NULL
)) {
8301 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8304 define
= grammar
->start
;
8305 if (define
->contModel
== NULL
) {
8306 ctxt
->pdef
= define
;
8309 exec
= xmlRegNewExecCtxt(define
->contModel
,
8310 xmlRelaxNGValidateProgressiveCallback
,
8315 xmlRelaxNGElemPush(ctxt
, exec
);
8319 if (elem
->ns
!= NULL
) {
8321 xmlRegExecPushString2(ctxt
->elem
, elem
->name
, elem
->ns
->href
,
8324 ret
= xmlRegExecPushString(ctxt
->elem
, elem
->name
, ctxt
);
8327 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, elem
->name
);
8329 if (ctxt
->pstate
== 0)
8331 else if (ctxt
->pstate
< 0)
8336 #ifdef DEBUG_PROGRESSIVE
8338 xmlGenericError(xmlGenericErrorContext
, "PushElem %s failed\n",
8345 * xmlRelaxNGValidatePushCData:
8346 * @ctxt: the RelaxNG validation context
8347 * @data: some character data read
8348 * @len: the lenght of the data
8350 * check the CData parsed for validation in the current stack
8352 * returns 1 if no validation problem was found or -1 otherwise
8355 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt
,
8356 const xmlChar
* data
, int len ATTRIBUTE_UNUSED
)
8360 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (data
== NULL
))
8363 #ifdef DEBUG_PROGRESSIVE
8364 xmlGenericError(xmlGenericErrorContext
, "CDATA %s %d\n", data
, len
);
8367 while (*data
!= 0) {
8368 if (!IS_BLANK_CH(*data
))
8375 ret
= xmlRegExecPushString(ctxt
->elem
, BAD_CAST
"#text", ctxt
);
8377 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
, BAD_CAST
" TODO ");
8378 #ifdef DEBUG_PROGRESSIVE
8379 xmlGenericError(xmlGenericErrorContext
, "CDATA failed\n");
8388 * xmlRelaxNGValidatePopElement:
8389 * @ctxt: the RelaxNG validation context
8390 * @doc: a document instance
8391 * @elem: an element instance
8393 * Pop the element end from the RelaxNG validation stack.
8395 * returns 1 if no validation problem was found or 0 otherwise
8398 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt
,
8399 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8403 xmlRegExecCtxtPtr exec
;
8405 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (elem
== NULL
))
8407 #ifdef DEBUG_PROGRESSIVE
8408 xmlGenericError(xmlGenericErrorContext
, "PopElem %s\n", elem
->name
);
8411 * verify that we reached a terminal state of the content model.
8413 exec
= xmlRelaxNGElemPop(ctxt
);
8414 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8417 * TODO: get some of the names needed to exit the current state of exec
8419 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8421 } else if (ret
< 0) {
8426 xmlRegFreeExecCtxt(exec
);
8427 #ifdef DEBUG_PROGRESSIVE
8429 xmlGenericError(xmlGenericErrorContext
, "PopElem %s failed\n",
8436 * xmlRelaxNGValidateFullElement:
8437 * @ctxt: the validation context
8438 * @doc: a document instance
8439 * @elem: an element instance
8441 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8442 * 0 and the content of the node has been expanded.
8444 * returns 1 if no validation problem was found or -1 in case of error.
8447 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt
,
8448 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8452 xmlRelaxNGValidStatePtr state
;
8454 if ((ctxt
== NULL
) || (ctxt
->pdef
== NULL
) || (elem
== NULL
))
8456 #ifdef DEBUG_PROGRESSIVE
8457 xmlGenericError(xmlGenericErrorContext
, "FullElem %s\n", elem
->name
);
8459 state
= xmlRelaxNGNewValidState(ctxt
, elem
->parent
);
8460 if (state
== NULL
) {
8464 ctxt
->state
= state
;
8465 ctxt
->errNo
= XML_RELAXNG_OK
;
8466 ret
= xmlRelaxNGValidateDefinition(ctxt
, ctxt
->pdef
);
8467 if ((ret
!= 0) || (ctxt
->errNo
!= XML_RELAXNG_OK
))
8471 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8473 #ifdef DEBUG_PROGRESSIVE
8475 xmlGenericError(xmlGenericErrorContext
, "FullElem %s failed\n",
8481 /************************************************************************
8483 * Generic interpreted validation implementation *
8485 ************************************************************************/
8486 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8487 xmlRelaxNGDefinePtr define
);
8490 * xmlRelaxNGSkipIgnored:
8491 * @ctxt: a schema validation context
8492 * @node: the top node.
8494 * Skip ignorable nodes in that context
8496 * Returns the new sibling or NULL in case of error.
8499 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
8503 * TODO complete and handle entities
8505 while ((node
!= NULL
) &&
8506 ((node
->type
== XML_COMMENT_NODE
) ||
8507 (node
->type
== XML_PI_NODE
) ||
8508 (node
->type
== XML_XINCLUDE_START
) ||
8509 (node
->type
== XML_XINCLUDE_END
) ||
8510 (((node
->type
== XML_TEXT_NODE
) ||
8511 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
8512 ((ctxt
->flags
& FLAGS_MIXED_CONTENT
) ||
8513 (IS_BLANK_NODE(node
)))))) {
8520 * xmlRelaxNGNormalize:
8521 * @ctxt: a schema validation context
8522 * @str: the string to normalize
8524 * Implements the normalizeWhiteSpace( s ) function from
8525 * section 6.2.9 of the spec
8527 * Returns the new string or NULL in case of error.
8530 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
, const xmlChar
* str
)
8543 ret
= (xmlChar
*) xmlMallocAtomic((len
+ 1) * sizeof(xmlChar
));
8545 xmlRngVErrMemory(ctxt
, "validating\n");
8549 while (IS_BLANK_CH(*str
))
8552 if (IS_BLANK_CH(*str
)) {
8553 while (IS_BLANK_CH(*str
))
8566 * xmlRelaxNGValidateDatatype:
8567 * @ctxt: a Relax-NG validation context
8568 * @value: the string value
8569 * @type: the datatype definition
8572 * Validate the given value against the dataype
8574 * Returns 0 if the validation succeeded or an error code.
8577 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt
,
8578 const xmlChar
* value
,
8579 xmlRelaxNGDefinePtr define
, xmlNodePtr node
)
8582 xmlRelaxNGTypeLibraryPtr lib
;
8583 void *result
= NULL
;
8584 xmlRelaxNGDefinePtr cur
;
8586 if ((define
== NULL
) || (define
->data
== NULL
)) {
8589 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8590 if (lib
->check
!= NULL
) {
8591 if ((define
->attrs
!= NULL
) &&
8592 (define
->attrs
->type
== XML_RELAXNG_PARAM
)) {
8594 lib
->check(lib
->data
, define
->name
, value
, &result
, node
);
8596 ret
= lib
->check(lib
->data
, define
->name
, value
, NULL
, node
);
8601 VALID_ERR2(XML_RELAXNG_ERR_TYPE
, define
->name
);
8602 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8603 lib
->freef(lib
->data
, result
);
8605 } else if (ret
== 1) {
8607 } else if (ret
== 2) {
8608 VALID_ERR2P(XML_RELAXNG_ERR_DUPID
, value
);
8610 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL
, define
->name
, value
);
8613 cur
= define
->attrs
;
8614 while ((ret
== 0) && (cur
!= NULL
) && (cur
->type
== XML_RELAXNG_PARAM
)) {
8615 if (lib
->facet
!= NULL
) {
8616 tmp
= lib
->facet(lib
->data
, define
->name
, cur
->name
,
8617 cur
->value
, value
, result
);
8623 if ((ret
== 0) && (define
->content
!= NULL
)) {
8624 const xmlChar
*oldvalue
, *oldendvalue
;
8626 oldvalue
= ctxt
->state
->value
;
8627 oldendvalue
= ctxt
->state
->endvalue
;
8628 ctxt
->state
->value
= (xmlChar
*) value
;
8629 ctxt
->state
->endvalue
= NULL
;
8630 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8631 ctxt
->state
->value
= (xmlChar
*) oldvalue
;
8632 ctxt
->state
->endvalue
= (xmlChar
*) oldendvalue
;
8634 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8635 lib
->freef(lib
->data
, result
);
8640 * xmlRelaxNGNextValue:
8641 * @ctxt: a Relax-NG validation context
8643 * Skip to the next value when validating within a list
8645 * Returns 0 if the operation succeeded or an error code.
8648 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt
)
8652 cur
= ctxt
->state
->value
;
8653 if ((cur
== NULL
) || (ctxt
->state
->endvalue
== NULL
)) {
8654 ctxt
->state
->value
= NULL
;
8655 ctxt
->state
->endvalue
= NULL
;
8660 while ((cur
!= ctxt
->state
->endvalue
) && (*cur
== 0))
8662 if (cur
== ctxt
->state
->endvalue
)
8663 ctxt
->state
->value
= NULL
;
8665 ctxt
->state
->value
= cur
;
8670 * xmlRelaxNGValidateValueList:
8671 * @ctxt: a Relax-NG validation context
8672 * @defines: the list of definitions to verify
8674 * Validate the given set of definitions for the current value
8676 * Returns 0 if the validation succeeded or an error code.
8679 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt
,
8680 xmlRelaxNGDefinePtr defines
)
8684 while (defines
!= NULL
) {
8685 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
8688 defines
= defines
->next
;
8694 * xmlRelaxNGValidateValue:
8695 * @ctxt: a Relax-NG validation context
8696 * @define: the definition to verify
8698 * Validate the given definition for the current value
8700 * Returns 0 if the validation succeeded or an error code.
8703 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8704 xmlRelaxNGDefinePtr define
)
8706 int ret
= 0, oldflags
;
8709 value
= ctxt
->state
->value
;
8710 switch (define
->type
) {
8711 case XML_RELAXNG_EMPTY
:{
8712 if ((value
!= NULL
) && (value
[0] != 0)) {
8715 while (IS_BLANK_CH(value
[idx
]))
8717 if (value
[idx
] != 0)
8722 case XML_RELAXNG_TEXT
:
8724 case XML_RELAXNG_VALUE
:{
8725 if (!xmlStrEqual(value
, define
->value
)) {
8726 if (define
->name
!= NULL
) {
8727 xmlRelaxNGTypeLibraryPtr lib
;
8729 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8730 if ((lib
!= NULL
) && (lib
->comp
!= NULL
)) {
8731 ret
= lib
->comp(lib
->data
, define
->name
,
8732 define
->value
, define
->node
,
8733 (void *) define
->attrs
,
8734 value
, ctxt
->state
->node
);
8738 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP
,
8741 } else if (ret
== 1) {
8747 xmlChar
*nval
, *nvalue
;
8750 * TODO: trivial optimizations are possible by
8751 * computing at compile-time
8753 nval
= xmlRelaxNGNormalize(ctxt
, define
->value
);
8754 nvalue
= xmlRelaxNGNormalize(ctxt
, value
);
8756 if ((nval
== NULL
) || (nvalue
== NULL
) ||
8757 (!xmlStrEqual(nval
, nvalue
)))
8766 xmlRelaxNGNextValue(ctxt
);
8769 case XML_RELAXNG_DATATYPE
:{
8770 ret
= xmlRelaxNGValidateDatatype(ctxt
, value
, define
,
8773 xmlRelaxNGNextValue(ctxt
);
8777 case XML_RELAXNG_CHOICE
:{
8778 xmlRelaxNGDefinePtr list
= define
->content
;
8781 oldflags
= ctxt
->flags
;
8782 ctxt
->flags
|= FLAGS_IGNORABLE
;
8784 oldvalue
= ctxt
->state
->value
;
8785 while (list
!= NULL
) {
8786 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8790 ctxt
->state
->value
= oldvalue
;
8793 ctxt
->flags
= oldflags
;
8795 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8796 xmlRelaxNGDumpValidError(ctxt
);
8798 if (ctxt
->errNr
> 0)
8799 xmlRelaxNGPopErrors(ctxt
, 0);
8803 case XML_RELAXNG_LIST
:{
8804 xmlRelaxNGDefinePtr list
= define
->content
;
8805 xmlChar
*oldvalue
, *oldend
, *val
, *cur
;
8811 oldvalue
= ctxt
->state
->value
;
8812 oldend
= ctxt
->state
->endvalue
;
8814 val
= xmlStrdup(oldvalue
);
8816 val
= xmlStrdup(BAD_CAST
"");
8819 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
8824 if (IS_BLANK_CH(*cur
)) {
8830 while (IS_BLANK_CH(*cur
))
8836 xmlGenericError(xmlGenericErrorContext
,
8837 "list value: '%s' found %d items\n",
8838 oldvalue
, nb_values
);
8841 ctxt
->state
->endvalue
= cur
;
8843 while ((*cur
== 0) && (cur
!= ctxt
->state
->endvalue
))
8846 ctxt
->state
->value
= cur
;
8848 while (list
!= NULL
) {
8849 if (ctxt
->state
->value
== ctxt
->state
->endvalue
)
8850 ctxt
->state
->value
= NULL
;
8851 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8854 xmlGenericError(xmlGenericErrorContext
,
8855 "Failed to validate value: '%s' with %d rule\n",
8856 ctxt
->state
->value
, nb_values
);
8866 if ((ret
== 0) && (ctxt
->state
->value
!= NULL
) &&
8867 (ctxt
->state
->value
!= ctxt
->state
->endvalue
)) {
8868 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA
,
8869 ctxt
->state
->value
);
8873 ctxt
->state
->value
= oldvalue
;
8874 ctxt
->state
->endvalue
= oldend
;
8877 case XML_RELAXNG_ONEORMORE
:
8878 ret
= xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8882 /* no break on purpose */
8883 case XML_RELAXNG_ZEROORMORE
:{
8884 xmlChar
*cur
, *temp
;
8886 oldflags
= ctxt
->flags
;
8887 ctxt
->flags
|= FLAGS_IGNORABLE
;
8888 cur
= ctxt
->state
->value
;
8890 while ((cur
!= NULL
) && (cur
!= ctxt
->state
->endvalue
) &&
8894 xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8896 ctxt
->state
->value
= temp
;
8900 cur
= ctxt
->state
->value
;
8902 ctxt
->flags
= oldflags
;
8903 if (ctxt
->errNr
> 0)
8904 xmlRelaxNGPopErrors(ctxt
, 0);
8907 case XML_RELAXNG_EXCEPT
:{
8908 xmlRelaxNGDefinePtr list
;
8910 list
= define
->content
;
8911 while (list
!= NULL
) {
8912 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8922 case XML_RELAXNG_DEF
:
8923 case XML_RELAXNG_GROUP
:{
8924 xmlRelaxNGDefinePtr list
;
8926 list
= define
->content
;
8927 while (list
!= NULL
) {
8928 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8938 case XML_RELAXNG_REF
:
8939 case XML_RELAXNG_PARENTREF
:
8940 if (define
->content
== NULL
) {
8941 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
8944 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8954 * xmlRelaxNGValidateValueContent:
8955 * @ctxt: a Relax-NG validation context
8956 * @defines: the list of definitions to verify
8958 * Validate the given definitions for the current value
8960 * Returns 0 if the validation succeeded or an error code.
8963 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt
,
8964 xmlRelaxNGDefinePtr defines
)
8968 while (defines
!= NULL
) {
8969 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
8972 defines
= defines
->next
;
8978 * xmlRelaxNGAttributeMatch:
8979 * @ctxt: a Relax-NG validation context
8980 * @define: the definition to check
8981 * @prop: the attribute
8983 * Check if the attribute matches the definition nameClass
8985 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8988 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt
,
8989 xmlRelaxNGDefinePtr define
, xmlAttrPtr prop
)
8993 if (define
->name
!= NULL
) {
8994 if (!xmlStrEqual(define
->name
, prop
->name
))
8997 if (define
->ns
!= NULL
) {
8998 if (define
->ns
[0] == 0) {
8999 if (prop
->ns
!= NULL
)
9002 if ((prop
->ns
== NULL
) ||
9003 (!xmlStrEqual(define
->ns
, prop
->ns
->href
)))
9007 if (define
->nameClass
== NULL
)
9009 define
= define
->nameClass
;
9010 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9011 xmlRelaxNGDefinePtr list
;
9013 list
= define
->content
;
9014 while (list
!= NULL
) {
9015 ret
= xmlRelaxNGAttributeMatch(ctxt
, list
, prop
);
9028 * xmlRelaxNGValidateAttribute:
9029 * @ctxt: a Relax-NG validation context
9030 * @define: the definition to verify
9032 * Validate the given attribute definition for that node
9034 * Returns 0 if the validation succeeded or an error code.
9037 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt
,
9038 xmlRelaxNGDefinePtr define
)
9041 xmlChar
*value
, *oldvalue
;
9042 xmlAttrPtr prop
= NULL
, tmp
;
9045 if (ctxt
->state
->nbAttrLeft
<= 0)
9047 if (define
->name
!= NULL
) {
9048 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9049 tmp
= ctxt
->state
->attrs
[i
];
9050 if ((tmp
!= NULL
) && (xmlStrEqual(define
->name
, tmp
->name
))) {
9051 if ((((define
->ns
== NULL
) || (define
->ns
[0] == 0)) &&
9052 (tmp
->ns
== NULL
)) ||
9053 ((tmp
->ns
!= NULL
) &&
9054 (xmlStrEqual(define
->ns
, tmp
->ns
->href
)))) {
9061 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9062 oldvalue
= ctxt
->state
->value
;
9063 oldseq
= ctxt
->state
->seq
;
9064 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9065 ctxt
->state
->value
= value
;
9066 ctxt
->state
->endvalue
= NULL
;
9067 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9068 if (ctxt
->state
->value
!= NULL
)
9069 value
= ctxt
->state
->value
;
9072 ctxt
->state
->value
= oldvalue
;
9073 ctxt
->state
->seq
= oldseq
;
9076 * flag the attribute as processed
9078 ctxt
->state
->attrs
[i
] = NULL
;
9079 ctxt
->state
->nbAttrLeft
--;
9085 xmlGenericError(xmlGenericErrorContext
,
9086 "xmlRelaxNGValidateAttribute(%s): %d\n",
9090 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9091 tmp
= ctxt
->state
->attrs
[i
];
9092 if ((tmp
!= NULL
) &&
9093 (xmlRelaxNGAttributeMatch(ctxt
, define
, tmp
) == 1)) {
9099 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9100 oldvalue
= ctxt
->state
->value
;
9101 oldseq
= ctxt
->state
->seq
;
9102 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9103 ctxt
->state
->value
= value
;
9104 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9105 if (ctxt
->state
->value
!= NULL
)
9106 value
= ctxt
->state
->value
;
9109 ctxt
->state
->value
= oldvalue
;
9110 ctxt
->state
->seq
= oldseq
;
9113 * flag the attribute as processed
9115 ctxt
->state
->attrs
[i
] = NULL
;
9116 ctxt
->state
->nbAttrLeft
--;
9122 if (define
->ns
!= NULL
) {
9123 xmlGenericError(xmlGenericErrorContext
,
9124 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9127 xmlGenericError(xmlGenericErrorContext
,
9128 "xmlRelaxNGValidateAttribute(anyName): %d\n",
9138 * xmlRelaxNGValidateAttributeList:
9139 * @ctxt: a Relax-NG validation context
9140 * @define: the list of definition to verify
9142 * Validate the given node against the list of attribute definitions
9144 * Returns 0 if the validation succeeded or an error code.
9147 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
9148 xmlRelaxNGDefinePtr defines
)
9152 xmlRelaxNGDefinePtr cur
;
9155 while (cur
!= NULL
) {
9156 if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
9157 if (xmlRelaxNGValidateAttribute(ctxt
, cur
) != 0)
9166 while (cur
!= NULL
) {
9167 if (cur
->type
!= XML_RELAXNG_ATTRIBUTE
) {
9168 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9169 res
= xmlRelaxNGValidateDefinition(ctxt
, cur
);
9173 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9176 if (res
== -1) /* continues on -2 */
9186 * xmlRelaxNGNodeMatchesList:
9188 * @list: a NULL terminated array of definitions
9190 * Check if a node can be matched by one of the definitions
9192 * Returns 1 if matches 0 otherwise
9195 xmlRelaxNGNodeMatchesList(xmlNodePtr node
, xmlRelaxNGDefinePtr
* list
)
9197 xmlRelaxNGDefinePtr cur
;
9200 if ((node
== NULL
) || (list
== NULL
))
9204 while (cur
!= NULL
) {
9205 if ((node
->type
== XML_ELEMENT_NODE
) &&
9206 (cur
->type
== XML_RELAXNG_ELEMENT
)) {
9207 tmp
= xmlRelaxNGElementMatch(NULL
, cur
, node
);
9210 } else if (((node
->type
== XML_TEXT_NODE
) ||
9211 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
9212 (cur
->type
== XML_RELAXNG_TEXT
)) {
9221 * xmlRelaxNGValidateInterleave:
9222 * @ctxt: a Relax-NG validation context
9223 * @define: the definition to verify
9225 * Validate an interleave definition for a node.
9227 * Returns 0 if the validation succeeded or an error code.
9230 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt
,
9231 xmlRelaxNGDefinePtr define
)
9233 int ret
= 0, i
, nbgroups
;
9234 int errNr
= ctxt
->errNr
;
9237 xmlRelaxNGValidStatePtr oldstate
;
9238 xmlRelaxNGPartitionPtr partitions
;
9239 xmlRelaxNGInterleaveGroupPtr group
= NULL
;
9240 xmlNodePtr cur
, start
, last
= NULL
, lastchg
= NULL
, lastelem
;
9241 xmlNodePtr
*list
= NULL
, *lasts
= NULL
;
9243 if (define
->data
!= NULL
) {
9244 partitions
= (xmlRelaxNGPartitionPtr
) define
->data
;
9245 nbgroups
= partitions
->nbgroups
;
9247 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA
);
9251 * Optimizations for MIXED
9253 oldflags
= ctxt
->flags
;
9254 if (define
->dflags
& IS_MIXED
) {
9255 ctxt
->flags
|= FLAGS_MIXED_CONTENT
;
9256 if (nbgroups
== 2) {
9258 * this is a pure <mixed> case
9260 if (ctxt
->state
!= NULL
)
9261 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9263 if (partitions
->groups
[0]->rule
->type
== XML_RELAXNG_TEXT
)
9264 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9265 partitions
->groups
[1]->
9268 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9269 partitions
->groups
[0]->
9272 if (ctxt
->state
!= NULL
)
9273 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9277 ctxt
->flags
= oldflags
;
9283 * Build arrays to store the first and last node of the chain
9284 * pertaining to each group
9286 list
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9288 xmlRngVErrMemory(ctxt
, "validating\n");
9291 memset(list
, 0, nbgroups
* sizeof(xmlNodePtr
));
9292 lasts
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9293 if (lasts
== NULL
) {
9294 xmlRngVErrMemory(ctxt
, "validating\n");
9297 memset(lasts
, 0, nbgroups
* sizeof(xmlNodePtr
));
9300 * Walk the sequence of children finding the right group and
9301 * sorting them in sequences.
9303 cur
= ctxt
->state
->seq
;
9304 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9306 while (cur
!= NULL
) {
9307 ctxt
->state
->seq
= cur
;
9308 if ((partitions
->triage
!= NULL
) &&
9309 (partitions
->flags
& IS_DETERMINIST
)) {
9312 if ((cur
->type
== XML_TEXT_NODE
) ||
9313 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
9314 tmp
= xmlHashLookup2(partitions
->triage
, BAD_CAST
"#text",
9316 } else if (cur
->type
== XML_ELEMENT_NODE
) {
9317 if (cur
->ns
!= NULL
) {
9318 tmp
= xmlHashLookup2(partitions
->triage
, cur
->name
,
9321 tmp
= xmlHashLookup2(partitions
->triage
,
9326 xmlHashLookup2(partitions
->triage
, cur
->name
,
9330 xmlHashLookup2(partitions
->triage
, BAD_CAST
"#any",
9337 i
= ((long) tmp
) - 1;
9338 if (partitions
->flags
& IS_NEEDCHECK
) {
9339 group
= partitions
->groups
[i
];
9340 if (!xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9345 for (i
= 0; i
< nbgroups
; i
++) {
9346 group
= partitions
->groups
[i
];
9349 if (xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9354 * We break as soon as an element not matched is found
9356 if (i
>= nbgroups
) {
9359 if (lasts
[i
] != NULL
) {
9360 lasts
[i
]->next
= cur
;
9366 if (cur
->next
!= NULL
)
9367 lastchg
= cur
->next
;
9370 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
->next
);
9373 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9378 oldstate
= ctxt
->state
;
9379 for (i
= 0; i
< nbgroups
; i
++) {
9380 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
, oldstate
);
9381 group
= partitions
->groups
[i
];
9382 if (lasts
[i
] != NULL
) {
9383 last
= lasts
[i
]->next
;
9384 lasts
[i
]->next
= NULL
;
9386 ctxt
->state
->seq
= list
[i
];
9387 ret
= xmlRelaxNGValidateDefinition(ctxt
, group
->rule
);
9390 if (ctxt
->state
!= NULL
) {
9391 cur
= ctxt
->state
->seq
;
9392 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9393 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9394 oldstate
= ctxt
->state
;
9397 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9399 ctxt
->state
= oldstate
;
9402 } else if (ctxt
->states
!= NULL
) {
9409 * PBM: what happen if there is attributes checks in the interleaves
9412 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9413 cur
= ctxt
->states
->tabState
[j
]->seq
;
9414 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9417 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9421 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9422 /* try to keep the latest one to mach old heuristic */
9423 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9428 } else if (found
== 0) {
9429 if (lowattr
== -1) {
9430 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9433 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9434 /* try to keep the latest one to mach old heuristic */
9435 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9441 * BIG PBM: here we pick only one restarting point :-(
9443 if (ctxt
->states
->nbState
> 0) {
9444 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9446 oldstate
= ctxt
->states
->tabState
[best
];
9447 ctxt
->states
->tabState
[best
] = NULL
;
9450 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1];
9451 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1] = NULL
;
9452 ctxt
->states
->nbState
--;
9455 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9456 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[j
]);
9458 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
9459 ctxt
->states
= NULL
;
9462 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, "noname");
9464 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9467 ctxt
->state
= oldstate
;
9474 if (lasts
[i
] != NULL
) {
9475 lasts
[i
]->next
= last
;
9478 if (ctxt
->state
!= NULL
)
9479 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
9480 ctxt
->state
= oldstate
;
9481 ctxt
->state
->seq
= lastelem
;
9483 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9489 ctxt
->flags
= oldflags
;
9491 * builds the next links chain from the prev one
9494 while (cur
!= NULL
) {
9495 if ((cur
== start
) || (cur
->prev
== NULL
))
9497 cur
->prev
->next
= cur
;
9501 if (ctxt
->errNr
> errNr
)
9502 xmlRelaxNGPopErrors(ctxt
, errNr
);
9511 * xmlRelaxNGValidateDefinitionList:
9512 * @ctxt: a Relax-NG validation context
9513 * @define: the list of definition to verify
9515 * Validate the given node content against the (list) of definitions
9517 * Returns 0 if the validation succeeded or an error code.
9520 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt
,
9521 xmlRelaxNGDefinePtr defines
)
9526 if (defines
== NULL
) {
9527 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL
,
9528 BAD_CAST
"NULL definition list");
9531 while (defines
!= NULL
) {
9532 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9533 res
= xmlRelaxNGValidateDefinition(ctxt
, defines
);
9537 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9540 if (res
== -1) /* continues on -2 */
9542 defines
= defines
->next
;
9549 * xmlRelaxNGElementMatch:
9550 * @ctxt: a Relax-NG validation context
9551 * @define: the definition to check
9552 * @elem: the element
9554 * Check if the element matches the definition nameClass
9556 * Returns 1 if the element matches, 0 if no, or -1 in case of error
9559 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
9560 xmlRelaxNGDefinePtr define
, xmlNodePtr elem
)
9562 int ret
= 0, oldflags
= 0;
9564 if (define
->name
!= NULL
) {
9565 if (!xmlStrEqual(elem
->name
, define
->name
)) {
9566 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME
, define
->name
, elem
->name
);
9570 if ((define
->ns
!= NULL
) && (define
->ns
[0] != 0)) {
9571 if (elem
->ns
== NULL
) {
9572 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS
, elem
->name
);
9574 } else if (!xmlStrEqual(elem
->ns
->href
, define
->ns
)) {
9575 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS
,
9576 elem
->name
, define
->ns
);
9579 } else if ((elem
->ns
!= NULL
) && (define
->ns
!= NULL
) &&
9580 (define
->name
== NULL
)) {
9581 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, elem
->name
);
9583 } else if ((elem
->ns
!= NULL
) && (define
->name
!= NULL
)) {
9584 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, define
->name
);
9588 if (define
->nameClass
== NULL
)
9591 define
= define
->nameClass
;
9592 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9593 xmlRelaxNGDefinePtr list
;
9596 oldflags
= ctxt
->flags
;
9597 ctxt
->flags
|= FLAGS_IGNORABLE
;
9600 list
= define
->content
;
9601 while (list
!= NULL
) {
9602 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9605 ctxt
->flags
= oldflags
;
9610 ctxt
->flags
= oldflags
;
9617 ctxt
->flags
= oldflags
;
9619 } else if (define
->type
== XML_RELAXNG_CHOICE
) {
9620 xmlRelaxNGDefinePtr list
;
9623 oldflags
= ctxt
->flags
;
9624 ctxt
->flags
|= FLAGS_IGNORABLE
;
9627 list
= define
->nameClass
;
9628 while (list
!= NULL
) {
9629 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9632 ctxt
->flags
= oldflags
;
9637 ctxt
->flags
= oldflags
;
9644 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9645 xmlRelaxNGDumpValidError(ctxt
);
9647 if (ctxt
->errNr
> 0)
9648 xmlRelaxNGPopErrors(ctxt
, 0);
9653 ctxt
->flags
= oldflags
;
9662 * xmlRelaxNGBestState:
9663 * @ctxt: a Relax-NG validation context
9665 * Find the "best" state in the ctxt->states list of states to report
9666 * errors about. I.e. a state with no element left in the child list
9667 * or the one with the less attributes left.
9668 * This is called only if a falidation error was detected
9670 * Returns the index of the "best" state or -1 in case of error
9673 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt
)
9675 xmlRelaxNGValidStatePtr state
;
9678 int value
= 1000000;
9680 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9681 (ctxt
->states
->nbState
<= 0))
9684 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9685 state
= ctxt
->states
->tabState
[i
];
9688 if (state
->seq
!= NULL
) {
9689 if ((best
== -1) || (value
> 100000)) {
9694 tmp
= state
->nbAttrLeft
;
9695 if ((best
== -1) || (value
> tmp
)) {
9705 * xmlRelaxNGLogBestError:
9706 * @ctxt: a Relax-NG validation context
9708 * Find the "best" state in the ctxt->states list of states to report
9709 * errors about and log it.
9712 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
)
9716 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9717 (ctxt
->states
->nbState
<= 0))
9720 best
= xmlRelaxNGBestState(ctxt
);
9721 if ((best
>= 0) && (best
< ctxt
->states
->nbState
)) {
9722 ctxt
->state
= ctxt
->states
->tabState
[best
];
9724 xmlRelaxNGValidateElementEnd(ctxt
, 1);
9729 * xmlRelaxNGValidateElementEnd:
9730 * @ctxt: a Relax-NG validation context
9731 * @dolog: indicate that error logging should be done
9733 * Validate the end of the element, implements check that
9734 * there is nothing left not consumed in the element content
9735 * or in the attribute list.
9737 * Returns 0 if the validation succeeded or an error code.
9740 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
, int dolog
)
9743 xmlRelaxNGValidStatePtr state
;
9745 state
= ctxt
->state
;
9746 if (state
->seq
!= NULL
) {
9747 state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, state
->seq
);
9748 if (state
->seq
!= NULL
) {
9750 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT
,
9751 state
->node
->name
, state
->seq
->name
);
9756 for (i
= 0; i
< state
->nbAttrs
; i
++) {
9757 if (state
->attrs
[i
] != NULL
) {
9759 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR
,
9760 state
->attrs
[i
]->name
, state
->node
->name
);
9769 * xmlRelaxNGValidateState:
9770 * @ctxt: a Relax-NG validation context
9771 * @define: the definition to verify
9773 * Validate the current state against the definition
9775 * Returns 0 if the validation succeeded or an error code.
9778 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt
,
9779 xmlRelaxNGDefinePtr define
)
9782 int ret
= 0, i
, tmp
, oldflags
, errNr
;
9783 xmlRelaxNGValidStatePtr oldstate
= NULL
, state
;
9785 if (define
== NULL
) {
9786 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
9790 if (ctxt
->state
!= NULL
) {
9791 node
= ctxt
->state
->seq
;
9796 for (i
= 0; i
< ctxt
->depth
; i
++)
9797 xmlGenericError(xmlGenericErrorContext
, " ");
9798 xmlGenericError(xmlGenericErrorContext
,
9799 "Start validating %s ", xmlRelaxNGDefName(define
));
9800 if (define
->name
!= NULL
)
9801 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
9802 if ((node
!= NULL
) && (node
->name
!= NULL
))
9803 xmlGenericError(xmlGenericErrorContext
, "on %s\n", node
->name
);
9805 xmlGenericError(xmlGenericErrorContext
, "\n");
9808 switch (define
->type
) {
9809 case XML_RELAXNG_EMPTY
:
9810 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
9813 case XML_RELAXNG_NOT_ALLOWED
:
9816 case XML_RELAXNG_TEXT
:
9817 while ((node
!= NULL
) &&
9818 ((node
->type
== XML_TEXT_NODE
) ||
9819 (node
->type
== XML_COMMENT_NODE
) ||
9820 (node
->type
== XML_PI_NODE
) ||
9821 (node
->type
== XML_CDATA_SECTION_NODE
)))
9823 ctxt
->state
->seq
= node
;
9825 case XML_RELAXNG_ELEMENT
:
9826 errNr
= ctxt
->errNr
;
9827 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
9829 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, define
->name
);
9831 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9832 xmlRelaxNGDumpValidError(ctxt
);
9835 if (node
->type
!= XML_ELEMENT_NODE
) {
9836 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
9838 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9839 xmlRelaxNGDumpValidError(ctxt
);
9843 * This node was already validated successfully against
9846 if (node
->psvi
== define
) {
9847 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
9848 if (ctxt
->errNr
> errNr
)
9849 xmlRelaxNGPopErrors(ctxt
, errNr
);
9850 if (ctxt
->errNr
!= 0) {
9851 while ((ctxt
->err
!= NULL
) &&
9852 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
)
9853 && (xmlStrEqual(ctxt
->err
->arg2
, node
->name
)))
9856 XML_RELAXNG_ERR_ELEMEXTRANS
)
9857 && (xmlStrEqual(ctxt
->err
->arg1
, node
->name
)))
9858 || (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
)
9859 || (ctxt
->err
->err
==
9860 XML_RELAXNG_ERR_NOTELEM
)))
9861 xmlRelaxNGValidErrorPop(ctxt
);
9866 ret
= xmlRelaxNGElementMatch(ctxt
, define
, node
);
9869 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9870 xmlRelaxNGDumpValidError(ctxt
);
9874 if (ctxt
->errNr
!= 0) {
9875 if (ctxt
->errNr
> errNr
)
9876 xmlRelaxNGPopErrors(ctxt
, errNr
);
9877 while ((ctxt
->err
!= NULL
) &&
9878 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
) &&
9879 (xmlStrEqual(ctxt
->err
->arg2
, node
->name
))) ||
9880 ((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMEXTRANS
) &&
9881 (xmlStrEqual(ctxt
->err
->arg1
, node
->name
))) ||
9882 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
) ||
9883 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOTELEM
)))
9884 xmlRelaxNGValidErrorPop(ctxt
);
9886 errNr
= ctxt
->errNr
;
9888 oldflags
= ctxt
->flags
;
9889 if (ctxt
->flags
& FLAGS_MIXED_CONTENT
) {
9890 ctxt
->flags
-= FLAGS_MIXED_CONTENT
;
9892 state
= xmlRelaxNGNewValidState(ctxt
, node
);
9893 if (state
== NULL
) {
9895 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9896 xmlRelaxNGDumpValidError(ctxt
);
9900 oldstate
= ctxt
->state
;
9901 ctxt
->state
= state
;
9902 if (define
->attrs
!= NULL
) {
9903 tmp
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
9906 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
9909 if (define
->contModel
!= NULL
) {
9910 xmlRelaxNGValidStatePtr nstate
, tmpstate
= ctxt
->state
;
9911 xmlRelaxNGStatesPtr tmpstates
= ctxt
->states
;
9914 nstate
= xmlRelaxNGNewValidState(ctxt
, node
);
9915 ctxt
->state
= nstate
;
9916 ctxt
->states
= NULL
;
9918 tmp
= xmlRelaxNGValidateCompiledContent(ctxt
,
9921 nseq
= ctxt
->state
->seq
;
9922 ctxt
->state
= tmpstate
;
9923 ctxt
->states
= tmpstates
;
9924 xmlRelaxNGFreeValidState(ctxt
, nstate
);
9926 #ifdef DEBUG_COMPILE
9927 xmlGenericError(xmlGenericErrorContext
,
9928 "Validating content of '%s' : %d\n",
9934 if (ctxt
->states
!= NULL
) {
9937 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9938 state
= ctxt
->states
->tabState
[i
];
9939 ctxt
->state
= state
;
9940 ctxt
->state
->seq
= nseq
;
9942 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
9949 * validation error, log the message for the "best" one
9951 ctxt
->flags
|= FLAGS_IGNORABLE
;
9952 xmlRelaxNGLogBestError(ctxt
);
9954 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9955 xmlRelaxNGFreeValidState(ctxt
,
9959 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
9960 ctxt
->flags
= oldflags
;
9961 ctxt
->states
= NULL
;
9962 if ((ret
== 0) && (tmp
== -1))
9965 state
= ctxt
->state
;
9966 if (ctxt
->state
!= NULL
)
9967 ctxt
->state
->seq
= nseq
;
9969 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
9970 xmlRelaxNGFreeValidState(ctxt
, state
);
9973 if (define
->content
!= NULL
) {
9974 tmp
= xmlRelaxNGValidateDefinitionList(ctxt
,
9979 if (ctxt
->state
== NULL
) {
9980 ctxt
->state
= oldstate
;
9981 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
9985 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
9991 if (ctxt
->states
!= NULL
) {
9994 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9995 state
= ctxt
->states
->tabState
[i
];
9996 ctxt
->state
= state
;
9998 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
10005 * validation error, log the message for the "best" one
10007 ctxt
->flags
|= FLAGS_IGNORABLE
;
10008 xmlRelaxNGLogBestError(ctxt
);
10010 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10011 xmlRelaxNGFreeValidState(ctxt
,
10012 ctxt
->states
->tabState
[i
]);
10013 ctxt
->states
->tabState
[i
] = NULL
;
10015 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10016 ctxt
->flags
= oldflags
;
10017 ctxt
->states
= NULL
;
10018 if ((ret
== 0) && (tmp
== -1))
10021 state
= ctxt
->state
;
10023 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
10024 xmlRelaxNGFreeValidState(ctxt
, state
);
10028 node
->psvi
= define
;
10030 ctxt
->flags
= oldflags
;
10031 ctxt
->state
= oldstate
;
10032 if (oldstate
!= NULL
)
10033 oldstate
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
10035 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10036 xmlRelaxNGDumpValidError(ctxt
);
10044 if (ctxt
->errNr
> errNr
)
10045 xmlRelaxNGPopErrors(ctxt
, errNr
);
10049 xmlGenericError(xmlGenericErrorContext
,
10050 "xmlRelaxNGValidateDefinition(): validated %s : %d",
10052 if (oldstate
== NULL
)
10053 xmlGenericError(xmlGenericErrorContext
, ": no state\n");
10054 else if (oldstate
->seq
== NULL
)
10055 xmlGenericError(xmlGenericErrorContext
, ": done\n");
10056 else if (oldstate
->seq
->type
== XML_ELEMENT_NODE
)
10057 xmlGenericError(xmlGenericErrorContext
, ": next elem %s\n",
10058 oldstate
->seq
->name
);
10060 xmlGenericError(xmlGenericErrorContext
, ": next %s %d\n",
10061 oldstate
->seq
->name
, oldstate
->seq
->type
);
10064 case XML_RELAXNG_OPTIONAL
:{
10065 errNr
= ctxt
->errNr
;
10066 oldflags
= ctxt
->flags
;
10067 ctxt
->flags
|= FLAGS_IGNORABLE
;
10068 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10070 xmlRelaxNGValidateDefinitionList(ctxt
,
10073 if (ctxt
->state
!= NULL
)
10074 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10075 ctxt
->state
= oldstate
;
10076 ctxt
->flags
= oldflags
;
10078 if (ctxt
->errNr
> errNr
)
10079 xmlRelaxNGPopErrors(ctxt
, errNr
);
10082 if (ctxt
->states
!= NULL
) {
10083 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10085 ctxt
->states
= xmlRelaxNGNewStates(ctxt
, 1);
10086 if (ctxt
->states
== NULL
) {
10087 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10088 ctxt
->flags
= oldflags
;
10090 if (ctxt
->errNr
> errNr
)
10091 xmlRelaxNGPopErrors(ctxt
, errNr
);
10094 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10095 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, ctxt
->state
);
10096 ctxt
->state
= NULL
;
10098 ctxt
->flags
= oldflags
;
10100 if (ctxt
->errNr
> errNr
)
10101 xmlRelaxNGPopErrors(ctxt
, errNr
);
10104 case XML_RELAXNG_ONEORMORE
:
10105 errNr
= ctxt
->errNr
;
10106 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10110 if (ctxt
->errNr
> errNr
)
10111 xmlRelaxNGPopErrors(ctxt
, errNr
);
10112 /* no break on purpose */
10113 case XML_RELAXNG_ZEROORMORE
:{
10115 xmlRelaxNGStatesPtr states
= NULL
, res
= NULL
;
10118 errNr
= ctxt
->errNr
;
10119 res
= xmlRelaxNGNewStates(ctxt
, 1);
10125 * All the input states are also exit states
10127 if (ctxt
->state
!= NULL
) {
10128 xmlRelaxNGAddStates(ctxt
, res
,
10129 xmlRelaxNGCopyValidState(ctxt
,
10133 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10134 xmlRelaxNGAddStates(ctxt
, res
,
10135 xmlRelaxNGCopyValidState(ctxt
,
10136 ctxt
->states
->tabState
[j
]));
10139 oldflags
= ctxt
->flags
;
10140 ctxt
->flags
|= FLAGS_IGNORABLE
;
10143 base
= res
->nbState
;
10145 if (ctxt
->states
!= NULL
) {
10146 states
= ctxt
->states
;
10147 for (i
= 0; i
< states
->nbState
; i
++) {
10148 ctxt
->state
= states
->tabState
[i
];
10149 ctxt
->states
= NULL
;
10150 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10154 if (ctxt
->state
!= NULL
) {
10155 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10157 ctxt
->state
= NULL
;
10160 } else if (ctxt
->states
!= NULL
) {
10161 for (j
= 0; j
< ctxt
->states
->nbState
;
10164 xmlRelaxNGAddStates(ctxt
, res
,
10165 ctxt
->states
->tabState
[j
]);
10169 xmlRelaxNGFreeStates(ctxt
,
10171 ctxt
->states
= NULL
;
10174 if (ctxt
->state
!= NULL
) {
10175 xmlRelaxNGFreeValidState(ctxt
,
10177 ctxt
->state
= NULL
;
10182 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10186 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10187 ctxt
->state
= NULL
;
10189 base
= res
->nbState
;
10190 if (ctxt
->state
!= NULL
) {
10191 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10193 ctxt
->state
= NULL
;
10196 } else if (ctxt
->states
!= NULL
) {
10197 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10198 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10199 ctxt
->states
->tabState
[j
]);
10203 if (states
== NULL
) {
10204 states
= ctxt
->states
;
10206 xmlRelaxNGFreeStates(ctxt
,
10209 ctxt
->states
= NULL
;
10215 * Collect all the new nodes added at that step
10216 * and make them the new node set
10218 if (res
->nbState
- base
== 1) {
10219 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
,
10224 if (states
== NULL
) {
10225 xmlRelaxNGNewStates(ctxt
,
10226 res
->nbState
- base
);
10227 states
= ctxt
->states
;
10228 if (states
== NULL
) {
10233 states
->nbState
= 0;
10234 for (i
= base
; i
< res
->nbState
; i
++)
10235 xmlRelaxNGAddStates(ctxt
, states
,
10236 xmlRelaxNGCopyValidState
10237 (ctxt
, res
->tabState
[i
]));
10238 ctxt
->states
= states
;
10241 } while (progress
== 1);
10242 if (states
!= NULL
) {
10243 xmlRelaxNGFreeStates(ctxt
, states
);
10245 ctxt
->states
= res
;
10246 ctxt
->flags
= oldflags
;
10249 * errors may have to be propagated back...
10251 if (ctxt
->errNr
> errNr
)
10252 xmlRelaxNGPopErrors(ctxt
, errNr
);
10257 case XML_RELAXNG_CHOICE
:{
10258 xmlRelaxNGDefinePtr list
= NULL
;
10259 xmlRelaxNGStatesPtr states
= NULL
;
10261 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10263 errNr
= ctxt
->errNr
;
10264 if ((define
->dflags
& IS_TRIABLE
) && (define
->data
!= NULL
) &&
10267 * node == NULL can't be optimized since IS_TRIABLE
10268 * doesn't account for choice which may lead to
10271 xmlHashTablePtr triage
=
10272 (xmlHashTablePtr
) define
->data
;
10275 * Something we can optimize cleanly there is only one
10276 * possble branch out !
10278 if ((node
->type
== XML_TEXT_NODE
) ||
10279 (node
->type
== XML_CDATA_SECTION_NODE
)) {
10281 xmlHashLookup2(triage
, BAD_CAST
"#text", NULL
);
10282 } else if (node
->type
== XML_ELEMENT_NODE
) {
10283 if (node
->ns
!= NULL
) {
10284 list
= xmlHashLookup2(triage
, node
->name
,
10288 xmlHashLookup2(triage
, BAD_CAST
"#any",
10292 xmlHashLookup2(triage
, node
->name
, NULL
);
10295 xmlHashLookup2(triage
, BAD_CAST
"#any",
10298 if (list
== NULL
) {
10300 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, node
->name
);
10303 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10309 list
= define
->content
;
10310 oldflags
= ctxt
->flags
;
10311 ctxt
->flags
|= FLAGS_IGNORABLE
;
10313 while (list
!= NULL
) {
10314 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10315 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10317 if (states
== NULL
) {
10318 states
= xmlRelaxNGNewStates(ctxt
, 1);
10320 if (ctxt
->state
!= NULL
) {
10321 xmlRelaxNGAddStates(ctxt
, states
, ctxt
->state
);
10322 } else if (ctxt
->states
!= NULL
) {
10323 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10324 xmlRelaxNGAddStates(ctxt
, states
,
10328 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10329 ctxt
->states
= NULL
;
10332 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10334 ctxt
->state
= oldstate
;
10337 if (states
!= NULL
) {
10338 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10339 ctxt
->states
= states
;
10340 ctxt
->state
= NULL
;
10343 ctxt
->states
= NULL
;
10345 ctxt
->flags
= oldflags
;
10347 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10348 xmlRelaxNGDumpValidError(ctxt
);
10351 if (ctxt
->errNr
> errNr
)
10352 xmlRelaxNGPopErrors(ctxt
, errNr
);
10356 case XML_RELAXNG_DEF
:
10357 case XML_RELAXNG_GROUP
:
10358 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10360 case XML_RELAXNG_INTERLEAVE
:
10361 ret
= xmlRelaxNGValidateInterleave(ctxt
, define
);
10363 case XML_RELAXNG_ATTRIBUTE
:
10364 ret
= xmlRelaxNGValidateAttribute(ctxt
, define
);
10366 case XML_RELAXNG_START
:
10367 case XML_RELAXNG_NOOP
:
10368 case XML_RELAXNG_REF
:
10369 case XML_RELAXNG_EXTERNALREF
:
10370 case XML_RELAXNG_PARENTREF
:
10371 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
->content
);
10373 case XML_RELAXNG_DATATYPE
:{
10375 xmlChar
*content
= NULL
;
10378 while (child
!= NULL
) {
10379 if (child
->type
== XML_ELEMENT_NODE
) {
10380 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM
,
10381 node
->parent
->name
);
10384 } else if ((child
->type
== XML_TEXT_NODE
) ||
10385 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10386 content
= xmlStrcat(content
, child
->content
);
10388 /* TODO: handle entities ... */
10389 child
= child
->next
;
10392 if (content
!= NULL
)
10396 if (content
== NULL
) {
10397 content
= xmlStrdup(BAD_CAST
"");
10398 if (content
== NULL
) {
10399 xmlRngVErrMemory(ctxt
, "validating\n");
10404 ret
= xmlRelaxNGValidateDatatype(ctxt
, content
, define
,
10407 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE
, define
->name
);
10408 } else if (ret
== 0) {
10409 ctxt
->state
->seq
= NULL
;
10411 if (content
!= NULL
)
10415 case XML_RELAXNG_VALUE
:{
10416 xmlChar
*content
= NULL
;
10421 while (child
!= NULL
) {
10422 if (child
->type
== XML_ELEMENT_NODE
) {
10423 VALID_ERR2(XML_RELAXNG_ERR_VALELEM
,
10424 node
->parent
->name
);
10427 } else if ((child
->type
== XML_TEXT_NODE
) ||
10428 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10429 content
= xmlStrcat(content
, child
->content
);
10431 /* TODO: handle entities ... */
10432 child
= child
->next
;
10435 if (content
!= NULL
)
10439 if (content
== NULL
) {
10440 content
= xmlStrdup(BAD_CAST
"");
10441 if (content
== NULL
) {
10442 xmlRngVErrMemory(ctxt
, "validating\n");
10447 oldvalue
= ctxt
->state
->value
;
10448 ctxt
->state
->value
= content
;
10449 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10450 ctxt
->state
->value
= oldvalue
;
10452 VALID_ERR2(XML_RELAXNG_ERR_VALUE
, define
->name
);
10453 } else if (ret
== 0) {
10454 ctxt
->state
->seq
= NULL
;
10456 if (content
!= NULL
)
10460 case XML_RELAXNG_LIST
:{
10463 xmlChar
*oldvalue
, *oldendvalue
;
10467 * Make sure it's only text nodes
10472 while (child
!= NULL
) {
10473 if (child
->type
== XML_ELEMENT_NODE
) {
10474 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM
,
10475 node
->parent
->name
);
10478 } else if ((child
->type
== XML_TEXT_NODE
) ||
10479 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10480 content
= xmlStrcat(content
, child
->content
);
10482 /* TODO: handle entities ... */
10483 child
= child
->next
;
10486 if (content
!= NULL
)
10490 if (content
== NULL
) {
10491 content
= xmlStrdup(BAD_CAST
"");
10492 if (content
== NULL
) {
10493 xmlRngVErrMemory(ctxt
, "validating\n");
10498 len
= xmlStrlen(content
);
10499 oldvalue
= ctxt
->state
->value
;
10500 oldendvalue
= ctxt
->state
->endvalue
;
10501 ctxt
->state
->value
= content
;
10502 ctxt
->state
->endvalue
= content
+ len
;
10503 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10504 ctxt
->state
->value
= oldvalue
;
10505 ctxt
->state
->endvalue
= oldendvalue
;
10507 VALID_ERR(XML_RELAXNG_ERR_LIST
);
10508 } else if ((ret
== 0) && (node
!= NULL
)) {
10509 ctxt
->state
->seq
= node
->next
;
10511 if (content
!= NULL
)
10515 case XML_RELAXNG_EXCEPT
:
10516 case XML_RELAXNG_PARAM
:
10522 for (i
= 0; i
< ctxt
->depth
; i
++)
10523 xmlGenericError(xmlGenericErrorContext
, " ");
10524 xmlGenericError(xmlGenericErrorContext
,
10525 "Validating %s ", xmlRelaxNGDefName(define
));
10526 if (define
->name
!= NULL
)
10527 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
10529 xmlGenericError(xmlGenericErrorContext
, "suceeded\n");
10531 xmlGenericError(xmlGenericErrorContext
, "failed\n");
10537 * xmlRelaxNGValidateDefinition:
10538 * @ctxt: a Relax-NG validation context
10539 * @define: the definition to verify
10541 * Validate the current node lists against the definition
10543 * Returns 0 if the validation succeeded or an error code.
10546 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
10547 xmlRelaxNGDefinePtr define
)
10549 xmlRelaxNGStatesPtr states
, res
;
10550 int i
, j
, k
, ret
, oldflags
;
10553 * We should NOT have both ctxt->state and ctxt->states
10555 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10556 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10557 ctxt
->state
= NULL
;
10560 if ((ctxt
->states
== NULL
) || (ctxt
->states
->nbState
== 1)) {
10561 if (ctxt
->states
!= NULL
) {
10562 ctxt
->state
= ctxt
->states
->tabState
[0];
10563 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10564 ctxt
->states
= NULL
;
10566 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10567 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10568 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10569 ctxt
->state
= NULL
;
10571 if ((ctxt
->states
!= NULL
) && (ctxt
->states
->nbState
== 1)) {
10572 ctxt
->state
= ctxt
->states
->tabState
[0];
10573 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10574 ctxt
->states
= NULL
;
10579 states
= ctxt
->states
;
10580 ctxt
->states
= NULL
;
10583 oldflags
= ctxt
->flags
;
10584 ctxt
->flags
|= FLAGS_IGNORABLE
;
10585 for (i
= 0; i
< states
->nbState
; i
++) {
10586 ctxt
->state
= states
->tabState
[i
];
10587 ctxt
->states
= NULL
;
10588 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10590 * We should NOT have both ctxt->state and ctxt->states
10592 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10593 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10594 ctxt
->state
= NULL
;
10597 if (ctxt
->states
== NULL
) {
10599 /* add the state to the container */
10600 xmlRelaxNGAddStates(ctxt
, res
, ctxt
->state
);
10601 ctxt
->state
= NULL
;
10603 /* add the state directly in states */
10604 states
->tabState
[j
++] = ctxt
->state
;
10605 ctxt
->state
= NULL
;
10609 /* make it the new container and copy other results */
10610 res
= ctxt
->states
;
10611 ctxt
->states
= NULL
;
10612 for (k
= 0; k
< j
; k
++)
10613 xmlRelaxNGAddStates(ctxt
, res
,
10614 states
->tabState
[k
]);
10616 /* add all the new results to res and reff the container */
10617 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10618 xmlRelaxNGAddStates(ctxt
, res
,
10619 ctxt
->states
->tabState
[k
]);
10620 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10621 ctxt
->states
= NULL
;
10625 if (ctxt
->state
!= NULL
) {
10626 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10627 ctxt
->state
= NULL
;
10628 } else if (ctxt
->states
!= NULL
) {
10629 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10630 xmlRelaxNGFreeValidState(ctxt
,
10631 ctxt
->states
->tabState
[k
]);
10632 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10633 ctxt
->states
= NULL
;
10637 ctxt
->flags
= oldflags
;
10639 xmlRelaxNGFreeStates(ctxt
, states
);
10640 ctxt
->states
= res
;
10642 } else if (j
> 1) {
10643 states
->nbState
= j
;
10644 ctxt
->states
= states
;
10646 } else if (j
== 1) {
10647 ctxt
->state
= states
->tabState
[0];
10648 xmlRelaxNGFreeStates(ctxt
, states
);
10652 xmlRelaxNGFreeStates(ctxt
, states
);
10653 if (ctxt
->states
!= NULL
) {
10654 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10655 ctxt
->states
= NULL
;
10658 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10659 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10660 ctxt
->state
= NULL
;
10666 * xmlRelaxNGValidateDocument:
10667 * @ctxt: a Relax-NG validation context
10668 * @doc: the document
10670 * Validate the given document
10672 * Returns 0 if the validation succeeded or an error code.
10675 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
10678 xmlRelaxNGPtr schema
;
10679 xmlRelaxNGGrammarPtr grammar
;
10680 xmlRelaxNGValidStatePtr state
;
10683 if ((ctxt
== NULL
) || (ctxt
->schema
== NULL
) || (doc
== NULL
))
10686 ctxt
->errNo
= XML_RELAXNG_OK
;
10687 schema
= ctxt
->schema
;
10688 grammar
= schema
->topgrammar
;
10689 if (grammar
== NULL
) {
10690 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
10693 state
= xmlRelaxNGNewValidState(ctxt
, NULL
);
10694 ctxt
->state
= state
;
10695 ret
= xmlRelaxNGValidateDefinition(ctxt
, grammar
->start
);
10696 if ((ctxt
->state
!= NULL
) && (state
->seq
!= NULL
)) {
10697 state
= ctxt
->state
;
10699 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10700 if (node
!= NULL
) {
10702 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10706 } else if (ctxt
->states
!= NULL
) {
10710 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10711 state
= ctxt
->states
->tabState
[i
];
10713 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10716 xmlRelaxNGFreeValidState(ctxt
, state
);
10720 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10725 if (ctxt
->state
!= NULL
) {
10726 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10727 ctxt
->state
= NULL
;
10730 xmlRelaxNGDumpValidError(ctxt
);
10732 else if (ctxt
->errNr
!= 0) {
10733 ctxt
->error(ctxt
->userData
,
10734 "%d Extra error messages left on stack !\n",
10736 xmlRelaxNGDumpValidError(ctxt
);
10739 #ifdef LIBXML_VALID_ENABLED
10740 if (ctxt
->idref
== 1) {
10741 xmlValidCtxt vctxt
;
10743 memset(&vctxt
, 0, sizeof(xmlValidCtxt
));
10745 vctxt
.error
= ctxt
->error
;
10746 vctxt
.warning
= ctxt
->warning
;
10747 vctxt
.userData
= ctxt
->userData
;
10749 if (xmlValidateDocumentFinal(&vctxt
, doc
) != 1)
10752 #endif /* LIBXML_VALID_ENABLED */
10753 if ((ret
== 0) && (ctxt
->errNo
!= XML_RELAXNG_OK
))
10760 * xmlRelaxNGCleanPSVI:
10761 * @node: an input element or document
10763 * Call this routine to speed up XPath computation on static documents.
10764 * This stamps all the element nodes with the document order
10765 * Like for line information, the order is kept in the element->content
10766 * field, the value stored is actually - the node number (starting at -1)
10767 * to be able to differentiate from line numbers.
10769 * Returns the number of elements found in the document or -1 in case
10773 xmlRelaxNGCleanPSVI(xmlNodePtr node
) {
10776 if ((node
== NULL
) ||
10777 ((node
->type
!= XML_ELEMENT_NODE
) &&
10778 (node
->type
!= XML_DOCUMENT_NODE
) &&
10779 (node
->type
!= XML_HTML_DOCUMENT_NODE
)))
10781 if (node
->type
== XML_ELEMENT_NODE
)
10784 cur
= node
->children
;
10785 while (cur
!= NULL
) {
10786 if (cur
->type
== XML_ELEMENT_NODE
) {
10788 if (cur
->children
!= NULL
) {
10789 cur
= cur
->children
;
10793 if (cur
->next
!= NULL
) {
10805 if (cur
->next
!= NULL
) {
10809 } while (cur
!= NULL
);
10813 /************************************************************************
10815 * Validation interfaces *
10817 ************************************************************************/
10820 * xmlRelaxNGNewValidCtxt:
10821 * @schema: a precompiled XML RelaxNGs
10823 * Create an XML RelaxNGs validation context based on the given schema
10825 * Returns the validation context or NULL in case of error
10827 xmlRelaxNGValidCtxtPtr
10828 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema
)
10830 xmlRelaxNGValidCtxtPtr ret
;
10832 ret
= (xmlRelaxNGValidCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGValidCtxt
));
10834 xmlRngVErrMemory(NULL
, "building context\n");
10837 memset(ret
, 0, sizeof(xmlRelaxNGValidCtxt
));
10838 ret
->schema
= schema
;
10839 ret
->error
= xmlGenericError
;
10840 ret
->userData
= xmlGenericErrorContext
;
10844 ret
->errTab
= NULL
;
10845 if (schema
!= NULL
)
10846 ret
->idref
= schema
->idref
;
10847 ret
->states
= NULL
;
10848 ret
->freeState
= NULL
;
10849 ret
->freeStates
= NULL
;
10850 ret
->errNo
= XML_RELAXNG_OK
;
10855 * xmlRelaxNGFreeValidCtxt:
10856 * @ctxt: the schema validation context
10858 * Free the resources associated to the schema validation context
10861 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt
)
10867 if (ctxt
->states
!= NULL
)
10868 xmlRelaxNGFreeStates(NULL
, ctxt
->states
);
10869 if (ctxt
->freeState
!= NULL
) {
10870 for (k
= 0; k
< ctxt
->freeState
->nbState
; k
++) {
10871 xmlRelaxNGFreeValidState(NULL
, ctxt
->freeState
->tabState
[k
]);
10873 xmlRelaxNGFreeStates(NULL
, ctxt
->freeState
);
10875 if (ctxt
->freeStates
!= NULL
) {
10876 for (k
= 0; k
< ctxt
->freeStatesNr
; k
++) {
10877 xmlRelaxNGFreeStates(NULL
, ctxt
->freeStates
[k
]);
10879 xmlFree(ctxt
->freeStates
);
10881 if (ctxt
->errTab
!= NULL
)
10882 xmlFree(ctxt
->errTab
);
10883 if (ctxt
->elemTab
!= NULL
) {
10884 xmlRegExecCtxtPtr exec
;
10886 exec
= xmlRelaxNGElemPop(ctxt
);
10887 while (exec
!= NULL
) {
10888 xmlRegFreeExecCtxt(exec
);
10889 exec
= xmlRelaxNGElemPop(ctxt
);
10891 xmlFree(ctxt
->elemTab
);
10897 * xmlRelaxNGSetValidErrors:
10898 * @ctxt: a Relax-NG validation context
10899 * @err: the error function
10900 * @warn: the warning function
10901 * @ctx: the functions context
10903 * Set the error and warning callback informations
10906 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
10907 xmlRelaxNGValidityErrorFunc err
,
10908 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
10913 ctxt
->warning
= warn
;
10914 ctxt
->userData
= ctx
;
10915 ctxt
->serror
= NULL
;
10919 * xmlRelaxNGSetValidStructuredErrors:
10920 * @ctxt: a Relax-NG validation context
10921 * @serror: the structured error function
10922 * @ctx: the functions context
10924 * Set the structured error callback
10927 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt
,
10928 xmlStructuredErrorFunc serror
, void *ctx
)
10932 ctxt
->serror
= serror
;
10933 ctxt
->error
= NULL
;
10934 ctxt
->warning
= NULL
;
10935 ctxt
->userData
= ctx
;
10939 * xmlRelaxNGGetValidErrors:
10940 * @ctxt: a Relax-NG validation context
10941 * @err: the error function result
10942 * @warn: the warning function result
10943 * @ctx: the functions context result
10945 * Get the error and warning callback informations
10947 * Returns -1 in case of error and 0 otherwise
10950 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
10951 xmlRelaxNGValidityErrorFunc
* err
,
10952 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
10957 *err
= ctxt
->error
;
10959 *warn
= ctxt
->warning
;
10961 *ctx
= ctxt
->userData
;
10966 * xmlRelaxNGValidateDoc:
10967 * @ctxt: a Relax-NG validation context
10968 * @doc: a parsed document tree
10970 * Validate a document tree in memory.
10972 * Returns 0 if the document is valid, a positive error code
10973 * number otherwise and -1 in case of internal or API error.
10976 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
10980 if ((ctxt
== NULL
) || (doc
== NULL
))
10985 ret
= xmlRelaxNGValidateDocument(ctxt
, doc
);
10987 * Remove all left PSVI
10989 xmlRelaxNGCleanPSVI((xmlNodePtr
) doc
);
10992 * TODO: build error codes
10999 #define bottom_relaxng
11000 #include "elfgcchack.h"
11001 #endif /* LIBXML_SCHEMAS_ENABLED */