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, typ) \
43 ((node != NULL) && (node->ns != NULL) && \
44 (node->type == XML_ELEMENT_NODE) && \
45 (xmlStrEqual(node->name, (const xmlChar *) typ)) && \
46 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
52 #define DEBUG_GRAMMAR 1
54 #define DEBUG_CONTENT 1
60 #define DEBUG_INTERLEAVE 1
64 #define DEBUG_INCLUDE 1
68 #define DEBUG_COMPILE 1
70 #define DEBUG_PROGRESSIVE 1
76 xmlGenericError(xmlGenericErrorContext, \
77 "Unimplemented block at %s:%d\n", \
80 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema
;
81 typedef xmlRelaxNGSchema
*xmlRelaxNGSchemaPtr
;
83 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine
;
84 typedef xmlRelaxNGDefine
*xmlRelaxNGDefinePtr
;
86 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument
;
87 typedef xmlRelaxNGDocument
*xmlRelaxNGDocumentPtr
;
89 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude
;
90 typedef xmlRelaxNGInclude
*xmlRelaxNGIncludePtr
;
93 XML_RELAXNG_COMBINE_UNDEFINED
= 0, /* undefined */
94 XML_RELAXNG_COMBINE_CHOICE
, /* choice */
95 XML_RELAXNG_COMBINE_INTERLEAVE
/* interleave */
99 XML_RELAXNG_CONTENT_ERROR
= -1,
100 XML_RELAXNG_CONTENT_EMPTY
= 0,
101 XML_RELAXNG_CONTENT_SIMPLE
,
102 XML_RELAXNG_CONTENT_COMPLEX
103 } xmlRelaxNGContentType
;
105 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar
;
106 typedef xmlRelaxNGGrammar
*xmlRelaxNGGrammarPtr
;
108 struct _xmlRelaxNGGrammar
{
109 xmlRelaxNGGrammarPtr parent
; /* the parent grammar if any */
110 xmlRelaxNGGrammarPtr children
; /* the children grammar if any */
111 xmlRelaxNGGrammarPtr next
; /* the next grammar if any */
112 xmlRelaxNGDefinePtr start
; /* <start> content */
113 xmlRelaxNGCombine combine
; /* the default combine value */
114 xmlRelaxNGDefinePtr startList
; /* list of <start> definitions */
115 xmlHashTablePtr defs
; /* define* */
116 xmlHashTablePtr refs
; /* references */
121 XML_RELAXNG_NOOP
= -1, /* a no operation from simplification */
122 XML_RELAXNG_EMPTY
= 0, /* an empty pattern */
123 XML_RELAXNG_NOT_ALLOWED
, /* not allowed top */
124 XML_RELAXNG_EXCEPT
, /* except present in nameclass defs */
125 XML_RELAXNG_TEXT
, /* textual content */
126 XML_RELAXNG_ELEMENT
, /* an element */
127 XML_RELAXNG_DATATYPE
, /* extenal data type definition */
128 XML_RELAXNG_PARAM
, /* extenal data type parameter */
129 XML_RELAXNG_VALUE
, /* value from an extenal data type definition */
130 XML_RELAXNG_LIST
, /* a list of patterns */
131 XML_RELAXNG_ATTRIBUTE
, /* an attrbute following a pattern */
132 XML_RELAXNG_DEF
, /* a definition */
133 XML_RELAXNG_REF
, /* reference to a definition */
134 XML_RELAXNG_EXTERNALREF
, /* reference to an external def */
135 XML_RELAXNG_PARENTREF
, /* reference to a def in the parent grammar */
136 XML_RELAXNG_OPTIONAL
, /* optional patterns */
137 XML_RELAXNG_ZEROORMORE
, /* zero or more non empty patterns */
138 XML_RELAXNG_ONEORMORE
, /* one or more non empty patterns */
139 XML_RELAXNG_CHOICE
, /* a choice between non empty patterns */
140 XML_RELAXNG_GROUP
, /* a pair/group of non empty patterns */
141 XML_RELAXNG_INTERLEAVE
, /* interleaving choice of non-empty patterns */
142 XML_RELAXNG_START
/* Used to keep track of starts on grammars */
145 #define IS_NULLABLE (1 << 0)
146 #define IS_NOT_NULLABLE (1 << 1)
147 #define IS_INDETERMINIST (1 << 2)
148 #define IS_MIXED (1 << 3)
149 #define IS_TRIABLE (1 << 4)
150 #define IS_PROCESSED (1 << 5)
151 #define IS_COMPILABLE (1 << 6)
152 #define IS_NOT_COMPILABLE (1 << 7)
153 #define IS_EXTERNAL_REF (1 << 8)
155 struct _xmlRelaxNGDefine
{
156 xmlRelaxNGType type
; /* the type of definition */
157 xmlNodePtr node
; /* the node in the source */
158 xmlChar
*name
; /* the element local name if present */
159 xmlChar
*ns
; /* the namespace local name if present */
160 xmlChar
*value
; /* value when available */
161 void *data
; /* data lib or specific pointer */
162 xmlRelaxNGDefinePtr content
; /* the expected content */
163 xmlRelaxNGDefinePtr parent
; /* the parent definition, if any */
164 xmlRelaxNGDefinePtr next
; /* list within grouping sequences */
165 xmlRelaxNGDefinePtr attrs
; /* list of attributes for elements */
166 xmlRelaxNGDefinePtr nameClass
; /* the nameClass definition if any */
167 xmlRelaxNGDefinePtr nextHash
; /* next define in defs/refs hash tables */
168 short depth
; /* used for the cycle detection */
169 short dflags
; /* define related flags */
170 xmlRegexpPtr contModel
; /* a compiled content model if available */
176 * A RelaxNGs definition
179 void *_private
; /* unused by the library for users or bindings */
180 xmlRelaxNGGrammarPtr topgrammar
;
183 int idref
; /* requires idref checking */
185 xmlHashTablePtr defs
; /* define */
186 xmlHashTablePtr refs
; /* references */
187 xmlRelaxNGDocumentPtr documents
; /* all the documents loaded */
188 xmlRelaxNGIncludePtr includes
; /* all the includes loaded */
189 int defNr
; /* number of defines used */
190 xmlRelaxNGDefinePtr
*defTab
; /* pointer to the allocated definitions */
194 #define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
195 #define XML_RELAXNG_IN_ONEORMORE (1 << 1)
196 #define XML_RELAXNG_IN_LIST (1 << 2)
197 #define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
198 #define XML_RELAXNG_IN_START (1 << 4)
199 #define XML_RELAXNG_IN_OOMGROUP (1 << 5)
200 #define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
201 #define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
202 #define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
203 #define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
205 struct _xmlRelaxNGParserCtxt
{
206 void *userData
; /* user specific data block */
207 xmlRelaxNGValidityErrorFunc error
; /* the callback in case of errors */
208 xmlRelaxNGValidityWarningFunc warning
; /* the callback in case of warning */
209 xmlStructuredErrorFunc serror
;
210 xmlRelaxNGValidErr err
;
212 xmlRelaxNGPtr schema
; /* The schema in use */
213 xmlRelaxNGGrammarPtr grammar
; /* the current grammar */
214 xmlRelaxNGGrammarPtr parentgrammar
; /* the parent grammar */
215 int flags
; /* parser flags */
216 int nbErrors
; /* number of errors at parse time */
217 int nbWarnings
; /* number of warnings at parse time */
218 const xmlChar
*define
; /* the current define scope */
219 xmlRelaxNGDefinePtr def
; /* the current define */
222 xmlHashTablePtr interleaves
; /* keep track of all the interleaves */
224 xmlRelaxNGDocumentPtr documents
; /* all the documents loaded */
225 xmlRelaxNGIncludePtr includes
; /* all the includes loaded */
229 int defNr
; /* number of defines used */
230 int defMax
; /* number of defines aloocated */
231 xmlRelaxNGDefinePtr
*defTab
; /* pointer to the allocated definitions */
236 /* the document stack */
237 xmlRelaxNGDocumentPtr doc
; /* Current parsed external ref */
238 int docNr
; /* Depth of the parsing stack */
239 int docMax
; /* Max depth of the parsing stack */
240 xmlRelaxNGDocumentPtr
*docTab
; /* array of docs */
242 /* the include stack */
243 xmlRelaxNGIncludePtr inc
; /* Current parsed include */
244 int incNr
; /* Depth of the include parsing stack */
245 int incMax
; /* Max depth of the parsing stack */
246 xmlRelaxNGIncludePtr
*incTab
; /* array of incs */
248 int idref
; /* requires idref checking */
250 /* used to compile content models */
251 xmlAutomataPtr am
; /* the automata */
252 xmlAutomataStatePtr state
; /* used to build the automata */
254 int crng
; /* compact syntax and other flags */
255 int freedoc
; /* need to free the document */
258 #define FLAGS_IGNORABLE 1
259 #define FLAGS_NEGATIVE 2
260 #define FLAGS_MIXED_CONTENT 4
261 #define FLAGS_NOERROR 8
264 * xmlRelaxNGInterleaveGroup:
266 * A RelaxNGs partition set associated to lists of definitions
268 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup
;
269 typedef xmlRelaxNGInterleaveGroup
*xmlRelaxNGInterleaveGroupPtr
;
270 struct _xmlRelaxNGInterleaveGroup
{
271 xmlRelaxNGDefinePtr rule
; /* the rule to satisfy */
272 xmlRelaxNGDefinePtr
*defs
; /* the array of element definitions */
273 xmlRelaxNGDefinePtr
*attrs
; /* the array of attributes definitions */
276 #define IS_DETERMINIST 1
277 #define IS_NEEDCHECK 2
280 * xmlRelaxNGPartitions:
282 * A RelaxNGs partition associated to an interleave group
284 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition
;
285 typedef xmlRelaxNGPartition
*xmlRelaxNGPartitionPtr
;
286 struct _xmlRelaxNGPartition
{
287 int nbgroups
; /* number of groups in the partitions */
288 xmlHashTablePtr triage
; /* hash table used to direct nodes to the
289 * right group when possible */
290 int flags
; /* determinist ? */
291 xmlRelaxNGInterleaveGroupPtr
*groups
;
295 * xmlRelaxNGValidState:
297 * A RelaxNGs validation state
300 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState
;
301 typedef xmlRelaxNGValidState
*xmlRelaxNGValidStatePtr
;
302 struct _xmlRelaxNGValidState
{
303 xmlNodePtr node
; /* the current node */
304 xmlNodePtr seq
; /* the sequence of children left to validate */
305 int nbAttrs
; /* the number of attributes */
306 int maxAttrs
; /* the size of attrs */
307 int nbAttrLeft
; /* the number of attributes left to validate */
308 xmlChar
*value
; /* the value when operating on string */
309 xmlChar
*endvalue
; /* the end value when operating on string */
310 xmlAttrPtr
*attrs
; /* the array of attributes */
316 * A RelaxNGs container for validation state
318 typedef struct _xmlRelaxNGStates xmlRelaxNGStates
;
319 typedef xmlRelaxNGStates
*xmlRelaxNGStatesPtr
;
320 struct _xmlRelaxNGStates
{
321 int nbState
; /* the number of states */
322 int maxState
; /* the size of the array */
323 xmlRelaxNGValidStatePtr
*tabState
;
326 #define ERROR_IS_DUP 1
329 * xmlRelaxNGValidError:
331 * A RelaxNGs validation error
333 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError
;
334 typedef xmlRelaxNGValidError
*xmlRelaxNGValidErrorPtr
;
335 struct _xmlRelaxNGValidError
{
336 xmlRelaxNGValidErr err
; /* the error number */
337 int flags
; /* flags */
338 xmlNodePtr node
; /* the current node */
339 xmlNodePtr seq
; /* the current child */
340 const xmlChar
*arg1
; /* first arg */
341 const xmlChar
*arg2
; /* second arg */
345 * xmlRelaxNGValidCtxt:
347 * A RelaxNGs validation context
350 struct _xmlRelaxNGValidCtxt
{
351 void *userData
; /* user specific data block */
352 xmlRelaxNGValidityErrorFunc error
; /* the callback in case of errors */
353 xmlRelaxNGValidityWarningFunc warning
; /* the callback in case of warning */
354 xmlStructuredErrorFunc serror
;
355 int nbErrors
; /* number of errors in validation */
357 xmlRelaxNGPtr schema
; /* The schema in use */
358 xmlDocPtr doc
; /* the document being validated */
359 int flags
; /* validation flags */
360 int depth
; /* validation depth */
361 int idref
; /* requires idref checking */
362 int errNo
; /* the first error found */
365 * Errors accumulated in branches may have to be stacked to be
366 * provided back when it's sure they affect validation.
368 xmlRelaxNGValidErrorPtr err
; /* Last error */
369 int errNr
; /* Depth of the error stack */
370 int errMax
; /* Max depth of the error stack */
371 xmlRelaxNGValidErrorPtr errTab
; /* stack of errors */
373 xmlRelaxNGValidStatePtr state
; /* the current validation state */
374 xmlRelaxNGStatesPtr states
; /* the accumulated state list */
376 xmlRelaxNGStatesPtr freeState
; /* the pool of free valid states */
379 xmlRelaxNGStatesPtr
*freeStates
; /* the pool of free state groups */
382 * This is used for "progressive" validation
384 xmlRegExecCtxtPtr elem
; /* the current element regexp */
385 int elemNr
; /* the number of element validated */
386 int elemMax
; /* the max depth of elements */
387 xmlRegExecCtxtPtr
*elemTab
; /* the stack of regexp runtime */
388 int pstate
; /* progressive state */
389 xmlNodePtr pnode
; /* the current node */
390 xmlRelaxNGDefinePtr pdef
; /* the non-streamable definition */
391 int perr
; /* signal error in content model
392 * outside the regexp */
398 * Structure associated to a RelaxNGs document element
400 struct _xmlRelaxNGInclude
{
401 xmlRelaxNGIncludePtr next
; /* keep a chain of includes */
402 xmlChar
*href
; /* the normalized href value */
403 xmlDocPtr doc
; /* the associated XML document */
404 xmlRelaxNGDefinePtr content
; /* the definitions */
405 xmlRelaxNGPtr schema
; /* the schema */
409 * xmlRelaxNGDocument:
411 * Structure associated to a RelaxNGs document element
413 struct _xmlRelaxNGDocument
{
414 xmlRelaxNGDocumentPtr next
; /* keep a chain of documents */
415 xmlChar
*href
; /* the normalized href value */
416 xmlDocPtr doc
; /* the associated XML document */
417 xmlRelaxNGDefinePtr content
; /* the definitions */
418 xmlRelaxNGPtr schema
; /* the schema */
419 int externalRef
; /* 1 if an external ref */
423 /************************************************************************
425 * Some factorized error routines *
427 ************************************************************************/
431 * @ctxt: an Relax-NG parser context
432 * @extra: extra informations
434 * Handle a redefinition of attribute error
437 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt
, const char *extra
)
439 xmlStructuredErrorFunc schannel
= NULL
;
440 xmlGenericErrorFunc channel
= NULL
;
444 if (ctxt
->serror
!= NULL
)
445 schannel
= ctxt
->serror
;
447 channel
= ctxt
->error
;
448 data
= ctxt
->userData
;
452 __xmlRaiseError(schannel
, channel
, data
,
453 NULL
, NULL
, XML_FROM_RELAXNGP
,
454 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, extra
,
456 "Memory allocation failed : %s\n", extra
);
458 __xmlRaiseError(schannel
, channel
, data
,
459 NULL
, NULL
, XML_FROM_RELAXNGP
,
460 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, NULL
,
461 NULL
, NULL
, 0, 0, "Memory allocation failed\n");
466 * @ctxt: a Relax-NG validation context
467 * @extra: extra informations
469 * Handle a redefinition of attribute error
472 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt
, const char *extra
)
474 xmlStructuredErrorFunc schannel
= NULL
;
475 xmlGenericErrorFunc channel
= NULL
;
479 if (ctxt
->serror
!= NULL
)
480 schannel
= ctxt
->serror
;
482 channel
= ctxt
->error
;
483 data
= ctxt
->userData
;
487 __xmlRaiseError(schannel
, channel
, data
,
488 NULL
, NULL
, XML_FROM_RELAXNGV
,
489 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, extra
,
491 "Memory allocation failed : %s\n", extra
);
493 __xmlRaiseError(schannel
, channel
, data
,
494 NULL
, NULL
, XML_FROM_RELAXNGV
,
495 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, NULL
,
496 NULL
, NULL
, 0, 0, "Memory allocation failed\n");
501 * @ctxt: a Relax-NG parser context
502 * @node: the node raising the error
503 * @error: the error code
508 * Handle a Relax NG Parsing error
511 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
, int error
,
512 const char *msg
, const xmlChar
* str1
, const xmlChar
* str2
)
514 xmlStructuredErrorFunc schannel
= NULL
;
515 xmlGenericErrorFunc channel
= NULL
;
519 if (ctxt
->serror
!= NULL
)
520 schannel
= ctxt
->serror
;
522 channel
= ctxt
->error
;
523 data
= ctxt
->userData
;
526 __xmlRaiseError(schannel
, channel
, data
,
527 NULL
, node
, XML_FROM_RELAXNGP
,
528 error
, XML_ERR_ERROR
, NULL
, 0,
529 (const char *) str1
, (const char *) str2
, NULL
, 0, 0,
535 * @ctxt: a Relax-NG validation context
536 * @node: the node raising the error
537 * @error: the error code
542 * Handle a Relax NG Validation error
545 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt
, xmlNodePtr node
, int error
,
546 const char *msg
, const xmlChar
* str1
, const xmlChar
* str2
)
548 xmlStructuredErrorFunc schannel
= NULL
;
549 xmlGenericErrorFunc channel
= NULL
;
553 if (ctxt
->serror
!= NULL
)
554 schannel
= ctxt
->serror
;
556 channel
= ctxt
->error
;
557 data
= ctxt
->userData
;
560 __xmlRaiseError(schannel
, channel
, data
,
561 NULL
, node
, XML_FROM_RELAXNGV
,
562 error
, XML_ERR_ERROR
, NULL
, 0,
563 (const char *) str1
, (const char *) str2
, NULL
, 0, 0,
567 /************************************************************************
569 * Preliminary type checking interfaces *
571 ************************************************************************/
574 * xmlRelaxNGTypeHave:
575 * @data: data needed for the library
576 * @type: the type name
577 * @value: the value to check
579 * Function provided by a type library to check if a type is exported
581 * Returns 1 if yes, 0 if no and -1 in case of error.
583 typedef int (*xmlRelaxNGTypeHave
) (void *data
, const xmlChar
* type
);
586 * xmlRelaxNGTypeCheck:
587 * @data: data needed for the library
588 * @type: the type name
589 * @value: the value to check
590 * @result: place to store the result if needed
592 * Function provided by a type library to check if a value match a type
594 * Returns 1 if yes, 0 if no and -1 in case of error.
596 typedef int (*xmlRelaxNGTypeCheck
) (void *data
, const xmlChar
* type
,
597 const xmlChar
* value
, void **result
,
601 * xmlRelaxNGFacetCheck:
602 * @data: data needed for the library
603 * @type: the type name
604 * @facet: the facet name
605 * @val: the facet value
606 * @strval: the string value
607 * @value: the value to check
609 * Function provided by a type library to check a value facet
611 * Returns 1 if yes, 0 if no and -1 in case of error.
613 typedef int (*xmlRelaxNGFacetCheck
) (void *data
, const xmlChar
* type
,
614 const xmlChar
* facet
,
616 const xmlChar
* strval
, void *value
);
619 * xmlRelaxNGTypeFree:
620 * @data: data needed for the library
621 * @result: the value to free
623 * Function provided by a type library to free a returned result
625 typedef void (*xmlRelaxNGTypeFree
) (void *data
, void *result
);
628 * xmlRelaxNGTypeCompare:
629 * @data: data needed for the library
630 * @type: the type name
631 * @value1: the first value
632 * @value2: the second value
634 * Function provided by a type library to compare two values accordingly
637 * Returns 1 if yes, 0 if no and -1 in case of error.
639 typedef int (*xmlRelaxNGTypeCompare
) (void *data
, const xmlChar
* type
,
640 const xmlChar
* value1
,
643 const xmlChar
* value2
,
645 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary
;
646 typedef xmlRelaxNGTypeLibrary
*xmlRelaxNGTypeLibraryPtr
;
647 struct _xmlRelaxNGTypeLibrary
{
648 const xmlChar
*namespace; /* the datatypeLibrary value */
649 void *data
; /* data needed for the library */
650 xmlRelaxNGTypeHave have
; /* the export function */
651 xmlRelaxNGTypeCheck check
; /* the checking function */
652 xmlRelaxNGTypeCompare comp
; /* the compare function */
653 xmlRelaxNGFacetCheck facet
; /* the facet check function */
654 xmlRelaxNGTypeFree freef
; /* the freeing function */
657 /************************************************************************
659 * Allocation functions *
661 ************************************************************************/
662 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar
);
663 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define
);
664 static void xmlRelaxNGNormExtSpace(xmlChar
* value
);
665 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema
);
666 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
668 xmlRelaxNGValidStatePtr state1
,
669 xmlRelaxNGValidStatePtr state2
);
670 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt
,
671 xmlRelaxNGValidStatePtr state
);
674 * xmlRelaxNGFreeDocument:
675 * @docu: a document structure
677 * Deallocate a RelaxNG document structure.
680 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu
)
685 if (docu
->href
!= NULL
)
687 if (docu
->doc
!= NULL
)
688 xmlFreeDoc(docu
->doc
);
689 if (docu
->schema
!= NULL
)
690 xmlRelaxNGFreeInnerSchema(docu
->schema
);
695 * xmlRelaxNGFreeDocumentList:
696 * @docu: a list of document structure
698 * Deallocate a RelaxNG document structures.
701 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu
)
703 xmlRelaxNGDocumentPtr next
;
705 while (docu
!= NULL
) {
707 xmlRelaxNGFreeDocument(docu
);
713 * xmlRelaxNGFreeInclude:
714 * @incl: a include structure
716 * Deallocate a RelaxNG include structure.
719 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl
)
724 if (incl
->href
!= NULL
)
726 if (incl
->doc
!= NULL
)
727 xmlFreeDoc(incl
->doc
);
728 if (incl
->schema
!= NULL
)
729 xmlRelaxNGFree(incl
->schema
);
734 * xmlRelaxNGFreeIncludeList:
735 * @incl: a include structure list
737 * Deallocate a RelaxNG include structure.
740 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl
)
742 xmlRelaxNGIncludePtr next
;
744 while (incl
!= NULL
) {
746 xmlRelaxNGFreeInclude(incl
);
752 * xmlRelaxNGNewRelaxNG:
753 * @ctxt: a Relax-NG validation context (optional)
755 * Allocate a new RelaxNG structure.
757 * Returns the newly allocated structure or NULL in case or error
760 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt
)
764 ret
= (xmlRelaxNGPtr
) xmlMalloc(sizeof(xmlRelaxNG
));
766 xmlRngPErrMemory(ctxt
, NULL
);
769 memset(ret
, 0, sizeof(xmlRelaxNG
));
775 * xmlRelaxNGFreeInnerSchema:
776 * @schema: a schema structure
778 * Deallocate a RelaxNG schema structure.
781 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema
)
786 if (schema
->doc
!= NULL
)
787 xmlFreeDoc(schema
->doc
);
788 if (schema
->defTab
!= NULL
) {
791 for (i
= 0; i
< schema
->defNr
; i
++)
792 xmlRelaxNGFreeDefine(schema
->defTab
[i
]);
793 xmlFree(schema
->defTab
);
801 * @schema: a schema structure
803 * Deallocate a RelaxNG structure.
806 xmlRelaxNGFree(xmlRelaxNGPtr schema
)
811 if (schema
->topgrammar
!= NULL
)
812 xmlRelaxNGFreeGrammar(schema
->topgrammar
);
813 if (schema
->doc
!= NULL
)
814 xmlFreeDoc(schema
->doc
);
815 if (schema
->documents
!= NULL
)
816 xmlRelaxNGFreeDocumentList(schema
->documents
);
817 if (schema
->includes
!= NULL
)
818 xmlRelaxNGFreeIncludeList(schema
->includes
);
819 if (schema
->defTab
!= NULL
) {
822 for (i
= 0; i
< schema
->defNr
; i
++)
823 xmlRelaxNGFreeDefine(schema
->defTab
[i
]);
824 xmlFree(schema
->defTab
);
831 * xmlRelaxNGNewGrammar:
832 * @ctxt: a Relax-NG validation context (optional)
834 * Allocate a new RelaxNG grammar.
836 * Returns the newly allocated structure or NULL in case or error
838 static xmlRelaxNGGrammarPtr
839 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt
)
841 xmlRelaxNGGrammarPtr ret
;
843 ret
= (xmlRelaxNGGrammarPtr
) xmlMalloc(sizeof(xmlRelaxNGGrammar
));
845 xmlRngPErrMemory(ctxt
, NULL
);
848 memset(ret
, 0, sizeof(xmlRelaxNGGrammar
));
854 * xmlRelaxNGFreeGrammar:
855 * @grammar: a grammar structure
857 * Deallocate a RelaxNG grammar structure.
860 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar
)
865 if (grammar
->children
!= NULL
) {
866 xmlRelaxNGFreeGrammar(grammar
->children
);
868 if (grammar
->next
!= NULL
) {
869 xmlRelaxNGFreeGrammar(grammar
->next
);
871 if (grammar
->refs
!= NULL
) {
872 xmlHashFree(grammar
->refs
, NULL
);
874 if (grammar
->defs
!= NULL
) {
875 xmlHashFree(grammar
->defs
, NULL
);
882 * xmlRelaxNGNewDefine:
883 * @ctxt: a Relax-NG validation context
884 * @node: the node in the input document.
886 * Allocate a new RelaxNG define.
888 * Returns the newly allocated structure or NULL in case or error
890 static xmlRelaxNGDefinePtr
891 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
893 xmlRelaxNGDefinePtr ret
;
895 if (ctxt
->defMax
== 0) {
898 ctxt
->defTab
= (xmlRelaxNGDefinePtr
*)
899 xmlMalloc(ctxt
->defMax
* sizeof(xmlRelaxNGDefinePtr
));
900 if (ctxt
->defTab
== NULL
) {
901 xmlRngPErrMemory(ctxt
, "allocating define\n");
904 } else if (ctxt
->defMax
<= ctxt
->defNr
) {
905 xmlRelaxNGDefinePtr
*tmp
;
908 tmp
= (xmlRelaxNGDefinePtr
*) xmlRealloc(ctxt
->defTab
,
911 (xmlRelaxNGDefinePtr
));
913 xmlRngPErrMemory(ctxt
, "allocating define\n");
918 ret
= (xmlRelaxNGDefinePtr
) xmlMalloc(sizeof(xmlRelaxNGDefine
));
920 xmlRngPErrMemory(ctxt
, "allocating define\n");
923 memset(ret
, 0, sizeof(xmlRelaxNGDefine
));
924 ctxt
->defTab
[ctxt
->defNr
++] = ret
;
931 * xmlRelaxNGFreePartition:
932 * @partitions: a partition set structure
934 * Deallocate RelaxNG partition set structures.
937 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions
)
939 xmlRelaxNGInterleaveGroupPtr group
;
942 if (partitions
!= NULL
) {
943 if (partitions
->groups
!= NULL
) {
944 for (j
= 0; j
< partitions
->nbgroups
; j
++) {
945 group
= partitions
->groups
[j
];
947 if (group
->defs
!= NULL
)
948 xmlFree(group
->defs
);
949 if (group
->attrs
!= NULL
)
950 xmlFree(group
->attrs
);
954 xmlFree(partitions
->groups
);
956 if (partitions
->triage
!= NULL
) {
957 xmlHashFree(partitions
->triage
, NULL
);
964 * xmlRelaxNGFreeDefine:
965 * @define: a define structure
967 * Deallocate a RelaxNG define structure.
970 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define
)
975 if ((define
->type
== XML_RELAXNG_VALUE
) && (define
->attrs
!= NULL
)) {
976 xmlRelaxNGTypeLibraryPtr lib
;
978 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
979 if ((lib
!= NULL
) && (lib
->freef
!= NULL
))
980 lib
->freef(lib
->data
, (void *) define
->attrs
);
982 if ((define
->data
!= NULL
) && (define
->type
== XML_RELAXNG_INTERLEAVE
))
983 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr
) define
->data
);
984 if ((define
->data
!= NULL
) && (define
->type
== XML_RELAXNG_CHOICE
))
985 xmlHashFree((xmlHashTablePtr
) define
->data
, NULL
);
986 if (define
->name
!= NULL
)
987 xmlFree(define
->name
);
988 if (define
->ns
!= NULL
)
990 if (define
->value
!= NULL
)
991 xmlFree(define
->value
);
992 if (define
->contModel
!= NULL
)
993 xmlRegFreeRegexp(define
->contModel
);
998 * xmlRelaxNGNewStates:
999 * @ctxt: a Relax-NG validation context
1000 * @size: the default size for the container
1002 * Allocate a new RelaxNG validation state container
1004 * Returns the newly allocated structure or NULL in case or error
1006 static xmlRelaxNGStatesPtr
1007 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt
, int size
)
1009 xmlRelaxNGStatesPtr ret
;
1011 if ((ctxt
!= NULL
) &&
1012 (ctxt
->freeStates
!= NULL
) && (ctxt
->freeStatesNr
> 0)) {
1013 ctxt
->freeStatesNr
--;
1014 ret
= ctxt
->freeStates
[ctxt
->freeStatesNr
];
1021 ret
= (xmlRelaxNGStatesPtr
) xmlMalloc(sizeof(xmlRelaxNGStates
) +
1024 sizeof(xmlRelaxNGValidStatePtr
));
1026 xmlRngVErrMemory(ctxt
, "allocating states\n");
1030 ret
->maxState
= size
;
1031 ret
->tabState
= (xmlRelaxNGValidStatePtr
*) xmlMalloc((size
) *
1033 (xmlRelaxNGValidStatePtr
));
1034 if (ret
->tabState
== NULL
) {
1035 xmlRngVErrMemory(ctxt
, "allocating states\n");
1043 * xmlRelaxNGAddStateUniq:
1044 * @ctxt: a Relax-NG validation context
1045 * @states: the states container
1046 * @state: the validation state
1048 * Add a RelaxNG validation state to the container without checking
1051 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1054 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt
,
1055 xmlRelaxNGStatesPtr states
,
1056 xmlRelaxNGValidStatePtr state
)
1058 if (state
== NULL
) {
1061 if (states
->nbState
>= states
->maxState
) {
1062 xmlRelaxNGValidStatePtr
*tmp
;
1065 size
= states
->maxState
* 2;
1066 tmp
= (xmlRelaxNGValidStatePtr
*) xmlRealloc(states
->tabState
,
1069 (xmlRelaxNGValidStatePtr
));
1071 xmlRngVErrMemory(ctxt
, "adding states\n");
1074 states
->tabState
= tmp
;
1075 states
->maxState
= size
;
1077 states
->tabState
[states
->nbState
++] = state
;
1082 * xmlRelaxNGAddState:
1083 * @ctxt: a Relax-NG validation context
1084 * @states: the states container
1085 * @state: the validation state
1087 * Add a RelaxNG validation state to the container
1089 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1092 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt
,
1093 xmlRelaxNGStatesPtr states
,
1094 xmlRelaxNGValidStatePtr state
)
1098 if (state
== NULL
|| states
== NULL
) {
1101 if (states
->nbState
>= states
->maxState
) {
1102 xmlRelaxNGValidStatePtr
*tmp
;
1105 size
= states
->maxState
* 2;
1106 tmp
= (xmlRelaxNGValidStatePtr
*) xmlRealloc(states
->tabState
,
1109 (xmlRelaxNGValidStatePtr
));
1111 xmlRngVErrMemory(ctxt
, "adding states\n");
1114 states
->tabState
= tmp
;
1115 states
->maxState
= size
;
1117 for (i
= 0; i
< states
->nbState
; i
++) {
1118 if (xmlRelaxNGEqualValidState(ctxt
, state
, states
->tabState
[i
])) {
1119 xmlRelaxNGFreeValidState(ctxt
, state
);
1123 states
->tabState
[states
->nbState
++] = state
;
1128 * xmlRelaxNGFreeStates:
1129 * @ctxt: a Relax-NG validation context
1130 * @states: teh container
1132 * Free a RelaxNG validation state container
1135 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt
,
1136 xmlRelaxNGStatesPtr states
)
1140 if ((ctxt
!= NULL
) && (ctxt
->freeStates
== NULL
)) {
1141 ctxt
->freeStatesMax
= 40;
1142 ctxt
->freeStatesNr
= 0;
1143 ctxt
->freeStates
= (xmlRelaxNGStatesPtr
*)
1144 xmlMalloc(ctxt
->freeStatesMax
* sizeof(xmlRelaxNGStatesPtr
));
1145 if (ctxt
->freeStates
== NULL
) {
1146 xmlRngVErrMemory(ctxt
, "storing states\n");
1148 } else if ((ctxt
!= NULL
)
1149 && (ctxt
->freeStatesNr
>= ctxt
->freeStatesMax
)) {
1150 xmlRelaxNGStatesPtr
*tmp
;
1152 tmp
= (xmlRelaxNGStatesPtr
*) xmlRealloc(ctxt
->freeStates
,
1153 2 * ctxt
->freeStatesMax
*
1155 (xmlRelaxNGStatesPtr
));
1157 xmlRngVErrMemory(ctxt
, "storing states\n");
1158 xmlFree(states
->tabState
);
1162 ctxt
->freeStates
= tmp
;
1163 ctxt
->freeStatesMax
*= 2;
1165 if ((ctxt
== NULL
) || (ctxt
->freeStates
== NULL
)) {
1166 xmlFree(states
->tabState
);
1169 ctxt
->freeStates
[ctxt
->freeStatesNr
++] = states
;
1174 * xmlRelaxNGNewValidState:
1175 * @ctxt: a Relax-NG validation context
1176 * @node: the current node or NULL for the document
1178 * Allocate a new RelaxNG validation state
1180 * Returns the newly allocated structure or NULL in case or error
1182 static xmlRelaxNGValidStatePtr
1183 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt
, xmlNodePtr node
)
1185 xmlRelaxNGValidStatePtr ret
;
1187 xmlAttrPtr attrs
[MAX_ATTR
];
1189 xmlNodePtr root
= NULL
;
1192 root
= xmlDocGetRootElement(ctxt
->doc
);
1196 attr
= node
->properties
;
1197 while (attr
!= NULL
) {
1198 if (nbAttrs
< MAX_ATTR
)
1199 attrs
[nbAttrs
++] = attr
;
1205 if ((ctxt
->freeState
!= NULL
) && (ctxt
->freeState
->nbState
> 0)) {
1206 ctxt
->freeState
->nbState
--;
1207 ret
= ctxt
->freeState
->tabState
[ctxt
->freeState
->nbState
];
1210 (xmlRelaxNGValidStatePtr
)
1211 xmlMalloc(sizeof(xmlRelaxNGValidState
));
1213 xmlRngVErrMemory(ctxt
, "allocating states\n");
1216 memset(ret
, 0, sizeof(xmlRelaxNGValidState
));
1219 ret
->endvalue
= NULL
;
1221 ret
->node
= (xmlNodePtr
) ctxt
->doc
;
1225 ret
->seq
= node
->children
;
1229 if (ret
->attrs
== NULL
) {
1233 ret
->maxAttrs
= nbAttrs
;
1234 ret
->attrs
= (xmlAttrPtr
*) xmlMalloc(ret
->maxAttrs
*
1235 sizeof(xmlAttrPtr
));
1236 if (ret
->attrs
== NULL
) {
1237 xmlRngVErrMemory(ctxt
, "allocating states\n");
1240 } else if (ret
->maxAttrs
< nbAttrs
) {
1243 tmp
= (xmlAttrPtr
*) xmlRealloc(ret
->attrs
, nbAttrs
*
1244 sizeof(xmlAttrPtr
));
1246 xmlRngVErrMemory(ctxt
, "allocating states\n");
1250 ret
->maxAttrs
= nbAttrs
;
1252 ret
->nbAttrs
= nbAttrs
;
1253 if (nbAttrs
< MAX_ATTR
) {
1254 memcpy(ret
->attrs
, attrs
, sizeof(xmlAttrPtr
) * nbAttrs
);
1256 attr
= node
->properties
;
1258 while (attr
!= NULL
) {
1259 ret
->attrs
[nbAttrs
++] = attr
;
1264 ret
->nbAttrLeft
= ret
->nbAttrs
;
1269 * xmlRelaxNGCopyValidState:
1270 * @ctxt: a Relax-NG validation context
1271 * @state: a validation state
1273 * Copy the validation state
1275 * Returns the newly allocated structure or NULL in case or error
1277 static xmlRelaxNGValidStatePtr
1278 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt
,
1279 xmlRelaxNGValidStatePtr state
)
1281 xmlRelaxNGValidStatePtr ret
;
1282 unsigned int maxAttrs
;
1287 if ((ctxt
->freeState
!= NULL
) && (ctxt
->freeState
->nbState
> 0)) {
1288 ctxt
->freeState
->nbState
--;
1289 ret
= ctxt
->freeState
->tabState
[ctxt
->freeState
->nbState
];
1292 (xmlRelaxNGValidStatePtr
)
1293 xmlMalloc(sizeof(xmlRelaxNGValidState
));
1295 xmlRngVErrMemory(ctxt
, "allocating states\n");
1298 memset(ret
, 0, sizeof(xmlRelaxNGValidState
));
1301 maxAttrs
= ret
->maxAttrs
;
1302 memcpy(ret
, state
, sizeof(xmlRelaxNGValidState
));
1304 ret
->maxAttrs
= maxAttrs
;
1305 if (state
->nbAttrs
> 0) {
1306 if (ret
->attrs
== NULL
) {
1307 ret
->maxAttrs
= state
->maxAttrs
;
1308 ret
->attrs
= (xmlAttrPtr
*) xmlMalloc(ret
->maxAttrs
*
1309 sizeof(xmlAttrPtr
));
1310 if (ret
->attrs
== NULL
) {
1311 xmlRngVErrMemory(ctxt
, "allocating states\n");
1315 } else if (ret
->maxAttrs
< state
->nbAttrs
) {
1318 tmp
= (xmlAttrPtr
*) xmlRealloc(ret
->attrs
, state
->maxAttrs
*
1319 sizeof(xmlAttrPtr
));
1321 xmlRngVErrMemory(ctxt
, "allocating states\n");
1325 ret
->maxAttrs
= state
->maxAttrs
;
1328 memcpy(ret
->attrs
, state
->attrs
,
1329 state
->nbAttrs
* sizeof(xmlAttrPtr
));
1335 * xmlRelaxNGEqualValidState:
1336 * @ctxt: a Relax-NG validation context
1337 * @state1: a validation state
1338 * @state2: a validation state
1340 * Compare the validation states for equality
1342 * Returns 1 if equald, 0 otherwise
1345 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
1346 xmlRelaxNGValidStatePtr state1
,
1347 xmlRelaxNGValidStatePtr state2
)
1351 if ((state1
== NULL
) || (state2
== NULL
))
1353 if (state1
== state2
)
1355 if (state1
->node
!= state2
->node
)
1357 if (state1
->seq
!= state2
->seq
)
1359 if (state1
->nbAttrLeft
!= state2
->nbAttrLeft
)
1361 if (state1
->nbAttrs
!= state2
->nbAttrs
)
1363 if (state1
->endvalue
!= state2
->endvalue
)
1365 if ((state1
->value
!= state2
->value
) &&
1366 (!xmlStrEqual(state1
->value
, state2
->value
)))
1368 for (i
= 0; i
< state1
->nbAttrs
; i
++) {
1369 if (state1
->attrs
[i
] != state2
->attrs
[i
])
1376 * xmlRelaxNGFreeValidState:
1377 * @state: a validation state structure
1379 * Deallocate a RelaxNG validation state structure.
1382 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt
,
1383 xmlRelaxNGValidStatePtr state
)
1388 if ((ctxt
!= NULL
) && (ctxt
->freeState
== NULL
)) {
1389 ctxt
->freeState
= xmlRelaxNGNewStates(ctxt
, 40);
1391 if ((ctxt
== NULL
) || (ctxt
->freeState
== NULL
)) {
1392 if (state
->attrs
!= NULL
)
1393 xmlFree(state
->attrs
);
1396 xmlRelaxNGAddStatesUniq(ctxt
, ctxt
->freeState
, state
);
1400 /************************************************************************
1402 * Semi internal functions *
1404 ************************************************************************/
1407 * xmlRelaxParserSetFlag:
1408 * @ctxt: a RelaxNG parser context
1409 * @flags: a set of flags values
1411 * Semi private function used to pass informations to a parser context
1412 * which are a combination of xmlRelaxNGParserFlag .
1414 * Returns 0 if success and -1 in case of error
1417 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt
, int flags
)
1419 if (ctxt
== NULL
) return(-1);
1420 if (flags
& XML_RELAXNGP_FREE_DOC
) {
1421 ctxt
->crng
|= XML_RELAXNGP_FREE_DOC
;
1422 flags
-= XML_RELAXNGP_FREE_DOC
;
1424 if (flags
& XML_RELAXNGP_CRNG
) {
1425 ctxt
->crng
|= XML_RELAXNGP_CRNG
;
1426 flags
-= XML_RELAXNGP_CRNG
;
1428 if (flags
!= 0) return(-1);
1432 /************************************************************************
1434 * Document functions *
1436 ************************************************************************/
1437 static xmlDocPtr
xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
,
1441 * xmlRelaxNGIncludePush:
1442 * @ctxt: the parser context
1443 * @value: the element doc
1445 * Pushes a new include on top of the include stack
1447 * Returns 0 in case of error, the index in the stack otherwise
1450 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt
,
1451 xmlRelaxNGIncludePtr value
)
1453 if (ctxt
->incTab
== NULL
) {
1457 (xmlRelaxNGIncludePtr
*) xmlMalloc(ctxt
->incMax
*
1458 sizeof(ctxt
->incTab
[0]));
1459 if (ctxt
->incTab
== NULL
) {
1460 xmlRngPErrMemory(ctxt
, "allocating include\n");
1464 if (ctxt
->incNr
>= ctxt
->incMax
) {
1467 (xmlRelaxNGIncludePtr
*) xmlRealloc(ctxt
->incTab
,
1469 sizeof(ctxt
->incTab
[0]));
1470 if (ctxt
->incTab
== NULL
) {
1471 xmlRngPErrMemory(ctxt
, "allocating include\n");
1475 ctxt
->incTab
[ctxt
->incNr
] = value
;
1477 return (ctxt
->incNr
++);
1481 * xmlRelaxNGIncludePop:
1482 * @ctxt: the parser context
1484 * Pops the top include from the include stack
1486 * Returns the include just removed
1488 static xmlRelaxNGIncludePtr
1489 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt
)
1491 xmlRelaxNGIncludePtr ret
;
1493 if (ctxt
->incNr
<= 0)
1496 if (ctxt
->incNr
> 0)
1497 ctxt
->inc
= ctxt
->incTab
[ctxt
->incNr
- 1];
1500 ret
= ctxt
->incTab
[ctxt
->incNr
];
1501 ctxt
->incTab
[ctxt
->incNr
] = NULL
;
1506 * xmlRelaxNGRemoveRedefine:
1507 * @ctxt: the parser context
1508 * @URL: the normalized URL
1509 * @target: the included target
1510 * @name: the define name to eliminate
1512 * Applies the elimination algorithm of 4.7
1514 * Returns 0 in case of error, 1 in case of success.
1517 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt
,
1518 const xmlChar
* URL ATTRIBUTE_UNUSED
,
1519 xmlNodePtr target
, const xmlChar
* name
)
1522 xmlNodePtr tmp
, tmp2
;
1525 #ifdef DEBUG_INCLUDE
1527 xmlGenericError(xmlGenericErrorContext
,
1528 "Elimination of <include> start from %s\n", URL
);
1530 xmlGenericError(xmlGenericErrorContext
,
1531 "Elimination of <include> define %s from %s\n",
1535 while (tmp
!= NULL
) {
1537 if ((name
== NULL
) && (IS_RELAXNG(tmp
, "start"))) {
1541 } else if ((name
!= NULL
) && (IS_RELAXNG(tmp
, "define"))) {
1542 name2
= xmlGetProp(tmp
, BAD_CAST
"name");
1543 xmlRelaxNGNormExtSpace(name2
);
1544 if (name2
!= NULL
) {
1545 if (xmlStrEqual(name
, name2
)) {
1552 } else if (IS_RELAXNG(tmp
, "include")) {
1553 xmlChar
*href
= NULL
;
1554 xmlRelaxNGDocumentPtr inc
= tmp
->psvi
;
1556 if ((inc
!= NULL
) && (inc
->doc
!= NULL
) &&
1557 (inc
->doc
->children
!= NULL
)) {
1560 (inc
->doc
->children
->name
, BAD_CAST
"grammar")) {
1561 #ifdef DEBUG_INCLUDE
1562 href
= xmlGetProp(tmp
, BAD_CAST
"href");
1564 if (xmlRelaxNGRemoveRedefine(ctxt
, href
,
1565 xmlDocGetRootElement(inc
->doc
)->children
,
1569 #ifdef DEBUG_INCLUDE
1582 * xmlRelaxNGLoadInclude:
1583 * @ctxt: the parser context
1584 * @URL: the normalized URL
1585 * @node: the include node.
1586 * @ns: the namespace passed from the context.
1588 * First lookup if the document is already loaded into the parser context,
1589 * check against recursion. If not found the resource is loaded and
1590 * the content is preprocessed before being returned back to the caller.
1592 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1594 static xmlRelaxNGIncludePtr
1595 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt
, const xmlChar
* URL
,
1596 xmlNodePtr node
, const xmlChar
* ns
)
1598 xmlRelaxNGIncludePtr ret
= NULL
;
1601 xmlNodePtr root
, cur
;
1603 #ifdef DEBUG_INCLUDE
1604 xmlGenericError(xmlGenericErrorContext
,
1605 "xmlRelaxNGLoadInclude(%s)\n", URL
);
1609 * check against recursion in the stack
1611 for (i
= 0; i
< ctxt
->incNr
; i
++) {
1612 if (xmlStrEqual(ctxt
->incTab
[i
]->href
, URL
)) {
1613 xmlRngPErr(ctxt
, NULL
, XML_RNGP_INCLUDE_RECURSE
,
1614 "Detected an Include recursion for %s\n", URL
,
1623 doc
= xmlReadFile((const char *) URL
,NULL
,0);
1625 xmlRngPErr(ctxt
, node
, XML_RNGP_PARSE_ERROR
,
1626 "xmlRelaxNG: could not load %s\n", URL
, NULL
);
1629 #ifdef DEBUG_INCLUDE
1630 xmlGenericError(xmlGenericErrorContext
, "Parsed %s Okay\n", URL
);
1634 * Allocate the document structures and register it first.
1636 ret
= (xmlRelaxNGIncludePtr
) xmlMalloc(sizeof(xmlRelaxNGInclude
));
1638 xmlRngPErrMemory(ctxt
, "allocating include\n");
1642 memset(ret
, 0, sizeof(xmlRelaxNGInclude
));
1644 ret
->href
= xmlStrdup(URL
);
1645 ret
->next
= ctxt
->includes
;
1646 ctxt
->includes
= ret
;
1649 * transmit the ns if needed
1652 root
= xmlDocGetRootElement(doc
);
1654 if (xmlHasProp(root
, BAD_CAST
"ns") == NULL
) {
1655 xmlSetProp(root
, BAD_CAST
"ns", ns
);
1661 * push it on the stack
1663 xmlRelaxNGIncludePush(ctxt
, ret
);
1666 * Some preprocessing of the document content, this include recursing
1667 * in the include stack.
1669 #ifdef DEBUG_INCLUDE
1670 xmlGenericError(xmlGenericErrorContext
, "cleanup of %s\n", URL
);
1673 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
1680 * Pop up the include from the stack
1682 xmlRelaxNGIncludePop(ctxt
);
1684 #ifdef DEBUG_INCLUDE
1685 xmlGenericError(xmlGenericErrorContext
, "Checking of %s\n", URL
);
1688 * Check that the top element is a grammar
1690 root
= xmlDocGetRootElement(doc
);
1692 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY
,
1693 "xmlRelaxNG: included document is empty %s\n", URL
,
1697 if (!IS_RELAXNG(root
, "grammar")) {
1698 xmlRngPErr(ctxt
, node
, XML_RNGP_GRAMMAR_MISSING
,
1699 "xmlRelaxNG: included document %s root is not a grammar\n",
1705 * Elimination of redefined rules in the include.
1707 cur
= node
->children
;
1708 while (cur
!= NULL
) {
1709 if (IS_RELAXNG(cur
, "start")) {
1713 xmlRelaxNGRemoveRedefine(ctxt
, URL
, root
->children
, NULL
);
1715 xmlRngPErr(ctxt
, node
, XML_RNGP_START_MISSING
,
1716 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1719 } else if (IS_RELAXNG(cur
, "define")) {
1722 name
= xmlGetProp(cur
, BAD_CAST
"name");
1724 xmlRngPErr(ctxt
, node
, XML_RNGP_NAME_MISSING
,
1725 "xmlRelaxNG: include %s has define without name\n",
1730 xmlRelaxNGNormExtSpace(name
);
1731 found
= xmlRelaxNGRemoveRedefine(ctxt
, URL
,
1732 root
->children
, name
);
1734 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_MISSING
,
1735 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1749 * xmlRelaxNGValidErrorPush:
1750 * @ctxt: the validation context
1751 * @err: the error code
1752 * @arg1: the first string argument
1753 * @arg2: the second string argument
1754 * @dup: arg need to be duplicated
1756 * Pushes a new error on top of the error stack
1758 * Returns 0 in case of error, the index in the stack otherwise
1761 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt
,
1762 xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
1763 const xmlChar
* arg2
, int dup
)
1765 xmlRelaxNGValidErrorPtr cur
;
1768 xmlGenericError(xmlGenericErrorContext
,
1769 "Pushing error %d at %d on stack\n", err
, ctxt
->errNr
);
1771 if (ctxt
->errTab
== NULL
) {
1775 (xmlRelaxNGValidErrorPtr
) xmlMalloc(ctxt
->errMax
*
1777 (xmlRelaxNGValidError
));
1778 if (ctxt
->errTab
== NULL
) {
1779 xmlRngVErrMemory(ctxt
, "pushing error\n");
1784 if (ctxt
->errNr
>= ctxt
->errMax
) {
1787 (xmlRelaxNGValidErrorPtr
) xmlRealloc(ctxt
->errTab
,
1790 (xmlRelaxNGValidError
));
1791 if (ctxt
->errTab
== NULL
) {
1792 xmlRngVErrMemory(ctxt
, "pushing error\n");
1795 ctxt
->err
= &ctxt
->errTab
[ctxt
->errNr
- 1];
1797 if ((ctxt
->err
!= NULL
) && (ctxt
->state
!= NULL
) &&
1798 (ctxt
->err
->node
== ctxt
->state
->node
) && (ctxt
->err
->err
== err
))
1799 return (ctxt
->errNr
);
1800 cur
= &ctxt
->errTab
[ctxt
->errNr
];
1803 cur
->arg1
= xmlStrdup(arg1
);
1804 cur
->arg2
= xmlStrdup(arg2
);
1805 cur
->flags
= ERROR_IS_DUP
;
1811 if (ctxt
->state
!= NULL
) {
1812 cur
->node
= ctxt
->state
->node
;
1813 cur
->seq
= ctxt
->state
->seq
;
1819 return (ctxt
->errNr
++);
1823 * xmlRelaxNGValidErrorPop:
1824 * @ctxt: the validation context
1826 * Pops the top error from the error stack
1829 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt
)
1831 xmlRelaxNGValidErrorPtr cur
;
1833 if (ctxt
->errNr
<= 0) {
1838 if (ctxt
->errNr
> 0)
1839 ctxt
->err
= &ctxt
->errTab
[ctxt
->errNr
- 1];
1842 cur
= &ctxt
->errTab
[ctxt
->errNr
];
1843 if (cur
->flags
& ERROR_IS_DUP
) {
1844 if (cur
->arg1
!= NULL
)
1845 xmlFree((xmlChar
*) cur
->arg1
);
1847 if (cur
->arg2
!= NULL
)
1848 xmlFree((xmlChar
*) cur
->arg2
);
1855 * xmlRelaxNGDocumentPush:
1856 * @ctxt: the parser context
1857 * @value: the element doc
1859 * Pushes a new doc on top of the doc stack
1861 * Returns 0 in case of error, the index in the stack otherwise
1864 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt
,
1865 xmlRelaxNGDocumentPtr value
)
1867 if (ctxt
->docTab
== NULL
) {
1871 (xmlRelaxNGDocumentPtr
*) xmlMalloc(ctxt
->docMax
*
1872 sizeof(ctxt
->docTab
[0]));
1873 if (ctxt
->docTab
== NULL
) {
1874 xmlRngPErrMemory(ctxt
, "adding document\n");
1878 if (ctxt
->docNr
>= ctxt
->docMax
) {
1881 (xmlRelaxNGDocumentPtr
*) xmlRealloc(ctxt
->docTab
,
1883 sizeof(ctxt
->docTab
[0]));
1884 if (ctxt
->docTab
== NULL
) {
1885 xmlRngPErrMemory(ctxt
, "adding document\n");
1889 ctxt
->docTab
[ctxt
->docNr
] = value
;
1891 return (ctxt
->docNr
++);
1895 * xmlRelaxNGDocumentPop:
1896 * @ctxt: the parser context
1898 * Pops the top doc from the doc stack
1900 * Returns the doc just removed
1902 static xmlRelaxNGDocumentPtr
1903 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt
)
1905 xmlRelaxNGDocumentPtr ret
;
1907 if (ctxt
->docNr
<= 0)
1910 if (ctxt
->docNr
> 0)
1911 ctxt
->doc
= ctxt
->docTab
[ctxt
->docNr
- 1];
1914 ret
= ctxt
->docTab
[ctxt
->docNr
];
1915 ctxt
->docTab
[ctxt
->docNr
] = NULL
;
1920 * xmlRelaxNGLoadExternalRef:
1921 * @ctxt: the parser context
1922 * @URL: the normalized URL
1923 * @ns: the inherited ns if any
1925 * First lookup if the document is already loaded into the parser context,
1926 * check against recursion. If not found the resource is loaded and
1927 * the content is preprocessed before being returned back to the caller.
1929 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1931 static xmlRelaxNGDocumentPtr
1932 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt
,
1933 const xmlChar
* URL
, const xmlChar
* ns
)
1935 xmlRelaxNGDocumentPtr ret
= NULL
;
1941 * check against recursion in the stack
1943 for (i
= 0; i
< ctxt
->docNr
; i
++) {
1944 if (xmlStrEqual(ctxt
->docTab
[i
]->href
, URL
)) {
1945 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EXTERNALREF_RECURSE
,
1946 "Detected an externalRef recursion for %s\n", URL
,
1955 doc
= xmlReadFile((const char *) URL
,NULL
,0);
1957 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
1958 "xmlRelaxNG: could not load %s\n", URL
, NULL
);
1963 * Allocate the document structures and register it first.
1965 ret
= (xmlRelaxNGDocumentPtr
) xmlMalloc(sizeof(xmlRelaxNGDocument
));
1967 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_ERR_NO_MEMORY
,
1968 "xmlRelaxNG: allocate memory for doc %s\n", URL
, NULL
);
1972 memset(ret
, 0, sizeof(xmlRelaxNGDocument
));
1974 ret
->href
= xmlStrdup(URL
);
1975 ret
->next
= ctxt
->documents
;
1976 ret
->externalRef
= 1;
1977 ctxt
->documents
= ret
;
1980 * transmit the ns if needed
1983 root
= xmlDocGetRootElement(doc
);
1985 if (xmlHasProp(root
, BAD_CAST
"ns") == NULL
) {
1986 xmlSetProp(root
, BAD_CAST
"ns", ns
);
1992 * push it on the stack and register it in the hash table
1994 xmlRelaxNGDocumentPush(ctxt
, ret
);
1997 * Some preprocessing of the document content
1999 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
2005 xmlRelaxNGDocumentPop(ctxt
);
2010 /************************************************************************
2014 ************************************************************************/
2016 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2017 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2018 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2019 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2020 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
2023 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def
)
2027 switch (def
->type
) {
2028 case XML_RELAXNG_EMPTY
:
2030 case XML_RELAXNG_NOT_ALLOWED
:
2031 return ("notAllowed");
2032 case XML_RELAXNG_EXCEPT
:
2034 case XML_RELAXNG_TEXT
:
2036 case XML_RELAXNG_ELEMENT
:
2038 case XML_RELAXNG_DATATYPE
:
2039 return ("datatype");
2040 case XML_RELAXNG_VALUE
:
2042 case XML_RELAXNG_LIST
:
2044 case XML_RELAXNG_ATTRIBUTE
:
2045 return ("attribute");
2046 case XML_RELAXNG_DEF
:
2048 case XML_RELAXNG_REF
:
2050 case XML_RELAXNG_EXTERNALREF
:
2051 return ("externalRef");
2052 case XML_RELAXNG_PARENTREF
:
2053 return ("parentRef");
2054 case XML_RELAXNG_OPTIONAL
:
2055 return ("optional");
2056 case XML_RELAXNG_ZEROORMORE
:
2057 return ("zeroOrMore");
2058 case XML_RELAXNG_ONEORMORE
:
2059 return ("oneOrMore");
2060 case XML_RELAXNG_CHOICE
:
2062 case XML_RELAXNG_GROUP
:
2064 case XML_RELAXNG_INTERLEAVE
:
2065 return ("interleave");
2066 case XML_RELAXNG_START
:
2068 case XML_RELAXNG_NOOP
:
2070 case XML_RELAXNG_PARAM
:
2077 * xmlRelaxNGGetErrorString:
2078 * @err: the error code
2079 * @arg1: the first string argument
2080 * @arg2: the second string argument
2082 * computes a formatted error string for the given error code and args
2084 * Returns the error string, it must be deallocated by the caller
2087 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
2088 const xmlChar
* arg2
)
2099 case XML_RELAXNG_OK
:
2101 case XML_RELAXNG_ERR_MEMORY
:
2102 return (xmlCharStrdup("out of memory\n"));
2103 case XML_RELAXNG_ERR_TYPE
:
2104 snprintf(msg
, 1000, "failed to validate type %s\n", arg1
);
2106 case XML_RELAXNG_ERR_TYPEVAL
:
2107 snprintf(msg
, 1000, "Type %s doesn't allow value '%s'\n", arg1
,
2110 case XML_RELAXNG_ERR_DUPID
:
2111 snprintf(msg
, 1000, "ID %s redefined\n", arg1
);
2113 case XML_RELAXNG_ERR_TYPECMP
:
2114 snprintf(msg
, 1000, "failed to compare type %s\n", arg1
);
2116 case XML_RELAXNG_ERR_NOSTATE
:
2117 return (xmlCharStrdup("Internal error: no state\n"));
2118 case XML_RELAXNG_ERR_NODEFINE
:
2119 return (xmlCharStrdup("Internal error: no define\n"));
2120 case XML_RELAXNG_ERR_INTERNAL
:
2121 snprintf(msg
, 1000, "Internal error: %s\n", arg1
);
2123 case XML_RELAXNG_ERR_LISTEXTRA
:
2124 snprintf(msg
, 1000, "Extra data in list: %s\n", arg1
);
2126 case XML_RELAXNG_ERR_INTERNODATA
:
2127 return (xmlCharStrdup
2128 ("Internal: interleave block has no data\n"));
2129 case XML_RELAXNG_ERR_INTERSEQ
:
2130 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2131 case XML_RELAXNG_ERR_INTEREXTRA
:
2132 snprintf(msg
, 1000, "Extra element %s in interleave\n", arg1
);
2134 case XML_RELAXNG_ERR_ELEMNAME
:
2135 snprintf(msg
, 1000, "Expecting element %s, got %s\n", arg1
,
2138 case XML_RELAXNG_ERR_ELEMNONS
:
2139 snprintf(msg
, 1000, "Expecting a namespace for element %s\n",
2142 case XML_RELAXNG_ERR_ELEMWRONGNS
:
2144 "Element %s has wrong namespace: expecting %s\n", arg1
,
2147 case XML_RELAXNG_ERR_ELEMWRONG
:
2148 snprintf(msg
, 1000, "Did not expect element %s there\n", arg1
);
2150 case XML_RELAXNG_ERR_TEXTWRONG
:
2152 "Did not expect text in element %s content\n", arg1
);
2154 case XML_RELAXNG_ERR_ELEMEXTRANS
:
2155 snprintf(msg
, 1000, "Expecting no namespace for element %s\n",
2158 case XML_RELAXNG_ERR_ELEMNOTEMPTY
:
2159 snprintf(msg
, 1000, "Expecting element %s to be empty\n", arg1
);
2161 case XML_RELAXNG_ERR_NOELEM
:
2162 snprintf(msg
, 1000, "Expecting an element %s, got nothing\n",
2165 case XML_RELAXNG_ERR_NOTELEM
:
2166 return (xmlCharStrdup("Expecting an element got text\n"));
2167 case XML_RELAXNG_ERR_ATTRVALID
:
2168 snprintf(msg
, 1000, "Element %s failed to validate attributes\n",
2171 case XML_RELAXNG_ERR_CONTENTVALID
:
2172 snprintf(msg
, 1000, "Element %s failed to validate content\n",
2175 case XML_RELAXNG_ERR_EXTRACONTENT
:
2176 snprintf(msg
, 1000, "Element %s has extra content: %s\n",
2179 case XML_RELAXNG_ERR_INVALIDATTR
:
2180 snprintf(msg
, 1000, "Invalid attribute %s for element %s\n",
2183 case XML_RELAXNG_ERR_LACKDATA
:
2184 snprintf(msg
, 1000, "Datatype element %s contains no data\n",
2187 case XML_RELAXNG_ERR_DATAELEM
:
2188 snprintf(msg
, 1000, "Datatype element %s has child elements\n",
2191 case XML_RELAXNG_ERR_VALELEM
:
2192 snprintf(msg
, 1000, "Value element %s has child elements\n",
2195 case XML_RELAXNG_ERR_LISTELEM
:
2196 snprintf(msg
, 1000, "List element %s has child elements\n",
2199 case XML_RELAXNG_ERR_DATATYPE
:
2200 snprintf(msg
, 1000, "Error validating datatype %s\n", arg1
);
2202 case XML_RELAXNG_ERR_VALUE
:
2203 snprintf(msg
, 1000, "Error validating value %s\n", arg1
);
2205 case XML_RELAXNG_ERR_LIST
:
2206 return (xmlCharStrdup("Error validating list\n"));
2207 case XML_RELAXNG_ERR_NOGRAMMAR
:
2208 return (xmlCharStrdup("No top grammar defined\n"));
2209 case XML_RELAXNG_ERR_EXTRADATA
:
2210 return (xmlCharStrdup("Extra data in the document\n"));
2212 return (xmlCharStrdup("Unknown error !\n"));
2215 snprintf(msg
, 1000, "Unknown error code %d\n", err
);
2218 return (xmlStrdup((xmlChar
*) msg
));
2222 * xmlRelaxNGShowValidError:
2223 * @ctxt: the validation context
2224 * @err: the error number
2226 * @child: the node child generating the problem.
2227 * @arg1: the first argument
2228 * @arg2: the second argument
2230 * Show a validation error.
2233 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt
,
2234 xmlRelaxNGValidErr err
, xmlNodePtr node
,
2235 xmlNodePtr child
, const xmlChar
* arg1
,
2236 const xmlChar
* arg2
)
2240 if (ctxt
->flags
& FLAGS_NOERROR
)
2244 xmlGenericError(xmlGenericErrorContext
, "Show error %d\n", err
);
2246 msg
= xmlRelaxNGGetErrorString(err
, arg1
, arg2
);
2250 if (ctxt
->errNo
== XML_RELAXNG_OK
)
2252 xmlRngVErr(ctxt
, (child
== NULL
? node
: child
), err
,
2253 (const char *) msg
, arg1
, arg2
);
2258 * xmlRelaxNGPopErrors:
2259 * @ctxt: the validation context
2260 * @level: the error level in the stack
2262 * pop and discard all errors until the given level is reached
2265 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt
, int level
)
2268 xmlRelaxNGValidErrorPtr err
;
2271 xmlGenericError(xmlGenericErrorContext
,
2272 "Pop errors till level %d\n", level
);
2274 for (i
= level
; i
< ctxt
->errNr
; i
++) {
2275 err
= &ctxt
->errTab
[i
];
2276 if (err
->flags
& ERROR_IS_DUP
) {
2277 if (err
->arg1
!= NULL
)
2278 xmlFree((xmlChar
*) err
->arg1
);
2280 if (err
->arg2
!= NULL
)
2281 xmlFree((xmlChar
*) err
->arg2
);
2286 ctxt
->errNr
= level
;
2287 if (ctxt
->errNr
<= 0)
2292 * xmlRelaxNGDumpValidError:
2293 * @ctxt: the validation context
2295 * Show all validation error over a given index.
2298 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt
)
2301 xmlRelaxNGValidErrorPtr err
, dup
;
2304 xmlGenericError(xmlGenericErrorContext
,
2305 "Dumping error stack %d errors\n", ctxt
->errNr
);
2307 for (i
= 0, k
= 0; i
< ctxt
->errNr
; i
++) {
2308 err
= &ctxt
->errTab
[i
];
2309 if (k
< MAX_ERROR
) {
2310 for (j
= 0; j
< i
; j
++) {
2311 dup
= &ctxt
->errTab
[j
];
2312 if ((err
->err
== dup
->err
) && (err
->node
== dup
->node
) &&
2313 (xmlStrEqual(err
->arg1
, dup
->arg1
)) &&
2314 (xmlStrEqual(err
->arg2
, dup
->arg2
))) {
2318 xmlRelaxNGShowValidError(ctxt
, err
->err
, err
->node
, err
->seq
,
2319 err
->arg1
, err
->arg2
);
2323 if (err
->flags
& ERROR_IS_DUP
) {
2324 if (err
->arg1
!= NULL
)
2325 xmlFree((xmlChar
*) err
->arg1
);
2327 if (err
->arg2
!= NULL
)
2328 xmlFree((xmlChar
*) err
->arg2
);
2337 * xmlRelaxNGAddValidError:
2338 * @ctxt: the validation context
2339 * @err: the error number
2340 * @arg1: the first argument
2341 * @arg2: the second argument
2342 * @dup: need to dup the args
2344 * Register a validation error, either generating it if it's sure
2345 * or stacking it for later handling if unsure.
2348 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt
,
2349 xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
2350 const xmlChar
* arg2
, int dup
)
2354 if (ctxt
->flags
& FLAGS_NOERROR
)
2358 xmlGenericError(xmlGenericErrorContext
, "Adding error %d\n", err
);
2361 * generate the error directly
2363 if (((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) ||
2364 (ctxt
->flags
& FLAGS_NEGATIVE
)) {
2365 xmlNodePtr node
, seq
;
2368 * Flush first any stacked error which might be the
2369 * real cause of the problem.
2371 if (ctxt
->errNr
!= 0)
2372 xmlRelaxNGDumpValidError(ctxt
);
2373 if (ctxt
->state
!= NULL
) {
2374 node
= ctxt
->state
->node
;
2375 seq
= ctxt
->state
->seq
;
2379 if ((node
== NULL
) && (seq
== NULL
)) {
2382 xmlRelaxNGShowValidError(ctxt
, err
, node
, seq
, arg1
, arg2
);
2385 * Stack the error for later processing if needed
2388 xmlRelaxNGValidErrorPush(ctxt
, err
, arg1
, arg2
, dup
);
2393 /************************************************************************
2395 * Type library hooks *
2397 ************************************************************************/
2398 static xmlChar
*xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
,
2399 const xmlChar
* str
);
2402 * xmlRelaxNGSchemaTypeHave:
2403 * @data: data needed for the library
2404 * @type: the type name
2406 * Check if the given type is provided by
2407 * the W3C XMLSchema Datatype library.
2409 * Returns 1 if yes, 0 if no and -1 in case of error.
2412 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED
, const xmlChar
* type
)
2414 xmlSchemaTypePtr typ
;
2418 typ
= xmlSchemaGetPredefinedType(type
,
2420 "http://www.w3.org/2001/XMLSchema");
2427 * xmlRelaxNGSchemaTypeCheck:
2428 * @data: data needed for the library
2429 * @type: the type name
2430 * @value: the value to check
2433 * Check if the given type and value are validated by
2434 * the W3C XMLSchema Datatype library.
2436 * Returns 1 if yes, 0 if no and -1 in case of error.
2439 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED
,
2440 const xmlChar
* type
,
2441 const xmlChar
* value
,
2442 void **result
, xmlNodePtr node
)
2444 xmlSchemaTypePtr typ
;
2447 if ((type
== NULL
) || (value
== NULL
))
2449 typ
= xmlSchemaGetPredefinedType(type
,
2451 "http://www.w3.org/2001/XMLSchema");
2454 ret
= xmlSchemaValPredefTypeNode(typ
, value
,
2455 (xmlSchemaValPtr
*) result
, node
);
2456 if (ret
== 2) /* special ID error code */
2466 * xmlRelaxNGSchemaFacetCheck:
2467 * @data: data needed for the library
2468 * @type: the type name
2469 * @facet: the facet name
2470 * @val: the facet value
2471 * @strval: the string value
2472 * @value: the value to check
2474 * Function provided by a type library to check a value facet
2476 * Returns 1 if yes, 0 if no and -1 in case of error.
2479 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED
,
2480 const xmlChar
* type
, const xmlChar
* facetname
,
2481 const xmlChar
* val
, const xmlChar
* strval
,
2484 xmlSchemaFacetPtr facet
;
2485 xmlSchemaTypePtr typ
;
2488 if ((type
== NULL
) || (strval
== NULL
))
2490 typ
= xmlSchemaGetPredefinedType(type
,
2492 "http://www.w3.org/2001/XMLSchema");
2496 facet
= xmlSchemaNewFacet();
2500 if (xmlStrEqual(facetname
, BAD_CAST
"minInclusive")) {
2501 facet
->type
= XML_SCHEMA_FACET_MININCLUSIVE
;
2502 } else if (xmlStrEqual(facetname
, BAD_CAST
"minExclusive")) {
2503 facet
->type
= XML_SCHEMA_FACET_MINEXCLUSIVE
;
2504 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxInclusive")) {
2505 facet
->type
= XML_SCHEMA_FACET_MAXINCLUSIVE
;
2506 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxExclusive")) {
2507 facet
->type
= XML_SCHEMA_FACET_MAXEXCLUSIVE
;
2508 } else if (xmlStrEqual(facetname
, BAD_CAST
"totalDigits")) {
2509 facet
->type
= XML_SCHEMA_FACET_TOTALDIGITS
;
2510 } else if (xmlStrEqual(facetname
, BAD_CAST
"fractionDigits")) {
2511 facet
->type
= XML_SCHEMA_FACET_FRACTIONDIGITS
;
2512 } else if (xmlStrEqual(facetname
, BAD_CAST
"pattern")) {
2513 facet
->type
= XML_SCHEMA_FACET_PATTERN
;
2514 } else if (xmlStrEqual(facetname
, BAD_CAST
"enumeration")) {
2515 facet
->type
= XML_SCHEMA_FACET_ENUMERATION
;
2516 } else if (xmlStrEqual(facetname
, BAD_CAST
"whiteSpace")) {
2517 facet
->type
= XML_SCHEMA_FACET_WHITESPACE
;
2518 } else if (xmlStrEqual(facetname
, BAD_CAST
"length")) {
2519 facet
->type
= XML_SCHEMA_FACET_LENGTH
;
2520 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxLength")) {
2521 facet
->type
= XML_SCHEMA_FACET_MAXLENGTH
;
2522 } else if (xmlStrEqual(facetname
, BAD_CAST
"minLength")) {
2523 facet
->type
= XML_SCHEMA_FACET_MINLENGTH
;
2525 xmlSchemaFreeFacet(facet
);
2529 ret
= xmlSchemaCheckFacet(facet
, typ
, NULL
, type
);
2531 xmlSchemaFreeFacet(facet
);
2534 ret
= xmlSchemaValidateFacet(typ
, facet
, strval
, value
);
2535 xmlSchemaFreeFacet(facet
);
2542 * xmlRelaxNGSchemaFreeValue:
2543 * @data: data needed for the library
2544 * @value: the value to free
2546 * Function provided by a type library to free a Schemas value
2548 * Returns 1 if yes, 0 if no and -1 in case of error.
2551 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED
, void *value
)
2553 xmlSchemaFreeValue(value
);
2557 * xmlRelaxNGSchemaTypeCompare:
2558 * @data: data needed for the library
2559 * @type: the type name
2560 * @value1: the first value
2561 * @value2: the second value
2563 * Compare two values for equality accordingly a type from the W3C XMLSchema
2566 * Returns 1 if equal, 0 if no and -1 in case of error.
2569 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED
,
2570 const xmlChar
* type
,
2571 const xmlChar
* value1
,
2574 const xmlChar
* value2
, xmlNodePtr ctxt2
)
2577 xmlSchemaTypePtr typ
;
2578 xmlSchemaValPtr res1
= NULL
, res2
= NULL
;
2580 if ((type
== NULL
) || (value1
== NULL
) || (value2
== NULL
))
2582 typ
= xmlSchemaGetPredefinedType(type
,
2584 "http://www.w3.org/2001/XMLSchema");
2587 if (comp1
== NULL
) {
2588 ret
= xmlSchemaValPredefTypeNode(typ
, value1
, &res1
, ctxt1
);
2594 res1
= (xmlSchemaValPtr
) comp1
;
2596 ret
= xmlSchemaValPredefTypeNode(typ
, value2
, &res2
, ctxt2
);
2598 if (res1
!= (xmlSchemaValPtr
) comp1
)
2599 xmlSchemaFreeValue(res1
);
2602 ret
= xmlSchemaCompareValues(res1
, res2
);
2603 if (res1
!= (xmlSchemaValPtr
) comp1
)
2604 xmlSchemaFreeValue(res1
);
2605 xmlSchemaFreeValue(res2
);
2614 * xmlRelaxNGDefaultTypeHave:
2615 * @data: data needed for the library
2616 * @type: the type name
2618 * Check if the given type is provided by
2619 * the default datatype library.
2621 * Returns 1 if yes, 0 if no and -1 in case of error.
2624 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED
,
2625 const xmlChar
* type
)
2629 if (xmlStrEqual(type
, BAD_CAST
"string"))
2631 if (xmlStrEqual(type
, BAD_CAST
"token"))
2637 * xmlRelaxNGDefaultTypeCheck:
2638 * @data: data needed for the library
2639 * @type: the type name
2640 * @value: the value to check
2643 * Check if the given type and value are validated by
2644 * the default datatype library.
2646 * Returns 1 if yes, 0 if no and -1 in case of error.
2649 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED
,
2650 const xmlChar
* type ATTRIBUTE_UNUSED
,
2651 const xmlChar
* value ATTRIBUTE_UNUSED
,
2652 void **result ATTRIBUTE_UNUSED
,
2653 xmlNodePtr node ATTRIBUTE_UNUSED
)
2657 if (xmlStrEqual(type
, BAD_CAST
"string"))
2659 if (xmlStrEqual(type
, BAD_CAST
"token")) {
2667 * xmlRelaxNGDefaultTypeCompare:
2668 * @data: data needed for the library
2669 * @type: the type name
2670 * @value1: the first value
2671 * @value2: the second value
2673 * Compare two values accordingly a type from the default
2676 * Returns 1 if yes, 0 if no and -1 in case of error.
2679 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED
,
2680 const xmlChar
* type
,
2681 const xmlChar
* value1
,
2682 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED
,
2683 void *comp1 ATTRIBUTE_UNUSED
,
2684 const xmlChar
* value2
,
2685 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED
)
2689 if (xmlStrEqual(type
, BAD_CAST
"string")) {
2690 ret
= xmlStrEqual(value1
, value2
);
2691 } else if (xmlStrEqual(type
, BAD_CAST
"token")) {
2692 if (!xmlStrEqual(value1
, value2
)) {
2693 xmlChar
*nval
, *nvalue
;
2696 * TODO: trivial optimizations are possible by
2697 * computing at compile-time
2699 nval
= xmlRelaxNGNormalize(NULL
, value1
);
2700 nvalue
= xmlRelaxNGNormalize(NULL
, value2
);
2702 if ((nval
== NULL
) || (nvalue
== NULL
))
2704 else if (xmlStrEqual(nval
, nvalue
))
2718 static int xmlRelaxNGTypeInitialized
= 0;
2719 static xmlHashTablePtr xmlRelaxNGRegisteredTypes
= NULL
;
2722 * xmlRelaxNGFreeTypeLibrary:
2723 * @lib: the type library structure
2724 * @namespace: the URI bound to the library
2726 * Free the structure associated to the type library
2729 xmlRelaxNGFreeTypeLibrary(xmlRelaxNGTypeLibraryPtr lib
,
2730 const xmlChar
* namespace ATTRIBUTE_UNUSED
)
2734 if (lib
->namespace != NULL
)
2735 xmlFree((xmlChar
*) lib
->namespace);
2740 * xmlRelaxNGRegisterTypeLibrary:
2741 * @namespace: the URI bound to the library
2742 * @data: data associated to the library
2743 * @have: the provide function
2744 * @check: the checking function
2745 * @comp: the comparison function
2747 * Register a new type library
2749 * Returns 0 in case of success and -1 in case of error.
2752 xmlRelaxNGRegisterTypeLibrary(const xmlChar
* namespace, void *data
,
2753 xmlRelaxNGTypeHave have
,
2754 xmlRelaxNGTypeCheck check
,
2755 xmlRelaxNGTypeCompare comp
,
2756 xmlRelaxNGFacetCheck facet
,
2757 xmlRelaxNGTypeFree freef
)
2759 xmlRelaxNGTypeLibraryPtr lib
;
2762 if ((xmlRelaxNGRegisteredTypes
== NULL
) || (namespace == NULL
) ||
2763 (check
== NULL
) || (comp
== NULL
))
2765 if (xmlHashLookup(xmlRelaxNGRegisteredTypes
, namespace) != NULL
) {
2766 xmlGenericError(xmlGenericErrorContext
,
2767 "Relax-NG types library '%s' already registered\n",
2772 (xmlRelaxNGTypeLibraryPtr
)
2773 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary
));
2775 xmlRngVErrMemory(NULL
, "adding types library\n");
2778 memset(lib
, 0, sizeof(xmlRelaxNGTypeLibrary
));
2779 lib
->namespace = xmlStrdup(namespace);
2786 ret
= xmlHashAddEntry(xmlRelaxNGRegisteredTypes
, namespace, lib
);
2788 xmlGenericError(xmlGenericErrorContext
,
2789 "Relax-NG types library failed to register '%s'\n",
2791 xmlRelaxNGFreeTypeLibrary(lib
, namespace);
2798 * xmlRelaxNGInitTypes:
2800 * Initilize the default type libraries.
2802 * Returns 0 in case of success and -1 in case of error.
2805 xmlRelaxNGInitTypes(void)
2807 if (xmlRelaxNGTypeInitialized
!= 0)
2809 xmlRelaxNGRegisteredTypes
= xmlHashCreate(10);
2810 if (xmlRelaxNGRegisteredTypes
== NULL
) {
2811 xmlGenericError(xmlGenericErrorContext
,
2812 "Failed to allocate sh table for Relax-NG types\n");
2815 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2816 "http://www.w3.org/2001/XMLSchema-datatypes",
2817 NULL
, xmlRelaxNGSchemaTypeHave
,
2818 xmlRelaxNGSchemaTypeCheck
,
2819 xmlRelaxNGSchemaTypeCompare
,
2820 xmlRelaxNGSchemaFacetCheck
,
2821 xmlRelaxNGSchemaFreeValue
);
2822 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs
, NULL
,
2823 xmlRelaxNGDefaultTypeHave
,
2824 xmlRelaxNGDefaultTypeCheck
,
2825 xmlRelaxNGDefaultTypeCompare
, NULL
,
2827 xmlRelaxNGTypeInitialized
= 1;
2832 * xmlRelaxNGCleanupTypes:
2834 * Cleanup the default Schemas type library associated to RelaxNG
2837 xmlRelaxNGCleanupTypes(void)
2839 xmlSchemaCleanupTypes();
2840 if (xmlRelaxNGTypeInitialized
== 0)
2842 xmlHashFree(xmlRelaxNGRegisteredTypes
, (xmlHashDeallocator
)
2843 xmlRelaxNGFreeTypeLibrary
);
2844 xmlRelaxNGTypeInitialized
= 0;
2847 /************************************************************************
2849 * Compiling element content into regexp *
2851 * Sometime the element content can be compiled into a pure regexp, *
2852 * This allows a faster execution and streamability at that level *
2854 ************************************************************************/
2856 /* from automata.c but not exported */
2857 void xmlAutomataSetFlags(xmlAutomataPtr am
, int flags
);
2860 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt
,
2861 xmlRelaxNGDefinePtr def
);
2864 * xmlRelaxNGIsCompileable:
2865 * @define: the definition to check
2867 * Check if a definition is nullable.
2869 * Returns 1 if yes, 0 if no and -1 in case of error
2872 xmlRelaxNGIsCompileable(xmlRelaxNGDefinePtr def
)
2879 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
2880 (def
->dflags
& IS_COMPILABLE
))
2882 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
2883 (def
->dflags
& IS_NOT_COMPILABLE
))
2885 switch (def
->type
) {
2886 case XML_RELAXNG_NOOP
:
2887 ret
= xmlRelaxNGIsCompileable(def
->content
);
2889 case XML_RELAXNG_TEXT
:
2890 case XML_RELAXNG_EMPTY
:
2893 case XML_RELAXNG_ELEMENT
:
2895 * Check if the element content is compileable
2897 if (((def
->dflags
& IS_NOT_COMPILABLE
) == 0) &&
2898 ((def
->dflags
& IS_COMPILABLE
) == 0)) {
2899 xmlRelaxNGDefinePtr list
;
2901 list
= def
->content
;
2902 while (list
!= NULL
) {
2903 ret
= xmlRelaxNGIsCompileable(list
);
2909 * Because the routine is recursive, we must guard against
2910 * discovering both COMPILABLE and NOT_COMPILABLE
2913 def
->dflags
&= ~IS_COMPILABLE
;
2914 def
->dflags
|= IS_NOT_COMPILABLE
;
2916 if ((ret
== 1) && !(def
->dflags
&= IS_NOT_COMPILABLE
))
2917 def
->dflags
|= IS_COMPILABLE
;
2918 #ifdef DEBUG_COMPILE
2920 xmlGenericError(xmlGenericErrorContext
,
2921 "element content for %s is compilable\n",
2923 } else if (ret
== 0) {
2924 xmlGenericError(xmlGenericErrorContext
,
2925 "element content for %s is not compilable\n",
2928 xmlGenericError(xmlGenericErrorContext
,
2929 "Problem in RelaxNGIsCompileable for element %s\n",
2935 * All elements return a compileable status unless they
2936 * are generic like anyName
2938 if ((def
->nameClass
!= NULL
) || (def
->name
== NULL
))
2943 case XML_RELAXNG_REF
:
2944 case XML_RELAXNG_EXTERNALREF
:
2945 case XML_RELAXNG_PARENTREF
:
2946 if (def
->depth
== -20) {
2949 xmlRelaxNGDefinePtr list
;
2952 list
= def
->content
;
2953 while (list
!= NULL
) {
2954 ret
= xmlRelaxNGIsCompileable(list
);
2961 case XML_RELAXNG_START
:
2962 case XML_RELAXNG_OPTIONAL
:
2963 case XML_RELAXNG_ZEROORMORE
:
2964 case XML_RELAXNG_ONEORMORE
:
2965 case XML_RELAXNG_CHOICE
:
2966 case XML_RELAXNG_GROUP
:
2967 case XML_RELAXNG_DEF
:{
2968 xmlRelaxNGDefinePtr list
;
2970 list
= def
->content
;
2971 while (list
!= NULL
) {
2972 ret
= xmlRelaxNGIsCompileable(list
);
2979 case XML_RELAXNG_EXCEPT
:
2980 case XML_RELAXNG_ATTRIBUTE
:
2981 case XML_RELAXNG_INTERLEAVE
:
2982 case XML_RELAXNG_DATATYPE
:
2983 case XML_RELAXNG_LIST
:
2984 case XML_RELAXNG_PARAM
:
2985 case XML_RELAXNG_VALUE
:
2986 case XML_RELAXNG_NOT_ALLOWED
:
2991 def
->dflags
|= IS_NOT_COMPILABLE
;
2993 def
->dflags
|= IS_COMPILABLE
;
2994 #ifdef DEBUG_COMPILE
2996 xmlGenericError(xmlGenericErrorContext
,
2997 "RelaxNGIsCompileable %s : true\n",
2998 xmlRelaxNGDefName(def
));
2999 } else if (ret
== 0) {
3000 xmlGenericError(xmlGenericErrorContext
,
3001 "RelaxNGIsCompileable %s : false\n",
3002 xmlRelaxNGDefName(def
));
3004 xmlGenericError(xmlGenericErrorContext
,
3005 "Problem in RelaxNGIsCompileable %s\n",
3006 xmlRelaxNGDefName(def
));
3013 * xmlRelaxNGCompile:
3014 * ctxt: the RelaxNG parser context
3015 * @define: the definition tree to compile
3017 * Compile the set of definitions, it works recursively, till the
3018 * element boundaries, where it tries to compile the content if possible
3020 * Returns 0 if success and -1 in case of error
3023 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt
, xmlRelaxNGDefinePtr def
)
3026 xmlRelaxNGDefinePtr list
;
3028 if ((ctxt
== NULL
) || (def
== NULL
))
3031 switch (def
->type
) {
3032 case XML_RELAXNG_START
:
3033 if ((xmlRelaxNGIsCompileable(def
) == 1) && (def
->depth
!= -25)) {
3034 xmlAutomataPtr oldam
= ctxt
->am
;
3035 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3039 list
= def
->content
;
3040 ctxt
->am
= xmlNewAutomata();
3041 if (ctxt
->am
== NULL
)
3045 * assume identical strings but not same pointer are different
3046 * atoms, needed for non-determinism detection
3047 * That way if 2 elements with the same name are in a choice
3048 * branch the automata is found non-deterministic and
3049 * we fallback to the normal validation which does the right
3050 * thing of exploring both choices.
3052 xmlAutomataSetFlags(ctxt
->am
, 1);
3054 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
3055 while (list
!= NULL
) {
3056 xmlRelaxNGCompile(ctxt
, list
);
3059 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
3060 if (xmlAutomataIsDeterminist(ctxt
->am
))
3061 def
->contModel
= xmlAutomataCompile(ctxt
->am
);
3063 xmlFreeAutomata(ctxt
->am
);
3064 ctxt
->state
= oldstate
;
3068 case XML_RELAXNG_ELEMENT
:
3069 if ((ctxt
->am
!= NULL
) && (def
->name
!= NULL
)) {
3070 ctxt
->state
= xmlAutomataNewTransition2(ctxt
->am
,
3075 if ((def
->dflags
& IS_COMPILABLE
) && (def
->depth
!= -25)) {
3076 xmlAutomataPtr oldam
= ctxt
->am
;
3077 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3081 list
= def
->content
;
3082 ctxt
->am
= xmlNewAutomata();
3083 if (ctxt
->am
== NULL
)
3085 xmlAutomataSetFlags(ctxt
->am
, 1);
3086 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
3087 while (list
!= NULL
) {
3088 xmlRelaxNGCompile(ctxt
, list
);
3091 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
3092 def
->contModel
= xmlAutomataCompile(ctxt
->am
);
3093 if (!xmlRegexpIsDeterminist(def
->contModel
)) {
3094 #ifdef DEBUG_COMPILE
3095 xmlGenericError(xmlGenericErrorContext
,
3096 "Content model not determinist %s\n",
3100 * we can only use the automata if it is determinist
3102 xmlRegFreeRegexp(def
->contModel
);
3103 def
->contModel
= NULL
;
3105 xmlFreeAutomata(ctxt
->am
);
3106 ctxt
->state
= oldstate
;
3109 xmlAutomataPtr oldam
= ctxt
->am
;
3112 * we can't build the content model for this element content
3113 * but it still might be possible to build it for some of its
3114 * children, recurse.
3116 ret
= xmlRelaxNGTryCompile(ctxt
, def
);
3120 case XML_RELAXNG_NOOP
:
3121 ret
= xmlRelaxNGCompile(ctxt
, def
->content
);
3123 case XML_RELAXNG_OPTIONAL
:{
3124 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3126 list
= def
->content
;
3127 while (list
!= NULL
) {
3128 xmlRelaxNGCompile(ctxt
, list
);
3131 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
3134 case XML_RELAXNG_ZEROORMORE
:{
3135 xmlAutomataStatePtr oldstate
;
3138 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3139 oldstate
= ctxt
->state
;
3140 list
= def
->content
;
3141 while (list
!= NULL
) {
3142 xmlRelaxNGCompile(ctxt
, list
);
3145 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldstate
);
3147 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3150 case XML_RELAXNG_ONEORMORE
:{
3151 xmlAutomataStatePtr oldstate
;
3153 list
= def
->content
;
3154 while (list
!= NULL
) {
3155 xmlRelaxNGCompile(ctxt
, list
);
3158 oldstate
= ctxt
->state
;
3159 list
= def
->content
;
3160 while (list
!= NULL
) {
3161 xmlRelaxNGCompile(ctxt
, list
);
3164 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldstate
);
3166 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3169 case XML_RELAXNG_CHOICE
:{
3170 xmlAutomataStatePtr target
= NULL
;
3171 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3173 list
= def
->content
;
3174 while (list
!= NULL
) {
3175 ctxt
->state
= oldstate
;
3176 ret
= xmlRelaxNGCompile(ctxt
, list
);
3180 target
= ctxt
->state
;
3182 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
,
3187 ctxt
->state
= target
;
3191 case XML_RELAXNG_REF
:
3192 case XML_RELAXNG_EXTERNALREF
:
3193 case XML_RELAXNG_PARENTREF
:
3194 case XML_RELAXNG_GROUP
:
3195 case XML_RELAXNG_DEF
:
3196 list
= def
->content
;
3197 while (list
!= NULL
) {
3198 ret
= xmlRelaxNGCompile(ctxt
, list
);
3204 case XML_RELAXNG_TEXT
:{
3205 xmlAutomataStatePtr oldstate
;
3208 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3209 oldstate
= ctxt
->state
;
3210 xmlRelaxNGCompile(ctxt
, def
->content
);
3211 xmlAutomataNewTransition(ctxt
->am
, ctxt
->state
,
3212 ctxt
->state
, BAD_CAST
"#text",
3215 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3218 case XML_RELAXNG_EMPTY
:
3220 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3222 case XML_RELAXNG_EXCEPT
:
3223 case XML_RELAXNG_ATTRIBUTE
:
3224 case XML_RELAXNG_INTERLEAVE
:
3225 case XML_RELAXNG_NOT_ALLOWED
:
3226 case XML_RELAXNG_DATATYPE
:
3227 case XML_RELAXNG_LIST
:
3228 case XML_RELAXNG_PARAM
:
3229 case XML_RELAXNG_VALUE
:
3230 /* This should not happen and generate an internal error */
3231 fprintf(stderr
, "RNG internal error trying to compile %s\n",
3232 xmlRelaxNGDefName(def
));
3239 * xmlRelaxNGTryCompile:
3240 * ctxt: the RelaxNG parser context
3241 * @define: the definition tree to compile
3243 * Try to compile the set of definitions, it works recursively,
3244 * possibly ignoring parts which cannot be compiled.
3246 * Returns 0 if success and -1 in case of error
3249 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt
, xmlRelaxNGDefinePtr def
)
3252 xmlRelaxNGDefinePtr list
;
3254 if ((ctxt
== NULL
) || (def
== NULL
))
3257 if ((def
->type
== XML_RELAXNG_START
) ||
3258 (def
->type
== XML_RELAXNG_ELEMENT
)) {
3259 ret
= xmlRelaxNGIsCompileable(def
);
3260 if ((def
->dflags
& IS_COMPILABLE
) && (def
->depth
!= -25)) {
3262 ret
= xmlRelaxNGCompile(ctxt
, def
);
3263 #ifdef DEBUG_PROGRESSIVE
3265 if (def
->type
== XML_RELAXNG_START
)
3266 xmlGenericError(xmlGenericErrorContext
,
3267 "compiled the start\n");
3269 xmlGenericError(xmlGenericErrorContext
,
3270 "compiled element %s\n", def
->name
);
3272 if (def
->type
== XML_RELAXNG_START
)
3273 xmlGenericError(xmlGenericErrorContext
,
3274 "failed to compile the start\n");
3276 xmlGenericError(xmlGenericErrorContext
,
3277 "failed to compile element %s\n",
3284 switch (def
->type
) {
3285 case XML_RELAXNG_NOOP
:
3286 ret
= xmlRelaxNGTryCompile(ctxt
, def
->content
);
3288 case XML_RELAXNG_TEXT
:
3289 case XML_RELAXNG_DATATYPE
:
3290 case XML_RELAXNG_LIST
:
3291 case XML_RELAXNG_PARAM
:
3292 case XML_RELAXNG_VALUE
:
3293 case XML_RELAXNG_EMPTY
:
3294 case XML_RELAXNG_ELEMENT
:
3297 case XML_RELAXNG_OPTIONAL
:
3298 case XML_RELAXNG_ZEROORMORE
:
3299 case XML_RELAXNG_ONEORMORE
:
3300 case XML_RELAXNG_CHOICE
:
3301 case XML_RELAXNG_GROUP
:
3302 case XML_RELAXNG_DEF
:
3303 case XML_RELAXNG_START
:
3304 case XML_RELAXNG_REF
:
3305 case XML_RELAXNG_EXTERNALREF
:
3306 case XML_RELAXNG_PARENTREF
:
3307 list
= def
->content
;
3308 while (list
!= NULL
) {
3309 ret
= xmlRelaxNGTryCompile(ctxt
, list
);
3315 case XML_RELAXNG_EXCEPT
:
3316 case XML_RELAXNG_ATTRIBUTE
:
3317 case XML_RELAXNG_INTERLEAVE
:
3318 case XML_RELAXNG_NOT_ALLOWED
:
3325 /************************************************************************
3327 * Parsing functions *
3329 ************************************************************************/
3331 static xmlRelaxNGDefinePtr
xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3332 ctxt
, xmlNodePtr node
);
3333 static xmlRelaxNGDefinePtr
xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3334 ctxt
, xmlNodePtr node
);
3335 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3336 ctxt
, xmlNodePtr nodes
,
3338 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3339 ctxt
, xmlNodePtr node
);
3340 static xmlRelaxNGPtr
xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
,
3342 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
3344 static xmlRelaxNGDefinePtr
xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3345 ctxt
, xmlNodePtr node
,
3348 static xmlRelaxNGGrammarPtr
xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3349 ctxt
, xmlNodePtr nodes
);
3350 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
3351 xmlRelaxNGDefinePtr define
,
3355 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3358 * xmlRelaxNGIsNullable:
3359 * @define: the definition to verify
3361 * Check if a definition is nullable.
3363 * Returns 1 if yes, 0 if no and -1 in case of error
3366 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define
)
3373 if (define
->dflags
& IS_NULLABLE
)
3375 if (define
->dflags
& IS_NOT_NULLABLE
)
3377 switch (define
->type
) {
3378 case XML_RELAXNG_EMPTY
:
3379 case XML_RELAXNG_TEXT
:
3382 case XML_RELAXNG_NOOP
:
3383 case XML_RELAXNG_DEF
:
3384 case XML_RELAXNG_REF
:
3385 case XML_RELAXNG_EXTERNALREF
:
3386 case XML_RELAXNG_PARENTREF
:
3387 case XML_RELAXNG_ONEORMORE
:
3388 ret
= xmlRelaxNGIsNullable(define
->content
);
3390 case XML_RELAXNG_EXCEPT
:
3391 case XML_RELAXNG_NOT_ALLOWED
:
3392 case XML_RELAXNG_ELEMENT
:
3393 case XML_RELAXNG_DATATYPE
:
3394 case XML_RELAXNG_PARAM
:
3395 case XML_RELAXNG_VALUE
:
3396 case XML_RELAXNG_LIST
:
3397 case XML_RELAXNG_ATTRIBUTE
:
3400 case XML_RELAXNG_CHOICE
:{
3401 xmlRelaxNGDefinePtr list
= define
->content
;
3403 while (list
!= NULL
) {
3404 ret
= xmlRelaxNGIsNullable(list
);
3412 case XML_RELAXNG_START
:
3413 case XML_RELAXNG_INTERLEAVE
:
3414 case XML_RELAXNG_GROUP
:{
3415 xmlRelaxNGDefinePtr list
= define
->content
;
3417 while (list
!= NULL
) {
3418 ret
= xmlRelaxNGIsNullable(list
);
3430 define
->dflags
|= IS_NOT_NULLABLE
;
3432 define
->dflags
|= IS_NULLABLE
;
3437 * xmlRelaxNGIsBlank:
3440 * Check if a string is ignorable c.f. 4.2. Whitespace
3442 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3445 xmlRelaxNGIsBlank(xmlChar
* str
)
3450 if (!(IS_BLANK_CH(*str
)))
3458 * xmlRelaxNGGetDataTypeLibrary:
3459 * @ctxt: a Relax-NG parser context
3460 * @node: the current data or value element
3462 * Applies algorithm from 4.3. datatypeLibrary attribute
3464 * Returns the datatypeLibary value or NULL if not found
3467 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
3470 xmlChar
*ret
, *escape
;
3475 if ((IS_RELAXNG(node
, "data")) || (IS_RELAXNG(node
, "value"))) {
3476 ret
= xmlGetProp(node
, BAD_CAST
"datatypeLibrary");
3482 escape
= xmlURIEscapeStr(ret
, BAD_CAST
":/#?");
3483 if (escape
== NULL
) {
3490 node
= node
->parent
;
3491 while ((node
!= NULL
) && (node
->type
== XML_ELEMENT_NODE
)) {
3492 ret
= xmlGetProp(node
, BAD_CAST
"datatypeLibrary");
3498 escape
= xmlURIEscapeStr(ret
, BAD_CAST
":/#?");
3499 if (escape
== NULL
) {
3505 node
= node
->parent
;
3511 * xmlRelaxNGParseValue:
3512 * @ctxt: a Relax-NG parser context
3513 * @node: the data node.
3515 * parse the content of a RelaxNG value node.
3517 * Returns the definition pointer or NULL in case of error
3519 static xmlRelaxNGDefinePtr
3520 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
3522 xmlRelaxNGDefinePtr def
= NULL
;
3523 xmlRelaxNGTypeLibraryPtr lib
= NULL
;
3528 def
= xmlRelaxNGNewDefine(ctxt
, node
);
3531 def
->type
= XML_RELAXNG_VALUE
;
3533 type
= xmlGetProp(node
, BAD_CAST
"type");
3535 xmlRelaxNGNormExtSpace(type
);
3536 if (xmlValidateNCName(type
, 0)) {
3537 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_VALUE
,
3538 "value type '%s' is not an NCName\n", type
, NULL
);
3540 library
= xmlRelaxNGGetDataTypeLibrary(ctxt
, node
);
3541 if (library
== NULL
)
3543 xmlStrdup(BAD_CAST
"http://relaxng.org/ns/structure/1.0");
3548 lib
= (xmlRelaxNGTypeLibraryPtr
)
3549 xmlHashLookup(xmlRelaxNGRegisteredTypes
, library
);
3551 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_TYPE_LIB
,
3552 "Use of unregistered type library '%s'\n", library
,
3557 if (lib
->have
== NULL
) {
3558 xmlRngPErr(ctxt
, node
, XML_RNGP_ERROR_TYPE_LIB
,
3559 "Internal error with type library '%s': no 'have'\n",
3562 success
= lib
->have(lib
->data
, def
->name
);
3564 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_NOT_FOUND
,
3565 "Error type '%s' is not exported by type library '%s'\n",
3566 def
->name
, library
);
3571 if (node
->children
== NULL
) {
3572 def
->value
= xmlStrdup(BAD_CAST
"");
3573 } else if (((node
->children
->type
!= XML_TEXT_NODE
) &&
3574 (node
->children
->type
!= XML_CDATA_SECTION_NODE
)) ||
3575 (node
->children
->next
!= NULL
)) {
3576 xmlRngPErr(ctxt
, node
, XML_RNGP_TEXT_EXPECTED
,
3577 "Expecting a single text value for <value>content\n",
3579 } else if (def
!= NULL
) {
3580 def
->value
= xmlNodeGetContent(node
);
3581 if (def
->value
== NULL
) {
3582 xmlRngPErr(ctxt
, node
, XML_RNGP_VALUE_NO_CONTENT
,
3583 "Element <value> has no content\n", NULL
, NULL
);
3584 } else if ((lib
!= NULL
) && (lib
->check
!= NULL
) && (success
== 1)) {
3588 lib
->check(lib
->data
, def
->name
, def
->value
, &val
, node
);
3590 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_VALUE
,
3591 "Value '%s' is not acceptable for type '%s'\n",
3592 def
->value
, def
->name
);
3603 * xmlRelaxNGParseData:
3604 * @ctxt: a Relax-NG parser context
3605 * @node: the data node.
3607 * parse the content of a RelaxNG data node.
3609 * Returns the definition pointer or NULL in case of error
3611 static xmlRelaxNGDefinePtr
3612 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
3614 xmlRelaxNGDefinePtr def
= NULL
, except
;
3615 xmlRelaxNGDefinePtr param
, lastparam
= NULL
;
3616 xmlRelaxNGTypeLibraryPtr lib
;
3622 type
= xmlGetProp(node
, BAD_CAST
"type");
3624 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_MISSING
, "data has no type\n", NULL
,
3628 xmlRelaxNGNormExtSpace(type
);
3629 if (xmlValidateNCName(type
, 0)) {
3630 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_VALUE
,
3631 "data type '%s' is not an NCName\n", type
, NULL
);
3633 library
= xmlRelaxNGGetDataTypeLibrary(ctxt
, node
);
3634 if (library
== NULL
)
3636 xmlStrdup(BAD_CAST
"http://relaxng.org/ns/structure/1.0");
3638 def
= xmlRelaxNGNewDefine(ctxt
, node
);
3643 def
->type
= XML_RELAXNG_DATATYPE
;
3647 lib
= (xmlRelaxNGTypeLibraryPtr
)
3648 xmlHashLookup(xmlRelaxNGRegisteredTypes
, library
);
3650 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_TYPE_LIB
,
3651 "Use of unregistered type library '%s'\n", library
,
3656 if (lib
->have
== NULL
) {
3657 xmlRngPErr(ctxt
, node
, XML_RNGP_ERROR_TYPE_LIB
,
3658 "Internal error with type library '%s': no 'have'\n",
3661 tmp
= lib
->have(lib
->data
, def
->name
);
3663 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_NOT_FOUND
,
3664 "Error type '%s' is not exported by type library '%s'\n",
3665 def
->name
, library
);
3670 "http://www.w3.org/2001/XMLSchema-datatypes"))
3671 && ((xmlStrEqual(def
->name
, BAD_CAST
"IDREF"))
3672 || (xmlStrEqual(def
->name
, BAD_CAST
"IDREFS")))) {
3677 content
= node
->children
;
3680 * Handle optional params
3682 while (content
!= NULL
) {
3683 if (!xmlStrEqual(content
->name
, BAD_CAST
"param"))
3685 if (xmlStrEqual(library
,
3686 BAD_CAST
"http://relaxng.org/ns/structure/1.0")) {
3687 xmlRngPErr(ctxt
, node
, XML_RNGP_PARAM_FORBIDDEN
,
3688 "Type library '%s' does not allow type parameters\n",
3690 content
= content
->next
;
3691 while ((content
!= NULL
) &&
3692 (xmlStrEqual(content
->name
, BAD_CAST
"param")))
3693 content
= content
->next
;
3695 param
= xmlRelaxNGNewDefine(ctxt
, node
);
3696 if (param
!= NULL
) {
3697 param
->type
= XML_RELAXNG_PARAM
;
3698 param
->name
= xmlGetProp(content
, BAD_CAST
"name");
3699 if (param
->name
== NULL
) {
3700 xmlRngPErr(ctxt
, node
, XML_RNGP_PARAM_NAME_MISSING
,
3701 "param has no name\n", NULL
, NULL
);
3703 param
->value
= xmlNodeGetContent(content
);
3704 if (lastparam
== NULL
) {
3705 def
->attrs
= lastparam
= param
;
3707 lastparam
->next
= param
;
3713 content
= content
->next
;
3717 * Handle optional except
3719 if ((content
!= NULL
)
3720 && (xmlStrEqual(content
->name
, BAD_CAST
"except"))) {
3722 xmlRelaxNGDefinePtr tmp2
, last
= NULL
;
3724 except
= xmlRelaxNGNewDefine(ctxt
, node
);
3725 if (except
== NULL
) {
3728 except
->type
= XML_RELAXNG_EXCEPT
;
3729 child
= content
->children
;
3730 def
->content
= except
;
3731 if (child
== NULL
) {
3732 xmlRngPErr(ctxt
, content
, XML_RNGP_EXCEPT_NO_CONTENT
,
3733 "except has no content\n", NULL
, NULL
);
3735 while (child
!= NULL
) {
3736 tmp2
= xmlRelaxNGParsePattern(ctxt
, child
);
3739 except
->content
= last
= tmp2
;
3745 child
= child
->next
;
3747 content
= content
->next
;
3750 * Check there is no unhandled data
3752 if (content
!= NULL
) {
3753 xmlRngPErr(ctxt
, content
, XML_RNGP_DATA_CONTENT
,
3754 "Element data has unexpected content %s\n",
3755 content
->name
, NULL
);
3761 static const xmlChar
*invalidName
= BAD_CAST
"\1";
3764 * xmlRelaxNGCompareNameClasses:
3765 * @defs1: the first element/attribute defs
3766 * @defs2: the second element/attribute defs
3767 * @name: the restriction on the name
3768 * @ns: the restriction on the namespace
3770 * Compare the 2 lists of element definitions. The comparison is
3771 * that if both lists do not accept the same QNames, it returns 1
3772 * If the 2 lists can accept the same QName the comparison returns 0
3774 * Returns 1 disttinct, 0 if equal
3777 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1
,
3778 xmlRelaxNGDefinePtr def2
)
3783 xmlRelaxNGValidCtxt ctxt
;
3785 memset(&ctxt
, 0, sizeof(xmlRelaxNGValidCtxt
));
3787 ctxt
.flags
= FLAGS_IGNORABLE
| FLAGS_NOERROR
;
3789 if ((def1
->type
== XML_RELAXNG_ELEMENT
) ||
3790 (def1
->type
== XML_RELAXNG_ATTRIBUTE
)) {
3791 if (def2
->type
== XML_RELAXNG_TEXT
)
3793 if (def1
->name
!= NULL
) {
3794 node
.name
= def1
->name
;
3796 node
.name
= invalidName
;
3798 if (def1
->ns
!= NULL
) {
3799 if (def1
->ns
[0] == 0) {
3808 if (xmlRelaxNGElementMatch(&ctxt
, def2
, &node
)) {
3809 if (def1
->nameClass
!= NULL
) {
3810 ret
= xmlRelaxNGCompareNameClasses(def1
->nameClass
, def2
);
3817 } else if (def1
->type
== XML_RELAXNG_TEXT
) {
3818 if (def2
->type
== XML_RELAXNG_TEXT
)
3821 } else if (def1
->type
== XML_RELAXNG_EXCEPT
) {
3828 if ((def2
->type
== XML_RELAXNG_ELEMENT
) ||
3829 (def2
->type
== XML_RELAXNG_ATTRIBUTE
)) {
3830 if (def2
->name
!= NULL
) {
3831 node
.name
= def2
->name
;
3833 node
.name
= invalidName
;
3836 if (def2
->ns
!= NULL
) {
3837 if (def2
->ns
[0] == 0) {
3843 ns
.href
= invalidName
;
3845 if (xmlRelaxNGElementMatch(&ctxt
, def1
, &node
)) {
3846 if (def2
->nameClass
!= NULL
) {
3847 ret
= xmlRelaxNGCompareNameClasses(def2
->nameClass
, def1
);
3862 * xmlRelaxNGCompareElemDefLists:
3863 * @ctxt: a Relax-NG parser context
3864 * @defs1: the first list of element/attribute defs
3865 * @defs2: the second list of element/attribute defs
3867 * Compare the 2 lists of element or attribute definitions. The comparison
3868 * is that if both lists do not accept the same QNames, it returns 1
3869 * If the 2 lists can accept the same QName the comparison returns 0
3871 * Returns 1 disttinct, 0 if equal
3874 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3875 ATTRIBUTE_UNUSED
, xmlRelaxNGDefinePtr
* def1
,
3876 xmlRelaxNGDefinePtr
* def2
)
3878 xmlRelaxNGDefinePtr
*basedef2
= def2
;
3880 if ((def1
== NULL
) || (def2
== NULL
))
3882 if ((*def1
== NULL
) || (*def2
== NULL
))
3884 while (*def1
!= NULL
) {
3885 while ((*def2
) != NULL
) {
3886 if (xmlRelaxNGCompareNameClasses(*def1
, *def2
) == 0)
3897 * xmlRelaxNGGenerateAttributes:
3898 * @ctxt: a Relax-NG parser context
3899 * @def: the definition definition
3901 * Check if the definition can only generate attributes
3903 * Returns 1 if yes, 0 if no and -1 in case of error.
3906 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt
,
3907 xmlRelaxNGDefinePtr def
)
3909 xmlRelaxNGDefinePtr parent
, cur
, tmp
;
3912 * Don't run that check in case of error. Infinite recursion
3915 if (ctxt
->nbErrors
!= 0)
3920 while (cur
!= NULL
) {
3921 if ((cur
->type
== XML_RELAXNG_ELEMENT
) ||
3922 (cur
->type
== XML_RELAXNG_TEXT
) ||
3923 (cur
->type
== XML_RELAXNG_DATATYPE
) ||
3924 (cur
->type
== XML_RELAXNG_PARAM
) ||
3925 (cur
->type
== XML_RELAXNG_LIST
) ||
3926 (cur
->type
== XML_RELAXNG_VALUE
) ||
3927 (cur
->type
== XML_RELAXNG_EMPTY
))
3929 if ((cur
->type
== XML_RELAXNG_CHOICE
) ||
3930 (cur
->type
== XML_RELAXNG_INTERLEAVE
) ||
3931 (cur
->type
== XML_RELAXNG_GROUP
) ||
3932 (cur
->type
== XML_RELAXNG_ONEORMORE
) ||
3933 (cur
->type
== XML_RELAXNG_ZEROORMORE
) ||
3934 (cur
->type
== XML_RELAXNG_OPTIONAL
) ||
3935 (cur
->type
== XML_RELAXNG_PARENTREF
) ||
3936 (cur
->type
== XML_RELAXNG_EXTERNALREF
) ||
3937 (cur
->type
== XML_RELAXNG_REF
) ||
3938 (cur
->type
== XML_RELAXNG_DEF
)) {
3939 if (cur
->content
!= NULL
) {
3943 while (tmp
!= NULL
) {
3944 tmp
->parent
= parent
;
3952 if (cur
->next
!= NULL
) {
3962 if (cur
->next
!= NULL
) {
3966 } while (cur
!= NULL
);
3972 * xmlRelaxNGGetElements:
3973 * @ctxt: a Relax-NG parser context
3974 * @def: the definition definition
3975 * @eora: gather elements (0) or attributes (1)
3977 * Compute the list of top elements a definition can generate
3979 * Returns a list of elements or NULL if none was found.
3981 static xmlRelaxNGDefinePtr
*
3982 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt
,
3983 xmlRelaxNGDefinePtr def
, int eora
)
3985 xmlRelaxNGDefinePtr
*ret
= NULL
, parent
, cur
, tmp
;
3990 * Don't run that check in case of error. Infinite recursion
3993 if (ctxt
->nbErrors
!= 0)
3998 while (cur
!= NULL
) {
3999 if (((eora
== 0) && ((cur
->type
== XML_RELAXNG_ELEMENT
) ||
4000 (cur
->type
== XML_RELAXNG_TEXT
))) ||
4001 ((eora
== 1) && (cur
->type
== XML_RELAXNG_ATTRIBUTE
))) {
4004 ret
= (xmlRelaxNGDefinePtr
*)
4005 xmlMalloc((max
+ 1) * sizeof(xmlRelaxNGDefinePtr
));
4007 xmlRngPErrMemory(ctxt
, "getting element list\n");
4010 } else if (max
<= len
) {
4011 xmlRelaxNGDefinePtr
*temp
;
4014 temp
= xmlRealloc(ret
,
4015 (max
+ 1) * sizeof(xmlRelaxNGDefinePtr
));
4017 xmlRngPErrMemory(ctxt
, "getting element list\n");
4025 } else if ((cur
->type
== XML_RELAXNG_CHOICE
) ||
4026 (cur
->type
== XML_RELAXNG_INTERLEAVE
) ||
4027 (cur
->type
== XML_RELAXNG_GROUP
) ||
4028 (cur
->type
== XML_RELAXNG_ONEORMORE
) ||
4029 (cur
->type
== XML_RELAXNG_ZEROORMORE
) ||
4030 (cur
->type
== XML_RELAXNG_OPTIONAL
) ||
4031 (cur
->type
== XML_RELAXNG_PARENTREF
) ||
4032 (cur
->type
== XML_RELAXNG_REF
) ||
4033 (cur
->type
== XML_RELAXNG_DEF
) ||
4034 (cur
->type
== XML_RELAXNG_EXTERNALREF
)) {
4036 * Don't go within elements or attributes or string values.
4037 * Just gather the element top list
4039 if (cur
->content
!= NULL
) {
4043 while (tmp
!= NULL
) {
4044 tmp
->parent
= parent
;
4052 if (cur
->next
!= NULL
) {
4062 if (cur
->next
!= NULL
) {
4066 } while (cur
!= NULL
);
4072 * xmlRelaxNGCheckChoiceDeterminism:
4073 * @ctxt: a Relax-NG parser context
4074 * @def: the choice definition
4076 * Also used to find indeterministic pattern in choice
4079 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt
,
4080 xmlRelaxNGDefinePtr def
)
4082 xmlRelaxNGDefinePtr
**list
;
4083 xmlRelaxNGDefinePtr cur
;
4084 int nbchild
= 0, i
, j
, ret
;
4085 int is_nullable
= 0;
4086 int is_indeterminist
= 0;
4087 xmlHashTablePtr triage
= NULL
;
4090 if ((def
== NULL
) || (def
->type
!= XML_RELAXNG_CHOICE
))
4093 if (def
->dflags
& IS_PROCESSED
)
4097 * Don't run that check in case of error. Infinite recursion
4100 if (ctxt
->nbErrors
!= 0)
4103 is_nullable
= xmlRelaxNGIsNullable(def
);
4106 while (cur
!= NULL
) {
4111 list
= (xmlRelaxNGDefinePtr
**) xmlMalloc(nbchild
*
4112 sizeof(xmlRelaxNGDefinePtr
4115 xmlRngPErrMemory(ctxt
, "building choice\n");
4120 * a bit strong but safe
4122 if (is_nullable
== 0) {
4123 triage
= xmlHashCreate(10);
4128 while (cur
!= NULL
) {
4129 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 0);
4130 if ((list
[i
] == NULL
) || (list
[i
][0] == NULL
)) {
4132 } else if (is_triable
== 1) {
4133 xmlRelaxNGDefinePtr
*tmp
;
4137 while ((*tmp
!= NULL
) && (is_triable
== 1)) {
4138 if ((*tmp
)->type
== XML_RELAXNG_TEXT
) {
4139 res
= xmlHashAddEntry2(triage
,
4140 BAD_CAST
"#text", NULL
,
4144 } else if (((*tmp
)->type
== XML_RELAXNG_ELEMENT
) &&
4145 ((*tmp
)->name
!= NULL
)) {
4146 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4147 res
= xmlHashAddEntry2(triage
,
4151 res
= xmlHashAddEntry2(triage
,
4152 (*tmp
)->name
, (*tmp
)->ns
,
4156 } else if ((*tmp
)->type
== XML_RELAXNG_ELEMENT
) {
4157 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4158 res
= xmlHashAddEntry2(triage
,
4159 BAD_CAST
"#any", NULL
,
4162 res
= xmlHashAddEntry2(triage
,
4163 BAD_CAST
"#any", (*tmp
)->ns
,
4177 for (i
= 0; i
< nbchild
; i
++) {
4178 if (list
[i
] == NULL
)
4180 for (j
= 0; j
< i
; j
++) {
4181 if (list
[j
] == NULL
)
4183 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, list
[i
], list
[j
]);
4185 is_indeterminist
= 1;
4189 for (i
= 0; i
< nbchild
; i
++) {
4190 if (list
[i
] != NULL
)
4195 if (is_indeterminist
) {
4196 def
->dflags
|= IS_INDETERMINIST
;
4198 if (is_triable
== 1) {
4199 def
->dflags
|= IS_TRIABLE
;
4201 } else if (triage
!= NULL
) {
4202 xmlHashFree(triage
, NULL
);
4204 def
->dflags
|= IS_PROCESSED
;
4208 * xmlRelaxNGCheckGroupAttrs:
4209 * @ctxt: a Relax-NG parser context
4210 * @def: the group definition
4212 * Detects violations of rule 7.3
4215 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt
,
4216 xmlRelaxNGDefinePtr def
)
4218 xmlRelaxNGDefinePtr
**list
;
4219 xmlRelaxNGDefinePtr cur
;
4220 int nbchild
= 0, i
, j
, ret
;
4222 if ((def
== NULL
) ||
4223 ((def
->type
!= XML_RELAXNG_GROUP
) &&
4224 (def
->type
!= XML_RELAXNG_ELEMENT
)))
4227 if (def
->dflags
& IS_PROCESSED
)
4231 * Don't run that check in case of error. Infinite recursion
4234 if (ctxt
->nbErrors
!= 0)
4238 while (cur
!= NULL
) {
4243 while (cur
!= NULL
) {
4248 list
= (xmlRelaxNGDefinePtr
**) xmlMalloc(nbchild
*
4249 sizeof(xmlRelaxNGDefinePtr
4252 xmlRngPErrMemory(ctxt
, "building group\n");
4257 while (cur
!= NULL
) {
4258 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 1);
4263 while (cur
!= NULL
) {
4264 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 1);
4269 for (i
= 0; i
< nbchild
; i
++) {
4270 if (list
[i
] == NULL
)
4272 for (j
= 0; j
< i
; j
++) {
4273 if (list
[j
] == NULL
)
4275 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, list
[i
], list
[j
]);
4277 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_GROUP_ATTR_CONFLICT
,
4278 "Attributes conflicts in group\n", NULL
, NULL
);
4282 for (i
= 0; i
< nbchild
; i
++) {
4283 if (list
[i
] != NULL
)
4288 def
->dflags
|= IS_PROCESSED
;
4292 * xmlRelaxNGComputeInterleaves:
4293 * @def: the interleave definition
4294 * @ctxt: a Relax-NG parser context
4295 * @name: the definition name
4297 * A lot of work for preprocessing interleave definitions
4298 * is potentially needed to get a decent execution speed at runtime
4299 * - trying to get a total order on the element nodes generated
4300 * by the interleaves, order the list of interleave definitions
4301 * following that order.
4302 * - if <text/> is used to handle mixed content, it is better to
4303 * flag this in the define and simplify the runtime checking
4307 xmlRelaxNGComputeInterleaves(xmlRelaxNGDefinePtr def
,
4308 xmlRelaxNGParserCtxtPtr ctxt
,
4309 xmlChar
* name ATTRIBUTE_UNUSED
)
4311 xmlRelaxNGDefinePtr cur
, *tmp
;
4313 xmlRelaxNGPartitionPtr partitions
= NULL
;
4314 xmlRelaxNGInterleaveGroupPtr
*groups
= NULL
;
4315 xmlRelaxNGInterleaveGroupPtr group
;
4320 int is_determinist
= 1;
4323 * Don't run that check in case of error. Infinite recursion
4326 if (ctxt
->nbErrors
!= 0)
4329 #ifdef DEBUG_INTERLEAVE
4330 xmlGenericError(xmlGenericErrorContext
,
4331 "xmlRelaxNGComputeInterleaves(%s)\n", name
);
4334 while (cur
!= NULL
) {
4339 #ifdef DEBUG_INTERLEAVE
4340 xmlGenericError(xmlGenericErrorContext
, " %d child\n", nbchild
);
4342 groups
= (xmlRelaxNGInterleaveGroupPtr
*)
4343 xmlMalloc(nbchild
* sizeof(xmlRelaxNGInterleaveGroupPtr
));
4347 while (cur
!= NULL
) {
4348 groups
[nbgroups
] = (xmlRelaxNGInterleaveGroupPtr
)
4349 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup
));
4350 if (groups
[nbgroups
] == NULL
)
4352 if (cur
->type
== XML_RELAXNG_TEXT
)
4354 groups
[nbgroups
]->rule
= cur
;
4355 groups
[nbgroups
]->defs
= xmlRelaxNGGetElements(ctxt
, cur
, 0);
4356 groups
[nbgroups
]->attrs
= xmlRelaxNGGetElements(ctxt
, cur
, 1);
4360 #ifdef DEBUG_INTERLEAVE
4361 xmlGenericError(xmlGenericErrorContext
, " %d groups\n", nbgroups
);
4365 * Let's check that all rules makes a partitions according to 7.4
4367 partitions
= (xmlRelaxNGPartitionPtr
)
4368 xmlMalloc(sizeof(xmlRelaxNGPartition
));
4369 if (partitions
== NULL
)
4371 memset(partitions
, 0, sizeof(xmlRelaxNGPartition
));
4372 partitions
->nbgroups
= nbgroups
;
4373 partitions
->triage
= xmlHashCreate(nbgroups
);
4374 for (i
= 0; i
< nbgroups
; i
++) {
4376 for (j
= i
+ 1; j
< nbgroups
; j
++) {
4377 if (groups
[j
] == NULL
)
4380 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, group
->defs
,
4383 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_ELEM_TEXT_CONFLICT
,
4384 "Element or text conflicts in interleave\n",
4387 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, group
->attrs
,
4390 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_ATTR_CONFLICT
,
4391 "Attributes conflicts in interleave\n", NULL
,
4396 if ((tmp
!= NULL
) && (*tmp
!= NULL
)) {
4397 while (*tmp
!= NULL
) {
4398 if ((*tmp
)->type
== XML_RELAXNG_TEXT
) {
4399 res
= xmlHashAddEntry2(partitions
->triage
,
4400 BAD_CAST
"#text", NULL
,
4401 (void *) (long) (i
+ 1));
4403 is_determinist
= -1;
4404 } else if (((*tmp
)->type
== XML_RELAXNG_ELEMENT
) &&
4405 ((*tmp
)->name
!= NULL
)) {
4406 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4407 res
= xmlHashAddEntry2(partitions
->triage
,
4409 (void *) (long) (i
+ 1));
4411 res
= xmlHashAddEntry2(partitions
->triage
,
4412 (*tmp
)->name
, (*tmp
)->ns
,
4413 (void *) (long) (i
+ 1));
4415 is_determinist
= -1;
4416 } else if ((*tmp
)->type
== XML_RELAXNG_ELEMENT
) {
4417 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4418 res
= xmlHashAddEntry2(partitions
->triage
,
4419 BAD_CAST
"#any", NULL
,
4420 (void *) (long) (i
+ 1));
4422 res
= xmlHashAddEntry2(partitions
->triage
,
4423 BAD_CAST
"#any", (*tmp
)->ns
,
4424 (void *) (long) (i
+ 1));
4425 if ((*tmp
)->nameClass
!= NULL
)
4428 is_determinist
= -1;
4430 is_determinist
= -1;
4438 partitions
->groups
= groups
;
4441 * and save the partition list back in the def
4443 def
->data
= partitions
;
4445 def
->dflags
|= IS_MIXED
;
4446 if (is_determinist
== 1)
4447 partitions
->flags
= IS_DETERMINIST
;
4448 if (is_determinist
== 2)
4449 partitions
->flags
= IS_DETERMINIST
| IS_NEEDCHECK
;
4453 xmlRngPErrMemory(ctxt
, "in interleave computation\n");
4454 if (groups
!= NULL
) {
4455 for (i
= 0; i
< nbgroups
; i
++)
4456 if (groups
[i
] != NULL
) {
4457 if (groups
[i
]->defs
!= NULL
)
4458 xmlFree(groups
[i
]->defs
);
4463 xmlRelaxNGFreePartition(partitions
);
4467 * xmlRelaxNGParseInterleave:
4468 * @ctxt: a Relax-NG parser context
4469 * @node: the data node.
4471 * parse the content of a RelaxNG interleave node.
4473 * Returns the definition pointer or NULL in case of error
4475 static xmlRelaxNGDefinePtr
4476 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4478 xmlRelaxNGDefinePtr def
= NULL
;
4479 xmlRelaxNGDefinePtr last
= NULL
, cur
;
4482 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4486 def
->type
= XML_RELAXNG_INTERLEAVE
;
4488 if (ctxt
->interleaves
== NULL
)
4489 ctxt
->interleaves
= xmlHashCreate(10);
4490 if (ctxt
->interleaves
== NULL
) {
4491 xmlRngPErrMemory(ctxt
, "create interleaves\n");
4495 snprintf(name
, 32, "interleave%d", ctxt
->nbInterleaves
++);
4496 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST name
, def
) < 0) {
4497 xmlRngPErr(ctxt
, node
, XML_RNGP_INTERLEAVE_ADD
,
4498 "Failed to add %s to hash table\n",
4499 (const xmlChar
*) name
, NULL
);
4502 child
= node
->children
;
4503 if (child
== NULL
) {
4504 xmlRngPErr(ctxt
, node
, XML_RNGP_INTERLEAVE_NO_CONTENT
,
4505 "Element interleave is empty\n", NULL
, NULL
);
4507 while (child
!= NULL
) {
4508 if (IS_RELAXNG(child
, "element")) {
4509 cur
= xmlRelaxNGParseElement(ctxt
, child
);
4511 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
4516 def
->content
= last
= cur
;
4522 child
= child
->next
;
4529 * xmlRelaxNGParseInclude:
4530 * @ctxt: a Relax-NG parser context
4531 * @node: the include node
4533 * Integrate the content of an include node in the current grammar
4535 * Returns 0 in case of success or -1 in case of error
4538 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4540 xmlRelaxNGIncludePtr incl
;
4546 xmlRngPErr(ctxt
, node
, XML_RNGP_INCLUDE_EMPTY
,
4547 "Include node has no data\n", NULL
, NULL
);
4550 root
= xmlDocGetRootElement(incl
->doc
);
4552 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY
, "Include document is empty\n",
4556 if (!xmlStrEqual(root
->name
, BAD_CAST
"grammar")) {
4557 xmlRngPErr(ctxt
, node
, XML_RNGP_GRAMMAR_MISSING
,
4558 "Include document root is not a grammar\n", NULL
, NULL
);
4563 * Merge the definition from both the include and the internal list
4565 if (root
->children
!= NULL
) {
4566 tmp
= xmlRelaxNGParseGrammarContent(ctxt
, root
->children
);
4570 if (node
->children
!= NULL
) {
4571 tmp
= xmlRelaxNGParseGrammarContent(ctxt
, node
->children
);
4579 * xmlRelaxNGParseDefine:
4580 * @ctxt: a Relax-NG parser context
4581 * @node: the define node
4583 * parse the content of a RelaxNG define element node.
4585 * Returns 0 in case of success or -1 in case of error
4588 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4592 xmlRelaxNGDefinePtr def
;
4593 const xmlChar
*olddefine
;
4595 name
= xmlGetProp(node
, BAD_CAST
"name");
4597 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_NAME_MISSING
,
4598 "define has no name\n", NULL
, NULL
);
4600 xmlRelaxNGNormExtSpace(name
);
4601 if (xmlValidateNCName(name
, 0)) {
4602 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_DEFINE_NAME
,
4603 "define name '%s' is not an NCName\n", name
, NULL
);
4605 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4610 def
->type
= XML_RELAXNG_DEF
;
4612 if (node
->children
== NULL
) {
4613 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_EMPTY
,
4614 "define has no children\n", NULL
, NULL
);
4616 olddefine
= ctxt
->define
;
4617 ctxt
->define
= name
;
4619 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4620 ctxt
->define
= olddefine
;
4622 if (ctxt
->grammar
->defs
== NULL
)
4623 ctxt
->grammar
->defs
= xmlHashCreate(10);
4624 if (ctxt
->grammar
->defs
== NULL
) {
4625 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_CREATE_FAILED
,
4626 "Could not create definition hash\n", NULL
, NULL
);
4629 tmp
= xmlHashAddEntry(ctxt
->grammar
->defs
, name
, def
);
4631 xmlRelaxNGDefinePtr prev
;
4633 prev
= xmlHashLookup(ctxt
->grammar
->defs
, name
);
4635 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_CREATE_FAILED
,
4636 "Internal error on define aggregation of %s\n",
4640 while (prev
->nextHash
!= NULL
)
4641 prev
= prev
->nextHash
;
4642 prev
->nextHash
= def
;
4651 * xmlRelaxNGParseImportRef:
4652 * @payload: the parser context
4653 * @data: the current grammar
4654 * @name: the reference name
4656 * Import import one references into the current grammar
4659 xmlRelaxNGParseImportRef(void *payload
, void *data
, xmlChar
*name
) {
4660 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
4661 xmlRelaxNGDefinePtr def
= (xmlRelaxNGDefinePtr
) payload
;
4664 def
->dflags
|= IS_EXTERNAL_REF
;
4666 tmp
= xmlHashAddEntry(ctxt
->grammar
->refs
, name
, def
);
4668 xmlRelaxNGDefinePtr prev
;
4670 prev
= (xmlRelaxNGDefinePtr
)
4671 xmlHashLookup(ctxt
->grammar
->refs
, def
->name
);
4673 if (def
->name
!= NULL
) {
4674 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4675 "Error refs definitions '%s'\n",
4678 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4679 "Error refs definitions\n",
4683 def
->nextHash
= prev
->nextHash
;
4684 prev
->nextHash
= def
;
4690 * xmlRelaxNGParseImportRefs:
4691 * @ctxt: the parser context
4692 * @grammar: the sub grammar
4694 * Import references from the subgrammar into the current grammar
4696 * Returns 0 in case of success, -1 in case of failure
4699 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt
,
4700 xmlRelaxNGGrammarPtr grammar
) {
4701 if ((ctxt
== NULL
) || (grammar
== NULL
) || (ctxt
->grammar
== NULL
))
4703 if (grammar
->refs
== NULL
)
4705 if (ctxt
->grammar
->refs
== NULL
)
4706 ctxt
->grammar
->refs
= xmlHashCreate(10);
4707 if (ctxt
->grammar
->refs
== NULL
) {
4708 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4709 "Could not create references hash\n", NULL
, NULL
);
4712 xmlHashScan(grammar
->refs
, xmlRelaxNGParseImportRef
, ctxt
);
4717 * xmlRelaxNGProcessExternalRef:
4718 * @ctxt: the parser context
4719 * @node: the externlRef node
4721 * Process and compile an externlRef node
4723 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4725 static xmlRelaxNGDefinePtr
4726 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4728 xmlRelaxNGDocumentPtr docu
;
4729 xmlNodePtr root
, tmp
;
4731 int newNs
= 0, oldflags
;
4732 xmlRelaxNGDefinePtr def
;
4736 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4739 def
->type
= XML_RELAXNG_EXTERNALREF
;
4741 if (docu
->content
== NULL
) {
4743 * Then do the parsing for good
4745 root
= xmlDocGetRootElement(docu
->doc
);
4747 xmlRngPErr(ctxt
, node
, XML_RNGP_EXTERNALREF_EMTPY
,
4748 "xmlRelaxNGParse: %s is empty\n", ctxt
->URL
,
4753 * ns transmission rules
4755 ns
= xmlGetProp(root
, BAD_CAST
"ns");
4758 while ((tmp
!= NULL
) && (tmp
->type
== XML_ELEMENT_NODE
)) {
4759 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
4766 xmlSetProp(root
, BAD_CAST
"ns", ns
);
4775 * Parsing to get a precompiled schemas.
4777 oldflags
= ctxt
->flags
;
4778 ctxt
->flags
|= XML_RELAXNG_IN_EXTERNALREF
;
4779 docu
->schema
= xmlRelaxNGParseDocument(ctxt
, root
);
4780 ctxt
->flags
= oldflags
;
4781 if ((docu
->schema
!= NULL
) &&
4782 (docu
->schema
->topgrammar
!= NULL
)) {
4783 docu
->content
= docu
->schema
->topgrammar
->start
;
4784 if (docu
->schema
->topgrammar
->refs
)
4785 xmlRelaxNGParseImportRefs(ctxt
, docu
->schema
->topgrammar
);
4789 * the externalRef may be reused in a different ns context
4792 xmlUnsetProp(root
, BAD_CAST
"ns");
4795 def
->content
= docu
->content
;
4803 * xmlRelaxNGParsePattern:
4804 * @ctxt: a Relax-NG parser context
4805 * @node: the pattern node.
4807 * parse the content of a RelaxNG pattern node.
4809 * Returns the definition pointer or NULL in case of error or if no
4810 * pattern is generated.
4812 static xmlRelaxNGDefinePtr
4813 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4815 xmlRelaxNGDefinePtr def
= NULL
;
4820 if (IS_RELAXNG(node
, "element")) {
4821 def
= xmlRelaxNGParseElement(ctxt
, node
);
4822 } else if (IS_RELAXNG(node
, "attribute")) {
4823 def
= xmlRelaxNGParseAttribute(ctxt
, node
);
4824 } else if (IS_RELAXNG(node
, "empty")) {
4825 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4828 def
->type
= XML_RELAXNG_EMPTY
;
4829 if (node
->children
!= NULL
) {
4830 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_NOT_EMPTY
,
4831 "empty: had a child node\n", NULL
, NULL
);
4833 } else if (IS_RELAXNG(node
, "text")) {
4834 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4837 def
->type
= XML_RELAXNG_TEXT
;
4838 if (node
->children
!= NULL
) {
4839 xmlRngPErr(ctxt
, node
, XML_RNGP_TEXT_HAS_CHILD
,
4840 "text: had a child node\n", NULL
, NULL
);
4842 } else if (IS_RELAXNG(node
, "zeroOrMore")) {
4843 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4846 def
->type
= XML_RELAXNG_ZEROORMORE
;
4847 if (node
->children
== NULL
) {
4848 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4849 "Element %s is empty\n", node
->name
, NULL
);
4852 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4854 } else if (IS_RELAXNG(node
, "oneOrMore")) {
4855 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4858 def
->type
= XML_RELAXNG_ONEORMORE
;
4859 if (node
->children
== NULL
) {
4860 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4861 "Element %s is empty\n", node
->name
, NULL
);
4864 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4866 } else if (IS_RELAXNG(node
, "optional")) {
4867 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4870 def
->type
= XML_RELAXNG_OPTIONAL
;
4871 if (node
->children
== NULL
) {
4872 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4873 "Element %s is empty\n", node
->name
, NULL
);
4876 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4878 } else if (IS_RELAXNG(node
, "choice")) {
4879 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4882 def
->type
= XML_RELAXNG_CHOICE
;
4883 if (node
->children
== NULL
) {
4884 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4885 "Element %s is empty\n", node
->name
, NULL
);
4888 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4890 } else if (IS_RELAXNG(node
, "group")) {
4891 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4894 def
->type
= XML_RELAXNG_GROUP
;
4895 if (node
->children
== NULL
) {
4896 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4897 "Element %s is empty\n", node
->name
, NULL
);
4900 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4902 } else if (IS_RELAXNG(node
, "ref")) {
4903 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4906 def
->type
= XML_RELAXNG_REF
;
4907 def
->name
= xmlGetProp(node
, BAD_CAST
"name");
4908 if (def
->name
== NULL
) {
4909 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NO_NAME
, "ref has no name\n",
4912 xmlRelaxNGNormExtSpace(def
->name
);
4913 if (xmlValidateNCName(def
->name
, 0)) {
4914 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NAME_INVALID
,
4915 "ref name '%s' is not an NCName\n", def
->name
,
4919 if (node
->children
!= NULL
) {
4920 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NOT_EMPTY
, "ref is not empty\n",
4923 if (ctxt
->grammar
->refs
== NULL
)
4924 ctxt
->grammar
->refs
= xmlHashCreate(10);
4925 if (ctxt
->grammar
->refs
== NULL
) {
4926 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4927 "Could not create references hash\n", NULL
, NULL
);
4932 tmp
= xmlHashAddEntry(ctxt
->grammar
->refs
, def
->name
, def
);
4934 xmlRelaxNGDefinePtr prev
;
4936 prev
= (xmlRelaxNGDefinePtr
)
4937 xmlHashLookup(ctxt
->grammar
->refs
, def
->name
);
4939 if (def
->name
!= NULL
) {
4940 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4941 "Error refs definitions '%s'\n",
4944 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4945 "Error refs definitions\n",
4950 def
->nextHash
= prev
->nextHash
;
4951 prev
->nextHash
= def
;
4955 } else if (IS_RELAXNG(node
, "data")) {
4956 def
= xmlRelaxNGParseData(ctxt
, node
);
4957 } else if (IS_RELAXNG(node
, "value")) {
4958 def
= xmlRelaxNGParseValue(ctxt
, node
);
4959 } else if (IS_RELAXNG(node
, "list")) {
4960 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4963 def
->type
= XML_RELAXNG_LIST
;
4964 if (node
->children
== NULL
) {
4965 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4966 "Element %s is empty\n", node
->name
, NULL
);
4969 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4971 } else if (IS_RELAXNG(node
, "interleave")) {
4972 def
= xmlRelaxNGParseInterleave(ctxt
, node
);
4973 } else if (IS_RELAXNG(node
, "externalRef")) {
4974 def
= xmlRelaxNGProcessExternalRef(ctxt
, node
);
4975 } else if (IS_RELAXNG(node
, "notAllowed")) {
4976 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4979 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
4980 if (node
->children
!= NULL
) {
4981 xmlRngPErr(ctxt
, node
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
4982 "xmlRelaxNGParse: notAllowed element is not empty\n",
4985 } else if (IS_RELAXNG(node
, "grammar")) {
4986 xmlRelaxNGGrammarPtr grammar
, old
;
4987 xmlRelaxNGGrammarPtr oldparent
;
4989 #ifdef DEBUG_GRAMMAR
4990 xmlGenericError(xmlGenericErrorContext
,
4991 "Found <grammar> pattern\n");
4994 oldparent
= ctxt
->parentgrammar
;
4995 old
= ctxt
->grammar
;
4996 ctxt
->parentgrammar
= old
;
4997 grammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
4999 ctxt
->grammar
= old
;
5000 ctxt
->parentgrammar
= oldparent
;
5002 if (grammar
!= NULL
) {
5003 grammar
->next
= old
->next
;
5004 old
->next
= grammar
;
5008 if (grammar
!= NULL
)
5009 def
= grammar
->start
;
5012 } else if (IS_RELAXNG(node
, "parentRef")) {
5013 if (ctxt
->parentgrammar
== NULL
) {
5014 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NO_PARENT
,
5015 "Use of parentRef without a parent grammar\n", NULL
,
5019 def
= xmlRelaxNGNewDefine(ctxt
, node
);
5022 def
->type
= XML_RELAXNG_PARENTREF
;
5023 def
->name
= xmlGetProp(node
, BAD_CAST
"name");
5024 if (def
->name
== NULL
) {
5025 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NO_NAME
,
5026 "parentRef has no name\n", NULL
, NULL
);
5028 xmlRelaxNGNormExtSpace(def
->name
);
5029 if (xmlValidateNCName(def
->name
, 0)) {
5030 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NAME_INVALID
,
5031 "parentRef name '%s' is not an NCName\n",
5035 if (node
->children
!= NULL
) {
5036 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NOT_EMPTY
,
5037 "parentRef is not empty\n", NULL
, NULL
);
5039 if (ctxt
->parentgrammar
->refs
== NULL
)
5040 ctxt
->parentgrammar
->refs
= xmlHashCreate(10);
5041 if (ctxt
->parentgrammar
->refs
== NULL
) {
5042 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_CREATE_FAILED
,
5043 "Could not create references hash\n", NULL
, NULL
);
5045 } else if (def
->name
!= NULL
) {
5049 xmlHashAddEntry(ctxt
->parentgrammar
->refs
, def
->name
, def
);
5051 xmlRelaxNGDefinePtr prev
;
5053 prev
= (xmlRelaxNGDefinePtr
)
5054 xmlHashLookup(ctxt
->parentgrammar
->refs
, def
->name
);
5056 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_CREATE_FAILED
,
5057 "Internal error parentRef definitions '%s'\n",
5061 def
->nextHash
= prev
->nextHash
;
5062 prev
->nextHash
= def
;
5066 } else if (IS_RELAXNG(node
, "mixed")) {
5067 if (node
->children
== NULL
) {
5068 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
, "Mixed is empty\n",
5072 def
= xmlRelaxNGParseInterleave(ctxt
, node
);
5074 xmlRelaxNGDefinePtr tmp
;
5076 if ((def
->content
!= NULL
) && (def
->content
->next
!= NULL
)) {
5077 tmp
= xmlRelaxNGNewDefine(ctxt
, node
);
5079 tmp
->type
= XML_RELAXNG_GROUP
;
5080 tmp
->content
= def
->content
;
5085 tmp
= xmlRelaxNGNewDefine(ctxt
, node
);
5088 tmp
->type
= XML_RELAXNG_TEXT
;
5089 tmp
->next
= def
->content
;
5094 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_CONSTRUCT
,
5095 "Unexpected node %s is not a pattern\n", node
->name
,
5103 * xmlRelaxNGParseAttribute:
5104 * @ctxt: a Relax-NG parser context
5105 * @node: the element node
5107 * parse the content of a RelaxNG attribute node.
5109 * Returns the definition pointer or NULL in case of error.
5111 static xmlRelaxNGDefinePtr
5112 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5114 xmlRelaxNGDefinePtr ret
, cur
;
5118 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5121 ret
->type
= XML_RELAXNG_ATTRIBUTE
;
5122 ret
->parent
= ctxt
->def
;
5123 child
= node
->children
;
5124 if (child
== NULL
) {
5125 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_EMPTY
,
5126 "xmlRelaxNGParseattribute: attribute has no children\n",
5130 old_flags
= ctxt
->flags
;
5131 ctxt
->flags
|= XML_RELAXNG_IN_ATTRIBUTE
;
5132 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5134 child
= child
->next
;
5136 if (child
!= NULL
) {
5137 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5139 switch (cur
->type
) {
5140 case XML_RELAXNG_EMPTY
:
5141 case XML_RELAXNG_NOT_ALLOWED
:
5142 case XML_RELAXNG_TEXT
:
5143 case XML_RELAXNG_ELEMENT
:
5144 case XML_RELAXNG_DATATYPE
:
5145 case XML_RELAXNG_VALUE
:
5146 case XML_RELAXNG_LIST
:
5147 case XML_RELAXNG_REF
:
5148 case XML_RELAXNG_PARENTREF
:
5149 case XML_RELAXNG_EXTERNALREF
:
5150 case XML_RELAXNG_DEF
:
5151 case XML_RELAXNG_ONEORMORE
:
5152 case XML_RELAXNG_ZEROORMORE
:
5153 case XML_RELAXNG_OPTIONAL
:
5154 case XML_RELAXNG_CHOICE
:
5155 case XML_RELAXNG_GROUP
:
5156 case XML_RELAXNG_INTERLEAVE
:
5157 case XML_RELAXNG_ATTRIBUTE
:
5161 case XML_RELAXNG_START
:
5162 case XML_RELAXNG_PARAM
:
5163 case XML_RELAXNG_EXCEPT
:
5164 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_CONTENT
,
5165 "attribute has invalid content\n", NULL
,
5168 case XML_RELAXNG_NOOP
:
5169 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_NOOP
,
5170 "RNG Internal error, noop found in attribute\n",
5175 child
= child
->next
;
5177 if (child
!= NULL
) {
5178 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_CHILDREN
,
5179 "attribute has multiple children\n", NULL
, NULL
);
5181 ctxt
->flags
= old_flags
;
5186 * xmlRelaxNGParseExceptNameClass:
5187 * @ctxt: a Relax-NG parser context
5188 * @node: the except node
5189 * @attr: 1 if within an attribute, 0 if within an element
5191 * parse the content of a RelaxNG nameClass node.
5193 * Returns the definition pointer or NULL in case of error.
5195 static xmlRelaxNGDefinePtr
5196 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt
,
5197 xmlNodePtr node
, int attr
)
5199 xmlRelaxNGDefinePtr ret
, cur
, last
= NULL
;
5202 if (!IS_RELAXNG(node
, "except")) {
5203 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_MISSING
,
5204 "Expecting an except node\n", NULL
, NULL
);
5207 if (node
->next
!= NULL
) {
5208 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_MULTIPLE
,
5209 "exceptNameClass allows only a single except node\n",
5212 if (node
->children
== NULL
) {
5213 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_EMPTY
, "except has no content\n",
5218 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5221 ret
->type
= XML_RELAXNG_EXCEPT
;
5222 child
= node
->children
;
5223 while (child
!= NULL
) {
5224 cur
= xmlRelaxNGNewDefine(ctxt
, child
);
5228 cur
->type
= XML_RELAXNG_ATTRIBUTE
;
5230 cur
->type
= XML_RELAXNG_ELEMENT
;
5232 if (xmlRelaxNGParseNameClass(ctxt
, child
, cur
) != NULL
) {
5240 child
= child
->next
;
5247 * xmlRelaxNGParseNameClass:
5248 * @ctxt: a Relax-NG parser context
5249 * @node: the nameClass node
5250 * @def: the current definition
5252 * parse the content of a RelaxNG nameClass node.
5254 * Returns the definition pointer or NULL in case of error.
5256 static xmlRelaxNGDefinePtr
5257 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
,
5258 xmlRelaxNGDefinePtr def
)
5260 xmlRelaxNGDefinePtr ret
, tmp
;
5264 if ((IS_RELAXNG(node
, "name")) || (IS_RELAXNG(node
, "anyName")) ||
5265 (IS_RELAXNG(node
, "nsName"))) {
5266 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
5267 (def
->type
!= XML_RELAXNG_ATTRIBUTE
)) {
5268 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5272 if (ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
)
5273 ret
->type
= XML_RELAXNG_ATTRIBUTE
;
5275 ret
->type
= XML_RELAXNG_ELEMENT
;
5278 if (IS_RELAXNG(node
, "name")) {
5279 val
= xmlNodeGetContent(node
);
5280 xmlRelaxNGNormExtSpace(val
);
5281 if (xmlValidateNCName(val
, 0)) {
5282 if (node
->parent
!= NULL
)
5283 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NAME
,
5284 "Element %s name '%s' is not an NCName\n",
5285 node
->parent
->name
, val
);
5287 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NAME
,
5288 "name '%s' is not an NCName\n",
5292 val
= xmlGetProp(node
, BAD_CAST
"ns");
5294 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5296 (xmlStrEqual(val
, BAD_CAST
"http://www.w3.org/2000/xmlns"))) {
5297 xmlRngPErr(ctxt
, node
, XML_RNGP_XML_NS
,
5298 "Attribute with namespace '%s' is not allowed\n",
5301 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5303 (val
[0] == 0) && (xmlStrEqual(ret
->name
, BAD_CAST
"xmlns"))) {
5304 xmlRngPErr(ctxt
, node
, XML_RNGP_XMLNS_NAME
,
5305 "Attribute with QName 'xmlns' is not allowed\n",
5308 } else if (IS_RELAXNG(node
, "anyName")) {
5311 if (node
->children
!= NULL
) {
5313 xmlRelaxNGParseExceptNameClass(ctxt
, node
->children
,
5315 XML_RELAXNG_ATTRIBUTE
));
5317 } else if (IS_RELAXNG(node
, "nsName")) {
5319 ret
->ns
= xmlGetProp(node
, BAD_CAST
"ns");
5320 if (ret
->ns
== NULL
) {
5321 xmlRngPErr(ctxt
, node
, XML_RNGP_NSNAME_NO_NS
,
5322 "nsName has no ns attribute\n", NULL
, NULL
);
5324 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5325 (ret
->ns
!= NULL
) &&
5327 (ret
->ns
, BAD_CAST
"http://www.w3.org/2000/xmlns"))) {
5328 xmlRngPErr(ctxt
, node
, XML_RNGP_XML_NS
,
5329 "Attribute with namespace '%s' is not allowed\n",
5332 if (node
->children
!= NULL
) {
5334 xmlRelaxNGParseExceptNameClass(ctxt
, node
->children
,
5336 XML_RELAXNG_ATTRIBUTE
));
5338 } else if (IS_RELAXNG(node
, "choice")) {
5340 xmlRelaxNGDefinePtr last
= NULL
;
5342 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5346 ret
->type
= XML_RELAXNG_CHOICE
;
5348 if (node
->children
== NULL
) {
5349 xmlRngPErr(ctxt
, node
, XML_RNGP_CHOICE_EMPTY
,
5350 "Element choice is empty\n", NULL
, NULL
);
5353 child
= node
->children
;
5354 while (child
!= NULL
) {
5355 tmp
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5358 last
= ret
->nameClass
= tmp
;
5364 child
= child
->next
;
5368 xmlRngPErr(ctxt
, node
, XML_RNGP_CHOICE_CONTENT
,
5369 "expecting name, anyName, nsName or choice : got %s\n",
5370 (node
== NULL
? (const xmlChar
*) "nothing" : node
->name
),
5375 if (def
->nameClass
== NULL
) {
5376 def
->nameClass
= ret
;
5378 tmp
= def
->nameClass
;
5379 while (tmp
->next
!= NULL
) {
5389 * xmlRelaxNGParseElement:
5390 * @ctxt: a Relax-NG parser context
5391 * @node: the element node
5393 * parse the content of a RelaxNG element node.
5395 * Returns the definition pointer or NULL in case of error.
5397 static xmlRelaxNGDefinePtr
5398 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5400 xmlRelaxNGDefinePtr ret
, cur
, last
;
5402 const xmlChar
*olddefine
;
5404 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5407 ret
->type
= XML_RELAXNG_ELEMENT
;
5408 ret
->parent
= ctxt
->def
;
5409 child
= node
->children
;
5410 if (child
== NULL
) {
5411 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_EMPTY
,
5412 "xmlRelaxNGParseElement: element has no children\n",
5416 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5418 child
= child
->next
;
5420 if (child
== NULL
) {
5421 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NO_CONTENT
,
5422 "xmlRelaxNGParseElement: element has no content\n",
5426 olddefine
= ctxt
->define
;
5427 ctxt
->define
= NULL
;
5429 while (child
!= NULL
) {
5430 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5433 switch (cur
->type
) {
5434 case XML_RELAXNG_EMPTY
:
5435 case XML_RELAXNG_NOT_ALLOWED
:
5436 case XML_RELAXNG_TEXT
:
5437 case XML_RELAXNG_ELEMENT
:
5438 case XML_RELAXNG_DATATYPE
:
5439 case XML_RELAXNG_VALUE
:
5440 case XML_RELAXNG_LIST
:
5441 case XML_RELAXNG_REF
:
5442 case XML_RELAXNG_PARENTREF
:
5443 case XML_RELAXNG_EXTERNALREF
:
5444 case XML_RELAXNG_DEF
:
5445 case XML_RELAXNG_ZEROORMORE
:
5446 case XML_RELAXNG_ONEORMORE
:
5447 case XML_RELAXNG_OPTIONAL
:
5448 case XML_RELAXNG_CHOICE
:
5449 case XML_RELAXNG_GROUP
:
5450 case XML_RELAXNG_INTERLEAVE
:
5452 ret
->content
= last
= cur
;
5454 if ((last
->type
== XML_RELAXNG_ELEMENT
) &&
5455 (ret
->content
== last
)) {
5456 ret
->content
= xmlRelaxNGNewDefine(ctxt
, node
);
5457 if (ret
->content
!= NULL
) {
5458 ret
->content
->type
= XML_RELAXNG_GROUP
;
5459 ret
->content
->content
= last
;
5461 ret
->content
= last
;
5468 case XML_RELAXNG_ATTRIBUTE
:
5469 cur
->next
= ret
->attrs
;
5472 case XML_RELAXNG_START
:
5473 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5474 "RNG Internal error, start found in element\n",
5477 case XML_RELAXNG_PARAM
:
5478 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5479 "RNG Internal error, param found in element\n",
5482 case XML_RELAXNG_EXCEPT
:
5483 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5484 "RNG Internal error, except found in element\n",
5487 case XML_RELAXNG_NOOP
:
5488 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5489 "RNG Internal error, noop found in element\n",
5494 child
= child
->next
;
5496 ctxt
->define
= olddefine
;
5501 * xmlRelaxNGParsePatterns:
5502 * @ctxt: a Relax-NG parser context
5503 * @nodes: list of nodes
5504 * @group: use an implicit <group> for elements
5506 * parse the content of a RelaxNG start node.
5508 * Returns the definition pointer or NULL in case of error.
5510 static xmlRelaxNGDefinePtr
5511 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
,
5514 xmlRelaxNGDefinePtr def
= NULL
, last
= NULL
, cur
, parent
;
5517 while (nodes
!= NULL
) {
5518 if (IS_RELAXNG(nodes
, "element")) {
5519 cur
= xmlRelaxNGParseElement(ctxt
, nodes
);
5523 if ((group
== 1) && (def
->type
== XML_RELAXNG_ELEMENT
) &&
5525 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5526 def
->type
= XML_RELAXNG_GROUP
;
5527 def
->content
= last
;
5532 cur
->parent
= parent
;
5534 cur
= xmlRelaxNGParsePattern(ctxt
, nodes
);
5544 nodes
= nodes
->next
;
5550 * xmlRelaxNGParseStart:
5551 * @ctxt: a Relax-NG parser context
5552 * @nodes: start children nodes
5554 * parse the content of a RelaxNG start node.
5556 * Returns 0 in case of success, -1 in case of error
5559 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
5562 xmlRelaxNGDefinePtr def
= NULL
, last
;
5564 if (nodes
== NULL
) {
5565 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
, "start has no children\n",
5569 if (IS_RELAXNG(nodes
, "empty")) {
5570 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5573 def
->type
= XML_RELAXNG_EMPTY
;
5574 if (nodes
->children
!= NULL
) {
5575 xmlRngPErr(ctxt
, nodes
, XML_RNGP_EMPTY_CONTENT
,
5576 "element empty is not empty\n", NULL
, NULL
);
5578 } else if (IS_RELAXNG(nodes
, "notAllowed")) {
5579 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5582 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
5583 if (nodes
->children
!= NULL
) {
5584 xmlRngPErr(ctxt
, nodes
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
5585 "element notAllowed is not empty\n", NULL
, NULL
);
5588 def
= xmlRelaxNGParsePatterns(ctxt
, nodes
, 1);
5590 if (ctxt
->grammar
->start
!= NULL
) {
5591 last
= ctxt
->grammar
->start
;
5592 while (last
->next
!= NULL
)
5596 ctxt
->grammar
->start
= def
;
5598 nodes
= nodes
->next
;
5599 if (nodes
!= NULL
) {
5600 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_CONTENT
,
5601 "start more than one children\n", NULL
, NULL
);
5608 * xmlRelaxNGParseGrammarContent:
5609 * @ctxt: a Relax-NG parser context
5610 * @nodes: grammar children nodes
5612 * parse the content of a RelaxNG grammar node.
5614 * Returns 0 in case of success, -1 in case of error
5617 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
5622 if (nodes
== NULL
) {
5623 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_EMPTY
,
5624 "grammar has no children\n", NULL
, NULL
);
5627 while (nodes
!= NULL
) {
5628 if (IS_RELAXNG(nodes
, "start")) {
5629 if (nodes
->children
== NULL
) {
5630 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
,
5631 "start has no children\n", NULL
, NULL
);
5633 tmp
= xmlRelaxNGParseStart(ctxt
, nodes
->children
);
5637 } else if (IS_RELAXNG(nodes
, "define")) {
5638 tmp
= xmlRelaxNGParseDefine(ctxt
, nodes
);
5641 } else if (IS_RELAXNG(nodes
, "include")) {
5642 tmp
= xmlRelaxNGParseInclude(ctxt
, nodes
);
5646 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
5647 "grammar has unexpected child %s\n", nodes
->name
,
5651 nodes
= nodes
->next
;
5657 * xmlRelaxNGCheckReference:
5659 * @ctxt: a Relax-NG parser context
5660 * @name: the name associated to the defines
5662 * Applies the 4.17. combine attribute rule for all the define
5663 * element of a given grammar using the same name.
5666 xmlRelaxNGCheckReference(xmlRelaxNGDefinePtr ref
,
5667 xmlRelaxNGParserCtxtPtr ctxt
,
5668 const xmlChar
* name
)
5670 xmlRelaxNGGrammarPtr grammar
;
5671 xmlRelaxNGDefinePtr def
, cur
;
5674 * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5676 if (ref
->dflags
& IS_EXTERNAL_REF
)
5679 grammar
= ctxt
->grammar
;
5680 if (grammar
== NULL
) {
5681 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5682 "Internal error: no grammar in CheckReference %s\n",
5686 if (ref
->content
!= NULL
) {
5687 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5688 "Internal error: reference has content in CheckReference %s\n",
5692 if (grammar
->defs
!= NULL
) {
5693 def
= xmlHashLookup(grammar
->defs
, name
);
5696 while (cur
!= NULL
) {
5698 cur
= cur
->nextHash
;
5701 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5702 "Reference %s has no matching definition\n", name
,
5706 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5707 "Reference %s has no matching definition\n", name
,
5713 * xmlRelaxNGCheckCombine:
5714 * @define: the define(s) list
5715 * @ctxt: a Relax-NG parser context
5716 * @name: the name associated to the defines
5718 * Applies the 4.17. combine attribute rule for all the define
5719 * element of a given grammar using the same name.
5722 xmlRelaxNGCheckCombine(xmlRelaxNGDefinePtr define
,
5723 xmlRelaxNGParserCtxtPtr ctxt
, const xmlChar
* name
)
5726 int choiceOrInterleave
= -1;
5728 xmlRelaxNGDefinePtr cur
, last
, tmp
, tmp2
;
5730 if (define
->nextHash
== NULL
)
5733 while (cur
!= NULL
) {
5734 combine
= xmlGetProp(cur
->node
, BAD_CAST
"combine");
5735 if (combine
!= NULL
) {
5736 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5737 if (choiceOrInterleave
== -1)
5738 choiceOrInterleave
= 1;
5739 else if (choiceOrInterleave
== 0) {
5740 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5741 "Defines for %s use both 'choice' and 'interleave'\n",
5744 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5745 if (choiceOrInterleave
== -1)
5746 choiceOrInterleave
= 0;
5747 else if (choiceOrInterleave
== 1) {
5748 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5749 "Defines for %s use both 'choice' and 'interleave'\n",
5753 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5754 "Defines for %s use unknown combine value '%s''\n",
5762 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_NEED_COMBINE
,
5763 "Some defines for %s needs the combine attribute\n",
5768 cur
= cur
->nextHash
;
5771 xmlGenericError(xmlGenericErrorContext
,
5772 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5773 name
, choiceOrInterleave
);
5775 if (choiceOrInterleave
== -1)
5776 choiceOrInterleave
= 0;
5777 cur
= xmlRelaxNGNewDefine(ctxt
, define
->node
);
5780 if (choiceOrInterleave
== 0)
5781 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5783 cur
->type
= XML_RELAXNG_CHOICE
;
5786 while (tmp
!= NULL
) {
5787 if (tmp
->content
!= NULL
) {
5788 if (tmp
->content
->next
!= NULL
) {
5790 * we need first to create a wrapper.
5792 tmp2
= xmlRelaxNGNewDefine(ctxt
, tmp
->content
->node
);
5795 tmp2
->type
= XML_RELAXNG_GROUP
;
5796 tmp2
->content
= tmp
->content
;
5798 tmp2
= tmp
->content
;
5801 cur
->content
= tmp2
;
5808 tmp
= tmp
->nextHash
;
5810 define
->content
= cur
;
5811 if (choiceOrInterleave
== 0) {
5812 if (ctxt
->interleaves
== NULL
)
5813 ctxt
->interleaves
= xmlHashCreate(10);
5814 if (ctxt
->interleaves
== NULL
) {
5815 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5816 "Failed to create interleaves hash table\n", NULL
,
5821 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5822 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5824 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5825 "Failed to add %s to hash table\n",
5826 (const xmlChar
*) tmpname
, NULL
);
5833 * xmlRelaxNGCombineStart:
5834 * @ctxt: a Relax-NG parser context
5835 * @grammar: the grammar
5837 * Applies the 4.17. combine rule for all the start
5838 * element of a given grammar.
5841 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt
,
5842 xmlRelaxNGGrammarPtr grammar
)
5844 xmlRelaxNGDefinePtr starts
;
5846 int choiceOrInterleave
= -1;
5848 xmlRelaxNGDefinePtr cur
;
5850 starts
= grammar
->start
;
5851 if ((starts
== NULL
) || (starts
->next
== NULL
))
5854 while (cur
!= NULL
) {
5855 if ((cur
->node
== NULL
) || (cur
->node
->parent
== NULL
) ||
5856 (!xmlStrEqual(cur
->node
->parent
->name
, BAD_CAST
"start"))) {
5858 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_MISSING
,
5859 "Internal error: start element not found\n", NULL
,
5862 combine
= xmlGetProp(cur
->node
->parent
, BAD_CAST
"combine");
5865 if (combine
!= NULL
) {
5866 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5867 if (choiceOrInterleave
== -1)
5868 choiceOrInterleave
= 1;
5869 else if (choiceOrInterleave
== 0) {
5870 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5871 "<start> use both 'choice' and 'interleave'\n",
5874 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5875 if (choiceOrInterleave
== -1)
5876 choiceOrInterleave
= 0;
5877 else if (choiceOrInterleave
== 1) {
5878 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5879 "<start> use both 'choice' and 'interleave'\n",
5883 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5884 "<start> uses unknown combine value '%s''\n",
5892 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NEED_COMBINE
,
5893 "Some <start> element miss the combine attribute\n",
5901 xmlGenericError(xmlGenericErrorContext
,
5902 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5903 choiceOrInterleave
);
5905 if (choiceOrInterleave
== -1)
5906 choiceOrInterleave
= 0;
5907 cur
= xmlRelaxNGNewDefine(ctxt
, starts
->node
);
5910 if (choiceOrInterleave
== 0)
5911 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5913 cur
->type
= XML_RELAXNG_CHOICE
;
5914 cur
->content
= grammar
->start
;
5915 grammar
->start
= cur
;
5916 if (choiceOrInterleave
== 0) {
5917 if (ctxt
->interleaves
== NULL
)
5918 ctxt
->interleaves
= xmlHashCreate(10);
5919 if (ctxt
->interleaves
== NULL
) {
5920 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5921 "Failed to create interleaves hash table\n", NULL
,
5926 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5927 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5929 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5930 "Failed to add %s to hash table\n",
5931 (const xmlChar
*) tmpname
, NULL
);
5938 * xmlRelaxNGCheckCycles:
5939 * @ctxt: a Relax-NG parser context
5940 * @nodes: grammar children nodes
5941 * @depth: the counter
5945 * Returns 0 if check passed, and -1 in case of error
5948 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt
,
5949 xmlRelaxNGDefinePtr cur
, int depth
)
5953 while ((ret
== 0) && (cur
!= NULL
)) {
5954 if ((cur
->type
== XML_RELAXNG_REF
) ||
5955 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
5956 if (cur
->depth
== -1) {
5958 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
5960 } else if (depth
== cur
->depth
) {
5961 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_CYCLE
,
5962 "Detected a cycle in %s references\n",
5966 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
5967 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
+ 1);
5969 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
5977 * xmlRelaxNGTryUnlink:
5978 * @ctxt: a Relax-NG parser context
5979 * @cur: the definition to unlink
5980 * @parent: the parent definition
5981 * @prev: the previous sibling definition
5983 * Try to unlink a definition. If not possble make it a NOOP
5985 * Returns the new prev definition
5987 static xmlRelaxNGDefinePtr
5988 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
5989 xmlRelaxNGDefinePtr cur
,
5990 xmlRelaxNGDefinePtr parent
, xmlRelaxNGDefinePtr prev
)
5993 prev
->next
= cur
->next
;
5995 if (parent
!= NULL
) {
5996 if (parent
->content
== cur
)
5997 parent
->content
= cur
->next
;
5998 else if (parent
->attrs
== cur
)
5999 parent
->attrs
= cur
->next
;
6000 else if (parent
->nameClass
== cur
)
6001 parent
->nameClass
= cur
->next
;
6003 cur
->type
= XML_RELAXNG_NOOP
;
6011 * xmlRelaxNGSimplify:
6012 * @ctxt: a Relax-NG parser context
6013 * @nodes: grammar children nodes
6015 * Check for simplification of empty and notAllowed
6018 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt
,
6019 xmlRelaxNGDefinePtr cur
, xmlRelaxNGDefinePtr parent
)
6021 xmlRelaxNGDefinePtr prev
= NULL
;
6023 while (cur
!= NULL
) {
6024 if ((cur
->type
== XML_RELAXNG_REF
) ||
6025 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6026 if (cur
->depth
!= -3) {
6028 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6030 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6031 cur
->parent
= parent
;
6032 if ((parent
!= NULL
) &&
6033 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6034 (parent
->type
== XML_RELAXNG_LIST
) ||
6035 (parent
->type
== XML_RELAXNG_GROUP
) ||
6036 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6037 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6038 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6039 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6042 if ((parent
!= NULL
) && (parent
->type
== XML_RELAXNG_CHOICE
)) {
6043 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6046 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6047 cur
->parent
= parent
;
6048 if ((parent
!= NULL
) &&
6049 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6050 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6051 parent
->type
= XML_RELAXNG_EMPTY
;
6054 if ((parent
!= NULL
) &&
6055 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6056 (parent
->type
== XML_RELAXNG_INTERLEAVE
))) {
6057 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6061 cur
->parent
= parent
;
6062 if (cur
->content
!= NULL
)
6063 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6064 if ((cur
->type
!= XML_RELAXNG_VALUE
) && (cur
->attrs
!= NULL
))
6065 xmlRelaxNGSimplify(ctxt
, cur
->attrs
, cur
);
6066 if (cur
->nameClass
!= NULL
)
6067 xmlRelaxNGSimplify(ctxt
, cur
->nameClass
, cur
);
6069 * On Elements, try to move attribute only generating rules on
6072 if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6074 xmlRelaxNGDefinePtr tmp
, pre
;
6076 while (cur
->content
!= NULL
) {
6078 xmlRelaxNGGenerateAttributes(ctxt
, cur
->content
);
6079 if (attronly
== 1) {
6081 * migrate cur->content to attrs
6084 cur
->content
= tmp
->next
;
6085 tmp
->next
= cur
->attrs
;
6089 * cur->content can generate elements or text
6095 while ((pre
!= NULL
) && (pre
->next
!= NULL
)) {
6097 attronly
= xmlRelaxNGGenerateAttributes(ctxt
, tmp
);
6098 if (attronly
== 1) {
6100 * migrate tmp to attrs
6102 pre
->next
= tmp
->next
;
6103 tmp
->next
= cur
->attrs
;
6111 * This may result in a simplification
6113 if ((cur
->type
== XML_RELAXNG_GROUP
) ||
6114 (cur
->type
== XML_RELAXNG_INTERLEAVE
)) {
6115 if (cur
->content
== NULL
)
6116 cur
->type
= XML_RELAXNG_EMPTY
;
6117 else if (cur
->content
->next
== NULL
) {
6118 if ((parent
== NULL
) && (prev
== NULL
)) {
6119 cur
->type
= XML_RELAXNG_NOOP
;
6120 } else if (prev
== NULL
) {
6121 parent
->content
= cur
->content
;
6122 cur
->content
->next
= cur
->next
;
6125 cur
->content
->next
= cur
->next
;
6126 prev
->next
= cur
->content
;
6132 * the current node may have been transformed back
6134 if ((cur
->type
== XML_RELAXNG_EXCEPT
) &&
6135 (cur
->content
!= NULL
) &&
6136 (cur
->content
->type
== XML_RELAXNG_NOT_ALLOWED
)) {
6137 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6138 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6139 if ((parent
!= NULL
) &&
6140 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6141 (parent
->type
== XML_RELAXNG_LIST
) ||
6142 (parent
->type
== XML_RELAXNG_GROUP
) ||
6143 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6144 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6145 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6146 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6149 if ((parent
!= NULL
) &&
6150 (parent
->type
== XML_RELAXNG_CHOICE
)) {
6151 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6154 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6155 if ((parent
!= NULL
) &&
6156 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6157 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6158 parent
->type
= XML_RELAXNG_EMPTY
;
6161 if ((parent
!= NULL
) &&
6162 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6163 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6164 (parent
->type
== XML_RELAXNG_CHOICE
))) {
6165 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6177 * xmlRelaxNGGroupContentType:
6178 * @ct1: the first content type
6179 * @ct2: the second content type
6181 * Try to group 2 content types
6183 * Returns the content type
6185 static xmlRelaxNGContentType
6186 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1
,
6187 xmlRelaxNGContentType ct2
)
6189 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6190 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6191 return (XML_RELAXNG_CONTENT_ERROR
);
6192 if (ct1
== XML_RELAXNG_CONTENT_EMPTY
)
6194 if (ct2
== XML_RELAXNG_CONTENT_EMPTY
)
6196 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) &&
6197 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6198 return (XML_RELAXNG_CONTENT_COMPLEX
);
6199 return (XML_RELAXNG_CONTENT_ERROR
);
6203 * xmlRelaxNGMaxContentType:
6204 * @ct1: the first content type
6205 * @ct2: the second content type
6207 * Compute the max content-type
6209 * Returns the content type
6211 static xmlRelaxNGContentType
6212 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1
,
6213 xmlRelaxNGContentType ct2
)
6215 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6216 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6217 return (XML_RELAXNG_CONTENT_ERROR
);
6218 if ((ct1
== XML_RELAXNG_CONTENT_SIMPLE
) ||
6219 (ct2
== XML_RELAXNG_CONTENT_SIMPLE
))
6220 return (XML_RELAXNG_CONTENT_SIMPLE
);
6221 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) ||
6222 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6223 return (XML_RELAXNG_CONTENT_COMPLEX
);
6224 return (XML_RELAXNG_CONTENT_EMPTY
);
6228 * xmlRelaxNGCheckRules:
6229 * @ctxt: a Relax-NG parser context
6230 * @cur: the current definition
6231 * @flags: some accumulated flags
6232 * @ptype: the parent type
6234 * Check for rules in section 7.1 and 7.2
6236 * Returns the content type of @cur
6238 static xmlRelaxNGContentType
6239 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt
,
6240 xmlRelaxNGDefinePtr cur
, int flags
,
6241 xmlRelaxNGType ptype
)
6244 xmlRelaxNGContentType ret
, tmp
, val
= XML_RELAXNG_CONTENT_EMPTY
;
6246 while (cur
!= NULL
) {
6247 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6248 if ((cur
->type
== XML_RELAXNG_REF
) ||
6249 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6251 * This should actually be caught by list//element(ref) at the
6252 * element boundaries, c.f. Bug #159968 local refs are dropped
6256 if (flags
& XML_RELAXNG_IN_LIST
) {
6257 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_REF
,
6258 "Found forbidden pattern list//ref\n", NULL
,
6262 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6263 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_REF
,
6264 "Found forbidden pattern data/except//ref\n",
6267 if (cur
->content
== NULL
) {
6268 if (cur
->type
== XML_RELAXNG_PARENTREF
)
6269 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6270 "Internal found no define for parent refs\n",
6273 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6274 "Internal found no define for ref %s\n",
6275 (cur
->name
? cur
->name
: BAD_CAST
"null"), NULL
);
6277 if (cur
->depth
> -4) {
6279 ret
= xmlRelaxNGCheckRules(ctxt
, cur
->content
,
6281 cur
->depth
= ret
- 15;
6282 } else if (cur
->depth
== -4) {
6283 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6285 ret
= (xmlRelaxNGContentType
) (cur
->depth
+ 15);
6287 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6289 * The 7.3 Attribute derivation rule for groups is plugged there
6291 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6292 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6293 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ELEM
,
6294 "Found forbidden pattern data/except//element(ref)\n",
6297 if (flags
& XML_RELAXNG_IN_LIST
) {
6298 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ELEM
,
6299 "Found forbidden pattern list//element(ref)\n",
6302 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6303 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6304 "Found forbidden pattern attribute//element(ref)\n",
6307 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6308 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6309 "Found forbidden pattern attribute//element(ref)\n",
6313 * reset since in the simple form elements are only child
6318 xmlRelaxNGCheckRules(ctxt
, cur
->attrs
, nflags
, cur
->type
);
6319 if (ret
!= XML_RELAXNG_CONTENT_EMPTY
) {
6320 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_EMPTY
,
6321 "Element %s attributes have a content type error\n",
6325 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6327 if (ret
== XML_RELAXNG_CONTENT_ERROR
) {
6328 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_ERROR
,
6329 "Element %s has a content type error\n",
6332 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6334 } else if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
6335 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6336 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ATTR
,
6337 "Found forbidden pattern attribute//attribute\n",
6340 if (flags
& XML_RELAXNG_IN_LIST
) {
6341 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ATTR
,
6342 "Found forbidden pattern list//attribute\n",
6345 if (flags
& XML_RELAXNG_IN_OOMGROUP
) {
6346 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_GROUP_ATTR
,
6347 "Found forbidden pattern oneOrMore//group//attribute\n",
6350 if (flags
& XML_RELAXNG_IN_OOMINTERLEAVE
) {
6351 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR
,
6352 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6355 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6356 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ATTR
,
6357 "Found forbidden pattern data/except//attribute\n",
6360 if (flags
& XML_RELAXNG_IN_START
) {
6361 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ATTR
,
6362 "Found forbidden pattern start//attribute\n",
6365 if ((!(flags
& XML_RELAXNG_IN_ONEORMORE
))
6366 && (cur
->name
== NULL
)) {
6367 if (cur
->ns
== NULL
) {
6368 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ANYNAME_ATTR_ANCESTOR
,
6369 "Found anyName attribute without oneOrMore ancestor\n",
6372 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NSNAME_ATTR_ANCESTOR
,
6373 "Found nsName attribute without oneOrMore ancestor\n",
6377 nflags
= flags
| XML_RELAXNG_IN_ATTRIBUTE
;
6378 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
, cur
->type
);
6379 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6380 } else if ((cur
->type
== XML_RELAXNG_ONEORMORE
) ||
6381 (cur
->type
== XML_RELAXNG_ZEROORMORE
)) {
6382 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6383 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE
,
6384 "Found forbidden pattern data/except//oneOrMore\n",
6387 if (flags
& XML_RELAXNG_IN_START
) {
6388 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ONEMORE
,
6389 "Found forbidden pattern start//oneOrMore\n",
6392 nflags
= flags
| XML_RELAXNG_IN_ONEORMORE
;
6394 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6396 ret
= xmlRelaxNGGroupContentType(ret
, ret
);
6397 } else if (cur
->type
== XML_RELAXNG_LIST
) {
6398 if (flags
& XML_RELAXNG_IN_LIST
) {
6399 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_LIST
,
6400 "Found forbidden pattern list//list\n", NULL
,
6403 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6404 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_LIST
,
6405 "Found forbidden pattern data/except//list\n",
6408 if (flags
& XML_RELAXNG_IN_START
) {
6409 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_LIST
,
6410 "Found forbidden pattern start//list\n", NULL
,
6413 nflags
= flags
| XML_RELAXNG_IN_LIST
;
6415 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6417 } else if (cur
->type
== XML_RELAXNG_GROUP
) {
6418 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6419 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_GROUP
,
6420 "Found forbidden pattern data/except//group\n",
6423 if (flags
& XML_RELAXNG_IN_START
) {
6424 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_GROUP
,
6425 "Found forbidden pattern start//group\n", NULL
,
6428 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6429 nflags
= flags
| XML_RELAXNG_IN_OOMGROUP
;
6433 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6436 * The 7.3 Attribute derivation rule for groups is plugged there
6438 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6439 } else if (cur
->type
== XML_RELAXNG_INTERLEAVE
) {
6440 if (flags
& XML_RELAXNG_IN_LIST
) {
6441 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_INTERLEAVE
,
6442 "Found forbidden pattern list//interleave\n",
6445 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6446 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6447 "Found forbidden pattern data/except//interleave\n",
6450 if (flags
& XML_RELAXNG_IN_START
) {
6451 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6452 "Found forbidden pattern start//interleave\n",
6455 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6456 nflags
= flags
| XML_RELAXNG_IN_OOMINTERLEAVE
;
6460 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6462 } else if (cur
->type
== XML_RELAXNG_EXCEPT
) {
6463 if ((cur
->parent
!= NULL
) &&
6464 (cur
->parent
->type
== XML_RELAXNG_DATATYPE
))
6465 nflags
= flags
| XML_RELAXNG_IN_DATAEXCEPT
;
6469 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6471 } else if (cur
->type
== XML_RELAXNG_DATATYPE
) {
6472 if (flags
& XML_RELAXNG_IN_START
) {
6473 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_DATA
,
6474 "Found forbidden pattern start//data\n", NULL
,
6477 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6478 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6479 } else if (cur
->type
== XML_RELAXNG_VALUE
) {
6480 if (flags
& XML_RELAXNG_IN_START
) {
6481 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_VALUE
,
6482 "Found forbidden pattern start//value\n", NULL
,
6485 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6486 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6487 } else if (cur
->type
== XML_RELAXNG_TEXT
) {
6488 if (flags
& XML_RELAXNG_IN_LIST
) {
6489 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_TEXT
,
6490 "Found forbidden pattern list//text\n", NULL
,
6493 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6494 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_TEXT
,
6495 "Found forbidden pattern data/except//text\n",
6498 if (flags
& XML_RELAXNG_IN_START
) {
6499 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_TEXT
,
6500 "Found forbidden pattern start//text\n", NULL
,
6503 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6504 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6505 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6506 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_EMPTY
,
6507 "Found forbidden pattern data/except//empty\n",
6510 if (flags
& XML_RELAXNG_IN_START
) {
6511 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_EMPTY
,
6512 "Found forbidden pattern start//empty\n", NULL
,
6515 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6516 } else if (cur
->type
== XML_RELAXNG_CHOICE
) {
6517 xmlRelaxNGCheckChoiceDeterminism(ctxt
, cur
);
6519 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6522 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6525 if (ptype
== XML_RELAXNG_GROUP
) {
6526 val
= xmlRelaxNGGroupContentType(val
, ret
);
6527 } else if (ptype
== XML_RELAXNG_INTERLEAVE
) {
6529 * TODO: scan complain that tmp is never used, seems on purpose
6530 * need double-checking
6532 tmp
= xmlRelaxNGGroupContentType(val
, ret
);
6533 if (tmp
!= XML_RELAXNG_CONTENT_ERROR
)
6534 tmp
= xmlRelaxNGMaxContentType(val
, ret
);
6535 } else if (ptype
== XML_RELAXNG_CHOICE
) {
6536 val
= xmlRelaxNGMaxContentType(val
, ret
);
6537 } else if (ptype
== XML_RELAXNG_LIST
) {
6538 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6539 } else if (ptype
== XML_RELAXNG_EXCEPT
) {
6540 if (ret
== XML_RELAXNG_CONTENT_ERROR
)
6541 val
= XML_RELAXNG_CONTENT_ERROR
;
6543 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6545 val
= xmlRelaxNGGroupContentType(val
, ret
);
6553 * xmlRelaxNGParseGrammar:
6554 * @ctxt: a Relax-NG parser context
6555 * @nodes: grammar children nodes
6557 * parse a Relax-NG <grammar> node
6559 * Returns the internal xmlRelaxNGGrammarPtr built or
6560 * NULL in case of error
6562 static xmlRelaxNGGrammarPtr
6563 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
6565 xmlRelaxNGGrammarPtr ret
, tmp
, old
;
6567 #ifdef DEBUG_GRAMMAR
6568 xmlGenericError(xmlGenericErrorContext
, "Parsing a new grammar\n");
6571 ret
= xmlRelaxNGNewGrammar(ctxt
);
6576 * Link the new grammar in the tree
6578 ret
->parent
= ctxt
->grammar
;
6579 if (ctxt
->grammar
!= NULL
) {
6580 tmp
= ctxt
->grammar
->children
;
6582 ctxt
->grammar
->children
= ret
;
6584 while (tmp
->next
!= NULL
)
6590 old
= ctxt
->grammar
;
6591 ctxt
->grammar
= ret
;
6592 xmlRelaxNGParseGrammarContent(ctxt
, nodes
);
6593 ctxt
->grammar
= ret
;
6594 if (ctxt
->grammar
== NULL
) {
6595 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
6596 "Failed to parse <grammar> content\n", NULL
, NULL
);
6597 } else if (ctxt
->grammar
->start
== NULL
) {
6598 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_NO_START
,
6599 "Element <grammar> has no <start>\n", NULL
, NULL
);
6603 * Apply 4.17 merging rules to defines and starts
6605 xmlRelaxNGCombineStart(ctxt
, ret
);
6606 if (ret
->defs
!= NULL
) {
6607 xmlHashScan(ret
->defs
, (xmlHashScanner
) xmlRelaxNGCheckCombine
,
6612 * link together defines and refs in this grammar
6614 if (ret
->refs
!= NULL
) {
6615 xmlHashScan(ret
->refs
, (xmlHashScanner
) xmlRelaxNGCheckReference
,
6622 ctxt
->grammar
= old
;
6627 * xmlRelaxNGParseDocument:
6628 * @ctxt: a Relax-NG parser context
6629 * @node: the root node of the RelaxNG schema
6631 * parse a Relax-NG definition resource and build an internal
6632 * xmlRelaxNG struture which can be used to validate instances.
6634 * Returns the internal XML RelaxNG structure built or
6635 * NULL in case of error
6637 static xmlRelaxNGPtr
6638 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6640 xmlRelaxNGPtr schema
= NULL
;
6641 const xmlChar
*olddefine
;
6642 xmlRelaxNGGrammarPtr old
;
6644 if ((ctxt
== NULL
) || (node
== NULL
))
6647 schema
= xmlRelaxNGNewRelaxNG(ctxt
);
6651 olddefine
= ctxt
->define
;
6652 ctxt
->define
= NULL
;
6653 if (IS_RELAXNG(node
, "grammar")) {
6654 schema
->topgrammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
6655 if (schema
->topgrammar
== NULL
) {
6656 xmlRelaxNGFree(schema
);
6660 xmlRelaxNGGrammarPtr tmp
, ret
;
6662 schema
->topgrammar
= ret
= xmlRelaxNGNewGrammar(ctxt
);
6663 if (schema
->topgrammar
== NULL
) {
6664 xmlRelaxNGFree(schema
);
6668 * Link the new grammar in the tree
6670 ret
->parent
= ctxt
->grammar
;
6671 if (ctxt
->grammar
!= NULL
) {
6672 tmp
= ctxt
->grammar
->children
;
6674 ctxt
->grammar
->children
= ret
;
6676 while (tmp
->next
!= NULL
)
6681 old
= ctxt
->grammar
;
6682 ctxt
->grammar
= ret
;
6683 xmlRelaxNGParseStart(ctxt
, node
);
6685 ctxt
->grammar
= old
;
6687 ctxt
->define
= olddefine
;
6688 if (schema
->topgrammar
->start
!= NULL
) {
6689 xmlRelaxNGCheckCycles(ctxt
, schema
->topgrammar
->start
, 0);
6690 if ((ctxt
->flags
& XML_RELAXNG_IN_EXTERNALREF
) == 0) {
6691 xmlRelaxNGSimplify(ctxt
, schema
->topgrammar
->start
, NULL
);
6692 while ((schema
->topgrammar
->start
!= NULL
) &&
6693 (schema
->topgrammar
->start
->type
== XML_RELAXNG_NOOP
) &&
6694 (schema
->topgrammar
->start
->next
!= NULL
))
6695 schema
->topgrammar
->start
=
6696 schema
->topgrammar
->start
->content
;
6697 xmlRelaxNGCheckRules(ctxt
, schema
->topgrammar
->start
,
6698 XML_RELAXNG_IN_START
, XML_RELAXNG_NOOP
);
6703 xmlGenericError(xmlGenericErrorContext
,
6704 "xmlRelaxNGParseDocument() failed\n");
6710 /************************************************************************
6712 * Reading RelaxNGs *
6714 ************************************************************************/
6717 * xmlRelaxNGNewParserCtxt:
6718 * @URL: the location of the schema
6720 * Create an XML RelaxNGs parse context for that file/resource expected
6721 * to contain an XML RelaxNGs file.
6723 * Returns the parser context or NULL in case of error
6725 xmlRelaxNGParserCtxtPtr
6726 xmlRelaxNGNewParserCtxt(const char *URL
)
6728 xmlRelaxNGParserCtxtPtr ret
;
6734 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6736 xmlRngPErrMemory(NULL
, "building parser\n");
6739 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6740 ret
->URL
= xmlStrdup((const xmlChar
*) URL
);
6741 ret
->error
= xmlGenericError
;
6742 ret
->userData
= xmlGenericErrorContext
;
6747 * xmlRelaxNGNewMemParserCtxt:
6748 * @buffer: a pointer to a char array containing the schemas
6749 * @size: the size of the array
6751 * Create an XML RelaxNGs parse context for that memory buffer expected
6752 * to contain an XML RelaxNGs file.
6754 * Returns the parser context or NULL in case of error
6756 xmlRelaxNGParserCtxtPtr
6757 xmlRelaxNGNewMemParserCtxt(const char *buffer
, int size
)
6759 xmlRelaxNGParserCtxtPtr ret
;
6761 if ((buffer
== NULL
) || (size
<= 0))
6765 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6767 xmlRngPErrMemory(NULL
, "building parser\n");
6770 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6771 ret
->buffer
= buffer
;
6773 ret
->error
= xmlGenericError
;
6774 ret
->userData
= xmlGenericErrorContext
;
6779 * xmlRelaxNGNewDocParserCtxt:
6780 * @doc: a preparsed document tree
6782 * Create an XML RelaxNGs parser context for that document.
6783 * Note: since the process of compiling a RelaxNG schemas modifies the
6784 * document, the @doc parameter is duplicated internally.
6786 * Returns the parser context or NULL in case of error
6788 xmlRelaxNGParserCtxtPtr
6789 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc
)
6791 xmlRelaxNGParserCtxtPtr ret
;
6796 copy
= xmlCopyDoc(doc
, 1);
6801 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6803 xmlRngPErrMemory(NULL
, "building parser\n");
6806 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6807 ret
->document
= copy
;
6809 ret
->userData
= xmlGenericErrorContext
;
6814 * xmlRelaxNGFreeParserCtxt:
6815 * @ctxt: the schema parser context
6817 * Free the resources associated to the schema parser context
6820 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt
)
6824 if (ctxt
->URL
!= NULL
)
6826 if (ctxt
->doc
!= NULL
)
6827 xmlRelaxNGFreeDocument(ctxt
->doc
);
6828 if (ctxt
->interleaves
!= NULL
)
6829 xmlHashFree(ctxt
->interleaves
, NULL
);
6830 if (ctxt
->documents
!= NULL
)
6831 xmlRelaxNGFreeDocumentList(ctxt
->documents
);
6832 if (ctxt
->includes
!= NULL
)
6833 xmlRelaxNGFreeIncludeList(ctxt
->includes
);
6834 if (ctxt
->docTab
!= NULL
)
6835 xmlFree(ctxt
->docTab
);
6836 if (ctxt
->incTab
!= NULL
)
6837 xmlFree(ctxt
->incTab
);
6838 if (ctxt
->defTab
!= NULL
) {
6841 for (i
= 0; i
< ctxt
->defNr
; i
++)
6842 xmlRelaxNGFreeDefine(ctxt
->defTab
[i
]);
6843 xmlFree(ctxt
->defTab
);
6845 if ((ctxt
->document
!= NULL
) && (ctxt
->freedoc
))
6846 xmlFreeDoc(ctxt
->document
);
6851 * xmlRelaxNGNormExtSpace:
6854 * Removes the leading and ending spaces of the value
6855 * The string is modified "in situ"
6858 xmlRelaxNGNormExtSpace(xmlChar
* value
)
6860 xmlChar
*start
= value
;
6861 xmlChar
*cur
= value
;
6866 while (IS_BLANK_CH(*cur
))
6870 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6875 while (IS_BLANK_CH(*cur
))
6884 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6890 /* don't try to normalize the inner spaces */
6891 while (IS_BLANK_CH(*cur
))
6903 * xmlRelaxNGCleanupAttributes:
6904 * @ctxt: a Relax-NG parser context
6905 * @node: a Relax-NG node
6907 * Check all the attributes on the given node
6910 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6912 xmlAttrPtr cur
, next
;
6914 cur
= node
->properties
;
6915 while (cur
!= NULL
) {
6917 if ((cur
->ns
== NULL
) ||
6918 (xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
6919 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
6920 if ((!xmlStrEqual(node
->name
, BAD_CAST
"element")) &&
6921 (!xmlStrEqual(node
->name
, BAD_CAST
"attribute")) &&
6922 (!xmlStrEqual(node
->name
, BAD_CAST
"ref")) &&
6923 (!xmlStrEqual(node
->name
, BAD_CAST
"parentRef")) &&
6924 (!xmlStrEqual(node
->name
, BAD_CAST
"param")) &&
6925 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6926 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6927 "Attribute %s is not allowed on %s\n",
6928 cur
->name
, node
->name
);
6930 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"type")) {
6931 if ((!xmlStrEqual(node
->name
, BAD_CAST
"value")) &&
6932 (!xmlStrEqual(node
->name
, BAD_CAST
"data"))) {
6933 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6934 "Attribute %s is not allowed on %s\n",
6935 cur
->name
, node
->name
);
6937 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"href")) {
6938 if ((!xmlStrEqual(node
->name
, BAD_CAST
"externalRef")) &&
6939 (!xmlStrEqual(node
->name
, BAD_CAST
"include"))) {
6940 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6941 "Attribute %s is not allowed on %s\n",
6942 cur
->name
, node
->name
);
6944 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"combine")) {
6945 if ((!xmlStrEqual(node
->name
, BAD_CAST
"start")) &&
6946 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6947 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6948 "Attribute %s is not allowed on %s\n",
6949 cur
->name
, node
->name
);
6951 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"datatypeLibrary")) {
6955 val
= xmlNodeListGetString(node
->doc
, cur
->children
, 1);
6958 uri
= xmlParseURI((const char *) val
);
6960 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_URI
,
6961 "Attribute %s contains invalid URI %s\n",
6964 if (uri
->scheme
== NULL
) {
6965 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_NOT_ABSOLUTE
,
6966 "Attribute %s URI %s is not absolute\n",
6969 if (uri
->fragment
!= NULL
) {
6970 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_FRAGMENT
,
6971 "Attribute %s URI %s has a fragment ID\n",
6979 } else if (!xmlStrEqual(cur
->name
, BAD_CAST
"ns")) {
6980 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_ATTRIBUTE
,
6981 "Unknown attribute %s on %s\n", cur
->name
,
6990 * xmlRelaxNGCleanupTree:
6991 * @ctxt: a Relax-NG parser context
6992 * @root: an xmlNodePtr subtree
6994 * Cleanup the subtree from unwanted nodes for parsing, resolve
6995 * Include and externalRef lookups.
6998 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr root
)
7000 xmlNodePtr cur
, delete;
7004 while (cur
!= NULL
) {
7005 if (delete != NULL
) {
7006 xmlUnlinkNode(delete);
7007 xmlFreeNode(delete);
7010 if (cur
->type
== XML_ELEMENT_NODE
) {
7012 * Simplification 4.1. Annotations
7014 if ((cur
->ns
== NULL
) ||
7015 (!xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
7016 if ((cur
->parent
!= NULL
) &&
7017 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
7018 ((xmlStrEqual(cur
->parent
->name
, BAD_CAST
"name")) ||
7019 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value")) ||
7020 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"param")))) {
7021 xmlRngPErr(ctxt
, cur
, XML_RNGP_FOREIGN_ELEMENT
,
7022 "element %s doesn't allow foreign elements\n",
7023 cur
->parent
->name
, NULL
);
7028 xmlRelaxNGCleanupAttributes(ctxt
, cur
);
7029 if (xmlStrEqual(cur
->name
, BAD_CAST
"externalRef")) {
7030 xmlChar
*href
, *ns
, *base
, *URL
;
7031 xmlRelaxNGDocumentPtr docu
;
7035 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7038 while ((tmp
!= NULL
) &&
7039 (tmp
->type
== XML_ELEMENT_NODE
)) {
7040 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7046 href
= xmlGetProp(cur
, BAD_CAST
"href");
7048 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7049 "xmlRelaxNGParse: externalRef has no href attribute\n",
7056 uri
= xmlParseURI((const char *) href
);
7058 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7059 "Incorrect URI for externalRef %s\n",
7068 if (uri
->fragment
!= NULL
) {
7069 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7070 "Fragment forbidden in URI for externalRef %s\n",
7081 base
= xmlNodeGetBase(cur
->doc
, cur
);
7082 URL
= xmlBuildURI(href
, base
);
7084 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7085 "Failed to compute URL for externalRef %s\n",
7100 docu
= xmlRelaxNGLoadExternalRef(ctxt
, URL
, ns
);
7102 xmlRngPErr(ctxt
, cur
, XML_RNGP_EXTERNAL_REF_FAILURE
,
7103 "Failed to load externalRef %s\n", URL
,
7115 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"include")) {
7116 xmlChar
*href
, *ns
, *base
, *URL
;
7117 xmlRelaxNGIncludePtr incl
;
7120 href
= xmlGetProp(cur
, BAD_CAST
"href");
7122 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7123 "xmlRelaxNGParse: include has no href attribute\n",
7128 base
= xmlNodeGetBase(cur
->doc
, cur
);
7129 URL
= xmlBuildURI(href
, base
);
7131 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7132 "Failed to compute URL for include %s\n",
7145 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7148 while ((tmp
!= NULL
) &&
7149 (tmp
->type
== XML_ELEMENT_NODE
)) {
7150 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7156 incl
= xmlRelaxNGLoadInclude(ctxt
, URL
, cur
, ns
);
7160 xmlRngPErr(ctxt
, cur
, XML_RNGP_INCLUDE_FAILURE
,
7161 "Failed to load include %s\n", URL
,
7169 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"element")) ||
7170 (xmlStrEqual(cur
->name
, BAD_CAST
"attribute")))
7173 xmlNodePtr text
= NULL
;
7176 * Simplification 4.8. name attribute of element
7177 * and attribute elements
7179 name
= xmlGetProp(cur
, BAD_CAST
"name");
7181 if (cur
->children
== NULL
) {
7183 xmlNewChild(cur
, cur
->ns
, BAD_CAST
"name",
7188 node
= xmlNewDocNode(cur
->doc
, cur
->ns
,
7189 BAD_CAST
"name", NULL
);
7191 xmlAddPrevSibling(cur
->children
, node
);
7192 text
= xmlNewText(name
);
7193 xmlAddChild(node
, text
);
7198 xmlRngPErr(ctxt
, cur
, XML_RNGP_CREATE_FAILURE
,
7199 "Failed to create a name %s element\n",
7202 xmlUnsetProp(cur
, BAD_CAST
"name");
7204 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7207 xmlSetProp(text
, BAD_CAST
"ns", ns
);
7208 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7211 } else if (xmlStrEqual(cur
->name
,
7212 BAD_CAST
"attribute")) {
7213 xmlSetProp(text
, BAD_CAST
"ns", BAD_CAST
"");
7216 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"name")) ||
7217 (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) ||
7218 (xmlStrEqual(cur
->name
, BAD_CAST
"value"))) {
7220 * Simplification 4.8. name attribute of element
7221 * and attribute elements
7223 if (xmlHasProp(cur
, BAD_CAST
"ns") == NULL
) {
7228 while ((node
!= NULL
) &&
7229 (node
->type
== XML_ELEMENT_NODE
)) {
7230 ns
= xmlGetProp(node
, BAD_CAST
"ns");
7234 node
= node
->parent
;
7237 xmlSetProp(cur
, BAD_CAST
"ns", BAD_CAST
"");
7239 xmlSetProp(cur
, BAD_CAST
"ns", ns
);
7243 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
7244 xmlChar
*name
, *local
, *prefix
;
7247 * Simplification: 4.10. QNames
7249 name
= xmlNodeGetContent(cur
);
7251 local
= xmlSplitQName2(name
, &prefix
);
7252 if (local
!= NULL
) {
7255 ns
= xmlSearchNs(cur
->doc
, cur
, prefix
);
7257 xmlRngPErr(ctxt
, cur
,
7258 XML_RNGP_PREFIX_UNDEFINED
,
7259 "xmlRelaxNGParse: no namespace for prefix %s\n",
7262 xmlSetProp(cur
, BAD_CAST
"ns",
7264 xmlNodeSetContent(cur
, local
);
7275 if (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) {
7276 if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7277 xmlRngPErr(ctxt
, cur
,
7278 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME
,
7279 "Found nsName/except//nsName forbidden construct\n",
7283 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"except")) &&
7285 int oldflags
= ctxt
->flags
;
7290 if ((cur
->parent
!= NULL
) &&
7292 (cur
->parent
->name
, BAD_CAST
"anyName"))) {
7293 ctxt
->flags
|= XML_RELAXNG_IN_ANYEXCEPT
;
7294 xmlRelaxNGCleanupTree(ctxt
, cur
);
7295 ctxt
->flags
= oldflags
;
7297 } else if ((cur
->parent
!= NULL
) &&
7299 (cur
->parent
->name
, BAD_CAST
"nsName"))) {
7300 ctxt
->flags
|= XML_RELAXNG_IN_NSEXCEPT
;
7301 xmlRelaxNGCleanupTree(ctxt
, cur
);
7302 ctxt
->flags
= oldflags
;
7305 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"anyName")) {
7309 if (ctxt
->flags
& XML_RELAXNG_IN_ANYEXCEPT
) {
7310 xmlRngPErr(ctxt
, cur
,
7311 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME
,
7312 "Found anyName/except//anyName forbidden construct\n",
7314 } else if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7315 xmlRngPErr(ctxt
, cur
,
7316 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME
,
7317 "Found nsName/except//anyName forbidden construct\n",
7322 * This is not an else since "include" is transformed
7325 if (xmlStrEqual(cur
->name
, BAD_CAST
"div")) {
7327 xmlNodePtr child
, ins
, tmp
;
7330 * implements rule 4.11
7333 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7335 child
= cur
->children
;
7337 while (child
!= NULL
) {
7339 if (!xmlHasProp(child
, BAD_CAST
"ns")) {
7340 xmlSetProp(child
, BAD_CAST
"ns", ns
);
7344 xmlUnlinkNode(child
);
7345 ins
= xmlAddNextSibling(ins
, child
);
7351 * Since we are about to delete cur, if its nsDef is non-NULL we
7352 * need to preserve it (it contains the ns definitions for the
7353 * children we just moved). We'll just stick it on to the end
7354 * of cur->parent's list, since it's never going to be re-serialized
7357 if ((cur
->nsDef
!= NULL
) && (cur
->parent
!= NULL
)) {
7358 xmlNsPtr parDef
= (xmlNsPtr
)&cur
->parent
->nsDef
;
7359 while (parDef
->next
!= NULL
)
7360 parDef
= parDef
->next
;
7361 parDef
->next
= cur
->nsDef
;
7370 * Simplification 4.2 whitespaces
7372 else if ((cur
->type
== XML_TEXT_NODE
) ||
7373 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
7374 if (IS_BLANK_NODE(cur
)) {
7375 if ((cur
->parent
!= NULL
) &&
7376 (cur
->parent
->type
== XML_ELEMENT_NODE
)) {
7377 if ((!xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value"))
7380 (cur
->parent
->name
, BAD_CAST
"param")))
7395 if (cur
->children
!= NULL
) {
7396 if ((cur
->children
->type
!= XML_ENTITY_DECL
) &&
7397 (cur
->children
->type
!= XML_ENTITY_REF_NODE
) &&
7398 (cur
->children
->type
!= XML_ENTITY_NODE
)) {
7399 cur
= cur
->children
;
7404 if (cur
->next
!= NULL
) {
7417 if (cur
->next
!= NULL
) {
7421 } while (cur
!= NULL
);
7423 if (delete != NULL
) {
7424 xmlUnlinkNode(delete);
7425 xmlFreeNode(delete);
7431 * xmlRelaxNGCleanupDoc:
7432 * @ctxt: a Relax-NG parser context
7433 * @doc: an xmldocPtr document pointer
7435 * Cleanup the document from unwanted nodes for parsing, resolve
7436 * Include and externalRef lookups.
7438 * Returns the cleaned up document or NULL in case of error
7441 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
, xmlDocPtr doc
)
7448 root
= xmlDocGetRootElement(doc
);
7450 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7454 xmlRelaxNGCleanupTree(ctxt
, root
);
7460 * @ctxt: a Relax-NG parser context
7462 * parse a schema definition resource and build an internal
7463 * XML Shema struture which can be used to validate instances.
7465 * Returns the internal XML RelaxNG structure built from the resource or
7466 * NULL in case of error
7469 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt
)
7471 xmlRelaxNGPtr ret
= NULL
;
7475 xmlRelaxNGInitTypes();
7481 * First step is to parse the input document into an DOM/Infoset
7483 if (ctxt
->URL
!= NULL
) {
7484 doc
= xmlReadFile((const char *) ctxt
->URL
,NULL
,0);
7486 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7487 "xmlRelaxNGParse: could not load %s\n", ctxt
->URL
,
7491 } else if (ctxt
->buffer
!= NULL
) {
7492 doc
= xmlReadMemory(ctxt
->buffer
, ctxt
->size
,NULL
,NULL
,0);
7494 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7495 "xmlRelaxNGParse: could not parse schemas\n", NULL
,
7499 doc
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7500 ctxt
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7501 } else if (ctxt
->document
!= NULL
) {
7502 doc
= ctxt
->document
;
7504 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EMPTY
,
7505 "xmlRelaxNGParse: nothing to parse\n", NULL
, NULL
);
7508 ctxt
->document
= doc
;
7511 * Some preprocessing of the document content
7513 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
7515 xmlFreeDoc(ctxt
->document
);
7516 ctxt
->document
= NULL
;
7521 * Then do the parsing for good
7523 root
= xmlDocGetRootElement(doc
);
7525 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
,
7526 XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7527 (ctxt
->URL
? ctxt
->URL
: BAD_CAST
"schemas"), NULL
);
7529 xmlFreeDoc(ctxt
->document
);
7530 ctxt
->document
= NULL
;
7533 ret
= xmlRelaxNGParseDocument(ctxt
, root
);
7535 xmlFreeDoc(ctxt
->document
);
7536 ctxt
->document
= NULL
;
7541 * Check the ref/defines links
7544 * try to preprocess interleaves
7546 if (ctxt
->interleaves
!= NULL
) {
7547 xmlHashScan(ctxt
->interleaves
,
7548 (xmlHashScanner
) xmlRelaxNGComputeInterleaves
, ctxt
);
7552 * if there was a parsing error return NULL
7554 if (ctxt
->nbErrors
> 0) {
7555 xmlRelaxNGFree(ret
);
7556 ctxt
->document
= NULL
;
7562 * try to compile (parts of) the schemas
7564 if ((ret
->topgrammar
!= NULL
) && (ret
->topgrammar
->start
!= NULL
)) {
7565 if (ret
->topgrammar
->start
->type
!= XML_RELAXNG_START
) {
7566 xmlRelaxNGDefinePtr def
;
7568 def
= xmlRelaxNGNewDefine(ctxt
, NULL
);
7570 def
->type
= XML_RELAXNG_START
;
7571 def
->content
= ret
->topgrammar
->start
;
7572 ret
->topgrammar
->start
= def
;
7575 xmlRelaxNGTryCompile(ctxt
, ret
->topgrammar
->start
);
7579 * Transfer the pointer for cleanup at the schema level.
7582 ctxt
->document
= NULL
;
7583 ret
->documents
= ctxt
->documents
;
7584 ctxt
->documents
= NULL
;
7586 ret
->includes
= ctxt
->includes
;
7587 ctxt
->includes
= NULL
;
7588 ret
->defNr
= ctxt
->defNr
;
7589 ret
->defTab
= ctxt
->defTab
;
7590 ctxt
->defTab
= NULL
;
7591 if (ctxt
->idref
== 1)
7598 * xmlRelaxNGSetParserErrors:
7599 * @ctxt: a Relax-NG validation context
7600 * @err: the error callback
7601 * @warn: the warning callback
7602 * @ctx: contextual data for the callbacks
7604 * Set the callback functions used to handle errors for a validation context
7607 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7608 xmlRelaxNGValidityErrorFunc err
,
7609 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
7614 ctxt
->warning
= warn
;
7615 ctxt
->serror
= NULL
;
7616 ctxt
->userData
= ctx
;
7620 * xmlRelaxNGGetParserErrors:
7621 * @ctxt: a Relax-NG validation context
7622 * @err: the error callback result
7623 * @warn: the warning callback result
7624 * @ctx: contextual data for the callbacks result
7626 * Get the callback information used to handle errors for a validation context
7628 * Returns -1 in case of failure, 0 otherwise.
7631 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7632 xmlRelaxNGValidityErrorFunc
* err
,
7633 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
7640 *warn
= ctxt
->warning
;
7642 *ctx
= ctxt
->userData
;
7647 * xmlRelaxNGSetParserStructuredErrors:
7648 * @ctxt: a Relax-NG parser context
7649 * @serror: the error callback
7650 * @ctx: contextual data for the callbacks
7652 * Set the callback functions used to handle errors for a parsing context
7655 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7656 xmlStructuredErrorFunc serror
,
7661 ctxt
->serror
= serror
;
7663 ctxt
->warning
= NULL
;
7664 ctxt
->userData
= ctx
;
7667 #ifdef LIBXML_OUTPUT_ENABLED
7669 /************************************************************************
7671 * Dump back a compiled form *
7673 ************************************************************************/
7674 static void xmlRelaxNGDumpDefine(FILE * output
,
7675 xmlRelaxNGDefinePtr define
);
7678 * xmlRelaxNGDumpDefines:
7679 * @output: the file output
7680 * @defines: a list of define structures
7682 * Dump a RelaxNG structure back
7685 xmlRelaxNGDumpDefines(FILE * output
, xmlRelaxNGDefinePtr defines
)
7687 while (defines
!= NULL
) {
7688 xmlRelaxNGDumpDefine(output
, defines
);
7689 defines
= defines
->next
;
7694 * xmlRelaxNGDumpDefine:
7695 * @output: the file output
7696 * @define: a define structure
7698 * Dump a RelaxNG structure back
7701 xmlRelaxNGDumpDefine(FILE * output
, xmlRelaxNGDefinePtr define
)
7705 switch (define
->type
) {
7706 case XML_RELAXNG_EMPTY
:
7707 fprintf(output
, "<empty/>\n");
7709 case XML_RELAXNG_NOT_ALLOWED
:
7710 fprintf(output
, "<notAllowed/>\n");
7712 case XML_RELAXNG_TEXT
:
7713 fprintf(output
, "<text/>\n");
7715 case XML_RELAXNG_ELEMENT
:
7716 fprintf(output
, "<element>\n");
7717 if (define
->name
!= NULL
) {
7718 fprintf(output
, "<name");
7719 if (define
->ns
!= NULL
)
7720 fprintf(output
, " ns=\"%s\"", define
->ns
);
7721 fprintf(output
, ">%s</name>\n", define
->name
);
7723 xmlRelaxNGDumpDefines(output
, define
->attrs
);
7724 xmlRelaxNGDumpDefines(output
, define
->content
);
7725 fprintf(output
, "</element>\n");
7727 case XML_RELAXNG_LIST
:
7728 fprintf(output
, "<list>\n");
7729 xmlRelaxNGDumpDefines(output
, define
->content
);
7730 fprintf(output
, "</list>\n");
7732 case XML_RELAXNG_ONEORMORE
:
7733 fprintf(output
, "<oneOrMore>\n");
7734 xmlRelaxNGDumpDefines(output
, define
->content
);
7735 fprintf(output
, "</oneOrMore>\n");
7737 case XML_RELAXNG_ZEROORMORE
:
7738 fprintf(output
, "<zeroOrMore>\n");
7739 xmlRelaxNGDumpDefines(output
, define
->content
);
7740 fprintf(output
, "</zeroOrMore>\n");
7742 case XML_RELAXNG_CHOICE
:
7743 fprintf(output
, "<choice>\n");
7744 xmlRelaxNGDumpDefines(output
, define
->content
);
7745 fprintf(output
, "</choice>\n");
7747 case XML_RELAXNG_GROUP
:
7748 fprintf(output
, "<group>\n");
7749 xmlRelaxNGDumpDefines(output
, define
->content
);
7750 fprintf(output
, "</group>\n");
7752 case XML_RELAXNG_INTERLEAVE
:
7753 fprintf(output
, "<interleave>\n");
7754 xmlRelaxNGDumpDefines(output
, define
->content
);
7755 fprintf(output
, "</interleave>\n");
7757 case XML_RELAXNG_OPTIONAL
:
7758 fprintf(output
, "<optional>\n");
7759 xmlRelaxNGDumpDefines(output
, define
->content
);
7760 fprintf(output
, "</optional>\n");
7762 case XML_RELAXNG_ATTRIBUTE
:
7763 fprintf(output
, "<attribute>\n");
7764 xmlRelaxNGDumpDefines(output
, define
->content
);
7765 fprintf(output
, "</attribute>\n");
7767 case XML_RELAXNG_DEF
:
7768 fprintf(output
, "<define");
7769 if (define
->name
!= NULL
)
7770 fprintf(output
, " name=\"%s\"", define
->name
);
7771 fprintf(output
, ">\n");
7772 xmlRelaxNGDumpDefines(output
, define
->content
);
7773 fprintf(output
, "</define>\n");
7775 case XML_RELAXNG_REF
:
7776 fprintf(output
, "<ref");
7777 if (define
->name
!= NULL
)
7778 fprintf(output
, " name=\"%s\"", define
->name
);
7779 fprintf(output
, ">\n");
7780 xmlRelaxNGDumpDefines(output
, define
->content
);
7781 fprintf(output
, "</ref>\n");
7783 case XML_RELAXNG_PARENTREF
:
7784 fprintf(output
, "<parentRef");
7785 if (define
->name
!= NULL
)
7786 fprintf(output
, " name=\"%s\"", define
->name
);
7787 fprintf(output
, ">\n");
7788 xmlRelaxNGDumpDefines(output
, define
->content
);
7789 fprintf(output
, "</parentRef>\n");
7791 case XML_RELAXNG_EXTERNALREF
:
7792 fprintf(output
, "<externalRef>");
7793 xmlRelaxNGDumpDefines(output
, define
->content
);
7794 fprintf(output
, "</externalRef>\n");
7796 case XML_RELAXNG_DATATYPE
:
7797 case XML_RELAXNG_VALUE
:
7799 case XML_RELAXNG_START
:
7800 case XML_RELAXNG_EXCEPT
:
7801 case XML_RELAXNG_PARAM
:
7803 case XML_RELAXNG_NOOP
:
7804 xmlRelaxNGDumpDefines(output
, define
->content
);
7810 * xmlRelaxNGDumpGrammar:
7811 * @output: the file output
7812 * @grammar: a grammar structure
7813 * @top: is this a top grammar
7815 * Dump a RelaxNG structure back
7818 xmlRelaxNGDumpGrammar(FILE * output
, xmlRelaxNGGrammarPtr grammar
, int top
)
7820 if (grammar
== NULL
)
7823 fprintf(output
, "<grammar");
7825 fprintf(output
, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7826 switch (grammar
->combine
) {
7827 case XML_RELAXNG_COMBINE_UNDEFINED
:
7829 case XML_RELAXNG_COMBINE_CHOICE
:
7830 fprintf(output
, " combine=\"choice\"");
7832 case XML_RELAXNG_COMBINE_INTERLEAVE
:
7833 fprintf(output
, " combine=\"interleave\"");
7836 fprintf(output
, " <!-- invalid combine value -->");
7838 fprintf(output
, ">\n");
7839 if (grammar
->start
== NULL
) {
7840 fprintf(output
, " <!-- grammar had no start -->");
7842 fprintf(output
, "<start>\n");
7843 xmlRelaxNGDumpDefine(output
, grammar
->start
);
7844 fprintf(output
, "</start>\n");
7846 /* TODO ? Dump the defines ? */
7847 fprintf(output
, "</grammar>\n");
7852 * @output: the file output
7853 * @schema: a schema structure
7855 * Dump a RelaxNG structure back
7858 xmlRelaxNGDump(FILE * output
, xmlRelaxNGPtr schema
)
7862 if (schema
== NULL
) {
7863 fprintf(output
, "RelaxNG empty or failed to compile\n");
7866 fprintf(output
, "RelaxNG: ");
7867 if (schema
->doc
== NULL
) {
7868 fprintf(output
, "no document\n");
7869 } else if (schema
->doc
->URL
!= NULL
) {
7870 fprintf(output
, "%s\n", schema
->doc
->URL
);
7872 fprintf(output
, "\n");
7874 if (schema
->topgrammar
== NULL
) {
7875 fprintf(output
, "RelaxNG has no top grammar\n");
7878 xmlRelaxNGDumpGrammar(output
, schema
->topgrammar
, 1);
7882 * xmlRelaxNGDumpTree:
7883 * @output: the file output
7884 * @schema: a schema structure
7886 * Dump the transformed RelaxNG tree.
7889 xmlRelaxNGDumpTree(FILE * output
, xmlRelaxNGPtr schema
)
7893 if (schema
== NULL
) {
7894 fprintf(output
, "RelaxNG empty or failed to compile\n");
7897 if (schema
->doc
== NULL
) {
7898 fprintf(output
, "no document\n");
7900 xmlDocDump(output
, schema
->doc
);
7903 #endif /* LIBXML_OUTPUT_ENABLED */
7905 /************************************************************************
7907 * Validation of compiled content *
7909 ************************************************************************/
7910 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
7911 xmlRelaxNGDefinePtr define
);
7914 * xmlRelaxNGValidateCompiledCallback:
7915 * @exec: the regular expression instance
7916 * @token: the token which matched
7917 * @transdata: callback data, the define for the subelement if available
7918 @ @inputdata: callback data, the Relax NG validation context
7920 * Handle the callback and if needed validate the element children.
7923 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED
,
7924 const xmlChar
* token
,
7925 void *transdata
, void *inputdata
)
7927 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
7928 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
7931 #ifdef DEBUG_COMPILE
7932 xmlGenericError(xmlGenericErrorContext
,
7933 "Compiled callback for: '%s'\n", token
);
7936 fprintf(stderr
, "callback on %s missing context\n", token
);
7939 if (define
== NULL
) {
7940 if (token
[0] == '#')
7942 fprintf(stderr
, "callback on %s missing define\n", token
);
7943 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7944 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7947 if ((ctxt
== NULL
) || (define
== NULL
)) {
7948 fprintf(stderr
, "callback on %s missing info\n", token
);
7949 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7950 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7952 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
7953 fprintf(stderr
, "callback on %s define is not element\n", token
);
7954 if (ctxt
->errNo
== XML_RELAXNG_OK
)
7955 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7958 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
);
7964 * xmlRelaxNGValidateCompiledContent:
7965 * @ctxt: the RelaxNG validation context
7966 * @regexp: the regular expression as compiled
7967 * @content: list of children to test against the regexp
7969 * Validate the content model of an element or start using the regexp
7971 * Returns 0 in case of success, -1 in case of error.
7974 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt
,
7975 xmlRegexpPtr regexp
, xmlNodePtr content
)
7977 xmlRegExecCtxtPtr exec
;
7982 if ((ctxt
== NULL
) || (regexp
== NULL
))
7984 oldperr
= ctxt
->perr
;
7985 exec
= xmlRegNewExecCtxt(regexp
,
7986 xmlRelaxNGValidateCompiledCallback
, ctxt
);
7989 while (cur
!= NULL
) {
7990 ctxt
->state
->seq
= cur
;
7991 switch (cur
->type
) {
7993 case XML_CDATA_SECTION_NODE
:
7994 if (xmlIsBlankNode(cur
))
7996 ret
= xmlRegExecPushString(exec
, BAD_CAST
"#text", ctxt
);
7998 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
,
8002 case XML_ELEMENT_NODE
:
8003 if (cur
->ns
!= NULL
) {
8004 ret
= xmlRegExecPushString2(exec
, cur
->name
,
8005 cur
->ns
->href
, ctxt
);
8007 ret
= xmlRegExecPushString(exec
, cur
->name
, ctxt
);
8010 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, cur
->name
);
8019 * Switch to next element
8023 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8026 ctxt
->state
->seq
= NULL
;
8027 } else if (ret
== 0) {
8029 * TODO: get some of the names needed to exit the current state of exec
8031 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8033 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8034 xmlRelaxNGDumpValidError(ctxt
);
8038 xmlRegFreeExecCtxt(exec
);
8040 * There might be content model errors outside of the pure
8041 * regexp validation, e.g. for attribute values.
8043 if ((ret
== 0) && (ctxt
->perr
!= 0)) {
8046 ctxt
->perr
= oldperr
;
8050 /************************************************************************
8052 * Progressive validation of when possible *
8054 ************************************************************************/
8055 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
8056 xmlRelaxNGDefinePtr defines
);
8057 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
,
8059 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
);
8062 * xmlRelaxNGElemPush:
8063 * @ctxt: the validation context
8064 * @exec: the regexp runtime for the new content model
8066 * Push a new regexp for the current node content model on the stack
8068 * Returns 0 in case of success and -1 in case of error.
8071 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt
, xmlRegExecCtxtPtr exec
)
8073 if (ctxt
->elemTab
== NULL
) {
8075 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlMalloc(ctxt
->elemMax
*
8077 (xmlRegExecCtxtPtr
));
8078 if (ctxt
->elemTab
== NULL
) {
8079 xmlRngVErrMemory(ctxt
, "validating\n");
8083 if (ctxt
->elemNr
>= ctxt
->elemMax
) {
8085 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlRealloc(ctxt
->elemTab
,
8088 (xmlRegExecCtxtPtr
));
8089 if (ctxt
->elemTab
== NULL
) {
8090 xmlRngVErrMemory(ctxt
, "validating\n");
8094 ctxt
->elemTab
[ctxt
->elemNr
++] = exec
;
8100 * xmlRelaxNGElemPop:
8101 * @ctxt: the validation context
8103 * Pop the regexp of the current node content model from the stack
8105 * Returns the exec or NULL if empty
8107 static xmlRegExecCtxtPtr
8108 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt
)
8110 xmlRegExecCtxtPtr ret
;
8112 if (ctxt
->elemNr
<= 0)
8115 ret
= ctxt
->elemTab
[ctxt
->elemNr
];
8116 ctxt
->elemTab
[ctxt
->elemNr
] = NULL
;
8117 if (ctxt
->elemNr
> 0)
8118 ctxt
->elem
= ctxt
->elemTab
[ctxt
->elemNr
- 1];
8125 * xmlRelaxNGValidateProgressiveCallback:
8126 * @exec: the regular expression instance
8127 * @token: the token which matched
8128 * @transdata: callback data, the define for the subelement if available
8129 @ @inputdata: callback data, the Relax NG validation context
8131 * Handle the callback and if needed validate the element children.
8132 * some of the in/out informations are passed via the context in @inputdata.
8135 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8137 const xmlChar
* token
,
8138 void *transdata
, void *inputdata
)
8140 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
8141 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
8142 xmlRelaxNGValidStatePtr state
, oldstate
;
8144 int ret
= 0, oldflags
;
8146 #ifdef DEBUG_PROGRESSIVE
8147 xmlGenericError(xmlGenericErrorContext
,
8148 "Progressive callback for: '%s'\n", token
);
8151 fprintf(stderr
, "callback on %s missing context\n", token
);
8156 if (define
== NULL
) {
8157 if (token
[0] == '#')
8159 fprintf(stderr
, "callback on %s missing define\n", token
);
8160 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8161 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8165 if ((ctxt
== NULL
) || (define
== NULL
)) {
8166 fprintf(stderr
, "callback on %s missing info\n", token
);
8167 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8168 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8171 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
8172 fprintf(stderr
, "callback on %s define is not element\n", token
);
8173 if (ctxt
->errNo
== XML_RELAXNG_OK
)
8174 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8178 if (node
->type
!= XML_ELEMENT_NODE
) {
8179 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
8180 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8181 xmlRelaxNGDumpValidError(ctxt
);
8185 if (define
->contModel
== NULL
) {
8187 * this node cannot be validated in a streamable fashion
8189 #ifdef DEBUG_PROGRESSIVE
8190 xmlGenericError(xmlGenericErrorContext
,
8191 "Element '%s' validation is not streamable\n",
8195 ctxt
->pdef
= define
;
8198 exec
= xmlRegNewExecCtxt(define
->contModel
,
8199 xmlRelaxNGValidateProgressiveCallback
, ctxt
);
8204 xmlRelaxNGElemPush(ctxt
, exec
);
8207 * Validate the attributes part of the content.
8209 state
= xmlRelaxNGNewValidState(ctxt
, node
);
8210 if (state
== NULL
) {
8214 oldstate
= ctxt
->state
;
8215 ctxt
->state
= state
;
8216 if (define
->attrs
!= NULL
) {
8217 ret
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
8220 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
8223 if (ctxt
->state
!= NULL
) {
8224 ctxt
->state
->seq
= NULL
;
8225 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
8229 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8230 } else if (ctxt
->states
!= NULL
) {
8233 oldflags
= ctxt
->flags
;
8235 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8236 state
= ctxt
->states
->tabState
[i
];
8237 ctxt
->state
= state
;
8238 ctxt
->state
->seq
= NULL
;
8240 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
8247 * validation error, log the message for the "best" one
8249 ctxt
->flags
|= FLAGS_IGNORABLE
;
8250 xmlRelaxNGLogBestError(ctxt
);
8252 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8253 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[i
]);
8255 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
8256 ctxt
->states
= NULL
;
8257 if ((ret
== 0) && (tmp
== -1))
8259 ctxt
->flags
= oldflags
;
8261 if (ctxt
->pstate
== -1) {
8262 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
8263 xmlRelaxNGDumpValidError(ctxt
);
8266 ctxt
->state
= oldstate
;
8270 * xmlRelaxNGValidatePushElement:
8271 * @ctxt: the validation context
8272 * @doc: a document instance
8273 * @elem: an element instance
8275 * Push a new element start on the RelaxNG validation stack.
8277 * returns 1 if no validation problem was found or 0 if validating the
8278 * element requires a full node, and -1 in case of error.
8281 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt
,
8282 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8287 if ((ctxt
== NULL
) || (elem
== NULL
))
8290 #ifdef DEBUG_PROGRESSIVE
8291 xmlGenericError(xmlGenericErrorContext
, "PushElem %s\n", elem
->name
);
8293 if (ctxt
->elem
== 0) {
8294 xmlRelaxNGPtr schema
;
8295 xmlRelaxNGGrammarPtr grammar
;
8296 xmlRegExecCtxtPtr exec
;
8297 xmlRelaxNGDefinePtr define
;
8299 schema
= ctxt
->schema
;
8300 if (schema
== NULL
) {
8301 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8304 grammar
= schema
->topgrammar
;
8305 if ((grammar
== NULL
) || (grammar
->start
== NULL
)) {
8306 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8309 define
= grammar
->start
;
8310 if (define
->contModel
== NULL
) {
8311 ctxt
->pdef
= define
;
8314 exec
= xmlRegNewExecCtxt(define
->contModel
,
8315 xmlRelaxNGValidateProgressiveCallback
,
8320 xmlRelaxNGElemPush(ctxt
, exec
);
8324 if (elem
->ns
!= NULL
) {
8326 xmlRegExecPushString2(ctxt
->elem
, elem
->name
, elem
->ns
->href
,
8329 ret
= xmlRegExecPushString(ctxt
->elem
, elem
->name
, ctxt
);
8332 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, elem
->name
);
8334 if (ctxt
->pstate
== 0)
8336 else if (ctxt
->pstate
< 0)
8341 #ifdef DEBUG_PROGRESSIVE
8343 xmlGenericError(xmlGenericErrorContext
, "PushElem %s failed\n",
8350 * xmlRelaxNGValidatePushCData:
8351 * @ctxt: the RelaxNG validation context
8352 * @data: some character data read
8353 * @len: the length of the data
8355 * check the CData parsed for validation in the current stack
8357 * returns 1 if no validation problem was found or -1 otherwise
8360 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt
,
8361 const xmlChar
* data
, int len ATTRIBUTE_UNUSED
)
8365 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (data
== NULL
))
8368 #ifdef DEBUG_PROGRESSIVE
8369 xmlGenericError(xmlGenericErrorContext
, "CDATA %s %d\n", data
, len
);
8372 while (*data
!= 0) {
8373 if (!IS_BLANK_CH(*data
))
8380 ret
= xmlRegExecPushString(ctxt
->elem
, BAD_CAST
"#text", ctxt
);
8382 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
, BAD_CAST
" TODO ");
8383 #ifdef DEBUG_PROGRESSIVE
8384 xmlGenericError(xmlGenericErrorContext
, "CDATA failed\n");
8393 * xmlRelaxNGValidatePopElement:
8394 * @ctxt: the RelaxNG validation context
8395 * @doc: a document instance
8396 * @elem: an element instance
8398 * Pop the element end from the RelaxNG validation stack.
8400 * returns 1 if no validation problem was found or 0 otherwise
8403 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt
,
8404 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8408 xmlRegExecCtxtPtr exec
;
8410 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (elem
== NULL
))
8412 #ifdef DEBUG_PROGRESSIVE
8413 xmlGenericError(xmlGenericErrorContext
, "PopElem %s\n", elem
->name
);
8416 * verify that we reached a terminal state of the content model.
8418 exec
= xmlRelaxNGElemPop(ctxt
);
8419 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8422 * TODO: get some of the names needed to exit the current state of exec
8424 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8426 } else if (ret
< 0) {
8431 xmlRegFreeExecCtxt(exec
);
8432 #ifdef DEBUG_PROGRESSIVE
8434 xmlGenericError(xmlGenericErrorContext
, "PopElem %s failed\n",
8441 * xmlRelaxNGValidateFullElement:
8442 * @ctxt: the validation context
8443 * @doc: a document instance
8444 * @elem: an element instance
8446 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8447 * 0 and the content of the node has been expanded.
8449 * returns 1 if no validation problem was found or -1 in case of error.
8452 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt
,
8453 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8457 xmlRelaxNGValidStatePtr state
;
8459 if ((ctxt
== NULL
) || (ctxt
->pdef
== NULL
) || (elem
== NULL
))
8461 #ifdef DEBUG_PROGRESSIVE
8462 xmlGenericError(xmlGenericErrorContext
, "FullElem %s\n", elem
->name
);
8464 state
= xmlRelaxNGNewValidState(ctxt
, elem
->parent
);
8465 if (state
== NULL
) {
8469 ctxt
->state
= state
;
8470 ctxt
->errNo
= XML_RELAXNG_OK
;
8471 ret
= xmlRelaxNGValidateDefinition(ctxt
, ctxt
->pdef
);
8472 if ((ret
!= 0) || (ctxt
->errNo
!= XML_RELAXNG_OK
))
8476 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8478 #ifdef DEBUG_PROGRESSIVE
8480 xmlGenericError(xmlGenericErrorContext
, "FullElem %s failed\n",
8486 /************************************************************************
8488 * Generic interpreted validation implementation *
8490 ************************************************************************/
8491 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8492 xmlRelaxNGDefinePtr define
);
8495 * xmlRelaxNGSkipIgnored:
8496 * @ctxt: a schema validation context
8497 * @node: the top node.
8499 * Skip ignorable nodes in that context
8501 * Returns the new sibling or NULL in case of error.
8504 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
8508 * TODO complete and handle entities
8510 while ((node
!= NULL
) &&
8511 ((node
->type
== XML_COMMENT_NODE
) ||
8512 (node
->type
== XML_PI_NODE
) ||
8513 (node
->type
== XML_XINCLUDE_START
) ||
8514 (node
->type
== XML_XINCLUDE_END
) ||
8515 (((node
->type
== XML_TEXT_NODE
) ||
8516 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
8517 ((ctxt
->flags
& FLAGS_MIXED_CONTENT
) ||
8518 (IS_BLANK_NODE(node
)))))) {
8525 * xmlRelaxNGNormalize:
8526 * @ctxt: a schema validation context
8527 * @str: the string to normalize
8529 * Implements the normalizeWhiteSpace( s ) function from
8530 * section 6.2.9 of the spec
8532 * Returns the new string or NULL in case of error.
8535 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
, const xmlChar
* str
)
8548 ret
= (xmlChar
*) xmlMallocAtomic((len
+ 1) * sizeof(xmlChar
));
8550 xmlRngVErrMemory(ctxt
, "validating\n");
8554 while (IS_BLANK_CH(*str
))
8557 if (IS_BLANK_CH(*str
)) {
8558 while (IS_BLANK_CH(*str
))
8571 * xmlRelaxNGValidateDatatype:
8572 * @ctxt: a Relax-NG validation context
8573 * @value: the string value
8574 * @type: the datatype definition
8577 * Validate the given value against the dataype
8579 * Returns 0 if the validation succeeded or an error code.
8582 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt
,
8583 const xmlChar
* value
,
8584 xmlRelaxNGDefinePtr define
, xmlNodePtr node
)
8587 xmlRelaxNGTypeLibraryPtr lib
;
8588 void *result
= NULL
;
8589 xmlRelaxNGDefinePtr cur
;
8591 if ((define
== NULL
) || (define
->data
== NULL
)) {
8594 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8595 if (lib
->check
!= NULL
) {
8596 if ((define
->attrs
!= NULL
) &&
8597 (define
->attrs
->type
== XML_RELAXNG_PARAM
)) {
8599 lib
->check(lib
->data
, define
->name
, value
, &result
, node
);
8601 ret
= lib
->check(lib
->data
, define
->name
, value
, NULL
, node
);
8606 VALID_ERR2(XML_RELAXNG_ERR_TYPE
, define
->name
);
8607 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8608 lib
->freef(lib
->data
, result
);
8610 } else if (ret
== 1) {
8612 } else if (ret
== 2) {
8613 VALID_ERR2P(XML_RELAXNG_ERR_DUPID
, value
);
8615 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL
, define
->name
, value
);
8618 cur
= define
->attrs
;
8619 while ((ret
== 0) && (cur
!= NULL
) && (cur
->type
== XML_RELAXNG_PARAM
)) {
8620 if (lib
->facet
!= NULL
) {
8621 tmp
= lib
->facet(lib
->data
, define
->name
, cur
->name
,
8622 cur
->value
, value
, result
);
8628 if ((ret
== 0) && (define
->content
!= NULL
)) {
8629 const xmlChar
*oldvalue
, *oldendvalue
;
8631 oldvalue
= ctxt
->state
->value
;
8632 oldendvalue
= ctxt
->state
->endvalue
;
8633 ctxt
->state
->value
= (xmlChar
*) value
;
8634 ctxt
->state
->endvalue
= NULL
;
8635 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8636 ctxt
->state
->value
= (xmlChar
*) oldvalue
;
8637 ctxt
->state
->endvalue
= (xmlChar
*) oldendvalue
;
8639 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8640 lib
->freef(lib
->data
, result
);
8645 * xmlRelaxNGNextValue:
8646 * @ctxt: a Relax-NG validation context
8648 * Skip to the next value when validating within a list
8650 * Returns 0 if the operation succeeded or an error code.
8653 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt
)
8657 cur
= ctxt
->state
->value
;
8658 if ((cur
== NULL
) || (ctxt
->state
->endvalue
== NULL
)) {
8659 ctxt
->state
->value
= NULL
;
8660 ctxt
->state
->endvalue
= NULL
;
8665 while ((cur
!= ctxt
->state
->endvalue
) && (*cur
== 0))
8667 if (cur
== ctxt
->state
->endvalue
)
8668 ctxt
->state
->value
= NULL
;
8670 ctxt
->state
->value
= cur
;
8675 * xmlRelaxNGValidateValueList:
8676 * @ctxt: a Relax-NG validation context
8677 * @defines: the list of definitions to verify
8679 * Validate the given set of definitions for the current value
8681 * Returns 0 if the validation succeeded or an error code.
8684 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt
,
8685 xmlRelaxNGDefinePtr defines
)
8689 while (defines
!= NULL
) {
8690 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
8693 defines
= defines
->next
;
8699 * xmlRelaxNGValidateValue:
8700 * @ctxt: a Relax-NG validation context
8701 * @define: the definition to verify
8703 * Validate the given definition for the current value
8705 * Returns 0 if the validation succeeded or an error code.
8708 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8709 xmlRelaxNGDefinePtr define
)
8711 int ret
= 0, oldflags
;
8714 value
= ctxt
->state
->value
;
8715 switch (define
->type
) {
8716 case XML_RELAXNG_EMPTY
:{
8717 if ((value
!= NULL
) && (value
[0] != 0)) {
8720 while (IS_BLANK_CH(value
[idx
]))
8722 if (value
[idx
] != 0)
8727 case XML_RELAXNG_TEXT
:
8729 case XML_RELAXNG_VALUE
:{
8730 if (!xmlStrEqual(value
, define
->value
)) {
8731 if (define
->name
!= NULL
) {
8732 xmlRelaxNGTypeLibraryPtr lib
;
8734 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8735 if ((lib
!= NULL
) && (lib
->comp
!= NULL
)) {
8736 ret
= lib
->comp(lib
->data
, define
->name
,
8737 define
->value
, define
->node
,
8738 (void *) define
->attrs
,
8739 value
, ctxt
->state
->node
);
8743 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP
,
8746 } else if (ret
== 1) {
8752 xmlChar
*nval
, *nvalue
;
8755 * TODO: trivial optimizations are possible by
8756 * computing at compile-time
8758 nval
= xmlRelaxNGNormalize(ctxt
, define
->value
);
8759 nvalue
= xmlRelaxNGNormalize(ctxt
, value
);
8761 if ((nval
== NULL
) || (nvalue
== NULL
) ||
8762 (!xmlStrEqual(nval
, nvalue
)))
8771 xmlRelaxNGNextValue(ctxt
);
8774 case XML_RELAXNG_DATATYPE
:{
8775 ret
= xmlRelaxNGValidateDatatype(ctxt
, value
, define
,
8778 xmlRelaxNGNextValue(ctxt
);
8782 case XML_RELAXNG_CHOICE
:{
8783 xmlRelaxNGDefinePtr list
= define
->content
;
8786 oldflags
= ctxt
->flags
;
8787 ctxt
->flags
|= FLAGS_IGNORABLE
;
8789 oldvalue
= ctxt
->state
->value
;
8790 while (list
!= NULL
) {
8791 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8795 ctxt
->state
->value
= oldvalue
;
8798 ctxt
->flags
= oldflags
;
8800 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8801 xmlRelaxNGDumpValidError(ctxt
);
8803 if (ctxt
->errNr
> 0)
8804 xmlRelaxNGPopErrors(ctxt
, 0);
8808 case XML_RELAXNG_LIST
:{
8809 xmlRelaxNGDefinePtr list
= define
->content
;
8810 xmlChar
*oldvalue
, *oldend
, *val
, *cur
;
8816 oldvalue
= ctxt
->state
->value
;
8817 oldend
= ctxt
->state
->endvalue
;
8819 val
= xmlStrdup(oldvalue
);
8821 val
= xmlStrdup(BAD_CAST
"");
8824 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
8829 if (IS_BLANK_CH(*cur
)) {
8835 while (IS_BLANK_CH(*cur
))
8841 xmlGenericError(xmlGenericErrorContext
,
8842 "list value: '%s' found %d items\n",
8843 oldvalue
, nb_values
);
8846 ctxt
->state
->endvalue
= cur
;
8848 while ((*cur
== 0) && (cur
!= ctxt
->state
->endvalue
))
8851 ctxt
->state
->value
= cur
;
8853 while (list
!= NULL
) {
8854 if (ctxt
->state
->value
== ctxt
->state
->endvalue
)
8855 ctxt
->state
->value
= NULL
;
8856 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8859 xmlGenericError(xmlGenericErrorContext
,
8860 "Failed to validate value: '%s' with %d rule\n",
8861 ctxt
->state
->value
, nb_values
);
8871 if ((ret
== 0) && (ctxt
->state
->value
!= NULL
) &&
8872 (ctxt
->state
->value
!= ctxt
->state
->endvalue
)) {
8873 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA
,
8874 ctxt
->state
->value
);
8878 ctxt
->state
->value
= oldvalue
;
8879 ctxt
->state
->endvalue
= oldend
;
8882 case XML_RELAXNG_ONEORMORE
:
8883 ret
= xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8887 /* no break on purpose */
8888 case XML_RELAXNG_ZEROORMORE
:{
8889 xmlChar
*cur
, *temp
;
8891 if ((ctxt
->state
->value
== NULL
) ||
8892 (*ctxt
->state
->value
== 0)) {
8896 oldflags
= ctxt
->flags
;
8897 ctxt
->flags
|= FLAGS_IGNORABLE
;
8898 cur
= ctxt
->state
->value
;
8900 while ((cur
!= NULL
) && (cur
!= ctxt
->state
->endvalue
) &&
8904 xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8906 ctxt
->state
->value
= temp
;
8910 cur
= ctxt
->state
->value
;
8912 ctxt
->flags
= oldflags
;
8913 if (ctxt
->errNr
> 0)
8914 xmlRelaxNGPopErrors(ctxt
, 0);
8917 case XML_RELAXNG_OPTIONAL
:{
8920 if ((ctxt
->state
->value
== NULL
) ||
8921 (*ctxt
->state
->value
== 0)) {
8925 oldflags
= ctxt
->flags
;
8926 ctxt
->flags
|= FLAGS_IGNORABLE
;
8927 temp
= ctxt
->state
->value
;
8928 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8929 ctxt
->flags
= oldflags
;
8931 ctxt
->state
->value
= temp
;
8932 if (ctxt
->errNr
> 0)
8933 xmlRelaxNGPopErrors(ctxt
, 0);
8937 if (ctxt
->errNr
> 0)
8938 xmlRelaxNGPopErrors(ctxt
, 0);
8941 case XML_RELAXNG_EXCEPT
:{
8942 xmlRelaxNGDefinePtr list
;
8944 list
= define
->content
;
8945 while (list
!= NULL
) {
8946 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8956 case XML_RELAXNG_DEF
:
8957 case XML_RELAXNG_GROUP
:{
8958 xmlRelaxNGDefinePtr list
;
8960 list
= define
->content
;
8961 while (list
!= NULL
) {
8962 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8972 case XML_RELAXNG_REF
:
8973 case XML_RELAXNG_PARENTREF
:
8974 if (define
->content
== NULL
) {
8975 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
8978 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8988 * xmlRelaxNGValidateValueContent:
8989 * @ctxt: a Relax-NG validation context
8990 * @defines: the list of definitions to verify
8992 * Validate the given definitions for the current value
8994 * Returns 0 if the validation succeeded or an error code.
8997 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt
,
8998 xmlRelaxNGDefinePtr defines
)
9002 while (defines
!= NULL
) {
9003 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
9006 defines
= defines
->next
;
9012 * xmlRelaxNGAttributeMatch:
9013 * @ctxt: a Relax-NG validation context
9014 * @define: the definition to check
9015 * @prop: the attribute
9017 * Check if the attribute matches the definition nameClass
9019 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
9022 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt
,
9023 xmlRelaxNGDefinePtr define
, xmlAttrPtr prop
)
9027 if (define
->name
!= NULL
) {
9028 if (!xmlStrEqual(define
->name
, prop
->name
))
9031 if (define
->ns
!= NULL
) {
9032 if (define
->ns
[0] == 0) {
9033 if (prop
->ns
!= NULL
)
9036 if ((prop
->ns
== NULL
) ||
9037 (!xmlStrEqual(define
->ns
, prop
->ns
->href
)))
9041 if (define
->nameClass
== NULL
)
9043 define
= define
->nameClass
;
9044 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9045 xmlRelaxNGDefinePtr list
;
9047 list
= define
->content
;
9048 while (list
!= NULL
) {
9049 ret
= xmlRelaxNGAttributeMatch(ctxt
, list
, prop
);
9056 } else if (define
->type
== XML_RELAXNG_CHOICE
) {
9057 xmlRelaxNGDefinePtr list
;
9059 list
= define
->nameClass
;
9060 while (list
!= NULL
) {
9061 ret
= xmlRelaxNGAttributeMatch(ctxt
, list
, prop
);
9075 * xmlRelaxNGValidateAttribute:
9076 * @ctxt: a Relax-NG validation context
9077 * @define: the definition to verify
9079 * Validate the given attribute definition for that node
9081 * Returns 0 if the validation succeeded or an error code.
9084 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt
,
9085 xmlRelaxNGDefinePtr define
)
9088 xmlChar
*value
, *oldvalue
;
9089 xmlAttrPtr prop
= NULL
, tmp
;
9092 if (ctxt
->state
->nbAttrLeft
<= 0)
9094 if (define
->name
!= NULL
) {
9095 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9096 tmp
= ctxt
->state
->attrs
[i
];
9097 if ((tmp
!= NULL
) && (xmlStrEqual(define
->name
, tmp
->name
))) {
9098 if ((((define
->ns
== NULL
) || (define
->ns
[0] == 0)) &&
9099 (tmp
->ns
== NULL
)) ||
9100 ((tmp
->ns
!= NULL
) &&
9101 (xmlStrEqual(define
->ns
, tmp
->ns
->href
)))) {
9108 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9109 oldvalue
= ctxt
->state
->value
;
9110 oldseq
= ctxt
->state
->seq
;
9111 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9112 ctxt
->state
->value
= value
;
9113 ctxt
->state
->endvalue
= NULL
;
9114 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9115 if (ctxt
->state
->value
!= NULL
)
9116 value
= ctxt
->state
->value
;
9119 ctxt
->state
->value
= oldvalue
;
9120 ctxt
->state
->seq
= oldseq
;
9123 * flag the attribute as processed
9125 ctxt
->state
->attrs
[i
] = NULL
;
9126 ctxt
->state
->nbAttrLeft
--;
9132 xmlGenericError(xmlGenericErrorContext
,
9133 "xmlRelaxNGValidateAttribute(%s): %d\n",
9137 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9138 tmp
= ctxt
->state
->attrs
[i
];
9139 if ((tmp
!= NULL
) &&
9140 (xmlRelaxNGAttributeMatch(ctxt
, define
, tmp
) == 1)) {
9146 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9147 oldvalue
= ctxt
->state
->value
;
9148 oldseq
= ctxt
->state
->seq
;
9149 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9150 ctxt
->state
->value
= value
;
9151 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9152 if (ctxt
->state
->value
!= NULL
)
9153 value
= ctxt
->state
->value
;
9156 ctxt
->state
->value
= oldvalue
;
9157 ctxt
->state
->seq
= oldseq
;
9160 * flag the attribute as processed
9162 ctxt
->state
->attrs
[i
] = NULL
;
9163 ctxt
->state
->nbAttrLeft
--;
9169 if (define
->ns
!= NULL
) {
9170 xmlGenericError(xmlGenericErrorContext
,
9171 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9174 xmlGenericError(xmlGenericErrorContext
,
9175 "xmlRelaxNGValidateAttribute(anyName): %d\n",
9185 * xmlRelaxNGValidateAttributeList:
9186 * @ctxt: a Relax-NG validation context
9187 * @define: the list of definition to verify
9189 * Validate the given node against the list of attribute definitions
9191 * Returns 0 if the validation succeeded or an error code.
9194 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
9195 xmlRelaxNGDefinePtr defines
)
9199 xmlRelaxNGDefinePtr cur
;
9202 while (cur
!= NULL
) {
9203 if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
9204 if (xmlRelaxNGValidateAttribute(ctxt
, cur
) != 0)
9213 while (cur
!= NULL
) {
9214 if (cur
->type
!= XML_RELAXNG_ATTRIBUTE
) {
9215 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9216 res
= xmlRelaxNGValidateDefinition(ctxt
, cur
);
9220 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9223 if (res
== -1) /* continues on -2 */
9233 * xmlRelaxNGNodeMatchesList:
9235 * @list: a NULL terminated array of definitions
9237 * Check if a node can be matched by one of the definitions
9239 * Returns 1 if matches 0 otherwise
9242 xmlRelaxNGNodeMatchesList(xmlNodePtr node
, xmlRelaxNGDefinePtr
* list
)
9244 xmlRelaxNGDefinePtr cur
;
9247 if ((node
== NULL
) || (list
== NULL
))
9251 while (cur
!= NULL
) {
9252 if ((node
->type
== XML_ELEMENT_NODE
) &&
9253 (cur
->type
== XML_RELAXNG_ELEMENT
)) {
9254 tmp
= xmlRelaxNGElementMatch(NULL
, cur
, node
);
9257 } else if (((node
->type
== XML_TEXT_NODE
) ||
9258 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
9259 (cur
->type
== XML_RELAXNG_TEXT
)) {
9268 * xmlRelaxNGValidateInterleave:
9269 * @ctxt: a Relax-NG validation context
9270 * @define: the definition to verify
9272 * Validate an interleave definition for a node.
9274 * Returns 0 if the validation succeeded or an error code.
9277 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt
,
9278 xmlRelaxNGDefinePtr define
)
9280 int ret
= 0, i
, nbgroups
;
9281 int errNr
= ctxt
->errNr
;
9284 xmlRelaxNGValidStatePtr oldstate
;
9285 xmlRelaxNGPartitionPtr partitions
;
9286 xmlRelaxNGInterleaveGroupPtr group
= NULL
;
9287 xmlNodePtr cur
, start
, last
= NULL
, lastchg
= NULL
, lastelem
;
9288 xmlNodePtr
*list
= NULL
, *lasts
= NULL
;
9290 if (define
->data
!= NULL
) {
9291 partitions
= (xmlRelaxNGPartitionPtr
) define
->data
;
9292 nbgroups
= partitions
->nbgroups
;
9294 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA
);
9298 * Optimizations for MIXED
9300 oldflags
= ctxt
->flags
;
9301 if (define
->dflags
& IS_MIXED
) {
9302 ctxt
->flags
|= FLAGS_MIXED_CONTENT
;
9303 if (nbgroups
== 2) {
9305 * this is a pure <mixed> case
9307 if (ctxt
->state
!= NULL
)
9308 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9310 if (partitions
->groups
[0]->rule
->type
== XML_RELAXNG_TEXT
)
9311 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9312 partitions
->groups
[1]->
9315 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9316 partitions
->groups
[0]->
9319 if (ctxt
->state
!= NULL
)
9320 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9324 ctxt
->flags
= oldflags
;
9330 * Build arrays to store the first and last node of the chain
9331 * pertaining to each group
9333 list
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9335 xmlRngVErrMemory(ctxt
, "validating\n");
9338 memset(list
, 0, nbgroups
* sizeof(xmlNodePtr
));
9339 lasts
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9340 if (lasts
== NULL
) {
9341 xmlRngVErrMemory(ctxt
, "validating\n");
9344 memset(lasts
, 0, nbgroups
* sizeof(xmlNodePtr
));
9347 * Walk the sequence of children finding the right group and
9348 * sorting them in sequences.
9350 cur
= ctxt
->state
->seq
;
9351 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9353 while (cur
!= NULL
) {
9354 ctxt
->state
->seq
= cur
;
9355 if ((partitions
->triage
!= NULL
) &&
9356 (partitions
->flags
& IS_DETERMINIST
)) {
9359 if ((cur
->type
== XML_TEXT_NODE
) ||
9360 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
9361 tmp
= xmlHashLookup2(partitions
->triage
, BAD_CAST
"#text",
9363 } else if (cur
->type
== XML_ELEMENT_NODE
) {
9364 if (cur
->ns
!= NULL
) {
9365 tmp
= xmlHashLookup2(partitions
->triage
, cur
->name
,
9368 tmp
= xmlHashLookup2(partitions
->triage
,
9373 xmlHashLookup2(partitions
->triage
, cur
->name
,
9377 xmlHashLookup2(partitions
->triage
, BAD_CAST
"#any",
9384 i
= ((long) tmp
) - 1;
9385 if (partitions
->flags
& IS_NEEDCHECK
) {
9386 group
= partitions
->groups
[i
];
9387 if (!xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9392 for (i
= 0; i
< nbgroups
; i
++) {
9393 group
= partitions
->groups
[i
];
9396 if (xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9401 * We break as soon as an element not matched is found
9403 if (i
>= nbgroups
) {
9406 if (lasts
[i
] != NULL
) {
9407 lasts
[i
]->next
= cur
;
9413 if (cur
->next
!= NULL
)
9414 lastchg
= cur
->next
;
9417 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
->next
);
9420 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9425 oldstate
= ctxt
->state
;
9426 for (i
= 0; i
< nbgroups
; i
++) {
9427 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
, oldstate
);
9428 if (ctxt
->state
== NULL
) {
9432 group
= partitions
->groups
[i
];
9433 if (lasts
[i
] != NULL
) {
9434 last
= lasts
[i
]->next
;
9435 lasts
[i
]->next
= NULL
;
9437 ctxt
->state
->seq
= list
[i
];
9438 ret
= xmlRelaxNGValidateDefinition(ctxt
, group
->rule
);
9441 if (ctxt
->state
!= NULL
) {
9442 cur
= ctxt
->state
->seq
;
9443 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9444 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9445 oldstate
= ctxt
->state
;
9448 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9450 ctxt
->state
= oldstate
;
9453 } else if (ctxt
->states
!= NULL
) {
9460 * PBM: what happen if there is attributes checks in the interleaves
9463 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9464 cur
= ctxt
->states
->tabState
[j
]->seq
;
9465 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9468 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9472 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9473 /* try to keep the latest one to mach old heuristic */
9474 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9479 } else if (found
== 0) {
9480 if (lowattr
== -1) {
9481 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9484 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9485 /* try to keep the latest one to mach old heuristic */
9486 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9492 * BIG PBM: here we pick only one restarting point :-(
9494 if (ctxt
->states
->nbState
> 0) {
9495 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9497 oldstate
= ctxt
->states
->tabState
[best
];
9498 ctxt
->states
->tabState
[best
] = NULL
;
9501 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1];
9502 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1] = NULL
;
9503 ctxt
->states
->nbState
--;
9506 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9507 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[j
]);
9509 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
9510 ctxt
->states
= NULL
;
9513 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
,
9514 (const xmlChar
*) "noname");
9516 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9519 ctxt
->state
= oldstate
;
9526 if (lasts
[i
] != NULL
) {
9527 lasts
[i
]->next
= last
;
9530 if (ctxt
->state
!= NULL
)
9531 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
9532 ctxt
->state
= oldstate
;
9533 ctxt
->state
->seq
= lastelem
;
9535 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9541 ctxt
->flags
= oldflags
;
9543 * builds the next links chain from the prev one
9546 while (cur
!= NULL
) {
9547 if ((cur
== start
) || (cur
->prev
== NULL
))
9549 cur
->prev
->next
= cur
;
9553 if (ctxt
->errNr
> errNr
)
9554 xmlRelaxNGPopErrors(ctxt
, errNr
);
9563 * xmlRelaxNGValidateDefinitionList:
9564 * @ctxt: a Relax-NG validation context
9565 * @define: the list of definition to verify
9567 * Validate the given node content against the (list) of definitions
9569 * Returns 0 if the validation succeeded or an error code.
9572 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt
,
9573 xmlRelaxNGDefinePtr defines
)
9578 if (defines
== NULL
) {
9579 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL
,
9580 BAD_CAST
"NULL definition list");
9583 while (defines
!= NULL
) {
9584 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9585 res
= xmlRelaxNGValidateDefinition(ctxt
, defines
);
9589 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9592 if (res
== -1) /* continues on -2 */
9594 defines
= defines
->next
;
9601 * xmlRelaxNGElementMatch:
9602 * @ctxt: a Relax-NG validation context
9603 * @define: the definition to check
9604 * @elem: the element
9606 * Check if the element matches the definition nameClass
9608 * Returns 1 if the element matches, 0 if no, or -1 in case of error
9611 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
9612 xmlRelaxNGDefinePtr define
, xmlNodePtr elem
)
9614 int ret
= 0, oldflags
= 0;
9616 if (define
->name
!= NULL
) {
9617 if (!xmlStrEqual(elem
->name
, define
->name
)) {
9618 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME
, define
->name
, elem
->name
);
9622 if ((define
->ns
!= NULL
) && (define
->ns
[0] != 0)) {
9623 if (elem
->ns
== NULL
) {
9624 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS
, elem
->name
);
9626 } else if (!xmlStrEqual(elem
->ns
->href
, define
->ns
)) {
9627 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS
,
9628 elem
->name
, define
->ns
);
9631 } else if ((elem
->ns
!= NULL
) && (define
->ns
!= NULL
) &&
9632 (define
->name
== NULL
)) {
9633 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, elem
->name
);
9635 } else if ((elem
->ns
!= NULL
) && (define
->name
!= NULL
)) {
9636 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, define
->name
);
9640 if (define
->nameClass
== NULL
)
9643 define
= define
->nameClass
;
9644 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9645 xmlRelaxNGDefinePtr list
;
9648 oldflags
= ctxt
->flags
;
9649 ctxt
->flags
|= FLAGS_IGNORABLE
;
9652 list
= define
->content
;
9653 while (list
!= NULL
) {
9654 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9657 ctxt
->flags
= oldflags
;
9662 ctxt
->flags
= oldflags
;
9669 ctxt
->flags
= oldflags
;
9671 } else if (define
->type
== XML_RELAXNG_CHOICE
) {
9672 xmlRelaxNGDefinePtr list
;
9675 oldflags
= ctxt
->flags
;
9676 ctxt
->flags
|= FLAGS_IGNORABLE
;
9679 list
= define
->nameClass
;
9680 while (list
!= NULL
) {
9681 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9684 ctxt
->flags
= oldflags
;
9689 ctxt
->flags
= oldflags
;
9696 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9697 xmlRelaxNGDumpValidError(ctxt
);
9699 if (ctxt
->errNr
> 0)
9700 xmlRelaxNGPopErrors(ctxt
, 0);
9705 ctxt
->flags
= oldflags
;
9714 * xmlRelaxNGBestState:
9715 * @ctxt: a Relax-NG validation context
9717 * Find the "best" state in the ctxt->states list of states to report
9718 * errors about. I.e. a state with no element left in the child list
9719 * or the one with the less attributes left.
9720 * This is called only if a falidation error was detected
9722 * Returns the index of the "best" state or -1 in case of error
9725 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt
)
9727 xmlRelaxNGValidStatePtr state
;
9730 int value
= 1000000;
9732 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9733 (ctxt
->states
->nbState
<= 0))
9736 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9737 state
= ctxt
->states
->tabState
[i
];
9740 if (state
->seq
!= NULL
) {
9741 if ((best
== -1) || (value
> 100000)) {
9746 tmp
= state
->nbAttrLeft
;
9747 if ((best
== -1) || (value
> tmp
)) {
9757 * xmlRelaxNGLogBestError:
9758 * @ctxt: a Relax-NG validation context
9760 * Find the "best" state in the ctxt->states list of states to report
9761 * errors about and log it.
9764 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
)
9768 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9769 (ctxt
->states
->nbState
<= 0))
9772 best
= xmlRelaxNGBestState(ctxt
);
9773 if ((best
>= 0) && (best
< ctxt
->states
->nbState
)) {
9774 ctxt
->state
= ctxt
->states
->tabState
[best
];
9776 xmlRelaxNGValidateElementEnd(ctxt
, 1);
9781 * xmlRelaxNGValidateElementEnd:
9782 * @ctxt: a Relax-NG validation context
9783 * @dolog: indicate that error logging should be done
9785 * Validate the end of the element, implements check that
9786 * there is nothing left not consumed in the element content
9787 * or in the attribute list.
9789 * Returns 0 if the validation succeeded or an error code.
9792 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
, int dolog
)
9795 xmlRelaxNGValidStatePtr state
;
9797 state
= ctxt
->state
;
9798 if (state
->seq
!= NULL
) {
9799 state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, state
->seq
);
9800 if (state
->seq
!= NULL
) {
9802 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT
,
9803 state
->node
->name
, state
->seq
->name
);
9808 for (i
= 0; i
< state
->nbAttrs
; i
++) {
9809 if (state
->attrs
[i
] != NULL
) {
9811 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR
,
9812 state
->attrs
[i
]->name
, state
->node
->name
);
9821 * xmlRelaxNGValidateState:
9822 * @ctxt: a Relax-NG validation context
9823 * @define: the definition to verify
9825 * Validate the current state against the definition
9827 * Returns 0 if the validation succeeded or an error code.
9830 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt
,
9831 xmlRelaxNGDefinePtr define
)
9834 int ret
= 0, i
, tmp
, oldflags
, errNr
;
9835 xmlRelaxNGValidStatePtr oldstate
= NULL
, state
;
9837 if (define
== NULL
) {
9838 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
9842 if (ctxt
->state
!= NULL
) {
9843 node
= ctxt
->state
->seq
;
9848 for (i
= 0; i
< ctxt
->depth
; i
++)
9849 xmlGenericError(xmlGenericErrorContext
, " ");
9850 xmlGenericError(xmlGenericErrorContext
,
9851 "Start validating %s ", xmlRelaxNGDefName(define
));
9852 if (define
->name
!= NULL
)
9853 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
9854 if ((node
!= NULL
) && (node
->name
!= NULL
))
9855 xmlGenericError(xmlGenericErrorContext
, "on %s\n", node
->name
);
9857 xmlGenericError(xmlGenericErrorContext
, "\n");
9860 switch (define
->type
) {
9861 case XML_RELAXNG_EMPTY
:
9862 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
9865 case XML_RELAXNG_NOT_ALLOWED
:
9868 case XML_RELAXNG_TEXT
:
9869 while ((node
!= NULL
) &&
9870 ((node
->type
== XML_TEXT_NODE
) ||
9871 (node
->type
== XML_COMMENT_NODE
) ||
9872 (node
->type
== XML_PI_NODE
) ||
9873 (node
->type
== XML_CDATA_SECTION_NODE
)))
9875 ctxt
->state
->seq
= node
;
9877 case XML_RELAXNG_ELEMENT
:
9878 errNr
= ctxt
->errNr
;
9879 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
9881 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, define
->name
);
9883 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9884 xmlRelaxNGDumpValidError(ctxt
);
9887 if (node
->type
!= XML_ELEMENT_NODE
) {
9888 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
9890 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9891 xmlRelaxNGDumpValidError(ctxt
);
9895 * This node was already validated successfully against
9898 if (node
->psvi
== define
) {
9899 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
9900 if (ctxt
->errNr
> errNr
)
9901 xmlRelaxNGPopErrors(ctxt
, errNr
);
9902 if (ctxt
->errNr
!= 0) {
9903 while ((ctxt
->err
!= NULL
) &&
9904 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
)
9905 && (xmlStrEqual(ctxt
->err
->arg2
, node
->name
)))
9908 XML_RELAXNG_ERR_ELEMEXTRANS
)
9909 && (xmlStrEqual(ctxt
->err
->arg1
, node
->name
)))
9910 || (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
)
9911 || (ctxt
->err
->err
==
9912 XML_RELAXNG_ERR_NOTELEM
)))
9913 xmlRelaxNGValidErrorPop(ctxt
);
9918 ret
= xmlRelaxNGElementMatch(ctxt
, define
, node
);
9921 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9922 xmlRelaxNGDumpValidError(ctxt
);
9926 if (ctxt
->errNr
!= 0) {
9927 if (ctxt
->errNr
> errNr
)
9928 xmlRelaxNGPopErrors(ctxt
, errNr
);
9929 while ((ctxt
->err
!= NULL
) &&
9930 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
) &&
9931 (xmlStrEqual(ctxt
->err
->arg2
, node
->name
))) ||
9932 ((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMEXTRANS
) &&
9933 (xmlStrEqual(ctxt
->err
->arg1
, node
->name
))) ||
9934 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
) ||
9935 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOTELEM
)))
9936 xmlRelaxNGValidErrorPop(ctxt
);
9938 errNr
= ctxt
->errNr
;
9940 oldflags
= ctxt
->flags
;
9941 if (ctxt
->flags
& FLAGS_MIXED_CONTENT
) {
9942 ctxt
->flags
-= FLAGS_MIXED_CONTENT
;
9944 state
= xmlRelaxNGNewValidState(ctxt
, node
);
9945 if (state
== NULL
) {
9947 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9948 xmlRelaxNGDumpValidError(ctxt
);
9952 oldstate
= ctxt
->state
;
9953 ctxt
->state
= state
;
9954 if (define
->attrs
!= NULL
) {
9955 tmp
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
9958 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
9961 if (define
->contModel
!= NULL
) {
9962 xmlRelaxNGValidStatePtr nstate
, tmpstate
= ctxt
->state
;
9963 xmlRelaxNGStatesPtr tmpstates
= ctxt
->states
;
9966 nstate
= xmlRelaxNGNewValidState(ctxt
, node
);
9967 ctxt
->state
= nstate
;
9968 ctxt
->states
= NULL
;
9970 tmp
= xmlRelaxNGValidateCompiledContent(ctxt
,
9973 nseq
= ctxt
->state
->seq
;
9974 ctxt
->state
= tmpstate
;
9975 ctxt
->states
= tmpstates
;
9976 xmlRelaxNGFreeValidState(ctxt
, nstate
);
9978 #ifdef DEBUG_COMPILE
9979 xmlGenericError(xmlGenericErrorContext
,
9980 "Validating content of '%s' : %d\n",
9986 if (ctxt
->states
!= NULL
) {
9989 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9990 state
= ctxt
->states
->tabState
[i
];
9991 ctxt
->state
= state
;
9992 ctxt
->state
->seq
= nseq
;
9994 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
10001 * validation error, log the message for the "best" one
10003 ctxt
->flags
|= FLAGS_IGNORABLE
;
10004 xmlRelaxNGLogBestError(ctxt
);
10006 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10007 xmlRelaxNGFreeValidState(ctxt
,
10011 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10012 ctxt
->flags
= oldflags
;
10013 ctxt
->states
= NULL
;
10014 if ((ret
== 0) && (tmp
== -1))
10017 state
= ctxt
->state
;
10018 if (ctxt
->state
!= NULL
)
10019 ctxt
->state
->seq
= nseq
;
10021 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
10022 xmlRelaxNGFreeValidState(ctxt
, state
);
10025 if (define
->content
!= NULL
) {
10026 tmp
= xmlRelaxNGValidateDefinitionList(ctxt
,
10031 if (ctxt
->state
== NULL
) {
10032 ctxt
->state
= oldstate
;
10033 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
10035 ctxt
->state
= NULL
;
10037 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
10043 if (ctxt
->states
!= NULL
) {
10046 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10047 state
= ctxt
->states
->tabState
[i
];
10048 ctxt
->state
= state
;
10050 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
10057 * validation error, log the message for the "best" one
10059 ctxt
->flags
|= FLAGS_IGNORABLE
;
10060 xmlRelaxNGLogBestError(ctxt
);
10062 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10063 xmlRelaxNGFreeValidState(ctxt
,
10064 ctxt
->states
->tabState
[i
]);
10065 ctxt
->states
->tabState
[i
] = NULL
;
10067 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10068 ctxt
->flags
= oldflags
;
10069 ctxt
->states
= NULL
;
10070 if ((ret
== 0) && (tmp
== -1))
10073 state
= ctxt
->state
;
10075 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
10076 xmlRelaxNGFreeValidState(ctxt
, state
);
10080 node
->psvi
= define
;
10082 ctxt
->flags
= oldflags
;
10083 ctxt
->state
= oldstate
;
10084 if (oldstate
!= NULL
)
10085 oldstate
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
10087 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10088 xmlRelaxNGDumpValidError(ctxt
);
10096 if (ctxt
->errNr
> errNr
)
10097 xmlRelaxNGPopErrors(ctxt
, errNr
);
10101 xmlGenericError(xmlGenericErrorContext
,
10102 "xmlRelaxNGValidateDefinition(): validated %s : %d",
10104 if (oldstate
== NULL
)
10105 xmlGenericError(xmlGenericErrorContext
, ": no state\n");
10106 else if (oldstate
->seq
== NULL
)
10107 xmlGenericError(xmlGenericErrorContext
, ": done\n");
10108 else if (oldstate
->seq
->type
== XML_ELEMENT_NODE
)
10109 xmlGenericError(xmlGenericErrorContext
, ": next elem %s\n",
10110 oldstate
->seq
->name
);
10112 xmlGenericError(xmlGenericErrorContext
, ": next %s %d\n",
10113 oldstate
->seq
->name
, oldstate
->seq
->type
);
10116 case XML_RELAXNG_OPTIONAL
:{
10117 errNr
= ctxt
->errNr
;
10118 oldflags
= ctxt
->flags
;
10119 ctxt
->flags
|= FLAGS_IGNORABLE
;
10120 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10122 xmlRelaxNGValidateDefinitionList(ctxt
,
10125 if (ctxt
->state
!= NULL
)
10126 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10127 ctxt
->state
= oldstate
;
10128 ctxt
->flags
= oldflags
;
10130 if (ctxt
->errNr
> errNr
)
10131 xmlRelaxNGPopErrors(ctxt
, errNr
);
10134 if (ctxt
->states
!= NULL
) {
10135 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10137 ctxt
->states
= xmlRelaxNGNewStates(ctxt
, 1);
10138 if (ctxt
->states
== NULL
) {
10139 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10140 ctxt
->flags
= oldflags
;
10142 if (ctxt
->errNr
> errNr
)
10143 xmlRelaxNGPopErrors(ctxt
, errNr
);
10146 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10147 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, ctxt
->state
);
10148 ctxt
->state
= NULL
;
10150 ctxt
->flags
= oldflags
;
10152 if (ctxt
->errNr
> errNr
)
10153 xmlRelaxNGPopErrors(ctxt
, errNr
);
10156 case XML_RELAXNG_ONEORMORE
:
10157 errNr
= ctxt
->errNr
;
10158 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10162 if (ctxt
->errNr
> errNr
)
10163 xmlRelaxNGPopErrors(ctxt
, errNr
);
10164 /* no break on purpose */
10165 case XML_RELAXNG_ZEROORMORE
:{
10167 xmlRelaxNGStatesPtr states
= NULL
, res
= NULL
;
10170 errNr
= ctxt
->errNr
;
10171 res
= xmlRelaxNGNewStates(ctxt
, 1);
10177 * All the input states are also exit states
10179 if (ctxt
->state
!= NULL
) {
10180 xmlRelaxNGAddStates(ctxt
, res
,
10181 xmlRelaxNGCopyValidState(ctxt
,
10185 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10186 xmlRelaxNGAddStates(ctxt
, res
,
10187 xmlRelaxNGCopyValidState(ctxt
,
10188 ctxt
->states
->tabState
[j
]));
10191 oldflags
= ctxt
->flags
;
10192 ctxt
->flags
|= FLAGS_IGNORABLE
;
10195 base
= res
->nbState
;
10197 if (ctxt
->states
!= NULL
) {
10198 states
= ctxt
->states
;
10199 for (i
= 0; i
< states
->nbState
; i
++) {
10200 ctxt
->state
= states
->tabState
[i
];
10201 ctxt
->states
= NULL
;
10202 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10206 if (ctxt
->state
!= NULL
) {
10207 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10209 ctxt
->state
= NULL
;
10212 } else if (ctxt
->states
!= NULL
) {
10213 for (j
= 0; j
< ctxt
->states
->nbState
;
10216 xmlRelaxNGAddStates(ctxt
, res
,
10217 ctxt
->states
->tabState
[j
]);
10221 xmlRelaxNGFreeStates(ctxt
,
10223 ctxt
->states
= NULL
;
10226 if (ctxt
->state
!= NULL
) {
10227 xmlRelaxNGFreeValidState(ctxt
,
10229 ctxt
->state
= NULL
;
10234 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10238 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10239 ctxt
->state
= NULL
;
10241 base
= res
->nbState
;
10242 if (ctxt
->state
!= NULL
) {
10243 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10245 ctxt
->state
= NULL
;
10248 } else if (ctxt
->states
!= NULL
) {
10249 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10250 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10251 ctxt
->states
->tabState
[j
]);
10255 if (states
== NULL
) {
10256 states
= ctxt
->states
;
10258 xmlRelaxNGFreeStates(ctxt
,
10261 ctxt
->states
= NULL
;
10267 * Collect all the new nodes added at that step
10268 * and make them the new node set
10270 if (res
->nbState
- base
== 1) {
10271 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
,
10276 if (states
== NULL
) {
10277 xmlRelaxNGNewStates(ctxt
,
10278 res
->nbState
- base
);
10279 states
= ctxt
->states
;
10280 if (states
== NULL
) {
10285 states
->nbState
= 0;
10286 for (i
= base
; i
< res
->nbState
; i
++)
10287 xmlRelaxNGAddStates(ctxt
, states
,
10288 xmlRelaxNGCopyValidState
10289 (ctxt
, res
->tabState
[i
]));
10290 ctxt
->states
= states
;
10293 } while (progress
== 1);
10294 if (states
!= NULL
) {
10295 xmlRelaxNGFreeStates(ctxt
, states
);
10297 ctxt
->states
= res
;
10298 ctxt
->flags
= oldflags
;
10301 * errors may have to be propagated back...
10303 if (ctxt
->errNr
> errNr
)
10304 xmlRelaxNGPopErrors(ctxt
, errNr
);
10309 case XML_RELAXNG_CHOICE
:{
10310 xmlRelaxNGDefinePtr list
= NULL
;
10311 xmlRelaxNGStatesPtr states
= NULL
;
10313 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10315 errNr
= ctxt
->errNr
;
10316 if ((define
->dflags
& IS_TRIABLE
) && (define
->data
!= NULL
) &&
10319 * node == NULL can't be optimized since IS_TRIABLE
10320 * doesn't account for choice which may lead to
10323 xmlHashTablePtr triage
=
10324 (xmlHashTablePtr
) define
->data
;
10327 * Something we can optimize cleanly there is only one
10328 * possble branch out !
10330 if ((node
->type
== XML_TEXT_NODE
) ||
10331 (node
->type
== XML_CDATA_SECTION_NODE
)) {
10333 xmlHashLookup2(triage
, BAD_CAST
"#text", NULL
);
10334 } else if (node
->type
== XML_ELEMENT_NODE
) {
10335 if (node
->ns
!= NULL
) {
10336 list
= xmlHashLookup2(triage
, node
->name
,
10340 xmlHashLookup2(triage
, BAD_CAST
"#any",
10344 xmlHashLookup2(triage
, node
->name
, NULL
);
10347 xmlHashLookup2(triage
, BAD_CAST
"#any",
10350 if (list
== NULL
) {
10352 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, node
->name
);
10355 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10361 list
= define
->content
;
10362 oldflags
= ctxt
->flags
;
10363 ctxt
->flags
|= FLAGS_IGNORABLE
;
10365 while (list
!= NULL
) {
10366 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10367 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10369 if (states
== NULL
) {
10370 states
= xmlRelaxNGNewStates(ctxt
, 1);
10372 if (ctxt
->state
!= NULL
) {
10373 xmlRelaxNGAddStates(ctxt
, states
, ctxt
->state
);
10374 } else if (ctxt
->states
!= NULL
) {
10375 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10376 xmlRelaxNGAddStates(ctxt
, states
,
10380 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10381 ctxt
->states
= NULL
;
10384 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10386 ctxt
->state
= oldstate
;
10389 if (states
!= NULL
) {
10390 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10391 ctxt
->states
= states
;
10392 ctxt
->state
= NULL
;
10395 ctxt
->states
= NULL
;
10397 ctxt
->flags
= oldflags
;
10399 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10400 xmlRelaxNGDumpValidError(ctxt
);
10403 if (ctxt
->errNr
> errNr
)
10404 xmlRelaxNGPopErrors(ctxt
, errNr
);
10408 case XML_RELAXNG_DEF
:
10409 case XML_RELAXNG_GROUP
:
10410 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10412 case XML_RELAXNG_INTERLEAVE
:
10413 ret
= xmlRelaxNGValidateInterleave(ctxt
, define
);
10415 case XML_RELAXNG_ATTRIBUTE
:
10416 ret
= xmlRelaxNGValidateAttribute(ctxt
, define
);
10418 case XML_RELAXNG_START
:
10419 case XML_RELAXNG_NOOP
:
10420 case XML_RELAXNG_REF
:
10421 case XML_RELAXNG_EXTERNALREF
:
10422 case XML_RELAXNG_PARENTREF
:
10423 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
->content
);
10425 case XML_RELAXNG_DATATYPE
:{
10427 xmlChar
*content
= NULL
;
10430 while (child
!= NULL
) {
10431 if (child
->type
== XML_ELEMENT_NODE
) {
10432 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM
,
10433 node
->parent
->name
);
10436 } else if ((child
->type
== XML_TEXT_NODE
) ||
10437 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10438 content
= xmlStrcat(content
, child
->content
);
10440 /* TODO: handle entities ... */
10441 child
= child
->next
;
10444 if (content
!= NULL
)
10448 if (content
== NULL
) {
10449 content
= xmlStrdup(BAD_CAST
"");
10450 if (content
== NULL
) {
10451 xmlRngVErrMemory(ctxt
, "validating\n");
10456 ret
= xmlRelaxNGValidateDatatype(ctxt
, content
, define
,
10459 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE
, define
->name
);
10460 } else if (ret
== 0) {
10461 ctxt
->state
->seq
= NULL
;
10463 if (content
!= NULL
)
10467 case XML_RELAXNG_VALUE
:{
10468 xmlChar
*content
= NULL
;
10473 while (child
!= NULL
) {
10474 if (child
->type
== XML_ELEMENT_NODE
) {
10475 VALID_ERR2(XML_RELAXNG_ERR_VALELEM
,
10476 node
->parent
->name
);
10479 } else if ((child
->type
== XML_TEXT_NODE
) ||
10480 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10481 content
= xmlStrcat(content
, child
->content
);
10483 /* TODO: handle entities ... */
10484 child
= child
->next
;
10487 if (content
!= NULL
)
10491 if (content
== NULL
) {
10492 content
= xmlStrdup(BAD_CAST
"");
10493 if (content
== NULL
) {
10494 xmlRngVErrMemory(ctxt
, "validating\n");
10499 oldvalue
= ctxt
->state
->value
;
10500 ctxt
->state
->value
= content
;
10501 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10502 ctxt
->state
->value
= oldvalue
;
10504 VALID_ERR2(XML_RELAXNG_ERR_VALUE
, define
->name
);
10505 } else if (ret
== 0) {
10506 ctxt
->state
->seq
= NULL
;
10508 if (content
!= NULL
)
10512 case XML_RELAXNG_LIST
:{
10515 xmlChar
*oldvalue
, *oldendvalue
;
10519 * Make sure it's only text nodes
10524 while (child
!= NULL
) {
10525 if (child
->type
== XML_ELEMENT_NODE
) {
10526 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM
,
10527 node
->parent
->name
);
10530 } else if ((child
->type
== XML_TEXT_NODE
) ||
10531 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10532 content
= xmlStrcat(content
, child
->content
);
10534 /* TODO: handle entities ... */
10535 child
= child
->next
;
10538 if (content
!= NULL
)
10542 if (content
== NULL
) {
10543 content
= xmlStrdup(BAD_CAST
"");
10544 if (content
== NULL
) {
10545 xmlRngVErrMemory(ctxt
, "validating\n");
10550 len
= xmlStrlen(content
);
10551 oldvalue
= ctxt
->state
->value
;
10552 oldendvalue
= ctxt
->state
->endvalue
;
10553 ctxt
->state
->value
= content
;
10554 ctxt
->state
->endvalue
= content
+ len
;
10555 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10556 ctxt
->state
->value
= oldvalue
;
10557 ctxt
->state
->endvalue
= oldendvalue
;
10559 VALID_ERR(XML_RELAXNG_ERR_LIST
);
10560 } else if ((ret
== 0) && (node
!= NULL
)) {
10561 ctxt
->state
->seq
= node
->next
;
10563 if (content
!= NULL
)
10567 case XML_RELAXNG_EXCEPT
:
10568 case XML_RELAXNG_PARAM
:
10574 for (i
= 0; i
< ctxt
->depth
; i
++)
10575 xmlGenericError(xmlGenericErrorContext
, " ");
10576 xmlGenericError(xmlGenericErrorContext
,
10577 "Validating %s ", xmlRelaxNGDefName(define
));
10578 if (define
->name
!= NULL
)
10579 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
10581 xmlGenericError(xmlGenericErrorContext
, "suceeded\n");
10583 xmlGenericError(xmlGenericErrorContext
, "failed\n");
10589 * xmlRelaxNGValidateDefinition:
10590 * @ctxt: a Relax-NG validation context
10591 * @define: the definition to verify
10593 * Validate the current node lists against the definition
10595 * Returns 0 if the validation succeeded or an error code.
10598 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
10599 xmlRelaxNGDefinePtr define
)
10601 xmlRelaxNGStatesPtr states
, res
;
10602 int i
, j
, k
, ret
, oldflags
;
10605 * We should NOT have both ctxt->state and ctxt->states
10607 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10608 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10609 ctxt
->state
= NULL
;
10612 if ((ctxt
->states
== NULL
) || (ctxt
->states
->nbState
== 1)) {
10613 if (ctxt
->states
!= NULL
) {
10614 ctxt
->state
= ctxt
->states
->tabState
[0];
10615 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10616 ctxt
->states
= NULL
;
10618 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10619 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10620 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10621 ctxt
->state
= NULL
;
10623 if ((ctxt
->states
!= NULL
) && (ctxt
->states
->nbState
== 1)) {
10624 ctxt
->state
= ctxt
->states
->tabState
[0];
10625 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10626 ctxt
->states
= NULL
;
10631 states
= ctxt
->states
;
10632 ctxt
->states
= NULL
;
10635 oldflags
= ctxt
->flags
;
10636 ctxt
->flags
|= FLAGS_IGNORABLE
;
10637 for (i
= 0; i
< states
->nbState
; i
++) {
10638 ctxt
->state
= states
->tabState
[i
];
10639 ctxt
->states
= NULL
;
10640 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10642 * We should NOT have both ctxt->state and ctxt->states
10644 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10645 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10646 ctxt
->state
= NULL
;
10649 if (ctxt
->states
== NULL
) {
10651 /* add the state to the container */
10652 xmlRelaxNGAddStates(ctxt
, res
, ctxt
->state
);
10653 ctxt
->state
= NULL
;
10655 /* add the state directly in states */
10656 states
->tabState
[j
++] = ctxt
->state
;
10657 ctxt
->state
= NULL
;
10661 /* make it the new container and copy other results */
10662 res
= ctxt
->states
;
10663 ctxt
->states
= NULL
;
10664 for (k
= 0; k
< j
; k
++)
10665 xmlRelaxNGAddStates(ctxt
, res
,
10666 states
->tabState
[k
]);
10668 /* add all the new results to res and reff the container */
10669 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10670 xmlRelaxNGAddStates(ctxt
, res
,
10671 ctxt
->states
->tabState
[k
]);
10672 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10673 ctxt
->states
= NULL
;
10677 if (ctxt
->state
!= NULL
) {
10678 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10679 ctxt
->state
= NULL
;
10680 } else if (ctxt
->states
!= NULL
) {
10681 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10682 xmlRelaxNGFreeValidState(ctxt
,
10683 ctxt
->states
->tabState
[k
]);
10684 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10685 ctxt
->states
= NULL
;
10689 ctxt
->flags
= oldflags
;
10691 xmlRelaxNGFreeStates(ctxt
, states
);
10692 ctxt
->states
= res
;
10694 } else if (j
> 1) {
10695 states
->nbState
= j
;
10696 ctxt
->states
= states
;
10698 } else if (j
== 1) {
10699 ctxt
->state
= states
->tabState
[0];
10700 xmlRelaxNGFreeStates(ctxt
, states
);
10704 xmlRelaxNGFreeStates(ctxt
, states
);
10705 if (ctxt
->states
!= NULL
) {
10706 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10707 ctxt
->states
= NULL
;
10710 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10711 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10712 ctxt
->state
= NULL
;
10718 * xmlRelaxNGValidateDocument:
10719 * @ctxt: a Relax-NG validation context
10720 * @doc: the document
10722 * Validate the given document
10724 * Returns 0 if the validation succeeded or an error code.
10727 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
10730 xmlRelaxNGPtr schema
;
10731 xmlRelaxNGGrammarPtr grammar
;
10732 xmlRelaxNGValidStatePtr state
;
10735 if ((ctxt
== NULL
) || (ctxt
->schema
== NULL
) || (doc
== NULL
))
10738 ctxt
->errNo
= XML_RELAXNG_OK
;
10739 schema
= ctxt
->schema
;
10740 grammar
= schema
->topgrammar
;
10741 if (grammar
== NULL
) {
10742 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
10745 state
= xmlRelaxNGNewValidState(ctxt
, NULL
);
10746 ctxt
->state
= state
;
10747 ret
= xmlRelaxNGValidateDefinition(ctxt
, grammar
->start
);
10748 if ((ctxt
->state
!= NULL
) && (state
->seq
!= NULL
)) {
10749 state
= ctxt
->state
;
10751 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10752 if (node
!= NULL
) {
10754 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10758 } else if (ctxt
->states
!= NULL
) {
10762 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10763 state
= ctxt
->states
->tabState
[i
];
10765 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10768 xmlRelaxNGFreeValidState(ctxt
, state
);
10772 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10777 if (ctxt
->state
!= NULL
) {
10778 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10779 ctxt
->state
= NULL
;
10782 xmlRelaxNGDumpValidError(ctxt
);
10784 else if (ctxt
->errNr
!= 0) {
10785 ctxt
->error(ctxt
->userData
,
10786 "%d Extra error messages left on stack !\n",
10788 xmlRelaxNGDumpValidError(ctxt
);
10791 #ifdef LIBXML_VALID_ENABLED
10792 if (ctxt
->idref
== 1) {
10793 xmlValidCtxt vctxt
;
10795 memset(&vctxt
, 0, sizeof(xmlValidCtxt
));
10797 vctxt
.error
= ctxt
->error
;
10798 vctxt
.warning
= ctxt
->warning
;
10799 vctxt
.userData
= ctxt
->userData
;
10801 if (xmlValidateDocumentFinal(&vctxt
, doc
) != 1)
10804 #endif /* LIBXML_VALID_ENABLED */
10805 if ((ret
== 0) && (ctxt
->errNo
!= XML_RELAXNG_OK
))
10812 * xmlRelaxNGCleanPSVI:
10813 * @node: an input element or document
10815 * Call this routine to speed up XPath computation on static documents.
10816 * This stamps all the element nodes with the document order
10817 * Like for line information, the order is kept in the element->content
10818 * field, the value stored is actually - the node number (starting at -1)
10819 * to be able to differentiate from line numbers.
10821 * Returns the number of elements found in the document or -1 in case
10825 xmlRelaxNGCleanPSVI(xmlNodePtr node
) {
10828 if ((node
== NULL
) ||
10829 ((node
->type
!= XML_ELEMENT_NODE
) &&
10830 (node
->type
!= XML_DOCUMENT_NODE
) &&
10831 (node
->type
!= XML_HTML_DOCUMENT_NODE
)))
10833 if (node
->type
== XML_ELEMENT_NODE
)
10836 cur
= node
->children
;
10837 while (cur
!= NULL
) {
10838 if (cur
->type
== XML_ELEMENT_NODE
) {
10840 if (cur
->children
!= NULL
) {
10841 cur
= cur
->children
;
10845 if (cur
->next
!= NULL
) {
10857 if (cur
->next
!= NULL
) {
10861 } while (cur
!= NULL
);
10865 /************************************************************************
10867 * Validation interfaces *
10869 ************************************************************************/
10872 * xmlRelaxNGNewValidCtxt:
10873 * @schema: a precompiled XML RelaxNGs
10875 * Create an XML RelaxNGs validation context based on the given schema
10877 * Returns the validation context or NULL in case of error
10879 xmlRelaxNGValidCtxtPtr
10880 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema
)
10882 xmlRelaxNGValidCtxtPtr ret
;
10884 ret
= (xmlRelaxNGValidCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGValidCtxt
));
10886 xmlRngVErrMemory(NULL
, "building context\n");
10889 memset(ret
, 0, sizeof(xmlRelaxNGValidCtxt
));
10890 ret
->schema
= schema
;
10891 ret
->error
= xmlGenericError
;
10892 ret
->userData
= xmlGenericErrorContext
;
10896 ret
->errTab
= NULL
;
10897 if (schema
!= NULL
)
10898 ret
->idref
= schema
->idref
;
10899 ret
->states
= NULL
;
10900 ret
->freeState
= NULL
;
10901 ret
->freeStates
= NULL
;
10902 ret
->errNo
= XML_RELAXNG_OK
;
10907 * xmlRelaxNGFreeValidCtxt:
10908 * @ctxt: the schema validation context
10910 * Free the resources associated to the schema validation context
10913 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt
)
10919 if (ctxt
->states
!= NULL
)
10920 xmlRelaxNGFreeStates(NULL
, ctxt
->states
);
10921 if (ctxt
->freeState
!= NULL
) {
10922 for (k
= 0; k
< ctxt
->freeState
->nbState
; k
++) {
10923 xmlRelaxNGFreeValidState(NULL
, ctxt
->freeState
->tabState
[k
]);
10925 xmlRelaxNGFreeStates(NULL
, ctxt
->freeState
);
10927 if (ctxt
->freeStates
!= NULL
) {
10928 for (k
= 0; k
< ctxt
->freeStatesNr
; k
++) {
10929 xmlRelaxNGFreeStates(NULL
, ctxt
->freeStates
[k
]);
10931 xmlFree(ctxt
->freeStates
);
10933 if (ctxt
->errTab
!= NULL
)
10934 xmlFree(ctxt
->errTab
);
10935 if (ctxt
->elemTab
!= NULL
) {
10936 xmlRegExecCtxtPtr exec
;
10938 exec
= xmlRelaxNGElemPop(ctxt
);
10939 while (exec
!= NULL
) {
10940 xmlRegFreeExecCtxt(exec
);
10941 exec
= xmlRelaxNGElemPop(ctxt
);
10943 xmlFree(ctxt
->elemTab
);
10949 * xmlRelaxNGSetValidErrors:
10950 * @ctxt: a Relax-NG validation context
10951 * @err: the error function
10952 * @warn: the warning function
10953 * @ctx: the functions context
10955 * Set the error and warning callback informations
10958 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
10959 xmlRelaxNGValidityErrorFunc err
,
10960 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
10965 ctxt
->warning
= warn
;
10966 ctxt
->userData
= ctx
;
10967 ctxt
->serror
= NULL
;
10971 * xmlRelaxNGSetValidStructuredErrors:
10972 * @ctxt: a Relax-NG validation context
10973 * @serror: the structured error function
10974 * @ctx: the functions context
10976 * Set the structured error callback
10979 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt
,
10980 xmlStructuredErrorFunc serror
, void *ctx
)
10984 ctxt
->serror
= serror
;
10985 ctxt
->error
= NULL
;
10986 ctxt
->warning
= NULL
;
10987 ctxt
->userData
= ctx
;
10991 * xmlRelaxNGGetValidErrors:
10992 * @ctxt: a Relax-NG validation context
10993 * @err: the error function result
10994 * @warn: the warning function result
10995 * @ctx: the functions context result
10997 * Get the error and warning callback informations
10999 * Returns -1 in case of error and 0 otherwise
11002 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
11003 xmlRelaxNGValidityErrorFunc
* err
,
11004 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
11009 *err
= ctxt
->error
;
11011 *warn
= ctxt
->warning
;
11013 *ctx
= ctxt
->userData
;
11018 * xmlRelaxNGValidateDoc:
11019 * @ctxt: a Relax-NG validation context
11020 * @doc: a parsed document tree
11022 * Validate a document tree in memory.
11024 * Returns 0 if the document is valid, a positive error code
11025 * number otherwise and -1 in case of internal or API error.
11028 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
11032 if ((ctxt
== NULL
) || (doc
== NULL
))
11037 ret
= xmlRelaxNGValidateDocument(ctxt
, doc
);
11039 * Remove all left PSVI
11041 xmlRelaxNGCleanPSVI((xmlNodePtr
) doc
);
11044 * TODO: build error codes
11051 #define bottom_relaxng
11052 #include "elfgcchack.h"
11053 #endif /* LIBXML_SCHEMAS_ENABLED */