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
? (const xmlChar
*) "nothing" : node
->name
),
5377 if (def
->nameClass
== NULL
) {
5378 def
->nameClass
= ret
;
5380 tmp
= def
->nameClass
;
5381 while (tmp
->next
!= NULL
) {
5391 * xmlRelaxNGParseElement:
5392 * @ctxt: a Relax-NG parser context
5393 * @node: the element node
5395 * parse the content of a RelaxNG element node.
5397 * Returns the definition pointer or NULL in case of error.
5399 static xmlRelaxNGDefinePtr
5400 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5402 xmlRelaxNGDefinePtr ret
, cur
, last
;
5404 const xmlChar
*olddefine
;
5406 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5409 ret
->type
= XML_RELAXNG_ELEMENT
;
5410 ret
->parent
= ctxt
->def
;
5411 child
= node
->children
;
5412 if (child
== NULL
) {
5413 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_EMPTY
,
5414 "xmlRelaxNGParseElement: element has no children\n",
5418 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5420 child
= child
->next
;
5422 if (child
== NULL
) {
5423 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NO_CONTENT
,
5424 "xmlRelaxNGParseElement: element has no content\n",
5428 olddefine
= ctxt
->define
;
5429 ctxt
->define
= NULL
;
5431 while (child
!= NULL
) {
5432 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5435 switch (cur
->type
) {
5436 case XML_RELAXNG_EMPTY
:
5437 case XML_RELAXNG_NOT_ALLOWED
:
5438 case XML_RELAXNG_TEXT
:
5439 case XML_RELAXNG_ELEMENT
:
5440 case XML_RELAXNG_DATATYPE
:
5441 case XML_RELAXNG_VALUE
:
5442 case XML_RELAXNG_LIST
:
5443 case XML_RELAXNG_REF
:
5444 case XML_RELAXNG_PARENTREF
:
5445 case XML_RELAXNG_EXTERNALREF
:
5446 case XML_RELAXNG_DEF
:
5447 case XML_RELAXNG_ZEROORMORE
:
5448 case XML_RELAXNG_ONEORMORE
:
5449 case XML_RELAXNG_OPTIONAL
:
5450 case XML_RELAXNG_CHOICE
:
5451 case XML_RELAXNG_GROUP
:
5452 case XML_RELAXNG_INTERLEAVE
:
5454 ret
->content
= last
= cur
;
5456 if ((last
->type
== XML_RELAXNG_ELEMENT
) &&
5457 (ret
->content
== last
)) {
5458 ret
->content
= xmlRelaxNGNewDefine(ctxt
, node
);
5459 if (ret
->content
!= NULL
) {
5460 ret
->content
->type
= XML_RELAXNG_GROUP
;
5461 ret
->content
->content
= last
;
5463 ret
->content
= last
;
5470 case XML_RELAXNG_ATTRIBUTE
:
5471 cur
->next
= ret
->attrs
;
5474 case XML_RELAXNG_START
:
5475 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5476 "RNG Internal error, start found in element\n",
5479 case XML_RELAXNG_PARAM
:
5480 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5481 "RNG Internal error, param found in element\n",
5484 case XML_RELAXNG_EXCEPT
:
5485 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5486 "RNG Internal error, except found in element\n",
5489 case XML_RELAXNG_NOOP
:
5490 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5491 "RNG Internal error, noop found in element\n",
5496 child
= child
->next
;
5498 ctxt
->define
= olddefine
;
5503 * xmlRelaxNGParsePatterns:
5504 * @ctxt: a Relax-NG parser context
5505 * @nodes: list of nodes
5506 * @group: use an implicit <group> for elements
5508 * parse the content of a RelaxNG start node.
5510 * Returns the definition pointer or NULL in case of error.
5512 static xmlRelaxNGDefinePtr
5513 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
,
5516 xmlRelaxNGDefinePtr def
= NULL
, last
= NULL
, cur
, parent
;
5519 while (nodes
!= NULL
) {
5520 if (IS_RELAXNG(nodes
, "element")) {
5521 cur
= xmlRelaxNGParseElement(ctxt
, nodes
);
5525 if ((group
== 1) && (def
->type
== XML_RELAXNG_ELEMENT
) &&
5527 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5528 def
->type
= XML_RELAXNG_GROUP
;
5529 def
->content
= last
;
5534 cur
->parent
= parent
;
5536 cur
= xmlRelaxNGParsePattern(ctxt
, nodes
);
5546 nodes
= nodes
->next
;
5552 * xmlRelaxNGParseStart:
5553 * @ctxt: a Relax-NG parser context
5554 * @nodes: start children nodes
5556 * parse the content of a RelaxNG start node.
5558 * Returns 0 in case of success, -1 in case of error
5561 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
5564 xmlRelaxNGDefinePtr def
= NULL
, last
;
5566 if (nodes
== NULL
) {
5567 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
, "start has no children\n",
5571 if (IS_RELAXNG(nodes
, "empty")) {
5572 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5575 def
->type
= XML_RELAXNG_EMPTY
;
5576 if (nodes
->children
!= NULL
) {
5577 xmlRngPErr(ctxt
, nodes
, XML_RNGP_EMPTY_CONTENT
,
5578 "element empty is not empty\n", NULL
, NULL
);
5580 } else if (IS_RELAXNG(nodes
, "notAllowed")) {
5581 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5584 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
5585 if (nodes
->children
!= NULL
) {
5586 xmlRngPErr(ctxt
, nodes
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
5587 "element notAllowed is not empty\n", NULL
, NULL
);
5590 def
= xmlRelaxNGParsePatterns(ctxt
, nodes
, 1);
5592 if (ctxt
->grammar
->start
!= NULL
) {
5593 last
= ctxt
->grammar
->start
;
5594 while (last
->next
!= NULL
)
5598 ctxt
->grammar
->start
= def
;
5600 nodes
= nodes
->next
;
5601 if (nodes
!= NULL
) {
5602 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_CONTENT
,
5603 "start more than one children\n", NULL
, NULL
);
5610 * xmlRelaxNGParseGrammarContent:
5611 * @ctxt: a Relax-NG parser context
5612 * @nodes: grammar children nodes
5614 * parse the content of a RelaxNG grammar node.
5616 * Returns 0 in case of success, -1 in case of error
5619 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
5624 if (nodes
== NULL
) {
5625 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_EMPTY
,
5626 "grammar has no children\n", NULL
, NULL
);
5629 while (nodes
!= NULL
) {
5630 if (IS_RELAXNG(nodes
, "start")) {
5631 if (nodes
->children
== NULL
) {
5632 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
,
5633 "start has no children\n", NULL
, NULL
);
5635 tmp
= xmlRelaxNGParseStart(ctxt
, nodes
->children
);
5639 } else if (IS_RELAXNG(nodes
, "define")) {
5640 tmp
= xmlRelaxNGParseDefine(ctxt
, nodes
);
5643 } else if (IS_RELAXNG(nodes
, "include")) {
5644 tmp
= xmlRelaxNGParseInclude(ctxt
, nodes
);
5648 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
5649 "grammar has unexpected child %s\n", nodes
->name
,
5653 nodes
= nodes
->next
;
5659 * xmlRelaxNGCheckReference:
5661 * @ctxt: a Relax-NG parser context
5662 * @name: the name associated to the defines
5664 * Applies the 4.17. combine attribute rule for all the define
5665 * element of a given grammar using the same name.
5668 xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref
,
5669 xmlRelaxNGParserCtxtPtr ctxt
,
5670 const xmlChar
* name
)
5672 xmlRelaxNGGrammarPtr grammar
;
5673 xmlRelaxNGDefinePtr def
, cur
;
5676 * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5678 if (ref
->dflags
& IS_EXTERNAL_REF
)
5681 grammar
= ctxt
->grammar
;
5682 if (grammar
== NULL
) {
5683 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5684 "Internal error: no grammar in CheckReference %s\n",
5688 if (ref
->content
!= NULL
) {
5689 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5690 "Internal error: reference has content in CheckReference %s\n",
5694 if (grammar
->defs
!= NULL
) {
5695 def
= xmlHashLookup(grammar
->defs
, name
);
5698 while (cur
!= NULL
) {
5700 cur
= cur
->nextHash
;
5703 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5704 "Reference %s has no matching definition\n", name
,
5708 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5709 "Reference %s has no matching definition\n", name
,
5715 * xmlRelaxNGCheckCombine:
5716 * @define: the define(s) list
5717 * @ctxt: a Relax-NG parser context
5718 * @name: the name associated to the defines
5720 * Applies the 4.17. combine attribute rule for all the define
5721 * element of a given grammar using the same name.
5724 xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define
,
5725 xmlRelaxNGParserCtxtPtr ctxt
, const xmlChar
* name
)
5728 int choiceOrInterleave
= -1;
5730 xmlRelaxNGDefinePtr cur
, last
, tmp
, tmp2
;
5732 if (define
->nextHash
== NULL
)
5735 while (cur
!= NULL
) {
5736 combine
= xmlGetProp(cur
->node
, BAD_CAST
"combine");
5737 if (combine
!= NULL
) {
5738 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5739 if (choiceOrInterleave
== -1)
5740 choiceOrInterleave
= 1;
5741 else if (choiceOrInterleave
== 0) {
5742 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5743 "Defines for %s use both 'choice' and 'interleave'\n",
5746 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5747 if (choiceOrInterleave
== -1)
5748 choiceOrInterleave
= 0;
5749 else if (choiceOrInterleave
== 1) {
5750 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5751 "Defines for %s use both 'choice' and 'interleave'\n",
5755 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5756 "Defines for %s use unknown combine value '%s''\n",
5764 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_NEED_COMBINE
,
5765 "Some defines for %s needs the combine attribute\n",
5770 cur
= cur
->nextHash
;
5773 xmlGenericError(xmlGenericErrorContext
,
5774 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5775 name
, choiceOrInterleave
);
5777 if (choiceOrInterleave
== -1)
5778 choiceOrInterleave
= 0;
5779 cur
= xmlRelaxNGNewDefine(ctxt
, define
->node
);
5782 if (choiceOrInterleave
== 0)
5783 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5785 cur
->type
= XML_RELAXNG_CHOICE
;
5788 while (tmp
!= NULL
) {
5789 if (tmp
->content
!= NULL
) {
5790 if (tmp
->content
->next
!= NULL
) {
5792 * we need first to create a wrapper.
5794 tmp2
= xmlRelaxNGNewDefine(ctxt
, tmp
->content
->node
);
5797 tmp2
->type
= XML_RELAXNG_GROUP
;
5798 tmp2
->content
= tmp
->content
;
5800 tmp2
= tmp
->content
;
5803 cur
->content
= tmp2
;
5810 tmp
= tmp
->nextHash
;
5812 define
->content
= cur
;
5813 if (choiceOrInterleave
== 0) {
5814 if (ctxt
->interleaves
== NULL
)
5815 ctxt
->interleaves
= xmlHashCreate(10);
5816 if (ctxt
->interleaves
== NULL
) {
5817 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5818 "Failed to create interleaves hash table\n", NULL
,
5823 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5824 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5826 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5827 "Failed to add %s to hash table\n",
5828 (const xmlChar
*) tmpname
, NULL
);
5835 * xmlRelaxNGCombineStart:
5836 * @ctxt: a Relax-NG parser context
5837 * @grammar: the grammar
5839 * Applies the 4.17. combine rule for all the start
5840 * element of a given grammar.
5843 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt
,
5844 xmlRelaxNGGrammarPtr grammar
)
5846 xmlRelaxNGDefinePtr starts
;
5848 int choiceOrInterleave
= -1;
5850 xmlRelaxNGDefinePtr cur
;
5852 starts
= grammar
->start
;
5853 if ((starts
== NULL
) || (starts
->next
== NULL
))
5856 while (cur
!= NULL
) {
5857 if ((cur
->node
== NULL
) || (cur
->node
->parent
== NULL
) ||
5858 (!xmlStrEqual(cur
->node
->parent
->name
, BAD_CAST
"start"))) {
5860 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_MISSING
,
5861 "Internal error: start element not found\n", NULL
,
5864 combine
= xmlGetProp(cur
->node
->parent
, BAD_CAST
"combine");
5867 if (combine
!= NULL
) {
5868 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5869 if (choiceOrInterleave
== -1)
5870 choiceOrInterleave
= 1;
5871 else if (choiceOrInterleave
== 0) {
5872 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5873 "<start> use both 'choice' and 'interleave'\n",
5876 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5877 if (choiceOrInterleave
== -1)
5878 choiceOrInterleave
= 0;
5879 else if (choiceOrInterleave
== 1) {
5880 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5881 "<start> use both 'choice' and 'interleave'\n",
5885 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5886 "<start> uses unknown combine value '%s''\n",
5894 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NEED_COMBINE
,
5895 "Some <start> element miss the combine attribute\n",
5903 xmlGenericError(xmlGenericErrorContext
,
5904 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5905 choiceOrInterleave
);
5907 if (choiceOrInterleave
== -1)
5908 choiceOrInterleave
= 0;
5909 cur
= xmlRelaxNGNewDefine(ctxt
, starts
->node
);
5912 if (choiceOrInterleave
== 0)
5913 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5915 cur
->type
= XML_RELAXNG_CHOICE
;
5916 cur
->content
= grammar
->start
;
5917 grammar
->start
= cur
;
5918 if (choiceOrInterleave
== 0) {
5919 if (ctxt
->interleaves
== NULL
)
5920 ctxt
->interleaves
= xmlHashCreate(10);
5921 if (ctxt
->interleaves
== NULL
) {
5922 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5923 "Failed to create interleaves hash table\n", NULL
,
5928 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5929 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5931 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5932 "Failed to add %s to hash table\n",
5933 (const xmlChar
*) tmpname
, NULL
);
5940 * xmlRelaxNGCheckCycles:
5941 * @ctxt: a Relax-NG parser context
5942 * @nodes: grammar children nodes
5943 * @depth: the counter
5947 * Returns 0 if check passed, and -1 in case of error
5950 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt
,
5951 xmlRelaxNGDefinePtr cur
, int depth
)
5955 while ((ret
== 0) && (cur
!= NULL
)) {
5956 if ((cur
->type
== XML_RELAXNG_REF
) ||
5957 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
5958 if (cur
->depth
== -1) {
5960 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
5962 } else if (depth
== cur
->depth
) {
5963 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_CYCLE
,
5964 "Detected a cycle in %s references\n",
5968 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
5969 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
+ 1);
5971 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
5979 * xmlRelaxNGTryUnlink:
5980 * @ctxt: a Relax-NG parser context
5981 * @cur: the definition to unlink
5982 * @parent: the parent definition
5983 * @prev: the previous sibling definition
5985 * Try to unlink a definition. If not possble make it a NOOP
5987 * Returns the new prev definition
5989 static xmlRelaxNGDefinePtr
5990 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
5991 xmlRelaxNGDefinePtr cur
,
5992 xmlRelaxNGDefinePtr parent
, xmlRelaxNGDefinePtr prev
)
5995 prev
->next
= cur
->next
;
5997 if (parent
!= NULL
) {
5998 if (parent
->content
== cur
)
5999 parent
->content
= cur
->next
;
6000 else if (parent
->attrs
== cur
)
6001 parent
->attrs
= cur
->next
;
6002 else if (parent
->nameClass
== cur
)
6003 parent
->nameClass
= cur
->next
;
6005 cur
->type
= XML_RELAXNG_NOOP
;
6013 * xmlRelaxNGSimplify:
6014 * @ctxt: a Relax-NG parser context
6015 * @nodes: grammar children nodes
6017 * Check for simplification of empty and notAllowed
6020 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt
,
6021 xmlRelaxNGDefinePtr cur
, xmlRelaxNGDefinePtr parent
)
6023 xmlRelaxNGDefinePtr prev
= NULL
;
6025 while (cur
!= NULL
) {
6026 if ((cur
->type
== XML_RELAXNG_REF
) ||
6027 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6028 if (cur
->depth
!= -3) {
6030 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6032 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6033 cur
->parent
= parent
;
6034 if ((parent
!= NULL
) &&
6035 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6036 (parent
->type
== XML_RELAXNG_LIST
) ||
6037 (parent
->type
== XML_RELAXNG_GROUP
) ||
6038 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6039 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6040 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6041 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6044 if ((parent
!= NULL
) && (parent
->type
== XML_RELAXNG_CHOICE
)) {
6045 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6048 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6049 cur
->parent
= parent
;
6050 if ((parent
!= NULL
) &&
6051 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6052 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6053 parent
->type
= XML_RELAXNG_EMPTY
;
6056 if ((parent
!= NULL
) &&
6057 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6058 (parent
->type
== XML_RELAXNG_INTERLEAVE
))) {
6059 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6063 cur
->parent
= parent
;
6064 if (cur
->content
!= NULL
)
6065 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6066 if ((cur
->type
!= XML_RELAXNG_VALUE
) && (cur
->attrs
!= NULL
))
6067 xmlRelaxNGSimplify(ctxt
, cur
->attrs
, cur
);
6068 if (cur
->nameClass
!= NULL
)
6069 xmlRelaxNGSimplify(ctxt
, cur
->nameClass
, cur
);
6071 * On Elements, try to move attribute only generating rules on
6074 if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6076 xmlRelaxNGDefinePtr tmp
, pre
;
6078 while (cur
->content
!= NULL
) {
6080 xmlRelaxNGGenerateAttributes(ctxt
, cur
->content
);
6081 if (attronly
== 1) {
6083 * migrate cur->content to attrs
6086 cur
->content
= tmp
->next
;
6087 tmp
->next
= cur
->attrs
;
6091 * cur->content can generate elements or text
6097 while ((pre
!= NULL
) && (pre
->next
!= NULL
)) {
6099 attronly
= xmlRelaxNGGenerateAttributes(ctxt
, tmp
);
6100 if (attronly
== 1) {
6102 * migrate tmp to attrs
6104 pre
->next
= tmp
->next
;
6105 tmp
->next
= cur
->attrs
;
6113 * This may result in a simplification
6115 if ((cur
->type
== XML_RELAXNG_GROUP
) ||
6116 (cur
->type
== XML_RELAXNG_INTERLEAVE
)) {
6117 if (cur
->content
== NULL
)
6118 cur
->type
= XML_RELAXNG_EMPTY
;
6119 else if (cur
->content
->next
== NULL
) {
6120 if ((parent
== NULL
) && (prev
== NULL
)) {
6121 cur
->type
= XML_RELAXNG_NOOP
;
6122 } else if (prev
== NULL
) {
6123 parent
->content
= cur
->content
;
6124 cur
->content
->next
= cur
->next
;
6127 cur
->content
->next
= cur
->next
;
6128 prev
->next
= cur
->content
;
6134 * the current node may have been transformed back
6136 if ((cur
->type
== XML_RELAXNG_EXCEPT
) &&
6137 (cur
->content
!= NULL
) &&
6138 (cur
->content
->type
== XML_RELAXNG_NOT_ALLOWED
)) {
6139 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6140 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6141 if ((parent
!= NULL
) &&
6142 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6143 (parent
->type
== XML_RELAXNG_LIST
) ||
6144 (parent
->type
== XML_RELAXNG_GROUP
) ||
6145 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6146 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6147 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6148 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6151 if ((parent
!= NULL
) &&
6152 (parent
->type
== XML_RELAXNG_CHOICE
)) {
6153 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6156 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6157 if ((parent
!= NULL
) &&
6158 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6159 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6160 parent
->type
= XML_RELAXNG_EMPTY
;
6163 if ((parent
!= NULL
) &&
6164 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6165 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6166 (parent
->type
== XML_RELAXNG_CHOICE
))) {
6167 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6179 * xmlRelaxNGGroupContentType:
6180 * @ct1: the first content type
6181 * @ct2: the second content type
6183 * Try to group 2 content types
6185 * Returns the content type
6187 static xmlRelaxNGContentType
6188 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1
,
6189 xmlRelaxNGContentType ct2
)
6191 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6192 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6193 return (XML_RELAXNG_CONTENT_ERROR
);
6194 if (ct1
== XML_RELAXNG_CONTENT_EMPTY
)
6196 if (ct2
== XML_RELAXNG_CONTENT_EMPTY
)
6198 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) &&
6199 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6200 return (XML_RELAXNG_CONTENT_COMPLEX
);
6201 return (XML_RELAXNG_CONTENT_ERROR
);
6205 * xmlRelaxNGMaxContentType:
6206 * @ct1: the first content type
6207 * @ct2: the second content type
6209 * Compute the max content-type
6211 * Returns the content type
6213 static xmlRelaxNGContentType
6214 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1
,
6215 xmlRelaxNGContentType ct2
)
6217 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6218 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6219 return (XML_RELAXNG_CONTENT_ERROR
);
6220 if ((ct1
== XML_RELAXNG_CONTENT_SIMPLE
) ||
6221 (ct2
== XML_RELAXNG_CONTENT_SIMPLE
))
6222 return (XML_RELAXNG_CONTENT_SIMPLE
);
6223 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) ||
6224 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6225 return (XML_RELAXNG_CONTENT_COMPLEX
);
6226 return (XML_RELAXNG_CONTENT_EMPTY
);
6230 * xmlRelaxNGCheckRules:
6231 * @ctxt: a Relax-NG parser context
6232 * @cur: the current definition
6233 * @flags: some accumulated flags
6234 * @ptype: the parent type
6236 * Check for rules in section 7.1 and 7.2
6238 * Returns the content type of @cur
6240 static xmlRelaxNGContentType
6241 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt
,
6242 xmlRelaxNGDefinePtr cur
, int flags
,
6243 xmlRelaxNGType ptype
)
6246 xmlRelaxNGContentType ret
, tmp
, val
= XML_RELAXNG_CONTENT_EMPTY
;
6248 while (cur
!= NULL
) {
6249 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6250 if ((cur
->type
== XML_RELAXNG_REF
) ||
6251 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6253 * This should actually be caught by list//element(ref) at the
6254 * element boundaries, c.f. Bug #159968 local refs are dropped
6258 if (flags
& XML_RELAXNG_IN_LIST
) {
6259 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_REF
,
6260 "Found forbidden pattern list//ref\n", NULL
,
6264 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6265 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_REF
,
6266 "Found forbidden pattern data/except//ref\n",
6269 if (cur
->content
== NULL
) {
6270 if (cur
->type
== XML_RELAXNG_PARENTREF
)
6271 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6272 "Internal found no define for parent refs\n",
6275 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6276 "Internal found no define for ref %s\n",
6277 (cur
->name
? cur
->name
: BAD_CAST
"null"), NULL
);
6279 if (cur
->depth
> -4) {
6281 ret
= xmlRelaxNGCheckRules(ctxt
, cur
->content
,
6283 cur
->depth
= ret
- 15;
6284 } else if (cur
->depth
== -4) {
6285 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6287 ret
= (xmlRelaxNGContentType
) (cur
->depth
+ 15);
6289 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6291 * The 7.3 Attribute derivation rule for groups is plugged there
6293 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6294 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6295 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ELEM
,
6296 "Found forbidden pattern data/except//element(ref)\n",
6299 if (flags
& XML_RELAXNG_IN_LIST
) {
6300 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ELEM
,
6301 "Found forbidden pattern list//element(ref)\n",
6304 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6305 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6306 "Found forbidden pattern attribute//element(ref)\n",
6309 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6310 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6311 "Found forbidden pattern attribute//element(ref)\n",
6315 * reset since in the simple form elements are only child
6320 xmlRelaxNGCheckRules(ctxt
, cur
->attrs
, nflags
, cur
->type
);
6321 if (ret
!= XML_RELAXNG_CONTENT_EMPTY
) {
6322 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_EMPTY
,
6323 "Element %s attributes have a content type error\n",
6327 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6329 if (ret
== XML_RELAXNG_CONTENT_ERROR
) {
6330 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_ERROR
,
6331 "Element %s has a content type error\n",
6334 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6336 } else if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
6337 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6338 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ATTR
,
6339 "Found forbidden pattern attribute//attribute\n",
6342 if (flags
& XML_RELAXNG_IN_LIST
) {
6343 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ATTR
,
6344 "Found forbidden pattern list//attribute\n",
6347 if (flags
& XML_RELAXNG_IN_OOMGROUP
) {
6348 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_GROUP_ATTR
,
6349 "Found forbidden pattern oneOrMore//group//attribute\n",
6352 if (flags
& XML_RELAXNG_IN_OOMINTERLEAVE
) {
6353 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR
,
6354 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6357 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6358 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ATTR
,
6359 "Found forbidden pattern data/except//attribute\n",
6362 if (flags
& XML_RELAXNG_IN_START
) {
6363 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ATTR
,
6364 "Found forbidden pattern start//attribute\n",
6367 if ((!(flags
& XML_RELAXNG_IN_ONEORMORE
))
6368 && (cur
->name
== NULL
)) {
6369 if (cur
->ns
== NULL
) {
6370 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ANYNAME_ATTR_ANCESTOR
,
6371 "Found anyName attribute without oneOrMore ancestor\n",
6374 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NSNAME_ATTR_ANCESTOR
,
6375 "Found nsName attribute without oneOrMore ancestor\n",
6379 nflags
= flags
| XML_RELAXNG_IN_ATTRIBUTE
;
6380 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
, cur
->type
);
6381 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6382 } else if ((cur
->type
== XML_RELAXNG_ONEORMORE
) ||
6383 (cur
->type
== XML_RELAXNG_ZEROORMORE
)) {
6384 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6385 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE
,
6386 "Found forbidden pattern data/except//oneOrMore\n",
6389 if (flags
& XML_RELAXNG_IN_START
) {
6390 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ONEMORE
,
6391 "Found forbidden pattern start//oneOrMore\n",
6394 nflags
= flags
| XML_RELAXNG_IN_ONEORMORE
;
6396 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6398 ret
= xmlRelaxNGGroupContentType(ret
, ret
);
6399 } else if (cur
->type
== XML_RELAXNG_LIST
) {
6400 if (flags
& XML_RELAXNG_IN_LIST
) {
6401 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_LIST
,
6402 "Found forbidden pattern list//list\n", NULL
,
6405 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6406 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_LIST
,
6407 "Found forbidden pattern data/except//list\n",
6410 if (flags
& XML_RELAXNG_IN_START
) {
6411 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_LIST
,
6412 "Found forbidden pattern start//list\n", NULL
,
6415 nflags
= flags
| XML_RELAXNG_IN_LIST
;
6417 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6419 } else if (cur
->type
== XML_RELAXNG_GROUP
) {
6420 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6421 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_GROUP
,
6422 "Found forbidden pattern data/except//group\n",
6425 if (flags
& XML_RELAXNG_IN_START
) {
6426 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_GROUP
,
6427 "Found forbidden pattern start//group\n", NULL
,
6430 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6431 nflags
= flags
| XML_RELAXNG_IN_OOMGROUP
;
6435 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6438 * The 7.3 Attribute derivation rule for groups is plugged there
6440 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6441 } else if (cur
->type
== XML_RELAXNG_INTERLEAVE
) {
6442 if (flags
& XML_RELAXNG_IN_LIST
) {
6443 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_INTERLEAVE
,
6444 "Found forbidden pattern list//interleave\n",
6447 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6448 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6449 "Found forbidden pattern data/except//interleave\n",
6452 if (flags
& XML_RELAXNG_IN_START
) {
6453 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6454 "Found forbidden pattern start//interleave\n",
6457 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6458 nflags
= flags
| XML_RELAXNG_IN_OOMINTERLEAVE
;
6462 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6464 } else if (cur
->type
== XML_RELAXNG_EXCEPT
) {
6465 if ((cur
->parent
!= NULL
) &&
6466 (cur
->parent
->type
== XML_RELAXNG_DATATYPE
))
6467 nflags
= flags
| XML_RELAXNG_IN_DATAEXCEPT
;
6471 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6473 } else if (cur
->type
== XML_RELAXNG_DATATYPE
) {
6474 if (flags
& XML_RELAXNG_IN_START
) {
6475 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_DATA
,
6476 "Found forbidden pattern start//data\n", NULL
,
6479 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6480 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6481 } else if (cur
->type
== XML_RELAXNG_VALUE
) {
6482 if (flags
& XML_RELAXNG_IN_START
) {
6483 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_VALUE
,
6484 "Found forbidden pattern start//value\n", NULL
,
6487 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6488 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6489 } else if (cur
->type
== XML_RELAXNG_TEXT
) {
6490 if (flags
& XML_RELAXNG_IN_LIST
) {
6491 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_TEXT
,
6492 "Found forbidden pattern list//text\n", NULL
,
6495 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6496 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_TEXT
,
6497 "Found forbidden pattern data/except//text\n",
6500 if (flags
& XML_RELAXNG_IN_START
) {
6501 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_TEXT
,
6502 "Found forbidden pattern start//text\n", NULL
,
6505 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6506 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6507 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6508 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_EMPTY
,
6509 "Found forbidden pattern data/except//empty\n",
6512 if (flags
& XML_RELAXNG_IN_START
) {
6513 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_EMPTY
,
6514 "Found forbidden pattern start//empty\n", NULL
,
6517 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6518 } else if (cur
->type
== XML_RELAXNG_CHOICE
) {
6519 xmlRelaxNGCheckChoiceDeterminism(ctxt
, cur
);
6521 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6524 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6527 if (ptype
== XML_RELAXNG_GROUP
) {
6528 val
= xmlRelaxNGGroupContentType(val
, ret
);
6529 } else if (ptype
== XML_RELAXNG_INTERLEAVE
) {
6531 * TODO: scan complain that tmp is never used, seems on purpose
6532 * need double-checking
6534 tmp
= xmlRelaxNGGroupContentType(val
, ret
);
6535 if (tmp
!= XML_RELAXNG_CONTENT_ERROR
)
6536 tmp
= xmlRelaxNGMaxContentType(val
, ret
);
6537 } else if (ptype
== XML_RELAXNG_CHOICE
) {
6538 val
= xmlRelaxNGMaxContentType(val
, ret
);
6539 } else if (ptype
== XML_RELAXNG_LIST
) {
6540 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6541 } else if (ptype
== XML_RELAXNG_EXCEPT
) {
6542 if (ret
== XML_RELAXNG_CONTENT_ERROR
)
6543 val
= XML_RELAXNG_CONTENT_ERROR
;
6545 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6547 val
= xmlRelaxNGGroupContentType(val
, ret
);
6555 * xmlRelaxNGParseGrammar:
6556 * @ctxt: a Relax-NG parser context
6557 * @nodes: grammar children nodes
6559 * parse a Relax-NG <grammar> node
6561 * Returns the internal xmlRelaxNGGrammarPtr built or
6562 * NULL in case of error
6564 static xmlRelaxNGGrammarPtr
6565 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
6567 xmlRelaxNGGrammarPtr ret
, tmp
, old
;
6569 #ifdef DEBUG_GRAMMAR
6570 xmlGenericError(xmlGenericErrorContext
, "Parsing a new grammar\n");
6573 ret
= xmlRelaxNGNewGrammar(ctxt
);
6578 * Link the new grammar in the tree
6580 ret
->parent
= ctxt
->grammar
;
6581 if (ctxt
->grammar
!= NULL
) {
6582 tmp
= ctxt
->grammar
->children
;
6584 ctxt
->grammar
->children
= ret
;
6586 while (tmp
->next
!= NULL
)
6592 old
= ctxt
->grammar
;
6593 ctxt
->grammar
= ret
;
6594 xmlRelaxNGParseGrammarContent(ctxt
, nodes
);
6595 ctxt
->grammar
= ret
;
6596 if (ctxt
->grammar
== NULL
) {
6597 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
6598 "Failed to parse <grammar> content\n", NULL
, NULL
);
6599 } else if (ctxt
->grammar
->start
== NULL
) {
6600 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_NO_START
,
6601 "Element <grammar> has no <start>\n", NULL
, NULL
);
6605 * Apply 4.17 mergingd rules to defines and starts
6607 xmlRelaxNGCombineStart(ctxt
, ret
);
6608 if (ret
->defs
!= NULL
) {
6609 xmlHashScan(ret
->defs
, (xmlHashScanner
) xmlRelaxNGCheckCombine
,
6614 * link together defines and refs in this grammar
6616 if (ret
->refs
!= NULL
) {
6617 xmlHashScan(ret
->refs
, (xmlHashScanner
) xmlRelaxNGCheckReference
,
6624 ctxt
->grammar
= old
;
6629 * xmlRelaxNGParseDocument:
6630 * @ctxt: a Relax-NG parser context
6631 * @node: the root node of the RelaxNG schema
6633 * parse a Relax-NG definition resource and build an internal
6634 * xmlRelaxNG struture which can be used to validate instances.
6636 * Returns the internal XML RelaxNG structure built or
6637 * NULL in case of error
6639 static xmlRelaxNGPtr
6640 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6642 xmlRelaxNGPtr schema
= NULL
;
6643 const xmlChar
*olddefine
;
6644 xmlRelaxNGGrammarPtr old
;
6646 if ((ctxt
== NULL
) || (node
== NULL
))
6649 schema
= xmlRelaxNGNewRelaxNG(ctxt
);
6653 olddefine
= ctxt
->define
;
6654 ctxt
->define
= NULL
;
6655 if (IS_RELAXNG(node
, "grammar")) {
6656 schema
->topgrammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
6658 xmlRelaxNGGrammarPtr tmp
, ret
;
6660 schema
->topgrammar
= ret
= xmlRelaxNGNewGrammar(ctxt
);
6661 if (schema
->topgrammar
== NULL
) {
6665 * Link the new grammar in the tree
6667 ret
->parent
= ctxt
->grammar
;
6668 if (ctxt
->grammar
!= NULL
) {
6669 tmp
= ctxt
->grammar
->children
;
6671 ctxt
->grammar
->children
= ret
;
6673 while (tmp
->next
!= NULL
)
6678 old
= ctxt
->grammar
;
6679 ctxt
->grammar
= ret
;
6680 xmlRelaxNGParseStart(ctxt
, node
);
6682 ctxt
->grammar
= old
;
6684 ctxt
->define
= olddefine
;
6685 if (schema
->topgrammar
->start
!= NULL
) {
6686 xmlRelaxNGCheckCycles(ctxt
, schema
->topgrammar
->start
, 0);
6687 if ((ctxt
->flags
& XML_RELAXNG_IN_EXTERNALREF
) == 0) {
6688 xmlRelaxNGSimplify(ctxt
, schema
->topgrammar
->start
, NULL
);
6689 while ((schema
->topgrammar
->start
!= NULL
) &&
6690 (schema
->topgrammar
->start
->type
== XML_RELAXNG_NOOP
) &&
6691 (schema
->topgrammar
->start
->next
!= NULL
))
6692 schema
->topgrammar
->start
=
6693 schema
->topgrammar
->start
->content
;
6694 xmlRelaxNGCheckRules(ctxt
, schema
->topgrammar
->start
,
6695 XML_RELAXNG_IN_START
, XML_RELAXNG_NOOP
);
6700 xmlGenericError(xmlGenericErrorContext
,
6701 "xmlRelaxNGParseDocument() failed\n");
6707 /************************************************************************
6709 * Reading RelaxNGs *
6711 ************************************************************************/
6714 * xmlRelaxNGNewParserCtxt:
6715 * @URL: the location of the schema
6717 * Create an XML RelaxNGs parse context for that file/resource expected
6718 * to contain an XML RelaxNGs file.
6720 * Returns the parser context or NULL in case of error
6722 xmlRelaxNGParserCtxtPtr
6723 xmlRelaxNGNewParserCtxt(const char *URL
)
6725 xmlRelaxNGParserCtxtPtr ret
;
6731 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6733 xmlRngPErrMemory(NULL
, "building parser\n");
6736 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6737 ret
->URL
= xmlStrdup((const xmlChar
*) URL
);
6738 ret
->error
= xmlGenericError
;
6739 ret
->userData
= xmlGenericErrorContext
;
6744 * xmlRelaxNGNewMemParserCtxt:
6745 * @buffer: a pointer to a char array containing the schemas
6746 * @size: the size of the array
6748 * Create an XML RelaxNGs parse context for that memory buffer expected
6749 * to contain an XML RelaxNGs file.
6751 * Returns the parser context or NULL in case of error
6753 xmlRelaxNGParserCtxtPtr
6754 xmlRelaxNGNewMemParserCtxt(const char *buffer
, int size
)
6756 xmlRelaxNGParserCtxtPtr ret
;
6758 if ((buffer
== NULL
) || (size
<= 0))
6762 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6764 xmlRngPErrMemory(NULL
, "building parser\n");
6767 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6768 ret
->buffer
= buffer
;
6770 ret
->error
= xmlGenericError
;
6771 ret
->userData
= xmlGenericErrorContext
;
6776 * xmlRelaxNGNewDocParserCtxt:
6777 * @doc: a preparsed document tree
6779 * Create an XML RelaxNGs parser context for that document.
6780 * Note: since the process of compiling a RelaxNG schemas modifies the
6781 * document, the @doc parameter is duplicated internally.
6783 * Returns the parser context or NULL in case of error
6785 xmlRelaxNGParserCtxtPtr
6786 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc
)
6788 xmlRelaxNGParserCtxtPtr ret
;
6793 copy
= xmlCopyDoc(doc
, 1);
6798 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6800 xmlRngPErrMemory(NULL
, "building parser\n");
6803 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6804 ret
->document
= copy
;
6806 ret
->userData
= xmlGenericErrorContext
;
6811 * xmlRelaxNGFreeParserCtxt:
6812 * @ctxt: the schema parser context
6814 * Free the resources associated to the schema parser context
6817 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt
)
6821 if (ctxt
->URL
!= NULL
)
6823 if (ctxt
->doc
!= NULL
)
6824 xmlRelaxNGFreeDocument(ctxt
->doc
);
6825 if (ctxt
->interleaves
!= NULL
)
6826 xmlHashFree(ctxt
->interleaves
, NULL
);
6827 if (ctxt
->documents
!= NULL
)
6828 xmlRelaxNGFreeDocumentList(ctxt
->documents
);
6829 if (ctxt
->includes
!= NULL
)
6830 xmlRelaxNGFreeIncludeList(ctxt
->includes
);
6831 if (ctxt
->docTab
!= NULL
)
6832 xmlFree(ctxt
->docTab
);
6833 if (ctxt
->incTab
!= NULL
)
6834 xmlFree(ctxt
->incTab
);
6835 if (ctxt
->defTab
!= NULL
) {
6838 for (i
= 0; i
< ctxt
->defNr
; i
++)
6839 xmlRelaxNGFreeDefine(ctxt
->defTab
[i
]);
6840 xmlFree(ctxt
->defTab
);
6842 if ((ctxt
->document
!= NULL
) && (ctxt
->freedoc
))
6843 xmlFreeDoc(ctxt
->document
);
6848 * xmlRelaxNGNormExtSpace:
6851 * Removes the leading and ending spaces of the value
6852 * The string is modified "in situ"
6855 xmlRelaxNGNormExtSpace(xmlChar
* value
)
6857 xmlChar
*start
= value
;
6858 xmlChar
*cur
= value
;
6863 while (IS_BLANK_CH(*cur
))
6867 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6872 while (IS_BLANK_CH(*cur
))
6881 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6887 /* don't try to normalize the inner spaces */
6888 while (IS_BLANK_CH(*cur
))
6900 * xmlRelaxNGCleanupAttributes:
6901 * @ctxt: a Relax-NG parser context
6902 * @node: a Relax-NG node
6904 * Check all the attributes on the given node
6907 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6909 xmlAttrPtr cur
, next
;
6911 cur
= node
->properties
;
6912 while (cur
!= NULL
) {
6914 if ((cur
->ns
== NULL
) ||
6915 (xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
6916 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
6917 if ((!xmlStrEqual(node
->name
, BAD_CAST
"element")) &&
6918 (!xmlStrEqual(node
->name
, BAD_CAST
"attribute")) &&
6919 (!xmlStrEqual(node
->name
, BAD_CAST
"ref")) &&
6920 (!xmlStrEqual(node
->name
, BAD_CAST
"parentRef")) &&
6921 (!xmlStrEqual(node
->name
, BAD_CAST
"param")) &&
6922 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6923 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6924 "Attribute %s is not allowed on %s\n",
6925 cur
->name
, node
->name
);
6927 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"type")) {
6928 if ((!xmlStrEqual(node
->name
, BAD_CAST
"value")) &&
6929 (!xmlStrEqual(node
->name
, BAD_CAST
"data"))) {
6930 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6931 "Attribute %s is not allowed on %s\n",
6932 cur
->name
, node
->name
);
6934 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"href")) {
6935 if ((!xmlStrEqual(node
->name
, BAD_CAST
"externalRef")) &&
6936 (!xmlStrEqual(node
->name
, BAD_CAST
"include"))) {
6937 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6938 "Attribute %s is not allowed on %s\n",
6939 cur
->name
, node
->name
);
6941 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"combine")) {
6942 if ((!xmlStrEqual(node
->name
, BAD_CAST
"start")) &&
6943 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6944 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6945 "Attribute %s is not allowed on %s\n",
6946 cur
->name
, node
->name
);
6948 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"datatypeLibrary")) {
6952 val
= xmlNodeListGetString(node
->doc
, cur
->children
, 1);
6955 uri
= xmlParseURI((const char *) val
);
6957 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_URI
,
6958 "Attribute %s contains invalid URI %s\n",
6961 if (uri
->scheme
== NULL
) {
6962 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_NOT_ABSOLUTE
,
6963 "Attribute %s URI %s is not absolute\n",
6966 if (uri
->fragment
!= NULL
) {
6967 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_FRAGMENT
,
6968 "Attribute %s URI %s has a fragment ID\n",
6976 } else if (!xmlStrEqual(cur
->name
, BAD_CAST
"ns")) {
6977 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_ATTRIBUTE
,
6978 "Unknown attribute %s on %s\n", cur
->name
,
6987 * xmlRelaxNGCleanupTree:
6988 * @ctxt: a Relax-NG parser context
6989 * @root: an xmlNodePtr subtree
6991 * Cleanup the subtree from unwanted nodes for parsing, resolve
6992 * Include and externalRef lookups.
6995 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr root
)
6997 xmlNodePtr cur
, delete;
7001 while (cur
!= NULL
) {
7002 if (delete != NULL
) {
7003 xmlUnlinkNode(delete);
7004 xmlFreeNode(delete);
7007 if (cur
->type
== XML_ELEMENT_NODE
) {
7009 * Simplification 4.1. Annotations
7011 if ((cur
->ns
== NULL
) ||
7012 (!xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
7013 if ((cur
->parent
!= NULL
) &&
7014 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
7015 ((xmlStrEqual(cur
->parent
->name
, BAD_CAST
"name")) ||
7016 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value")) ||
7017 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"param")))) {
7018 xmlRngPErr(ctxt
, cur
, XML_RNGP_FOREIGN_ELEMENT
,
7019 "element %s doesn't allow foreign elements\n",
7020 cur
->parent
->name
, NULL
);
7025 xmlRelaxNGCleanupAttributes(ctxt
, cur
);
7026 if (xmlStrEqual(cur
->name
, BAD_CAST
"externalRef")) {
7027 xmlChar
*href
, *ns
, *base
, *URL
;
7028 xmlRelaxNGDocumentPtr docu
;
7032 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7035 while ((tmp
!= NULL
) &&
7036 (tmp
->type
== XML_ELEMENT_NODE
)) {
7037 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7043 href
= xmlGetProp(cur
, BAD_CAST
"href");
7045 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7046 "xmlRelaxNGParse: externalRef has no href attribute\n",
7053 uri
= xmlParseURI((const char *) href
);
7055 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7056 "Incorrect URI for externalRef %s\n",
7065 if (uri
->fragment
!= NULL
) {
7066 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7067 "Fragment forbidden in URI for externalRef %s\n",
7078 base
= xmlNodeGetBase(cur
->doc
, cur
);
7079 URL
= xmlBuildURI(href
, base
);
7081 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7082 "Failed to compute URL for externalRef %s\n",
7097 docu
= xmlRelaxNGLoadExternalRef(ctxt
, URL
, ns
);
7099 xmlRngPErr(ctxt
, cur
, XML_RNGP_EXTERNAL_REF_FAILURE
,
7100 "Failed to load externalRef %s\n", URL
,
7112 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"include")) {
7113 xmlChar
*href
, *ns
, *base
, *URL
;
7114 xmlRelaxNGIncludePtr incl
;
7117 href
= xmlGetProp(cur
, BAD_CAST
"href");
7119 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7120 "xmlRelaxNGParse: include has no href attribute\n",
7125 base
= xmlNodeGetBase(cur
->doc
, cur
);
7126 URL
= xmlBuildURI(href
, base
);
7128 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7129 "Failed to compute URL for include %s\n",
7142 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7145 while ((tmp
!= NULL
) &&
7146 (tmp
->type
== XML_ELEMENT_NODE
)) {
7147 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7153 incl
= xmlRelaxNGLoadInclude(ctxt
, URL
, cur
, ns
);
7157 xmlRngPErr(ctxt
, cur
, XML_RNGP_INCLUDE_FAILURE
,
7158 "Failed to load include %s\n", URL
,
7166 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"element")) ||
7167 (xmlStrEqual(cur
->name
, BAD_CAST
"attribute")))
7170 xmlNodePtr text
= NULL
;
7173 * Simplification 4.8. name attribute of element
7174 * and attribute elements
7176 name
= xmlGetProp(cur
, BAD_CAST
"name");
7178 if (cur
->children
== NULL
) {
7180 xmlNewChild(cur
, cur
->ns
, BAD_CAST
"name",
7185 node
= xmlNewDocNode(cur
->doc
, cur
->ns
,
7186 BAD_CAST
"name", NULL
);
7188 xmlAddPrevSibling(cur
->children
, node
);
7189 text
= xmlNewText(name
);
7190 xmlAddChild(node
, text
);
7195 xmlRngPErr(ctxt
, cur
, XML_RNGP_CREATE_FAILURE
,
7196 "Failed to create a name %s element\n",
7199 xmlUnsetProp(cur
, BAD_CAST
"name");
7201 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7204 xmlSetProp(text
, BAD_CAST
"ns", ns
);
7205 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7208 } else if (xmlStrEqual(cur
->name
,
7209 BAD_CAST
"attribute")) {
7210 xmlSetProp(text
, BAD_CAST
"ns", BAD_CAST
"");
7213 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"name")) ||
7214 (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) ||
7215 (xmlStrEqual(cur
->name
, BAD_CAST
"value"))) {
7217 * Simplification 4.8. name attribute of element
7218 * and attribute elements
7220 if (xmlHasProp(cur
, BAD_CAST
"ns") == NULL
) {
7225 while ((node
!= NULL
) &&
7226 (node
->type
== XML_ELEMENT_NODE
)) {
7227 ns
= xmlGetProp(node
, BAD_CAST
"ns");
7231 node
= node
->parent
;
7234 xmlSetProp(cur
, BAD_CAST
"ns", BAD_CAST
"");
7236 xmlSetProp(cur
, BAD_CAST
"ns", ns
);
7240 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
7241 xmlChar
*name
, *local
, *prefix
;
7244 * Simplification: 4.10. QNames
7246 name
= xmlNodeGetContent(cur
);
7248 local
= xmlSplitQName2(name
, &prefix
);
7249 if (local
!= NULL
) {
7252 ns
= xmlSearchNs(cur
->doc
, cur
, prefix
);
7254 xmlRngPErr(ctxt
, cur
,
7255 XML_RNGP_PREFIX_UNDEFINED
,
7256 "xmlRelaxNGParse: no namespace for prefix %s\n",
7259 xmlSetProp(cur
, BAD_CAST
"ns",
7261 xmlNodeSetContent(cur
, local
);
7272 if (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) {
7273 if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7274 xmlRngPErr(ctxt
, cur
,
7275 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME
,
7276 "Found nsName/except//nsName forbidden construct\n",
7280 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"except")) &&
7282 int oldflags
= ctxt
->flags
;
7287 if ((cur
->parent
!= NULL
) &&
7289 (cur
->parent
->name
, BAD_CAST
"anyName"))) {
7290 ctxt
->flags
|= XML_RELAXNG_IN_ANYEXCEPT
;
7291 xmlRelaxNGCleanupTree(ctxt
, cur
);
7292 ctxt
->flags
= oldflags
;
7294 } else if ((cur
->parent
!= NULL
) &&
7296 (cur
->parent
->name
, BAD_CAST
"nsName"))) {
7297 ctxt
->flags
|= XML_RELAXNG_IN_NSEXCEPT
;
7298 xmlRelaxNGCleanupTree(ctxt
, cur
);
7299 ctxt
->flags
= oldflags
;
7302 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"anyName")) {
7306 if (ctxt
->flags
& XML_RELAXNG_IN_ANYEXCEPT
) {
7307 xmlRngPErr(ctxt
, cur
,
7308 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME
,
7309 "Found anyName/except//anyName forbidden construct\n",
7311 } else if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7312 xmlRngPErr(ctxt
, cur
,
7313 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME
,
7314 "Found nsName/except//anyName forbidden construct\n",
7319 * Thisd is not an else since "include" is transformed
7322 if (xmlStrEqual(cur
->name
, BAD_CAST
"div")) {
7324 xmlNodePtr child
, ins
, tmp
;
7327 * implements rule 4.11
7330 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7332 child
= cur
->children
;
7334 while (child
!= NULL
) {
7336 if (!xmlHasProp(child
, BAD_CAST
"ns")) {
7337 xmlSetProp(child
, BAD_CAST
"ns", ns
);
7341 xmlUnlinkNode(child
);
7342 ins
= xmlAddNextSibling(ins
, child
);
7348 * Since we are about to delete cur, if it's nsDef is non-NULL we
7349 * need to preserve it (it contains the ns definitions for the
7350 * children we just moved). We'll just stick it on to the end
7351 * of cur->parent's list, since it's never going to be re-serialized
7354 if (cur
->nsDef
!= NULL
) {
7355 xmlNsPtr parDef
= (xmlNsPtr
)&cur
->parent
->nsDef
;
7356 while (parDef
->next
!= NULL
)
7357 parDef
= parDef
->next
;
7358 parDef
->next
= cur
->nsDef
;
7367 * Simplification 4.2 whitespaces
7369 else if ((cur
->type
== XML_TEXT_NODE
) ||
7370 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
7371 if (IS_BLANK_NODE(cur
)) {
7372 if (cur
->parent
->type
== XML_ELEMENT_NODE
) {
7373 if ((!xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value"))
7376 (cur
->parent
->name
, BAD_CAST
"param")))
7391 if (cur
->children
!= NULL
) {
7392 if ((cur
->children
->type
!= XML_ENTITY_DECL
) &&
7393 (cur
->children
->type
!= XML_ENTITY_REF_NODE
) &&
7394 (cur
->children
->type
!= XML_ENTITY_NODE
)) {
7395 cur
= cur
->children
;
7400 if (cur
->next
!= NULL
) {
7413 if (cur
->next
!= NULL
) {
7417 } while (cur
!= NULL
);
7419 if (delete != NULL
) {
7420 xmlUnlinkNode(delete);
7421 xmlFreeNode(delete);
7427 * xmlRelaxNGCleanupDoc:
7428 * @ctxt: a Relax-NG parser context
7429 * @doc: an xmldocPtr document pointer
7431 * Cleanup the document from unwanted nodes for parsing, resolve
7432 * Include and externalRef lookups.
7434 * Returns the cleaned up document or NULL in case of error
7437 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
, xmlDocPtr doc
)
7444 root
= xmlDocGetRootElement(doc
);
7446 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7450 xmlRelaxNGCleanupTree(ctxt
, root
);
7456 * @ctxt: a Relax-NG parser context
7458 * parse a schema definition resource and build an internal
7459 * XML Shema struture which can be used to validate instances.
7461 * Returns the internal XML RelaxNG structure built from the resource or
7462 * NULL in case of error
7465 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt
)
7467 xmlRelaxNGPtr ret
= NULL
;
7471 xmlRelaxNGInitTypes();
7477 * First step is to parse the input document into an DOM/Infoset
7479 if (ctxt
->URL
!= NULL
) {
7480 doc
= xmlReadFile((const char *) ctxt
->URL
,NULL
,0);
7482 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7483 "xmlRelaxNGParse: could not load %s\n", ctxt
->URL
,
7487 } else if (ctxt
->buffer
!= NULL
) {
7488 doc
= xmlReadMemory(ctxt
->buffer
, ctxt
->size
,NULL
,NULL
,0);
7490 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7491 "xmlRelaxNGParse: could not parse schemas\n", NULL
,
7495 doc
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7496 ctxt
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7497 } else if (ctxt
->document
!= NULL
) {
7498 doc
= ctxt
->document
;
7500 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EMPTY
,
7501 "xmlRelaxNGParse: nothing to parse\n", NULL
, NULL
);
7504 ctxt
->document
= doc
;
7507 * Some preprocessing of the document content
7509 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
7511 xmlFreeDoc(ctxt
->document
);
7512 ctxt
->document
= NULL
;
7517 * Then do the parsing for good
7519 root
= xmlDocGetRootElement(doc
);
7521 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
,
7522 XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7523 (ctxt
->URL
? ctxt
->URL
: BAD_CAST
"schemas"), NULL
);
7525 xmlFreeDoc(ctxt
->document
);
7526 ctxt
->document
= NULL
;
7529 ret
= xmlRelaxNGParseDocument(ctxt
, root
);
7531 xmlFreeDoc(ctxt
->document
);
7532 ctxt
->document
= NULL
;
7537 * Check the ref/defines links
7540 * try to preprocess interleaves
7542 if (ctxt
->interleaves
!= NULL
) {
7543 xmlHashScan(ctxt
->interleaves
,
7544 (xmlHashScanner
) xmlRelaxNGComputeInterleaves
, ctxt
);
7548 * if there was a parsing error return NULL
7550 if (ctxt
->nbErrors
> 0) {
7551 xmlRelaxNGFree(ret
);
7552 ctxt
->document
= NULL
;
7558 * try to compile (parts of) the schemas
7560 if ((ret
->topgrammar
!= NULL
) && (ret
->topgrammar
->start
!= NULL
)) {
7561 if (ret
->topgrammar
->start
->type
!= XML_RELAXNG_START
) {
7562 xmlRelaxNGDefinePtr def
;
7564 def
= xmlRelaxNGNewDefine(ctxt
, NULL
);
7566 def
->type
= XML_RELAXNG_START
;
7567 def
->content
= ret
->topgrammar
->start
;
7568 ret
->topgrammar
->start
= def
;
7571 xmlRelaxNGTryCompile(ctxt
, ret
->topgrammar
->start
);
7575 * Transfer the pointer for cleanup at the schema level.
7578 ctxt
->document
= NULL
;
7579 ret
->documents
= ctxt
->documents
;
7580 ctxt
->documents
= NULL
;
7582 ret
->includes
= ctxt
->includes
;
7583 ctxt
->includes
= NULL
;
7584 ret
->defNr
= ctxt
->defNr
;
7585 ret
->defTab
= ctxt
->defTab
;
7586 ctxt
->defTab
= NULL
;
7587 if (ctxt
->idref
== 1)
7594 * xmlRelaxNGSetParserErrors:
7595 * @ctxt: a Relax-NG validation context
7596 * @err: the error callback
7597 * @warn: the warning callback
7598 * @ctx: contextual data for the callbacks
7600 * Set the callback functions used to handle errors for a validation context
7603 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7604 xmlRelaxNGValidityErrorFunc err
,
7605 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
7610 ctxt
->warning
= warn
;
7611 ctxt
->serror
= NULL
;
7612 ctxt
->userData
= ctx
;
7616 * xmlRelaxNGGetParserErrors:
7617 * @ctxt: a Relax-NG validation context
7618 * @err: the error callback result
7619 * @warn: the warning callback result
7620 * @ctx: contextual data for the callbacks result
7622 * Get the callback information used to handle errors for a validation context
7624 * Returns -1 in case of failure, 0 otherwise.
7627 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7628 xmlRelaxNGValidityErrorFunc
* err
,
7629 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
7636 *warn
= ctxt
->warning
;
7638 *ctx
= ctxt
->userData
;
7643 * xmlRelaxNGSetParserStructuredErrors:
7644 * @ctxt: a Relax-NG parser context
7645 * @serror: the error callback
7646 * @ctx: contextual data for the callbacks
7648 * Set the callback functions used to handle errors for a parsing context
7651 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7652 xmlStructuredErrorFunc serror
,
7657 ctxt
->serror
= serror
;
7659 ctxt
->warning
= NULL
;
7660 ctxt
->userData
= ctx
;
7663 #ifdef LIBXML_OUTPUT_ENABLED
7665 /************************************************************************
7667 * Dump back a compiled form *
7669 ************************************************************************/
7670 static void xmlRelaxNGDumpDefine(FILE * output
,
7671 xmlRelaxNGDefinePtr define
);
7674 * xmlRelaxNGDumpDefines:
7675 * @output: the file output
7676 * @defines: a list of define structures
7678 * Dump a RelaxNG structure back
7681 xmlRelaxNGDumpDefines(FILE * output
, xmlRelaxNGDefinePtr defines
)
7683 while (defines
!= NULL
) {
7684 xmlRelaxNGDumpDefine(output
, defines
);
7685 defines
= defines
->next
;
7690 * xmlRelaxNGDumpDefine:
7691 * @output: the file output
7692 * @define: a define structure
7694 * Dump a RelaxNG structure back
7697 xmlRelaxNGDumpDefine(FILE * output
, xmlRelaxNGDefinePtr define
)
7701 switch (define
->type
) {
7702 case XML_RELAXNG_EMPTY
:
7703 fprintf(output
, "<empty/>\n");
7705 case XML_RELAXNG_NOT_ALLOWED
:
7706 fprintf(output
, "<notAllowed/>\n");
7708 case XML_RELAXNG_TEXT
:
7709 fprintf(output
, "<text/>\n");
7711 case XML_RELAXNG_ELEMENT
:
7712 fprintf(output
, "<element>\n");
7713 if (define
->name
!= NULL
) {
7714 fprintf(output
, "<name");
7715 if (define
->ns
!= NULL
)
7716 fprintf(output
, " ns=\"%s\"", define
->ns
);
7717 fprintf(output
, ">%s</name>\n", define
->name
);
7719 xmlRelaxNGDumpDefines(output
, define
->attrs
);
7720 xmlRelaxNGDumpDefines(output
, define
->content
);
7721 fprintf(output
, "</element>\n");
7723 case XML_RELAXNG_LIST
:
7724 fprintf(output
, "<list>\n");
7725 xmlRelaxNGDumpDefines(output
, define
->content
);
7726 fprintf(output
, "</list>\n");
7728 case XML_RELAXNG_ONEORMORE
:
7729 fprintf(output
, "<oneOrMore>\n");
7730 xmlRelaxNGDumpDefines(output
, define
->content
);
7731 fprintf(output
, "</oneOrMore>\n");
7733 case XML_RELAXNG_ZEROORMORE
:
7734 fprintf(output
, "<zeroOrMore>\n");
7735 xmlRelaxNGDumpDefines(output
, define
->content
);
7736 fprintf(output
, "</zeroOrMore>\n");
7738 case XML_RELAXNG_CHOICE
:
7739 fprintf(output
, "<choice>\n");
7740 xmlRelaxNGDumpDefines(output
, define
->content
);
7741 fprintf(output
, "</choice>\n");
7743 case XML_RELAXNG_GROUP
:
7744 fprintf(output
, "<group>\n");
7745 xmlRelaxNGDumpDefines(output
, define
->content
);
7746 fprintf(output
, "</group>\n");
7748 case XML_RELAXNG_INTERLEAVE
:
7749 fprintf(output
, "<interleave>\n");
7750 xmlRelaxNGDumpDefines(output
, define
->content
);
7751 fprintf(output
, "</interleave>\n");
7753 case XML_RELAXNG_OPTIONAL
:
7754 fprintf(output
, "<optional>\n");
7755 xmlRelaxNGDumpDefines(output
, define
->content
);
7756 fprintf(output
, "</optional>\n");
7758 case XML_RELAXNG_ATTRIBUTE
:
7759 fprintf(output
, "<attribute>\n");
7760 xmlRelaxNGDumpDefines(output
, define
->content
);
7761 fprintf(output
, "</attribute>\n");
7763 case XML_RELAXNG_DEF
:
7764 fprintf(output
, "<define");
7765 if (define
->name
!= NULL
)
7766 fprintf(output
, " name=\"%s\"", define
->name
);
7767 fprintf(output
, ">\n");
7768 xmlRelaxNGDumpDefines(output
, define
->content
);
7769 fprintf(output
, "</define>\n");
7771 case XML_RELAXNG_REF
:
7772 fprintf(output
, "<ref");
7773 if (define
->name
!= NULL
)
7774 fprintf(output
, " name=\"%s\"", define
->name
);
7775 fprintf(output
, ">\n");
7776 xmlRelaxNGDumpDefines(output
, define
->content
);
7777 fprintf(output
, "</ref>\n");
7779 case XML_RELAXNG_PARENTREF
:
7780 fprintf(output
, "<parentRef");
7781 if (define
->name
!= NULL
)
7782 fprintf(output
, " name=\"%s\"", define
->name
);
7783 fprintf(output
, ">\n");
7784 xmlRelaxNGDumpDefines(output
, define
->content
);
7785 fprintf(output
, "</parentRef>\n");
7787 case XML_RELAXNG_EXTERNALREF
:
7788 fprintf(output
, "<externalRef>");
7789 xmlRelaxNGDumpDefines(output
, define
->content
);
7790 fprintf(output
, "</externalRef>\n");
7792 case XML_RELAXNG_DATATYPE
:
7793 case XML_RELAXNG_VALUE
:
7795 case XML_RELAXNG_START
:
7796 case XML_RELAXNG_EXCEPT
:
7797 case XML_RELAXNG_PARAM
:
7799 case XML_RELAXNG_NOOP
:
7800 xmlRelaxNGDumpDefines(output
, define
->content
);
7806 * xmlRelaxNGDumpGrammar:
7807 * @output: the file output
7808 * @grammar: a grammar structure
7809 * @top: is this a top grammar
7811 * Dump a RelaxNG structure back
7814 xmlRelaxNGDumpGrammar(FILE * output
, xmlRelaxNGGrammarPtr grammar
, int top
)
7816 if (grammar
== NULL
)
7819 fprintf(output
, "<grammar");
7821 fprintf(output
, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7822 switch (grammar
->combine
) {
7823 case XML_RELAXNG_COMBINE_UNDEFINED
:
7825 case XML_RELAXNG_COMBINE_CHOICE
:
7826 fprintf(output
, " combine=\"choice\"");
7828 case XML_RELAXNG_COMBINE_INTERLEAVE
:
7829 fprintf(output
, " combine=\"interleave\"");
7832 fprintf(output
, " <!-- invalid combine value -->");
7834 fprintf(output
, ">\n");
7835 if (grammar
->start
== NULL
) {
7836 fprintf(output
, " <!-- grammar had no start -->");
7838 fprintf(output
, "<start>\n");
7839 xmlRelaxNGDumpDefine(output
, grammar
->start
);
7840 fprintf(output
, "</start>\n");
7842 /* TODO ? Dump the defines ? */
7843 fprintf(output
, "</grammar>\n");
7848 * @output: the file output
7849 * @schema: a schema structure
7851 * Dump a RelaxNG structure back
7854 xmlRelaxNGDump(FILE * output
, xmlRelaxNGPtr schema
)
7858 if (schema
== NULL
) {
7859 fprintf(output
, "RelaxNG empty or failed to compile\n");
7862 fprintf(output
, "RelaxNG: ");
7863 if (schema
->doc
== NULL
) {
7864 fprintf(output
, "no document\n");
7865 } else if (schema
->doc
->URL
!= NULL
) {
7866 fprintf(output
, "%s\n", schema
->doc
->URL
);
7868 fprintf(output
, "\n");
7870 if (schema
->topgrammar
== NULL
) {
7871 fprintf(output
, "RelaxNG has no top grammar\n");
7874 xmlRelaxNGDumpGrammar(output
, schema
->topgrammar
, 1);
7878 * xmlRelaxNGDumpTree:
7879 * @output: the file output
7880 * @schema: a schema structure
7882 * Dump the transformed RelaxNG tree.
7885 xmlRelaxNGDumpTree(FILE * output
, xmlRelaxNGPtr schema
)
7889 if (schema
== NULL
) {
7890 fprintf(output
, "RelaxNG empty or failed to compile\n");
7893 if (schema
->doc
== NULL
) {
7894 fprintf(output
, "no document\n");
7896 xmlDocDump(output
, schema
->doc
);
7899 #endif /* LIBXML_OUTPUT_ENABLED */
7901 /************************************************************************
7903 * Validation of compiled content *
7905 ************************************************************************/
7906 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
7907 xmlRelaxNGDefinePtr define
);
7910 * xmlRelaxNGValidateCompiledCallback:
7911 * @exec: the regular expression instance
7912 * @token: the token which matched
7913 * @transdata: callback data, the define for the subelement if available
7914 @ @inputdata: callback data, the Relax NG validation context
7916 * Handle the callback and if needed validate the element children.
7919 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED
,
7920 const xmlChar
* token
,
7921 void *transdata
, void *inputdata
)
7923 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
7924 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
7927 #ifdef DEBUG_COMPILE
7928 xmlGenericError(xmlGenericErrorContext
,
7929 "Compiled callback for: '%s'\n", token
);
7932 fprintf(stderr
, "callback on %s missing context\n", token
);
7935 if (define
== NULL
) {
7936 if (token
[0] == '#')
7938 fprintf(stderr
, "callback on %s missing define\n", token
);
7939 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7940 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7943 if ((ctxt
== NULL
) || (define
== NULL
)) {
7944 fprintf(stderr
, "callback on %s missing info\n", token
);
7945 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7946 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7948 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
7949 fprintf(stderr
, "callback on %s define is not element\n", token
);
7950 if (ctxt
->errNo
== XML_RELAXNG_OK
)
7951 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7954 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
);
7960 * xmlRelaxNGValidateCompiledContent:
7961 * @ctxt: the RelaxNG validation context
7962 * @regexp: the regular expression as compiled
7963 * @content: list of children to test against the regexp
7965 * Validate the content model of an element or start using the regexp
7967 * Returns 0 in case of success, -1 in case of error.
7970 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt
,
7971 xmlRegexpPtr regexp
, xmlNodePtr content
)
7973 xmlRegExecCtxtPtr exec
;
7978 if ((ctxt
== NULL
) || (regexp
== NULL
))
7980 oldperr
= ctxt
->perr
;
7981 exec
= xmlRegNewExecCtxt(regexp
,
7982 xmlRelaxNGValidateCompiledCallback
, ctxt
);
7985 while (cur
!= NULL
) {
7986 ctxt
->state
->seq
= cur
;
7987 switch (cur
->type
) {
7989 case XML_CDATA_SECTION_NODE
:
7990 if (xmlIsBlankNode(cur
))
7992 ret
= xmlRegExecPushString(exec
, BAD_CAST
"#text", ctxt
);
7994 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
,
7998 case XML_ELEMENT_NODE
:
7999 if (cur
->ns
!= NULL
) {
8000 ret
= xmlRegExecPushString2(exec
, cur
->name
,
8001 cur
->ns
->href
, ctxt
);
8003 ret
= xmlRegExecPushString(exec
, cur
->name
, ctxt
);
8006 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, cur
->name
);
8015 * Switch to next element
8019 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8022 ctxt
->state
->seq
= NULL
;
8023 } else if (ret
== 0) {
8025 * TODO: get some of the names needed to exit the current state of exec
8027 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8029 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8030 xmlRelaxNGDumpValidError(ctxt
);
8034 xmlRegFreeExecCtxt(exec
);
8036 * There might be content model errors outside of the pure
8037 * regexp validation, e.g. for attribute values.
8039 if ((ret
== 0) && (ctxt
->perr
!= 0)) {
8042 ctxt
->perr
= oldperr
;
8046 /************************************************************************
8048 * Progressive validation of when possible *
8050 ************************************************************************/
8051 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
8052 xmlRelaxNGDefinePtr defines
);
8053 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
,
8055 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
);
8058 * xmlRelaxNGElemPush:
8059 * @ctxt: the validation context
8060 * @exec: the regexp runtime for the new content model
8062 * Push a new regexp for the current node content model on the stack
8064 * Returns 0 in case of success and -1 in case of error.
8067 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt
, xmlRegExecCtxtPtr exec
)
8069 if (ctxt
->elemTab
== NULL
) {
8071 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlMalloc(ctxt
->elemMax
*
8073 (xmlRegExecCtxtPtr
));
8074 if (ctxt
->elemTab
== NULL
) {
8075 xmlRngVErrMemory(ctxt
, "validating\n");
8079 if (ctxt
->elemNr
>= ctxt
->elemMax
) {
8081 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlRealloc(ctxt
->elemTab
,
8084 (xmlRegExecCtxtPtr
));
8085 if (ctxt
->elemTab
== NULL
) {
8086 xmlRngVErrMemory(ctxt
, "validating\n");
8090 ctxt
->elemTab
[ctxt
->elemNr
++] = exec
;
8096 * xmlRelaxNGElemPop:
8097 * @ctxt: the validation context
8099 * Pop the regexp of the current node content model from the stack
8101 * Returns the exec or NULL if empty
8103 static xmlRegExecCtxtPtr
8104 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt
)
8106 xmlRegExecCtxtPtr ret
;
8108 if (ctxt
->elemNr
<= 0)
8111 ret
= ctxt
->elemTab
[ctxt
->elemNr
];
8112 ctxt
->elemTab
[ctxt
->elemNr
] = NULL
;
8113 if (ctxt
->elemNr
> 0)
8114 ctxt
->elem
= ctxt
->elemTab
[ctxt
->elemNr
- 1];
8121 * xmlRelaxNGValidateProgressiveCallback:
8122 * @exec: the regular expression instance
8123 * @token: the token which matched
8124 * @transdata: callback data, the define for the subelement if available
8125 @ @inputdata: callback data, the Relax NG validation context
8127 * Handle the callback and if needed validate the element children.
8128 * some of the in/out informations are passed via the context in @inputdata.
8131 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8133 const xmlChar
* token
,
8134 void *transdata
, void *inputdata
)
8136 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
8137 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
8138 xmlRelaxNGValidStatePtr state
, oldstate
;
8140 int ret
= 0, oldflags
;
8142 #ifdef DEBUG_PROGRESSIVE
8143 xmlGenericError(xmlGenericErrorContext
,
8144 "Progressive callback for: '%s'\n", token
);
8147 fprintf(stderr
, "callback on %s missing context\n", token
);
8152 if (define
== NULL
) {
8153 if (token
[0] == '#')
8155 fprintf(stderr
, "callback on %s missing define\n", token
);
8156 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8157 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8161 if ((ctxt
== NULL
) || (define
== NULL
)) {
8162 fprintf(stderr
, "callback on %s missing info\n", token
);
8163 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8164 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8167 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
8168 fprintf(stderr
, "callback on %s define is not element\n", token
);
8169 if (ctxt
->errNo
== XML_RELAXNG_OK
)
8170 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8174 if (node
->type
!= XML_ELEMENT_NODE
) {
8175 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
8176 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8177 xmlRelaxNGDumpValidError(ctxt
);
8181 if (define
->contModel
== NULL
) {
8183 * this node cannot be validated in a streamable fashion
8185 #ifdef DEBUG_PROGRESSIVE
8186 xmlGenericError(xmlGenericErrorContext
,
8187 "Element '%s' validation is not streamable\n",
8191 ctxt
->pdef
= define
;
8194 exec
= xmlRegNewExecCtxt(define
->contModel
,
8195 xmlRelaxNGValidateProgressiveCallback
, ctxt
);
8200 xmlRelaxNGElemPush(ctxt
, exec
);
8203 * Validate the attributes part of the content.
8205 state
= xmlRelaxNGNewValidState(ctxt
, node
);
8206 if (state
== NULL
) {
8210 oldstate
= ctxt
->state
;
8211 ctxt
->state
= state
;
8212 if (define
->attrs
!= NULL
) {
8213 ret
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
8216 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
8219 if (ctxt
->state
!= NULL
) {
8220 ctxt
->state
->seq
= NULL
;
8221 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
8225 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8226 } else if (ctxt
->states
!= NULL
) {
8229 oldflags
= ctxt
->flags
;
8231 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8232 state
= ctxt
->states
->tabState
[i
];
8233 ctxt
->state
= state
;
8234 ctxt
->state
->seq
= NULL
;
8236 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
8243 * validation error, log the message for the "best" one
8245 ctxt
->flags
|= FLAGS_IGNORABLE
;
8246 xmlRelaxNGLogBestError(ctxt
);
8248 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8249 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[i
]);
8251 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
8252 ctxt
->states
= NULL
;
8253 if ((ret
== 0) && (tmp
== -1))
8255 ctxt
->flags
= oldflags
;
8257 if (ctxt
->pstate
== -1) {
8258 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
8259 xmlRelaxNGDumpValidError(ctxt
);
8262 ctxt
->state
= oldstate
;
8266 * xmlRelaxNGValidatePushElement:
8267 * @ctxt: the validation context
8268 * @doc: a document instance
8269 * @elem: an element instance
8271 * Push a new element start on the RelaxNG validation stack.
8273 * returns 1 if no validation problem was found or 0 if validating the
8274 * element requires a full node, and -1 in case of error.
8277 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt
,
8278 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8283 if ((ctxt
== NULL
) || (elem
== NULL
))
8286 #ifdef DEBUG_PROGRESSIVE
8287 xmlGenericError(xmlGenericErrorContext
, "PushElem %s\n", elem
->name
);
8289 if (ctxt
->elem
== 0) {
8290 xmlRelaxNGPtr schema
;
8291 xmlRelaxNGGrammarPtr grammar
;
8292 xmlRegExecCtxtPtr exec
;
8293 xmlRelaxNGDefinePtr define
;
8295 schema
= ctxt
->schema
;
8296 if (schema
== NULL
) {
8297 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8300 grammar
= schema
->topgrammar
;
8301 if ((grammar
== NULL
) || (grammar
->start
== NULL
)) {
8302 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8305 define
= grammar
->start
;
8306 if (define
->contModel
== NULL
) {
8307 ctxt
->pdef
= define
;
8310 exec
= xmlRegNewExecCtxt(define
->contModel
,
8311 xmlRelaxNGValidateProgressiveCallback
,
8316 xmlRelaxNGElemPush(ctxt
, exec
);
8320 if (elem
->ns
!= NULL
) {
8322 xmlRegExecPushString2(ctxt
->elem
, elem
->name
, elem
->ns
->href
,
8325 ret
= xmlRegExecPushString(ctxt
->elem
, elem
->name
, ctxt
);
8328 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, elem
->name
);
8330 if (ctxt
->pstate
== 0)
8332 else if (ctxt
->pstate
< 0)
8337 #ifdef DEBUG_PROGRESSIVE
8339 xmlGenericError(xmlGenericErrorContext
, "PushElem %s failed\n",
8346 * xmlRelaxNGValidatePushCData:
8347 * @ctxt: the RelaxNG validation context
8348 * @data: some character data read
8349 * @len: the lenght of the data
8351 * check the CData parsed for validation in the current stack
8353 * returns 1 if no validation problem was found or -1 otherwise
8356 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt
,
8357 const xmlChar
* data
, int len ATTRIBUTE_UNUSED
)
8361 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (data
== NULL
))
8364 #ifdef DEBUG_PROGRESSIVE
8365 xmlGenericError(xmlGenericErrorContext
, "CDATA %s %d\n", data
, len
);
8368 while (*data
!= 0) {
8369 if (!IS_BLANK_CH(*data
))
8376 ret
= xmlRegExecPushString(ctxt
->elem
, BAD_CAST
"#text", ctxt
);
8378 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
, BAD_CAST
" TODO ");
8379 #ifdef DEBUG_PROGRESSIVE
8380 xmlGenericError(xmlGenericErrorContext
, "CDATA failed\n");
8389 * xmlRelaxNGValidatePopElement:
8390 * @ctxt: the RelaxNG validation context
8391 * @doc: a document instance
8392 * @elem: an element instance
8394 * Pop the element end from the RelaxNG validation stack.
8396 * returns 1 if no validation problem was found or 0 otherwise
8399 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt
,
8400 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8404 xmlRegExecCtxtPtr exec
;
8406 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (elem
== NULL
))
8408 #ifdef DEBUG_PROGRESSIVE
8409 xmlGenericError(xmlGenericErrorContext
, "PopElem %s\n", elem
->name
);
8412 * verify that we reached a terminal state of the content model.
8414 exec
= xmlRelaxNGElemPop(ctxt
);
8415 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8418 * TODO: get some of the names needed to exit the current state of exec
8420 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8422 } else if (ret
< 0) {
8427 xmlRegFreeExecCtxt(exec
);
8428 #ifdef DEBUG_PROGRESSIVE
8430 xmlGenericError(xmlGenericErrorContext
, "PopElem %s failed\n",
8437 * xmlRelaxNGValidateFullElement:
8438 * @ctxt: the validation context
8439 * @doc: a document instance
8440 * @elem: an element instance
8442 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8443 * 0 and the content of the node has been expanded.
8445 * returns 1 if no validation problem was found or -1 in case of error.
8448 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt
,
8449 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8453 xmlRelaxNGValidStatePtr state
;
8455 if ((ctxt
== NULL
) || (ctxt
->pdef
== NULL
) || (elem
== NULL
))
8457 #ifdef DEBUG_PROGRESSIVE
8458 xmlGenericError(xmlGenericErrorContext
, "FullElem %s\n", elem
->name
);
8460 state
= xmlRelaxNGNewValidState(ctxt
, elem
->parent
);
8461 if (state
== NULL
) {
8465 ctxt
->state
= state
;
8466 ctxt
->errNo
= XML_RELAXNG_OK
;
8467 ret
= xmlRelaxNGValidateDefinition(ctxt
, ctxt
->pdef
);
8468 if ((ret
!= 0) || (ctxt
->errNo
!= XML_RELAXNG_OK
))
8472 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8474 #ifdef DEBUG_PROGRESSIVE
8476 xmlGenericError(xmlGenericErrorContext
, "FullElem %s failed\n",
8482 /************************************************************************
8484 * Generic interpreted validation implementation *
8486 ************************************************************************/
8487 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8488 xmlRelaxNGDefinePtr define
);
8491 * xmlRelaxNGSkipIgnored:
8492 * @ctxt: a schema validation context
8493 * @node: the top node.
8495 * Skip ignorable nodes in that context
8497 * Returns the new sibling or NULL in case of error.
8500 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
8504 * TODO complete and handle entities
8506 while ((node
!= NULL
) &&
8507 ((node
->type
== XML_COMMENT_NODE
) ||
8508 (node
->type
== XML_PI_NODE
) ||
8509 (node
->type
== XML_XINCLUDE_START
) ||
8510 (node
->type
== XML_XINCLUDE_END
) ||
8511 (((node
->type
== XML_TEXT_NODE
) ||
8512 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
8513 ((ctxt
->flags
& FLAGS_MIXED_CONTENT
) ||
8514 (IS_BLANK_NODE(node
)))))) {
8521 * xmlRelaxNGNormalize:
8522 * @ctxt: a schema validation context
8523 * @str: the string to normalize
8525 * Implements the normalizeWhiteSpace( s ) function from
8526 * section 6.2.9 of the spec
8528 * Returns the new string or NULL in case of error.
8531 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
, const xmlChar
* str
)
8544 ret
= (xmlChar
*) xmlMallocAtomic((len
+ 1) * sizeof(xmlChar
));
8546 xmlRngVErrMemory(ctxt
, "validating\n");
8550 while (IS_BLANK_CH(*str
))
8553 if (IS_BLANK_CH(*str
)) {
8554 while (IS_BLANK_CH(*str
))
8567 * xmlRelaxNGValidateDatatype:
8568 * @ctxt: a Relax-NG validation context
8569 * @value: the string value
8570 * @type: the datatype definition
8573 * Validate the given value against the dataype
8575 * Returns 0 if the validation succeeded or an error code.
8578 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt
,
8579 const xmlChar
* value
,
8580 xmlRelaxNGDefinePtr define
, xmlNodePtr node
)
8583 xmlRelaxNGTypeLibraryPtr lib
;
8584 void *result
= NULL
;
8585 xmlRelaxNGDefinePtr cur
;
8587 if ((define
== NULL
) || (define
->data
== NULL
)) {
8590 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8591 if (lib
->check
!= NULL
) {
8592 if ((define
->attrs
!= NULL
) &&
8593 (define
->attrs
->type
== XML_RELAXNG_PARAM
)) {
8595 lib
->check(lib
->data
, define
->name
, value
, &result
, node
);
8597 ret
= lib
->check(lib
->data
, define
->name
, value
, NULL
, node
);
8602 VALID_ERR2(XML_RELAXNG_ERR_TYPE
, define
->name
);
8603 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8604 lib
->freef(lib
->data
, result
);
8606 } else if (ret
== 1) {
8608 } else if (ret
== 2) {
8609 VALID_ERR2P(XML_RELAXNG_ERR_DUPID
, value
);
8611 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL
, define
->name
, value
);
8614 cur
= define
->attrs
;
8615 while ((ret
== 0) && (cur
!= NULL
) && (cur
->type
== XML_RELAXNG_PARAM
)) {
8616 if (lib
->facet
!= NULL
) {
8617 tmp
= lib
->facet(lib
->data
, define
->name
, cur
->name
,
8618 cur
->value
, value
, result
);
8624 if ((ret
== 0) && (define
->content
!= NULL
)) {
8625 const xmlChar
*oldvalue
, *oldendvalue
;
8627 oldvalue
= ctxt
->state
->value
;
8628 oldendvalue
= ctxt
->state
->endvalue
;
8629 ctxt
->state
->value
= (xmlChar
*) value
;
8630 ctxt
->state
->endvalue
= NULL
;
8631 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8632 ctxt
->state
->value
= (xmlChar
*) oldvalue
;
8633 ctxt
->state
->endvalue
= (xmlChar
*) oldendvalue
;
8635 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8636 lib
->freef(lib
->data
, result
);
8641 * xmlRelaxNGNextValue:
8642 * @ctxt: a Relax-NG validation context
8644 * Skip to the next value when validating within a list
8646 * Returns 0 if the operation succeeded or an error code.
8649 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt
)
8653 cur
= ctxt
->state
->value
;
8654 if ((cur
== NULL
) || (ctxt
->state
->endvalue
== NULL
)) {
8655 ctxt
->state
->value
= NULL
;
8656 ctxt
->state
->endvalue
= NULL
;
8661 while ((cur
!= ctxt
->state
->endvalue
) && (*cur
== 0))
8663 if (cur
== ctxt
->state
->endvalue
)
8664 ctxt
->state
->value
= NULL
;
8666 ctxt
->state
->value
= cur
;
8671 * xmlRelaxNGValidateValueList:
8672 * @ctxt: a Relax-NG validation context
8673 * @defines: the list of definitions to verify
8675 * Validate the given set of definitions for the current value
8677 * Returns 0 if the validation succeeded or an error code.
8680 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt
,
8681 xmlRelaxNGDefinePtr defines
)
8685 while (defines
!= NULL
) {
8686 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
8689 defines
= defines
->next
;
8695 * xmlRelaxNGValidateValue:
8696 * @ctxt: a Relax-NG validation context
8697 * @define: the definition to verify
8699 * Validate the given definition for the current value
8701 * Returns 0 if the validation succeeded or an error code.
8704 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8705 xmlRelaxNGDefinePtr define
)
8707 int ret
= 0, oldflags
;
8710 value
= ctxt
->state
->value
;
8711 switch (define
->type
) {
8712 case XML_RELAXNG_EMPTY
:{
8713 if ((value
!= NULL
) && (value
[0] != 0)) {
8716 while (IS_BLANK_CH(value
[idx
]))
8718 if (value
[idx
] != 0)
8723 case XML_RELAXNG_TEXT
:
8725 case XML_RELAXNG_VALUE
:{
8726 if (!xmlStrEqual(value
, define
->value
)) {
8727 if (define
->name
!= NULL
) {
8728 xmlRelaxNGTypeLibraryPtr lib
;
8730 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8731 if ((lib
!= NULL
) && (lib
->comp
!= NULL
)) {
8732 ret
= lib
->comp(lib
->data
, define
->name
,
8733 define
->value
, define
->node
,
8734 (void *) define
->attrs
,
8735 value
, ctxt
->state
->node
);
8739 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP
,
8742 } else if (ret
== 1) {
8748 xmlChar
*nval
, *nvalue
;
8751 * TODO: trivial optimizations are possible by
8752 * computing at compile-time
8754 nval
= xmlRelaxNGNormalize(ctxt
, define
->value
);
8755 nvalue
= xmlRelaxNGNormalize(ctxt
, value
);
8757 if ((nval
== NULL
) || (nvalue
== NULL
) ||
8758 (!xmlStrEqual(nval
, nvalue
)))
8767 xmlRelaxNGNextValue(ctxt
);
8770 case XML_RELAXNG_DATATYPE
:{
8771 ret
= xmlRelaxNGValidateDatatype(ctxt
, value
, define
,
8774 xmlRelaxNGNextValue(ctxt
);
8778 case XML_RELAXNG_CHOICE
:{
8779 xmlRelaxNGDefinePtr list
= define
->content
;
8782 oldflags
= ctxt
->flags
;
8783 ctxt
->flags
|= FLAGS_IGNORABLE
;
8785 oldvalue
= ctxt
->state
->value
;
8786 while (list
!= NULL
) {
8787 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8791 ctxt
->state
->value
= oldvalue
;
8794 ctxt
->flags
= oldflags
;
8796 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8797 xmlRelaxNGDumpValidError(ctxt
);
8799 if (ctxt
->errNr
> 0)
8800 xmlRelaxNGPopErrors(ctxt
, 0);
8804 case XML_RELAXNG_LIST
:{
8805 xmlRelaxNGDefinePtr list
= define
->content
;
8806 xmlChar
*oldvalue
, *oldend
, *val
, *cur
;
8812 oldvalue
= ctxt
->state
->value
;
8813 oldend
= ctxt
->state
->endvalue
;
8815 val
= xmlStrdup(oldvalue
);
8817 val
= xmlStrdup(BAD_CAST
"");
8820 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
8825 if (IS_BLANK_CH(*cur
)) {
8831 while (IS_BLANK_CH(*cur
))
8837 xmlGenericError(xmlGenericErrorContext
,
8838 "list value: '%s' found %d items\n",
8839 oldvalue
, nb_values
);
8842 ctxt
->state
->endvalue
= cur
;
8844 while ((*cur
== 0) && (cur
!= ctxt
->state
->endvalue
))
8847 ctxt
->state
->value
= cur
;
8849 while (list
!= NULL
) {
8850 if (ctxt
->state
->value
== ctxt
->state
->endvalue
)
8851 ctxt
->state
->value
= NULL
;
8852 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8855 xmlGenericError(xmlGenericErrorContext
,
8856 "Failed to validate value: '%s' with %d rule\n",
8857 ctxt
->state
->value
, nb_values
);
8867 if ((ret
== 0) && (ctxt
->state
->value
!= NULL
) &&
8868 (ctxt
->state
->value
!= ctxt
->state
->endvalue
)) {
8869 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA
,
8870 ctxt
->state
->value
);
8874 ctxt
->state
->value
= oldvalue
;
8875 ctxt
->state
->endvalue
= oldend
;
8878 case XML_RELAXNG_ONEORMORE
:
8879 ret
= xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8883 /* no break on purpose */
8884 case XML_RELAXNG_ZEROORMORE
:{
8885 xmlChar
*cur
, *temp
;
8887 oldflags
= ctxt
->flags
;
8888 ctxt
->flags
|= FLAGS_IGNORABLE
;
8889 cur
= ctxt
->state
->value
;
8891 while ((cur
!= NULL
) && (cur
!= ctxt
->state
->endvalue
) &&
8895 xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8897 ctxt
->state
->value
= temp
;
8901 cur
= ctxt
->state
->value
;
8903 ctxt
->flags
= oldflags
;
8904 if (ctxt
->errNr
> 0)
8905 xmlRelaxNGPopErrors(ctxt
, 0);
8908 case XML_RELAXNG_EXCEPT
:{
8909 xmlRelaxNGDefinePtr list
;
8911 list
= define
->content
;
8912 while (list
!= NULL
) {
8913 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8923 case XML_RELAXNG_DEF
:
8924 case XML_RELAXNG_GROUP
:{
8925 xmlRelaxNGDefinePtr list
;
8927 list
= define
->content
;
8928 while (list
!= NULL
) {
8929 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8939 case XML_RELAXNG_REF
:
8940 case XML_RELAXNG_PARENTREF
:
8941 if (define
->content
== NULL
) {
8942 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
8945 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8955 * xmlRelaxNGValidateValueContent:
8956 * @ctxt: a Relax-NG validation context
8957 * @defines: the list of definitions to verify
8959 * Validate the given definitions for the current value
8961 * Returns 0 if the validation succeeded or an error code.
8964 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt
,
8965 xmlRelaxNGDefinePtr defines
)
8969 while (defines
!= NULL
) {
8970 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
8973 defines
= defines
->next
;
8979 * xmlRelaxNGAttributeMatch:
8980 * @ctxt: a Relax-NG validation context
8981 * @define: the definition to check
8982 * @prop: the attribute
8984 * Check if the attribute matches the definition nameClass
8986 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
8989 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt
,
8990 xmlRelaxNGDefinePtr define
, xmlAttrPtr prop
)
8994 if (define
->name
!= NULL
) {
8995 if (!xmlStrEqual(define
->name
, prop
->name
))
8998 if (define
->ns
!= NULL
) {
8999 if (define
->ns
[0] == 0) {
9000 if (prop
->ns
!= NULL
)
9003 if ((prop
->ns
== NULL
) ||
9004 (!xmlStrEqual(define
->ns
, prop
->ns
->href
)))
9008 if (define
->nameClass
== NULL
)
9010 define
= define
->nameClass
;
9011 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9012 xmlRelaxNGDefinePtr list
;
9014 list
= define
->content
;
9015 while (list
!= NULL
) {
9016 ret
= xmlRelaxNGAttributeMatch(ctxt
, list
, prop
);
9029 * xmlRelaxNGValidateAttribute:
9030 * @ctxt: a Relax-NG validation context
9031 * @define: the definition to verify
9033 * Validate the given attribute definition for that node
9035 * Returns 0 if the validation succeeded or an error code.
9038 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt
,
9039 xmlRelaxNGDefinePtr define
)
9042 xmlChar
*value
, *oldvalue
;
9043 xmlAttrPtr prop
= NULL
, tmp
;
9046 if (ctxt
->state
->nbAttrLeft
<= 0)
9048 if (define
->name
!= NULL
) {
9049 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9050 tmp
= ctxt
->state
->attrs
[i
];
9051 if ((tmp
!= NULL
) && (xmlStrEqual(define
->name
, tmp
->name
))) {
9052 if ((((define
->ns
== NULL
) || (define
->ns
[0] == 0)) &&
9053 (tmp
->ns
== NULL
)) ||
9054 ((tmp
->ns
!= NULL
) &&
9055 (xmlStrEqual(define
->ns
, tmp
->ns
->href
)))) {
9062 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9063 oldvalue
= ctxt
->state
->value
;
9064 oldseq
= ctxt
->state
->seq
;
9065 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9066 ctxt
->state
->value
= value
;
9067 ctxt
->state
->endvalue
= NULL
;
9068 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9069 if (ctxt
->state
->value
!= NULL
)
9070 value
= ctxt
->state
->value
;
9073 ctxt
->state
->value
= oldvalue
;
9074 ctxt
->state
->seq
= oldseq
;
9077 * flag the attribute as processed
9079 ctxt
->state
->attrs
[i
] = NULL
;
9080 ctxt
->state
->nbAttrLeft
--;
9086 xmlGenericError(xmlGenericErrorContext
,
9087 "xmlRelaxNGValidateAttribute(%s): %d\n",
9091 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9092 tmp
= ctxt
->state
->attrs
[i
];
9093 if ((tmp
!= NULL
) &&
9094 (xmlRelaxNGAttributeMatch(ctxt
, define
, tmp
) == 1)) {
9100 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9101 oldvalue
= ctxt
->state
->value
;
9102 oldseq
= ctxt
->state
->seq
;
9103 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9104 ctxt
->state
->value
= value
;
9105 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9106 if (ctxt
->state
->value
!= NULL
)
9107 value
= ctxt
->state
->value
;
9110 ctxt
->state
->value
= oldvalue
;
9111 ctxt
->state
->seq
= oldseq
;
9114 * flag the attribute as processed
9116 ctxt
->state
->attrs
[i
] = NULL
;
9117 ctxt
->state
->nbAttrLeft
--;
9123 if (define
->ns
!= NULL
) {
9124 xmlGenericError(xmlGenericErrorContext
,
9125 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9128 xmlGenericError(xmlGenericErrorContext
,
9129 "xmlRelaxNGValidateAttribute(anyName): %d\n",
9139 * xmlRelaxNGValidateAttributeList:
9140 * @ctxt: a Relax-NG validation context
9141 * @define: the list of definition to verify
9143 * Validate the given node against the list of attribute definitions
9145 * Returns 0 if the validation succeeded or an error code.
9148 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
9149 xmlRelaxNGDefinePtr defines
)
9153 xmlRelaxNGDefinePtr cur
;
9156 while (cur
!= NULL
) {
9157 if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
9158 if (xmlRelaxNGValidateAttribute(ctxt
, cur
) != 0)
9167 while (cur
!= NULL
) {
9168 if (cur
->type
!= XML_RELAXNG_ATTRIBUTE
) {
9169 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9170 res
= xmlRelaxNGValidateDefinition(ctxt
, cur
);
9174 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9177 if (res
== -1) /* continues on -2 */
9187 * xmlRelaxNGNodeMatchesList:
9189 * @list: a NULL terminated array of definitions
9191 * Check if a node can be matched by one of the definitions
9193 * Returns 1 if matches 0 otherwise
9196 xmlRelaxNGNodeMatchesList(xmlNodePtr node
, xmlRelaxNGDefinePtr
* list
)
9198 xmlRelaxNGDefinePtr cur
;
9201 if ((node
== NULL
) || (list
== NULL
))
9205 while (cur
!= NULL
) {
9206 if ((node
->type
== XML_ELEMENT_NODE
) &&
9207 (cur
->type
== XML_RELAXNG_ELEMENT
)) {
9208 tmp
= xmlRelaxNGElementMatch(NULL
, cur
, node
);
9211 } else if (((node
->type
== XML_TEXT_NODE
) ||
9212 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
9213 (cur
->type
== XML_RELAXNG_TEXT
)) {
9222 * xmlRelaxNGValidateInterleave:
9223 * @ctxt: a Relax-NG validation context
9224 * @define: the definition to verify
9226 * Validate an interleave definition for a node.
9228 * Returns 0 if the validation succeeded or an error code.
9231 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt
,
9232 xmlRelaxNGDefinePtr define
)
9234 int ret
= 0, i
, nbgroups
;
9235 int errNr
= ctxt
->errNr
;
9238 xmlRelaxNGValidStatePtr oldstate
;
9239 xmlRelaxNGPartitionPtr partitions
;
9240 xmlRelaxNGInterleaveGroupPtr group
= NULL
;
9241 xmlNodePtr cur
, start
, last
= NULL
, lastchg
= NULL
, lastelem
;
9242 xmlNodePtr
*list
= NULL
, *lasts
= NULL
;
9244 if (define
->data
!= NULL
) {
9245 partitions
= (xmlRelaxNGPartitionPtr
) define
->data
;
9246 nbgroups
= partitions
->nbgroups
;
9248 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA
);
9252 * Optimizations for MIXED
9254 oldflags
= ctxt
->flags
;
9255 if (define
->dflags
& IS_MIXED
) {
9256 ctxt
->flags
|= FLAGS_MIXED_CONTENT
;
9257 if (nbgroups
== 2) {
9259 * this is a pure <mixed> case
9261 if (ctxt
->state
!= NULL
)
9262 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9264 if (partitions
->groups
[0]->rule
->type
== XML_RELAXNG_TEXT
)
9265 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9266 partitions
->groups
[1]->
9269 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9270 partitions
->groups
[0]->
9273 if (ctxt
->state
!= NULL
)
9274 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9278 ctxt
->flags
= oldflags
;
9284 * Build arrays to store the first and last node of the chain
9285 * pertaining to each group
9287 list
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9289 xmlRngVErrMemory(ctxt
, "validating\n");
9292 memset(list
, 0, nbgroups
* sizeof(xmlNodePtr
));
9293 lasts
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9294 if (lasts
== NULL
) {
9295 xmlRngVErrMemory(ctxt
, "validating\n");
9298 memset(lasts
, 0, nbgroups
* sizeof(xmlNodePtr
));
9301 * Walk the sequence of children finding the right group and
9302 * sorting them in sequences.
9304 cur
= ctxt
->state
->seq
;
9305 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9307 while (cur
!= NULL
) {
9308 ctxt
->state
->seq
= cur
;
9309 if ((partitions
->triage
!= NULL
) &&
9310 (partitions
->flags
& IS_DETERMINIST
)) {
9313 if ((cur
->type
== XML_TEXT_NODE
) ||
9314 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
9315 tmp
= xmlHashLookup2(partitions
->triage
, BAD_CAST
"#text",
9317 } else if (cur
->type
== XML_ELEMENT_NODE
) {
9318 if (cur
->ns
!= NULL
) {
9319 tmp
= xmlHashLookup2(partitions
->triage
, cur
->name
,
9322 tmp
= xmlHashLookup2(partitions
->triage
,
9327 xmlHashLookup2(partitions
->triage
, cur
->name
,
9331 xmlHashLookup2(partitions
->triage
, BAD_CAST
"#any",
9338 i
= ((long) tmp
) - 1;
9339 if (partitions
->flags
& IS_NEEDCHECK
) {
9340 group
= partitions
->groups
[i
];
9341 if (!xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9346 for (i
= 0; i
< nbgroups
; i
++) {
9347 group
= partitions
->groups
[i
];
9350 if (xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9355 * We break as soon as an element not matched is found
9357 if (i
>= nbgroups
) {
9360 if (lasts
[i
] != NULL
) {
9361 lasts
[i
]->next
= cur
;
9367 if (cur
->next
!= NULL
)
9368 lastchg
= cur
->next
;
9371 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
->next
);
9374 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9379 oldstate
= ctxt
->state
;
9380 for (i
= 0; i
< nbgroups
; i
++) {
9381 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
, oldstate
);
9382 group
= partitions
->groups
[i
];
9383 if (lasts
[i
] != NULL
) {
9384 last
= lasts
[i
]->next
;
9385 lasts
[i
]->next
= NULL
;
9387 ctxt
->state
->seq
= list
[i
];
9388 ret
= xmlRelaxNGValidateDefinition(ctxt
, group
->rule
);
9391 if (ctxt
->state
!= NULL
) {
9392 cur
= ctxt
->state
->seq
;
9393 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9394 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9395 oldstate
= ctxt
->state
;
9398 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9400 ctxt
->state
= oldstate
;
9403 } else if (ctxt
->states
!= NULL
) {
9410 * PBM: what happen if there is attributes checks in the interleaves
9413 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9414 cur
= ctxt
->states
->tabState
[j
]->seq
;
9415 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9418 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9422 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9423 /* try to keep the latest one to mach old heuristic */
9424 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9429 } else if (found
== 0) {
9430 if (lowattr
== -1) {
9431 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9434 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9435 /* try to keep the latest one to mach old heuristic */
9436 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9442 * BIG PBM: here we pick only one restarting point :-(
9444 if (ctxt
->states
->nbState
> 0) {
9445 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9447 oldstate
= ctxt
->states
->tabState
[best
];
9448 ctxt
->states
->tabState
[best
] = NULL
;
9451 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1];
9452 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1] = NULL
;
9453 ctxt
->states
->nbState
--;
9456 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9457 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[j
]);
9459 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
9460 ctxt
->states
= NULL
;
9463 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
,
9464 (const xmlChar
*) "noname");
9466 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9469 ctxt
->state
= oldstate
;
9476 if (lasts
[i
] != NULL
) {
9477 lasts
[i
]->next
= last
;
9480 if (ctxt
->state
!= NULL
)
9481 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
9482 ctxt
->state
= oldstate
;
9483 ctxt
->state
->seq
= lastelem
;
9485 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9491 ctxt
->flags
= oldflags
;
9493 * builds the next links chain from the prev one
9496 while (cur
!= NULL
) {
9497 if ((cur
== start
) || (cur
->prev
== NULL
))
9499 cur
->prev
->next
= cur
;
9503 if (ctxt
->errNr
> errNr
)
9504 xmlRelaxNGPopErrors(ctxt
, errNr
);
9513 * xmlRelaxNGValidateDefinitionList:
9514 * @ctxt: a Relax-NG validation context
9515 * @define: the list of definition to verify
9517 * Validate the given node content against the (list) of definitions
9519 * Returns 0 if the validation succeeded or an error code.
9522 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt
,
9523 xmlRelaxNGDefinePtr defines
)
9528 if (defines
== NULL
) {
9529 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL
,
9530 BAD_CAST
"NULL definition list");
9533 while (defines
!= NULL
) {
9534 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9535 res
= xmlRelaxNGValidateDefinition(ctxt
, defines
);
9539 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9542 if (res
== -1) /* continues on -2 */
9544 defines
= defines
->next
;
9551 * xmlRelaxNGElementMatch:
9552 * @ctxt: a Relax-NG validation context
9553 * @define: the definition to check
9554 * @elem: the element
9556 * Check if the element matches the definition nameClass
9558 * Returns 1 if the element matches, 0 if no, or -1 in case of error
9561 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
9562 xmlRelaxNGDefinePtr define
, xmlNodePtr elem
)
9564 int ret
= 0, oldflags
= 0;
9566 if (define
->name
!= NULL
) {
9567 if (!xmlStrEqual(elem
->name
, define
->name
)) {
9568 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME
, define
->name
, elem
->name
);
9572 if ((define
->ns
!= NULL
) && (define
->ns
[0] != 0)) {
9573 if (elem
->ns
== NULL
) {
9574 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS
, elem
->name
);
9576 } else if (!xmlStrEqual(elem
->ns
->href
, define
->ns
)) {
9577 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS
,
9578 elem
->name
, define
->ns
);
9581 } else if ((elem
->ns
!= NULL
) && (define
->ns
!= NULL
) &&
9582 (define
->name
== NULL
)) {
9583 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, elem
->name
);
9585 } else if ((elem
->ns
!= NULL
) && (define
->name
!= NULL
)) {
9586 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, define
->name
);
9590 if (define
->nameClass
== NULL
)
9593 define
= define
->nameClass
;
9594 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9595 xmlRelaxNGDefinePtr list
;
9598 oldflags
= ctxt
->flags
;
9599 ctxt
->flags
|= FLAGS_IGNORABLE
;
9602 list
= define
->content
;
9603 while (list
!= NULL
) {
9604 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9607 ctxt
->flags
= oldflags
;
9612 ctxt
->flags
= oldflags
;
9619 ctxt
->flags
= oldflags
;
9621 } else if (define
->type
== XML_RELAXNG_CHOICE
) {
9622 xmlRelaxNGDefinePtr list
;
9625 oldflags
= ctxt
->flags
;
9626 ctxt
->flags
|= FLAGS_IGNORABLE
;
9629 list
= define
->nameClass
;
9630 while (list
!= NULL
) {
9631 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9634 ctxt
->flags
= oldflags
;
9639 ctxt
->flags
= oldflags
;
9646 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9647 xmlRelaxNGDumpValidError(ctxt
);
9649 if (ctxt
->errNr
> 0)
9650 xmlRelaxNGPopErrors(ctxt
, 0);
9655 ctxt
->flags
= oldflags
;
9664 * xmlRelaxNGBestState:
9665 * @ctxt: a Relax-NG validation context
9667 * Find the "best" state in the ctxt->states list of states to report
9668 * errors about. I.e. a state with no element left in the child list
9669 * or the one with the less attributes left.
9670 * This is called only if a falidation error was detected
9672 * Returns the index of the "best" state or -1 in case of error
9675 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt
)
9677 xmlRelaxNGValidStatePtr state
;
9680 int value
= 1000000;
9682 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9683 (ctxt
->states
->nbState
<= 0))
9686 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9687 state
= ctxt
->states
->tabState
[i
];
9690 if (state
->seq
!= NULL
) {
9691 if ((best
== -1) || (value
> 100000)) {
9696 tmp
= state
->nbAttrLeft
;
9697 if ((best
== -1) || (value
> tmp
)) {
9707 * xmlRelaxNGLogBestError:
9708 * @ctxt: a Relax-NG validation context
9710 * Find the "best" state in the ctxt->states list of states to report
9711 * errors about and log it.
9714 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
)
9718 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9719 (ctxt
->states
->nbState
<= 0))
9722 best
= xmlRelaxNGBestState(ctxt
);
9723 if ((best
>= 0) && (best
< ctxt
->states
->nbState
)) {
9724 ctxt
->state
= ctxt
->states
->tabState
[best
];
9726 xmlRelaxNGValidateElementEnd(ctxt
, 1);
9731 * xmlRelaxNGValidateElementEnd:
9732 * @ctxt: a Relax-NG validation context
9733 * @dolog: indicate that error logging should be done
9735 * Validate the end of the element, implements check that
9736 * there is nothing left not consumed in the element content
9737 * or in the attribute list.
9739 * Returns 0 if the validation succeeded or an error code.
9742 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
, int dolog
)
9745 xmlRelaxNGValidStatePtr state
;
9747 state
= ctxt
->state
;
9748 if (state
->seq
!= NULL
) {
9749 state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, state
->seq
);
9750 if (state
->seq
!= NULL
) {
9752 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT
,
9753 state
->node
->name
, state
->seq
->name
);
9758 for (i
= 0; i
< state
->nbAttrs
; i
++) {
9759 if (state
->attrs
[i
] != NULL
) {
9761 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR
,
9762 state
->attrs
[i
]->name
, state
->node
->name
);
9771 * xmlRelaxNGValidateState:
9772 * @ctxt: a Relax-NG validation context
9773 * @define: the definition to verify
9775 * Validate the current state against the definition
9777 * Returns 0 if the validation succeeded or an error code.
9780 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt
,
9781 xmlRelaxNGDefinePtr define
)
9784 int ret
= 0, i
, tmp
, oldflags
, errNr
;
9785 xmlRelaxNGValidStatePtr oldstate
= NULL
, state
;
9787 if (define
== NULL
) {
9788 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
9792 if (ctxt
->state
!= NULL
) {
9793 node
= ctxt
->state
->seq
;
9798 for (i
= 0; i
< ctxt
->depth
; i
++)
9799 xmlGenericError(xmlGenericErrorContext
, " ");
9800 xmlGenericError(xmlGenericErrorContext
,
9801 "Start validating %s ", xmlRelaxNGDefName(define
));
9802 if (define
->name
!= NULL
)
9803 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
9804 if ((node
!= NULL
) && (node
->name
!= NULL
))
9805 xmlGenericError(xmlGenericErrorContext
, "on %s\n", node
->name
);
9807 xmlGenericError(xmlGenericErrorContext
, "\n");
9810 switch (define
->type
) {
9811 case XML_RELAXNG_EMPTY
:
9812 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
9815 case XML_RELAXNG_NOT_ALLOWED
:
9818 case XML_RELAXNG_TEXT
:
9819 while ((node
!= NULL
) &&
9820 ((node
->type
== XML_TEXT_NODE
) ||
9821 (node
->type
== XML_COMMENT_NODE
) ||
9822 (node
->type
== XML_PI_NODE
) ||
9823 (node
->type
== XML_CDATA_SECTION_NODE
)))
9825 ctxt
->state
->seq
= node
;
9827 case XML_RELAXNG_ELEMENT
:
9828 errNr
= ctxt
->errNr
;
9829 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
9831 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, define
->name
);
9833 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9834 xmlRelaxNGDumpValidError(ctxt
);
9837 if (node
->type
!= XML_ELEMENT_NODE
) {
9838 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
9840 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9841 xmlRelaxNGDumpValidError(ctxt
);
9845 * This node was already validated successfully against
9848 if (node
->psvi
== define
) {
9849 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
9850 if (ctxt
->errNr
> errNr
)
9851 xmlRelaxNGPopErrors(ctxt
, errNr
);
9852 if (ctxt
->errNr
!= 0) {
9853 while ((ctxt
->err
!= NULL
) &&
9854 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
)
9855 && (xmlStrEqual(ctxt
->err
->arg2
, node
->name
)))
9858 XML_RELAXNG_ERR_ELEMEXTRANS
)
9859 && (xmlStrEqual(ctxt
->err
->arg1
, node
->name
)))
9860 || (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
)
9861 || (ctxt
->err
->err
==
9862 XML_RELAXNG_ERR_NOTELEM
)))
9863 xmlRelaxNGValidErrorPop(ctxt
);
9868 ret
= xmlRelaxNGElementMatch(ctxt
, define
, node
);
9871 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9872 xmlRelaxNGDumpValidError(ctxt
);
9876 if (ctxt
->errNr
!= 0) {
9877 if (ctxt
->errNr
> errNr
)
9878 xmlRelaxNGPopErrors(ctxt
, errNr
);
9879 while ((ctxt
->err
!= NULL
) &&
9880 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
) &&
9881 (xmlStrEqual(ctxt
->err
->arg2
, node
->name
))) ||
9882 ((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMEXTRANS
) &&
9883 (xmlStrEqual(ctxt
->err
->arg1
, node
->name
))) ||
9884 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
) ||
9885 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOTELEM
)))
9886 xmlRelaxNGValidErrorPop(ctxt
);
9888 errNr
= ctxt
->errNr
;
9890 oldflags
= ctxt
->flags
;
9891 if (ctxt
->flags
& FLAGS_MIXED_CONTENT
) {
9892 ctxt
->flags
-= FLAGS_MIXED_CONTENT
;
9894 state
= xmlRelaxNGNewValidState(ctxt
, node
);
9895 if (state
== NULL
) {
9897 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9898 xmlRelaxNGDumpValidError(ctxt
);
9902 oldstate
= ctxt
->state
;
9903 ctxt
->state
= state
;
9904 if (define
->attrs
!= NULL
) {
9905 tmp
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
9908 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
9911 if (define
->contModel
!= NULL
) {
9912 xmlRelaxNGValidStatePtr nstate
, tmpstate
= ctxt
->state
;
9913 xmlRelaxNGStatesPtr tmpstates
= ctxt
->states
;
9916 nstate
= xmlRelaxNGNewValidState(ctxt
, node
);
9917 ctxt
->state
= nstate
;
9918 ctxt
->states
= NULL
;
9920 tmp
= xmlRelaxNGValidateCompiledContent(ctxt
,
9923 nseq
= ctxt
->state
->seq
;
9924 ctxt
->state
= tmpstate
;
9925 ctxt
->states
= tmpstates
;
9926 xmlRelaxNGFreeValidState(ctxt
, nstate
);
9928 #ifdef DEBUG_COMPILE
9929 xmlGenericError(xmlGenericErrorContext
,
9930 "Validating content of '%s' : %d\n",
9936 if (ctxt
->states
!= NULL
) {
9939 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9940 state
= ctxt
->states
->tabState
[i
];
9941 ctxt
->state
= state
;
9942 ctxt
->state
->seq
= nseq
;
9944 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
9951 * validation error, log the message for the "best" one
9953 ctxt
->flags
|= FLAGS_IGNORABLE
;
9954 xmlRelaxNGLogBestError(ctxt
);
9956 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9957 xmlRelaxNGFreeValidState(ctxt
,
9961 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
9962 ctxt
->flags
= oldflags
;
9963 ctxt
->states
= NULL
;
9964 if ((ret
== 0) && (tmp
== -1))
9967 state
= ctxt
->state
;
9968 if (ctxt
->state
!= NULL
)
9969 ctxt
->state
->seq
= nseq
;
9971 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
9972 xmlRelaxNGFreeValidState(ctxt
, state
);
9975 if (define
->content
!= NULL
) {
9976 tmp
= xmlRelaxNGValidateDefinitionList(ctxt
,
9981 if (ctxt
->state
== NULL
) {
9982 ctxt
->state
= oldstate
;
9983 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
9987 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
9993 if (ctxt
->states
!= NULL
) {
9996 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9997 state
= ctxt
->states
->tabState
[i
];
9998 ctxt
->state
= state
;
10000 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
10007 * validation error, log the message for the "best" one
10009 ctxt
->flags
|= FLAGS_IGNORABLE
;
10010 xmlRelaxNGLogBestError(ctxt
);
10012 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10013 xmlRelaxNGFreeValidState(ctxt
,
10014 ctxt
->states
->tabState
[i
]);
10015 ctxt
->states
->tabState
[i
] = NULL
;
10017 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10018 ctxt
->flags
= oldflags
;
10019 ctxt
->states
= NULL
;
10020 if ((ret
== 0) && (tmp
== -1))
10023 state
= ctxt
->state
;
10025 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
10026 xmlRelaxNGFreeValidState(ctxt
, state
);
10030 node
->psvi
= define
;
10032 ctxt
->flags
= oldflags
;
10033 ctxt
->state
= oldstate
;
10034 if (oldstate
!= NULL
)
10035 oldstate
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
10037 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10038 xmlRelaxNGDumpValidError(ctxt
);
10046 if (ctxt
->errNr
> errNr
)
10047 xmlRelaxNGPopErrors(ctxt
, errNr
);
10051 xmlGenericError(xmlGenericErrorContext
,
10052 "xmlRelaxNGValidateDefinition(): validated %s : %d",
10054 if (oldstate
== NULL
)
10055 xmlGenericError(xmlGenericErrorContext
, ": no state\n");
10056 else if (oldstate
->seq
== NULL
)
10057 xmlGenericError(xmlGenericErrorContext
, ": done\n");
10058 else if (oldstate
->seq
->type
== XML_ELEMENT_NODE
)
10059 xmlGenericError(xmlGenericErrorContext
, ": next elem %s\n",
10060 oldstate
->seq
->name
);
10062 xmlGenericError(xmlGenericErrorContext
, ": next %s %d\n",
10063 oldstate
->seq
->name
, oldstate
->seq
->type
);
10066 case XML_RELAXNG_OPTIONAL
:{
10067 errNr
= ctxt
->errNr
;
10068 oldflags
= ctxt
->flags
;
10069 ctxt
->flags
|= FLAGS_IGNORABLE
;
10070 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10072 xmlRelaxNGValidateDefinitionList(ctxt
,
10075 if (ctxt
->state
!= NULL
)
10076 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10077 ctxt
->state
= oldstate
;
10078 ctxt
->flags
= oldflags
;
10080 if (ctxt
->errNr
> errNr
)
10081 xmlRelaxNGPopErrors(ctxt
, errNr
);
10084 if (ctxt
->states
!= NULL
) {
10085 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10087 ctxt
->states
= xmlRelaxNGNewStates(ctxt
, 1);
10088 if (ctxt
->states
== NULL
) {
10089 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10090 ctxt
->flags
= oldflags
;
10092 if (ctxt
->errNr
> errNr
)
10093 xmlRelaxNGPopErrors(ctxt
, errNr
);
10096 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10097 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, ctxt
->state
);
10098 ctxt
->state
= NULL
;
10100 ctxt
->flags
= oldflags
;
10102 if (ctxt
->errNr
> errNr
)
10103 xmlRelaxNGPopErrors(ctxt
, errNr
);
10106 case XML_RELAXNG_ONEORMORE
:
10107 errNr
= ctxt
->errNr
;
10108 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10112 if (ctxt
->errNr
> errNr
)
10113 xmlRelaxNGPopErrors(ctxt
, errNr
);
10114 /* no break on purpose */
10115 case XML_RELAXNG_ZEROORMORE
:{
10117 xmlRelaxNGStatesPtr states
= NULL
, res
= NULL
;
10120 errNr
= ctxt
->errNr
;
10121 res
= xmlRelaxNGNewStates(ctxt
, 1);
10127 * All the input states are also exit states
10129 if (ctxt
->state
!= NULL
) {
10130 xmlRelaxNGAddStates(ctxt
, res
,
10131 xmlRelaxNGCopyValidState(ctxt
,
10135 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10136 xmlRelaxNGAddStates(ctxt
, res
,
10137 xmlRelaxNGCopyValidState(ctxt
,
10138 ctxt
->states
->tabState
[j
]));
10141 oldflags
= ctxt
->flags
;
10142 ctxt
->flags
|= FLAGS_IGNORABLE
;
10145 base
= res
->nbState
;
10147 if (ctxt
->states
!= NULL
) {
10148 states
= ctxt
->states
;
10149 for (i
= 0; i
< states
->nbState
; i
++) {
10150 ctxt
->state
= states
->tabState
[i
];
10151 ctxt
->states
= NULL
;
10152 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10156 if (ctxt
->state
!= NULL
) {
10157 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10159 ctxt
->state
= NULL
;
10162 } else if (ctxt
->states
!= NULL
) {
10163 for (j
= 0; j
< ctxt
->states
->nbState
;
10166 xmlRelaxNGAddStates(ctxt
, res
,
10167 ctxt
->states
->tabState
[j
]);
10171 xmlRelaxNGFreeStates(ctxt
,
10173 ctxt
->states
= NULL
;
10176 if (ctxt
->state
!= NULL
) {
10177 xmlRelaxNGFreeValidState(ctxt
,
10179 ctxt
->state
= NULL
;
10184 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10188 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10189 ctxt
->state
= NULL
;
10191 base
= res
->nbState
;
10192 if (ctxt
->state
!= NULL
) {
10193 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10195 ctxt
->state
= NULL
;
10198 } else if (ctxt
->states
!= NULL
) {
10199 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10200 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10201 ctxt
->states
->tabState
[j
]);
10205 if (states
== NULL
) {
10206 states
= ctxt
->states
;
10208 xmlRelaxNGFreeStates(ctxt
,
10211 ctxt
->states
= NULL
;
10217 * Collect all the new nodes added at that step
10218 * and make them the new node set
10220 if (res
->nbState
- base
== 1) {
10221 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
,
10226 if (states
== NULL
) {
10227 xmlRelaxNGNewStates(ctxt
,
10228 res
->nbState
- base
);
10229 states
= ctxt
->states
;
10230 if (states
== NULL
) {
10235 states
->nbState
= 0;
10236 for (i
= base
; i
< res
->nbState
; i
++)
10237 xmlRelaxNGAddStates(ctxt
, states
,
10238 xmlRelaxNGCopyValidState
10239 (ctxt
, res
->tabState
[i
]));
10240 ctxt
->states
= states
;
10243 } while (progress
== 1);
10244 if (states
!= NULL
) {
10245 xmlRelaxNGFreeStates(ctxt
, states
);
10247 ctxt
->states
= res
;
10248 ctxt
->flags
= oldflags
;
10251 * errors may have to be propagated back...
10253 if (ctxt
->errNr
> errNr
)
10254 xmlRelaxNGPopErrors(ctxt
, errNr
);
10259 case XML_RELAXNG_CHOICE
:{
10260 xmlRelaxNGDefinePtr list
= NULL
;
10261 xmlRelaxNGStatesPtr states
= NULL
;
10263 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10265 errNr
= ctxt
->errNr
;
10266 if ((define
->dflags
& IS_TRIABLE
) && (define
->data
!= NULL
) &&
10269 * node == NULL can't be optimized since IS_TRIABLE
10270 * doesn't account for choice which may lead to
10273 xmlHashTablePtr triage
=
10274 (xmlHashTablePtr
) define
->data
;
10277 * Something we can optimize cleanly there is only one
10278 * possble branch out !
10280 if ((node
->type
== XML_TEXT_NODE
) ||
10281 (node
->type
== XML_CDATA_SECTION_NODE
)) {
10283 xmlHashLookup2(triage
, BAD_CAST
"#text", NULL
);
10284 } else if (node
->type
== XML_ELEMENT_NODE
) {
10285 if (node
->ns
!= NULL
) {
10286 list
= xmlHashLookup2(triage
, node
->name
,
10290 xmlHashLookup2(triage
, BAD_CAST
"#any",
10294 xmlHashLookup2(triage
, node
->name
, NULL
);
10297 xmlHashLookup2(triage
, BAD_CAST
"#any",
10300 if (list
== NULL
) {
10302 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, node
->name
);
10305 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10311 list
= define
->content
;
10312 oldflags
= ctxt
->flags
;
10313 ctxt
->flags
|= FLAGS_IGNORABLE
;
10315 while (list
!= NULL
) {
10316 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10317 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10319 if (states
== NULL
) {
10320 states
= xmlRelaxNGNewStates(ctxt
, 1);
10322 if (ctxt
->state
!= NULL
) {
10323 xmlRelaxNGAddStates(ctxt
, states
, ctxt
->state
);
10324 } else if (ctxt
->states
!= NULL
) {
10325 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10326 xmlRelaxNGAddStates(ctxt
, states
,
10330 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10331 ctxt
->states
= NULL
;
10334 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10336 ctxt
->state
= oldstate
;
10339 if (states
!= NULL
) {
10340 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10341 ctxt
->states
= states
;
10342 ctxt
->state
= NULL
;
10345 ctxt
->states
= NULL
;
10347 ctxt
->flags
= oldflags
;
10349 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10350 xmlRelaxNGDumpValidError(ctxt
);
10353 if (ctxt
->errNr
> errNr
)
10354 xmlRelaxNGPopErrors(ctxt
, errNr
);
10358 case XML_RELAXNG_DEF
:
10359 case XML_RELAXNG_GROUP
:
10360 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10362 case XML_RELAXNG_INTERLEAVE
:
10363 ret
= xmlRelaxNGValidateInterleave(ctxt
, define
);
10365 case XML_RELAXNG_ATTRIBUTE
:
10366 ret
= xmlRelaxNGValidateAttribute(ctxt
, define
);
10368 case XML_RELAXNG_START
:
10369 case XML_RELAXNG_NOOP
:
10370 case XML_RELAXNG_REF
:
10371 case XML_RELAXNG_EXTERNALREF
:
10372 case XML_RELAXNG_PARENTREF
:
10373 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
->content
);
10375 case XML_RELAXNG_DATATYPE
:{
10377 xmlChar
*content
= NULL
;
10380 while (child
!= NULL
) {
10381 if (child
->type
== XML_ELEMENT_NODE
) {
10382 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM
,
10383 node
->parent
->name
);
10386 } else if ((child
->type
== XML_TEXT_NODE
) ||
10387 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10388 content
= xmlStrcat(content
, child
->content
);
10390 /* TODO: handle entities ... */
10391 child
= child
->next
;
10394 if (content
!= NULL
)
10398 if (content
== NULL
) {
10399 content
= xmlStrdup(BAD_CAST
"");
10400 if (content
== NULL
) {
10401 xmlRngVErrMemory(ctxt
, "validating\n");
10406 ret
= xmlRelaxNGValidateDatatype(ctxt
, content
, define
,
10409 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE
, define
->name
);
10410 } else if (ret
== 0) {
10411 ctxt
->state
->seq
= NULL
;
10413 if (content
!= NULL
)
10417 case XML_RELAXNG_VALUE
:{
10418 xmlChar
*content
= NULL
;
10423 while (child
!= NULL
) {
10424 if (child
->type
== XML_ELEMENT_NODE
) {
10425 VALID_ERR2(XML_RELAXNG_ERR_VALELEM
,
10426 node
->parent
->name
);
10429 } else if ((child
->type
== XML_TEXT_NODE
) ||
10430 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10431 content
= xmlStrcat(content
, child
->content
);
10433 /* TODO: handle entities ... */
10434 child
= child
->next
;
10437 if (content
!= NULL
)
10441 if (content
== NULL
) {
10442 content
= xmlStrdup(BAD_CAST
"");
10443 if (content
== NULL
) {
10444 xmlRngVErrMemory(ctxt
, "validating\n");
10449 oldvalue
= ctxt
->state
->value
;
10450 ctxt
->state
->value
= content
;
10451 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10452 ctxt
->state
->value
= oldvalue
;
10454 VALID_ERR2(XML_RELAXNG_ERR_VALUE
, define
->name
);
10455 } else if (ret
== 0) {
10456 ctxt
->state
->seq
= NULL
;
10458 if (content
!= NULL
)
10462 case XML_RELAXNG_LIST
:{
10465 xmlChar
*oldvalue
, *oldendvalue
;
10469 * Make sure it's only text nodes
10474 while (child
!= NULL
) {
10475 if (child
->type
== XML_ELEMENT_NODE
) {
10476 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM
,
10477 node
->parent
->name
);
10480 } else if ((child
->type
== XML_TEXT_NODE
) ||
10481 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10482 content
= xmlStrcat(content
, child
->content
);
10484 /* TODO: handle entities ... */
10485 child
= child
->next
;
10488 if (content
!= NULL
)
10492 if (content
== NULL
) {
10493 content
= xmlStrdup(BAD_CAST
"");
10494 if (content
== NULL
) {
10495 xmlRngVErrMemory(ctxt
, "validating\n");
10500 len
= xmlStrlen(content
);
10501 oldvalue
= ctxt
->state
->value
;
10502 oldendvalue
= ctxt
->state
->endvalue
;
10503 ctxt
->state
->value
= content
;
10504 ctxt
->state
->endvalue
= content
+ len
;
10505 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10506 ctxt
->state
->value
= oldvalue
;
10507 ctxt
->state
->endvalue
= oldendvalue
;
10509 VALID_ERR(XML_RELAXNG_ERR_LIST
);
10510 } else if ((ret
== 0) && (node
!= NULL
)) {
10511 ctxt
->state
->seq
= node
->next
;
10513 if (content
!= NULL
)
10517 case XML_RELAXNG_EXCEPT
:
10518 case XML_RELAXNG_PARAM
:
10524 for (i
= 0; i
< ctxt
->depth
; i
++)
10525 xmlGenericError(xmlGenericErrorContext
, " ");
10526 xmlGenericError(xmlGenericErrorContext
,
10527 "Validating %s ", xmlRelaxNGDefName(define
));
10528 if (define
->name
!= NULL
)
10529 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
10531 xmlGenericError(xmlGenericErrorContext
, "suceeded\n");
10533 xmlGenericError(xmlGenericErrorContext
, "failed\n");
10539 * xmlRelaxNGValidateDefinition:
10540 * @ctxt: a Relax-NG validation context
10541 * @define: the definition to verify
10543 * Validate the current node lists against the definition
10545 * Returns 0 if the validation succeeded or an error code.
10548 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
10549 xmlRelaxNGDefinePtr define
)
10551 xmlRelaxNGStatesPtr states
, res
;
10552 int i
, j
, k
, ret
, oldflags
;
10555 * We should NOT have both ctxt->state and ctxt->states
10557 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10558 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10559 ctxt
->state
= NULL
;
10562 if ((ctxt
->states
== NULL
) || (ctxt
->states
->nbState
== 1)) {
10563 if (ctxt
->states
!= NULL
) {
10564 ctxt
->state
= ctxt
->states
->tabState
[0];
10565 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10566 ctxt
->states
= NULL
;
10568 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10569 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10570 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10571 ctxt
->state
= NULL
;
10573 if ((ctxt
->states
!= NULL
) && (ctxt
->states
->nbState
== 1)) {
10574 ctxt
->state
= ctxt
->states
->tabState
[0];
10575 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10576 ctxt
->states
= NULL
;
10581 states
= ctxt
->states
;
10582 ctxt
->states
= NULL
;
10585 oldflags
= ctxt
->flags
;
10586 ctxt
->flags
|= FLAGS_IGNORABLE
;
10587 for (i
= 0; i
< states
->nbState
; i
++) {
10588 ctxt
->state
= states
->tabState
[i
];
10589 ctxt
->states
= NULL
;
10590 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10592 * We should NOT have both ctxt->state and ctxt->states
10594 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10595 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10596 ctxt
->state
= NULL
;
10599 if (ctxt
->states
== NULL
) {
10601 /* add the state to the container */
10602 xmlRelaxNGAddStates(ctxt
, res
, ctxt
->state
);
10603 ctxt
->state
= NULL
;
10605 /* add the state directly in states */
10606 states
->tabState
[j
++] = ctxt
->state
;
10607 ctxt
->state
= NULL
;
10611 /* make it the new container and copy other results */
10612 res
= ctxt
->states
;
10613 ctxt
->states
= NULL
;
10614 for (k
= 0; k
< j
; k
++)
10615 xmlRelaxNGAddStates(ctxt
, res
,
10616 states
->tabState
[k
]);
10618 /* add all the new results to res and reff the container */
10619 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10620 xmlRelaxNGAddStates(ctxt
, res
,
10621 ctxt
->states
->tabState
[k
]);
10622 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10623 ctxt
->states
= NULL
;
10627 if (ctxt
->state
!= NULL
) {
10628 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10629 ctxt
->state
= NULL
;
10630 } else if (ctxt
->states
!= NULL
) {
10631 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10632 xmlRelaxNGFreeValidState(ctxt
,
10633 ctxt
->states
->tabState
[k
]);
10634 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10635 ctxt
->states
= NULL
;
10639 ctxt
->flags
= oldflags
;
10641 xmlRelaxNGFreeStates(ctxt
, states
);
10642 ctxt
->states
= res
;
10644 } else if (j
> 1) {
10645 states
->nbState
= j
;
10646 ctxt
->states
= states
;
10648 } else if (j
== 1) {
10649 ctxt
->state
= states
->tabState
[0];
10650 xmlRelaxNGFreeStates(ctxt
, states
);
10654 xmlRelaxNGFreeStates(ctxt
, states
);
10655 if (ctxt
->states
!= NULL
) {
10656 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10657 ctxt
->states
= NULL
;
10660 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10661 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10662 ctxt
->state
= NULL
;
10668 * xmlRelaxNGValidateDocument:
10669 * @ctxt: a Relax-NG validation context
10670 * @doc: the document
10672 * Validate the given document
10674 * Returns 0 if the validation succeeded or an error code.
10677 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
10680 xmlRelaxNGPtr schema
;
10681 xmlRelaxNGGrammarPtr grammar
;
10682 xmlRelaxNGValidStatePtr state
;
10685 if ((ctxt
== NULL
) || (ctxt
->schema
== NULL
) || (doc
== NULL
))
10688 ctxt
->errNo
= XML_RELAXNG_OK
;
10689 schema
= ctxt
->schema
;
10690 grammar
= schema
->topgrammar
;
10691 if (grammar
== NULL
) {
10692 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
10695 state
= xmlRelaxNGNewValidState(ctxt
, NULL
);
10696 ctxt
->state
= state
;
10697 ret
= xmlRelaxNGValidateDefinition(ctxt
, grammar
->start
);
10698 if ((ctxt
->state
!= NULL
) && (state
->seq
!= NULL
)) {
10699 state
= ctxt
->state
;
10701 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10702 if (node
!= NULL
) {
10704 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10708 } else if (ctxt
->states
!= NULL
) {
10712 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10713 state
= ctxt
->states
->tabState
[i
];
10715 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10718 xmlRelaxNGFreeValidState(ctxt
, state
);
10722 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10727 if (ctxt
->state
!= NULL
) {
10728 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10729 ctxt
->state
= NULL
;
10732 xmlRelaxNGDumpValidError(ctxt
);
10734 else if (ctxt
->errNr
!= 0) {
10735 ctxt
->error(ctxt
->userData
,
10736 "%d Extra error messages left on stack !\n",
10738 xmlRelaxNGDumpValidError(ctxt
);
10741 #ifdef LIBXML_VALID_ENABLED
10742 if (ctxt
->idref
== 1) {
10743 xmlValidCtxt vctxt
;
10745 memset(&vctxt
, 0, sizeof(xmlValidCtxt
));
10747 vctxt
.error
= ctxt
->error
;
10748 vctxt
.warning
= ctxt
->warning
;
10749 vctxt
.userData
= ctxt
->userData
;
10751 if (xmlValidateDocumentFinal(&vctxt
, doc
) != 1)
10754 #endif /* LIBXML_VALID_ENABLED */
10755 if ((ret
== 0) && (ctxt
->errNo
!= XML_RELAXNG_OK
))
10762 * xmlRelaxNGCleanPSVI:
10763 * @node: an input element or document
10765 * Call this routine to speed up XPath computation on static documents.
10766 * This stamps all the element nodes with the document order
10767 * Like for line information, the order is kept in the element->content
10768 * field, the value stored is actually - the node number (starting at -1)
10769 * to be able to differentiate from line numbers.
10771 * Returns the number of elements found in the document or -1 in case
10775 xmlRelaxNGCleanPSVI(xmlNodePtr node
) {
10778 if ((node
== NULL
) ||
10779 ((node
->type
!= XML_ELEMENT_NODE
) &&
10780 (node
->type
!= XML_DOCUMENT_NODE
) &&
10781 (node
->type
!= XML_HTML_DOCUMENT_NODE
)))
10783 if (node
->type
== XML_ELEMENT_NODE
)
10786 cur
= node
->children
;
10787 while (cur
!= NULL
) {
10788 if (cur
->type
== XML_ELEMENT_NODE
) {
10790 if (cur
->children
!= NULL
) {
10791 cur
= cur
->children
;
10795 if (cur
->next
!= NULL
) {
10807 if (cur
->next
!= NULL
) {
10811 } while (cur
!= NULL
);
10815 /************************************************************************
10817 * Validation interfaces *
10819 ************************************************************************/
10822 * xmlRelaxNGNewValidCtxt:
10823 * @schema: a precompiled XML RelaxNGs
10825 * Create an XML RelaxNGs validation context based on the given schema
10827 * Returns the validation context or NULL in case of error
10829 xmlRelaxNGValidCtxtPtr
10830 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema
)
10832 xmlRelaxNGValidCtxtPtr ret
;
10834 ret
= (xmlRelaxNGValidCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGValidCtxt
));
10836 xmlRngVErrMemory(NULL
, "building context\n");
10839 memset(ret
, 0, sizeof(xmlRelaxNGValidCtxt
));
10840 ret
->schema
= schema
;
10841 ret
->error
= xmlGenericError
;
10842 ret
->userData
= xmlGenericErrorContext
;
10846 ret
->errTab
= NULL
;
10847 if (schema
!= NULL
)
10848 ret
->idref
= schema
->idref
;
10849 ret
->states
= NULL
;
10850 ret
->freeState
= NULL
;
10851 ret
->freeStates
= NULL
;
10852 ret
->errNo
= XML_RELAXNG_OK
;
10857 * xmlRelaxNGFreeValidCtxt:
10858 * @ctxt: the schema validation context
10860 * Free the resources associated to the schema validation context
10863 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt
)
10869 if (ctxt
->states
!= NULL
)
10870 xmlRelaxNGFreeStates(NULL
, ctxt
->states
);
10871 if (ctxt
->freeState
!= NULL
) {
10872 for (k
= 0; k
< ctxt
->freeState
->nbState
; k
++) {
10873 xmlRelaxNGFreeValidState(NULL
, ctxt
->freeState
->tabState
[k
]);
10875 xmlRelaxNGFreeStates(NULL
, ctxt
->freeState
);
10877 if (ctxt
->freeStates
!= NULL
) {
10878 for (k
= 0; k
< ctxt
->freeStatesNr
; k
++) {
10879 xmlRelaxNGFreeStates(NULL
, ctxt
->freeStates
[k
]);
10881 xmlFree(ctxt
->freeStates
);
10883 if (ctxt
->errTab
!= NULL
)
10884 xmlFree(ctxt
->errTab
);
10885 if (ctxt
->elemTab
!= NULL
) {
10886 xmlRegExecCtxtPtr exec
;
10888 exec
= xmlRelaxNGElemPop(ctxt
);
10889 while (exec
!= NULL
) {
10890 xmlRegFreeExecCtxt(exec
);
10891 exec
= xmlRelaxNGElemPop(ctxt
);
10893 xmlFree(ctxt
->elemTab
);
10899 * xmlRelaxNGSetValidErrors:
10900 * @ctxt: a Relax-NG validation context
10901 * @err: the error function
10902 * @warn: the warning function
10903 * @ctx: the functions context
10905 * Set the error and warning callback informations
10908 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
10909 xmlRelaxNGValidityErrorFunc err
,
10910 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
10915 ctxt
->warning
= warn
;
10916 ctxt
->userData
= ctx
;
10917 ctxt
->serror
= NULL
;
10921 * xmlRelaxNGSetValidStructuredErrors:
10922 * @ctxt: a Relax-NG validation context
10923 * @serror: the structured error function
10924 * @ctx: the functions context
10926 * Set the structured error callback
10929 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt
,
10930 xmlStructuredErrorFunc serror
, void *ctx
)
10934 ctxt
->serror
= serror
;
10935 ctxt
->error
= NULL
;
10936 ctxt
->warning
= NULL
;
10937 ctxt
->userData
= ctx
;
10941 * xmlRelaxNGGetValidErrors:
10942 * @ctxt: a Relax-NG validation context
10943 * @err: the error function result
10944 * @warn: the warning function result
10945 * @ctx: the functions context result
10947 * Get the error and warning callback informations
10949 * Returns -1 in case of error and 0 otherwise
10952 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
10953 xmlRelaxNGValidityErrorFunc
* err
,
10954 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
10959 *err
= ctxt
->error
;
10961 *warn
= ctxt
->warning
;
10963 *ctx
= ctxt
->userData
;
10968 * xmlRelaxNGValidateDoc:
10969 * @ctxt: a Relax-NG validation context
10970 * @doc: a parsed document tree
10972 * Validate a document tree in memory.
10974 * Returns 0 if the document is valid, a positive error code
10975 * number otherwise and -1 in case of internal or API error.
10978 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
10982 if ((ctxt
== NULL
) || (doc
== NULL
))
10987 ret
= xmlRelaxNGValidateDocument(ctxt
, doc
);
10989 * Remove all left PSVI
10991 xmlRelaxNGCleanPSVI((xmlNodePtr
) doc
);
10994 * TODO: build error codes
11001 #define bottom_relaxng
11002 #include "elfgcchack.h"
11003 #endif /* LIBXML_SCHEMAS_ENABLED */