2 * relaxng.c : implementation of the Relax-NG handling and validity checking
4 * See Copyright for the status of this software.
6 * Daniel Veillard <veillard@redhat.com>
11 * - add support for DTD compatibility spec
12 * http://www.oasis-open.org/committees/relax-ng/compatibility-20011203.html
13 * - report better mem allocations pbms at runtime and abort immediately.
19 #ifdef LIBXML_SCHEMAS_ENABLED
24 #include <libxml/xmlmemory.h>
25 #include <libxml/parser.h>
26 #include <libxml/parserInternals.h>
27 #include <libxml/hash.h>
28 #include <libxml/uri.h>
30 #include <libxml/relaxng.h>
32 #include <libxml/xmlschemastypes.h>
33 #include <libxml/xmlautomata.h>
34 #include <libxml/xmlregexp.h>
35 #include <libxml/xmlschemastypes.h>
38 * The Relax-NG namespace
40 static const xmlChar
*xmlRelaxNGNs
= (const xmlChar
*)
41 "http://relaxng.org/ns/structure/1.0";
43 #define IS_RELAXNG(node, typ) \
44 ((node != NULL) && (node->ns != NULL) && \
45 (node->type == XML_ELEMENT_NODE) && \
46 (xmlStrEqual(node->name, (const xmlChar *) typ)) && \
47 (xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
53 #define DEBUG_GRAMMAR 1
55 #define DEBUG_CONTENT 1
61 #define DEBUG_INTERLEAVE 1
65 #define DEBUG_INCLUDE 1
69 #define DEBUG_COMPILE 1
71 #define DEBUG_PROGRESSIVE 1
77 xmlGenericError(xmlGenericErrorContext, \
78 "Unimplemented block at %s:%d\n", \
81 typedef struct _xmlRelaxNGSchema xmlRelaxNGSchema
;
82 typedef xmlRelaxNGSchema
*xmlRelaxNGSchemaPtr
;
84 typedef struct _xmlRelaxNGDefine xmlRelaxNGDefine
;
85 typedef xmlRelaxNGDefine
*xmlRelaxNGDefinePtr
;
87 typedef struct _xmlRelaxNGDocument xmlRelaxNGDocument
;
88 typedef xmlRelaxNGDocument
*xmlRelaxNGDocumentPtr
;
90 typedef struct _xmlRelaxNGInclude xmlRelaxNGInclude
;
91 typedef xmlRelaxNGInclude
*xmlRelaxNGIncludePtr
;
94 XML_RELAXNG_COMBINE_UNDEFINED
= 0, /* undefined */
95 XML_RELAXNG_COMBINE_CHOICE
, /* choice */
96 XML_RELAXNG_COMBINE_INTERLEAVE
/* interleave */
100 XML_RELAXNG_CONTENT_ERROR
= -1,
101 XML_RELAXNG_CONTENT_EMPTY
= 0,
102 XML_RELAXNG_CONTENT_SIMPLE
,
103 XML_RELAXNG_CONTENT_COMPLEX
104 } xmlRelaxNGContentType
;
106 typedef struct _xmlRelaxNGGrammar xmlRelaxNGGrammar
;
107 typedef xmlRelaxNGGrammar
*xmlRelaxNGGrammarPtr
;
109 struct _xmlRelaxNGGrammar
{
110 xmlRelaxNGGrammarPtr parent
; /* the parent grammar if any */
111 xmlRelaxNGGrammarPtr children
; /* the children grammar if any */
112 xmlRelaxNGGrammarPtr next
; /* the next grammar if any */
113 xmlRelaxNGDefinePtr start
; /* <start> content */
114 xmlRelaxNGCombine combine
; /* the default combine value */
115 xmlRelaxNGDefinePtr startList
; /* list of <start> definitions */
116 xmlHashTablePtr defs
; /* define* */
117 xmlHashTablePtr refs
; /* references */
122 XML_RELAXNG_NOOP
= -1, /* a no operation from simplification */
123 XML_RELAXNG_EMPTY
= 0, /* an empty pattern */
124 XML_RELAXNG_NOT_ALLOWED
, /* not allowed top */
125 XML_RELAXNG_EXCEPT
, /* except present in nameclass defs */
126 XML_RELAXNG_TEXT
, /* textual content */
127 XML_RELAXNG_ELEMENT
, /* an element */
128 XML_RELAXNG_DATATYPE
, /* external data type definition */
129 XML_RELAXNG_PARAM
, /* external data type parameter */
130 XML_RELAXNG_VALUE
, /* value from an external data type definition */
131 XML_RELAXNG_LIST
, /* a list of patterns */
132 XML_RELAXNG_ATTRIBUTE
, /* an attribute following a pattern */
133 XML_RELAXNG_DEF
, /* a definition */
134 XML_RELAXNG_REF
, /* reference to a definition */
135 XML_RELAXNG_EXTERNALREF
, /* reference to an external def */
136 XML_RELAXNG_PARENTREF
, /* reference to a def in the parent grammar */
137 XML_RELAXNG_OPTIONAL
, /* optional patterns */
138 XML_RELAXNG_ZEROORMORE
, /* zero or more non empty patterns */
139 XML_RELAXNG_ONEORMORE
, /* one or more non empty patterns */
140 XML_RELAXNG_CHOICE
, /* a choice between non empty patterns */
141 XML_RELAXNG_GROUP
, /* a pair/group of non empty patterns */
142 XML_RELAXNG_INTERLEAVE
, /* interleaving choice of non-empty patterns */
143 XML_RELAXNG_START
/* Used to keep track of starts on grammars */
146 #define IS_NULLABLE (1 << 0)
147 #define IS_NOT_NULLABLE (1 << 1)
148 #define IS_INDETERMINIST (1 << 2)
149 #define IS_MIXED (1 << 3)
150 #define IS_TRIABLE (1 << 4)
151 #define IS_PROCESSED (1 << 5)
152 #define IS_COMPILABLE (1 << 6)
153 #define IS_NOT_COMPILABLE (1 << 7)
154 #define IS_EXTERNAL_REF (1 << 8)
156 struct _xmlRelaxNGDefine
{
157 xmlRelaxNGType type
; /* the type of definition */
158 xmlNodePtr node
; /* the node in the source */
159 xmlChar
*name
; /* the element local name if present */
160 xmlChar
*ns
; /* the namespace local name if present */
161 xmlChar
*value
; /* value when available */
162 void *data
; /* data lib or specific pointer */
163 xmlRelaxNGDefinePtr content
; /* the expected content */
164 xmlRelaxNGDefinePtr parent
; /* the parent definition, if any */
165 xmlRelaxNGDefinePtr next
; /* list within grouping sequences */
166 xmlRelaxNGDefinePtr attrs
; /* list of attributes for elements */
167 xmlRelaxNGDefinePtr nameClass
; /* the nameClass definition if any */
168 xmlRelaxNGDefinePtr nextHash
; /* next define in defs/refs hash tables */
169 short depth
; /* used for the cycle detection */
170 short dflags
; /* define related flags */
171 xmlRegexpPtr contModel
; /* a compiled content model if available */
177 * A RelaxNGs definition
180 void *_private
; /* unused by the library for users or bindings */
181 xmlRelaxNGGrammarPtr topgrammar
;
184 int idref
; /* requires idref checking */
186 xmlHashTablePtr defs
; /* define */
187 xmlHashTablePtr refs
; /* references */
188 xmlRelaxNGDocumentPtr documents
; /* all the documents loaded */
189 xmlRelaxNGIncludePtr includes
; /* all the includes loaded */
190 int defNr
; /* number of defines used */
191 xmlRelaxNGDefinePtr
*defTab
; /* pointer to the allocated definitions */
195 #define XML_RELAXNG_IN_ATTRIBUTE (1 << 0)
196 #define XML_RELAXNG_IN_ONEORMORE (1 << 1)
197 #define XML_RELAXNG_IN_LIST (1 << 2)
198 #define XML_RELAXNG_IN_DATAEXCEPT (1 << 3)
199 #define XML_RELAXNG_IN_START (1 << 4)
200 #define XML_RELAXNG_IN_OOMGROUP (1 << 5)
201 #define XML_RELAXNG_IN_OOMINTERLEAVE (1 << 6)
202 #define XML_RELAXNG_IN_EXTERNALREF (1 << 7)
203 #define XML_RELAXNG_IN_ANYEXCEPT (1 << 8)
204 #define XML_RELAXNG_IN_NSEXCEPT (1 << 9)
206 struct _xmlRelaxNGParserCtxt
{
207 void *userData
; /* user specific data block */
208 xmlRelaxNGValidityErrorFunc error
; /* the callback in case of errors */
209 xmlRelaxNGValidityWarningFunc warning
; /* the callback in case of warning */
210 xmlStructuredErrorFunc serror
;
211 xmlRelaxNGValidErr err
;
213 xmlRelaxNGPtr schema
; /* The schema in use */
214 xmlRelaxNGGrammarPtr grammar
; /* the current grammar */
215 xmlRelaxNGGrammarPtr parentgrammar
; /* the parent grammar */
216 int flags
; /* parser flags */
217 int nbErrors
; /* number of errors at parse time */
218 int nbWarnings
; /* number of warnings at parse time */
219 const xmlChar
*define
; /* the current define scope */
220 xmlRelaxNGDefinePtr def
; /* the current define */
223 xmlHashTablePtr interleaves
; /* keep track of all the interleaves */
225 xmlRelaxNGDocumentPtr documents
; /* all the documents loaded */
226 xmlRelaxNGIncludePtr includes
; /* all the includes loaded */
230 int defNr
; /* number of defines used */
231 int defMax
; /* number of defines allocated */
232 xmlRelaxNGDefinePtr
*defTab
; /* pointer to the allocated definitions */
237 /* the document stack */
238 xmlRelaxNGDocumentPtr doc
; /* Current parsed external ref */
239 int docNr
; /* Depth of the parsing stack */
240 int docMax
; /* Max depth of the parsing stack */
241 xmlRelaxNGDocumentPtr
*docTab
; /* array of docs */
243 /* the include stack */
244 xmlRelaxNGIncludePtr inc
; /* Current parsed include */
245 int incNr
; /* Depth of the include parsing stack */
246 int incMax
; /* Max depth of the parsing stack */
247 xmlRelaxNGIncludePtr
*incTab
; /* array of incs */
249 int idref
; /* requires idref checking */
251 /* used to compile content models */
252 xmlAutomataPtr am
; /* the automata */
253 xmlAutomataStatePtr state
; /* used to build the automata */
255 int crng
; /* compact syntax and other flags */
256 int freedoc
; /* need to free the document */
259 #define FLAGS_IGNORABLE 1
260 #define FLAGS_NEGATIVE 2
261 #define FLAGS_MIXED_CONTENT 4
262 #define FLAGS_NOERROR 8
265 * xmlRelaxNGInterleaveGroup:
267 * A RelaxNGs partition set associated to lists of definitions
269 typedef struct _xmlRelaxNGInterleaveGroup xmlRelaxNGInterleaveGroup
;
270 typedef xmlRelaxNGInterleaveGroup
*xmlRelaxNGInterleaveGroupPtr
;
271 struct _xmlRelaxNGInterleaveGroup
{
272 xmlRelaxNGDefinePtr rule
; /* the rule to satisfy */
273 xmlRelaxNGDefinePtr
*defs
; /* the array of element definitions */
274 xmlRelaxNGDefinePtr
*attrs
; /* the array of attributes definitions */
277 #define IS_DETERMINIST 1
278 #define IS_NEEDCHECK 2
281 * xmlRelaxNGPartitions:
283 * A RelaxNGs partition associated to an interleave group
285 typedef struct _xmlRelaxNGPartition xmlRelaxNGPartition
;
286 typedef xmlRelaxNGPartition
*xmlRelaxNGPartitionPtr
;
287 struct _xmlRelaxNGPartition
{
288 int nbgroups
; /* number of groups in the partitions */
289 xmlHashTablePtr triage
; /* hash table used to direct nodes to the
290 * right group when possible */
291 int flags
; /* determinist ? */
292 xmlRelaxNGInterleaveGroupPtr
*groups
;
296 * xmlRelaxNGValidState:
298 * A RelaxNGs validation state
301 typedef struct _xmlRelaxNGValidState xmlRelaxNGValidState
;
302 typedef xmlRelaxNGValidState
*xmlRelaxNGValidStatePtr
;
303 struct _xmlRelaxNGValidState
{
304 xmlNodePtr node
; /* the current node */
305 xmlNodePtr seq
; /* the sequence of children left to validate */
306 int nbAttrs
; /* the number of attributes */
307 int maxAttrs
; /* the size of attrs */
308 int nbAttrLeft
; /* the number of attributes left to validate */
309 xmlChar
*value
; /* the value when operating on string */
310 xmlChar
*endvalue
; /* the end value when operating on string */
311 xmlAttrPtr
*attrs
; /* the array of attributes */
317 * A RelaxNGs container for validation state
319 typedef struct _xmlRelaxNGStates xmlRelaxNGStates
;
320 typedef xmlRelaxNGStates
*xmlRelaxNGStatesPtr
;
321 struct _xmlRelaxNGStates
{
322 int nbState
; /* the number of states */
323 int maxState
; /* the size of the array */
324 xmlRelaxNGValidStatePtr
*tabState
;
327 #define ERROR_IS_DUP 1
330 * xmlRelaxNGValidError:
332 * A RelaxNGs validation error
334 typedef struct _xmlRelaxNGValidError xmlRelaxNGValidError
;
335 typedef xmlRelaxNGValidError
*xmlRelaxNGValidErrorPtr
;
336 struct _xmlRelaxNGValidError
{
337 xmlRelaxNGValidErr err
; /* the error number */
338 int flags
; /* flags */
339 xmlNodePtr node
; /* the current node */
340 xmlNodePtr seq
; /* the current child */
341 const xmlChar
*arg1
; /* first arg */
342 const xmlChar
*arg2
; /* second arg */
346 * xmlRelaxNGValidCtxt:
348 * A RelaxNGs validation context
351 struct _xmlRelaxNGValidCtxt
{
352 void *userData
; /* user specific data block */
353 xmlRelaxNGValidityErrorFunc error
; /* the callback in case of errors */
354 xmlRelaxNGValidityWarningFunc warning
; /* the callback in case of warning */
355 xmlStructuredErrorFunc serror
;
356 int nbErrors
; /* number of errors in validation */
358 xmlRelaxNGPtr schema
; /* The schema in use */
359 xmlDocPtr doc
; /* the document being validated */
360 int flags
; /* validation flags */
361 int depth
; /* validation depth */
362 int idref
; /* requires idref checking */
363 int errNo
; /* the first error found */
366 * Errors accumulated in branches may have to be stacked to be
367 * provided back when it's sure they affect validation.
369 xmlRelaxNGValidErrorPtr err
; /* Last error */
370 int errNr
; /* Depth of the error stack */
371 int errMax
; /* Max depth of the error stack */
372 xmlRelaxNGValidErrorPtr errTab
; /* stack of errors */
374 xmlRelaxNGValidStatePtr state
; /* the current validation state */
375 xmlRelaxNGStatesPtr states
; /* the accumulated state list */
377 xmlRelaxNGStatesPtr freeState
; /* the pool of free valid states */
380 xmlRelaxNGStatesPtr
*freeStates
; /* the pool of free state groups */
383 * This is used for "progressive" validation
385 xmlRegExecCtxtPtr elem
; /* the current element regexp */
386 int elemNr
; /* the number of element validated */
387 int elemMax
; /* the max depth of elements */
388 xmlRegExecCtxtPtr
*elemTab
; /* the stack of regexp runtime */
389 int pstate
; /* progressive state */
390 xmlNodePtr pnode
; /* the current node */
391 xmlRelaxNGDefinePtr pdef
; /* the non-streamable definition */
392 int perr
; /* signal error in content model
393 * outside the regexp */
399 * Structure associated to a RelaxNGs document element
401 struct _xmlRelaxNGInclude
{
402 xmlRelaxNGIncludePtr next
; /* keep a chain of includes */
403 xmlChar
*href
; /* the normalized href value */
404 xmlDocPtr doc
; /* the associated XML document */
405 xmlRelaxNGDefinePtr content
; /* the definitions */
406 xmlRelaxNGPtr schema
; /* the schema */
410 * xmlRelaxNGDocument:
412 * Structure associated to a RelaxNGs document element
414 struct _xmlRelaxNGDocument
{
415 xmlRelaxNGDocumentPtr next
; /* keep a chain of documents */
416 xmlChar
*href
; /* the normalized href value */
417 xmlDocPtr doc
; /* the associated XML document */
418 xmlRelaxNGDefinePtr content
; /* the definitions */
419 xmlRelaxNGPtr schema
; /* the schema */
420 int externalRef
; /* 1 if an external ref */
424 /************************************************************************
426 * Some factorized error routines *
428 ************************************************************************/
432 * @ctxt: an Relax-NG parser context
433 * @extra: extra information
435 * Handle a redefinition of attribute error
438 xmlRngPErrMemory(xmlRelaxNGParserCtxtPtr ctxt
, const char *extra
)
440 xmlStructuredErrorFunc schannel
= NULL
;
441 xmlGenericErrorFunc channel
= NULL
;
445 if (ctxt
->serror
!= NULL
)
446 schannel
= ctxt
->serror
;
448 channel
= ctxt
->error
;
449 data
= ctxt
->userData
;
453 __xmlRaiseError(schannel
, channel
, data
,
454 NULL
, NULL
, XML_FROM_RELAXNGP
,
455 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, extra
,
457 "Memory allocation failed : %s\n", extra
);
459 __xmlRaiseError(schannel
, channel
, data
,
460 NULL
, NULL
, XML_FROM_RELAXNGP
,
461 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, NULL
,
462 NULL
, NULL
, 0, 0, "Memory allocation failed\n");
467 * @ctxt: a Relax-NG validation context
468 * @extra: extra information
470 * Handle a redefinition of attribute error
473 xmlRngVErrMemory(xmlRelaxNGValidCtxtPtr ctxt
, const char *extra
)
475 xmlStructuredErrorFunc schannel
= NULL
;
476 xmlGenericErrorFunc channel
= NULL
;
480 if (ctxt
->serror
!= NULL
)
481 schannel
= ctxt
->serror
;
483 channel
= ctxt
->error
;
484 data
= ctxt
->userData
;
488 __xmlRaiseError(schannel
, channel
, data
,
489 NULL
, NULL
, XML_FROM_RELAXNGV
,
490 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, extra
,
492 "Memory allocation failed : %s\n", extra
);
494 __xmlRaiseError(schannel
, channel
, data
,
495 NULL
, NULL
, XML_FROM_RELAXNGV
,
496 XML_ERR_NO_MEMORY
, XML_ERR_FATAL
, NULL
, 0, NULL
,
497 NULL
, NULL
, 0, 0, "Memory allocation failed\n");
502 * @ctxt: a Relax-NG parser context
503 * @node: the node raising the error
504 * @error: the error code
509 * Handle a Relax NG Parsing error
511 static void LIBXML_ATTR_FORMAT(4,0)
512 xmlRngPErr(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
, int error
,
513 const char *msg
, const xmlChar
* str1
, const xmlChar
* str2
)
515 xmlStructuredErrorFunc schannel
= NULL
;
516 xmlGenericErrorFunc channel
= NULL
;
520 if (ctxt
->serror
!= NULL
)
521 schannel
= ctxt
->serror
;
523 channel
= ctxt
->error
;
524 data
= ctxt
->userData
;
527 __xmlRaiseError(schannel
, channel
, data
,
528 NULL
, node
, XML_FROM_RELAXNGP
,
529 error
, XML_ERR_ERROR
, NULL
, 0,
530 (const char *) str1
, (const char *) str2
, NULL
, 0, 0,
536 * @ctxt: a Relax-NG validation context
537 * @node: the node raising the error
538 * @error: the error code
543 * Handle a Relax NG Validation error
545 static void LIBXML_ATTR_FORMAT(4,0)
546 xmlRngVErr(xmlRelaxNGValidCtxtPtr ctxt
, xmlNodePtr node
, int error
,
547 const char *msg
, const xmlChar
* str1
, const xmlChar
* str2
)
549 xmlStructuredErrorFunc schannel
= NULL
;
550 xmlGenericErrorFunc channel
= NULL
;
554 if (ctxt
->serror
!= NULL
)
555 schannel
= ctxt
->serror
;
557 channel
= ctxt
->error
;
558 data
= ctxt
->userData
;
561 __xmlRaiseError(schannel
, channel
, data
,
562 NULL
, node
, XML_FROM_RELAXNGV
,
563 error
, XML_ERR_ERROR
, NULL
, 0,
564 (const char *) str1
, (const char *) str2
, NULL
, 0, 0,
568 /************************************************************************
570 * Preliminary type checking interfaces *
572 ************************************************************************/
575 * xmlRelaxNGTypeHave:
576 * @data: data needed for the library
577 * @type: the type name
578 * @value: the value to check
580 * Function provided by a type library to check if a type is exported
582 * Returns 1 if yes, 0 if no and -1 in case of error.
584 typedef int (*xmlRelaxNGTypeHave
) (void *data
, const xmlChar
* type
);
587 * xmlRelaxNGTypeCheck:
588 * @data: data needed for the library
589 * @type: the type name
590 * @value: the value to check
591 * @result: place to store the result if needed
593 * Function provided by a type library to check if a value match a type
595 * Returns 1 if yes, 0 if no and -1 in case of error.
597 typedef int (*xmlRelaxNGTypeCheck
) (void *data
, const xmlChar
* type
,
598 const xmlChar
* value
, void **result
,
602 * xmlRelaxNGFacetCheck:
603 * @data: data needed for the library
604 * @type: the type name
605 * @facet: the facet name
606 * @val: the facet value
607 * @strval: the string value
608 * @value: the value to check
610 * Function provided by a type library to check a value facet
612 * Returns 1 if yes, 0 if no and -1 in case of error.
614 typedef int (*xmlRelaxNGFacetCheck
) (void *data
, const xmlChar
* type
,
615 const xmlChar
* facet
,
617 const xmlChar
* strval
, void *value
);
620 * xmlRelaxNGTypeFree:
621 * @data: data needed for the library
622 * @result: the value to free
624 * Function provided by a type library to free a returned result
626 typedef void (*xmlRelaxNGTypeFree
) (void *data
, void *result
);
629 * xmlRelaxNGTypeCompare:
630 * @data: data needed for the library
631 * @type: the type name
632 * @value1: the first value
633 * @value2: the second value
635 * Function provided by a type library to compare two values accordingly
638 * Returns 1 if yes, 0 if no and -1 in case of error.
640 typedef int (*xmlRelaxNGTypeCompare
) (void *data
, const xmlChar
* type
,
641 const xmlChar
* value1
,
644 const xmlChar
* value2
,
646 typedef struct _xmlRelaxNGTypeLibrary xmlRelaxNGTypeLibrary
;
647 typedef xmlRelaxNGTypeLibrary
*xmlRelaxNGTypeLibraryPtr
;
648 struct _xmlRelaxNGTypeLibrary
{
649 const xmlChar
*namespace; /* the datatypeLibrary value */
650 void *data
; /* data needed for the library */
651 xmlRelaxNGTypeHave have
; /* the export function */
652 xmlRelaxNGTypeCheck check
; /* the checking function */
653 xmlRelaxNGTypeCompare comp
; /* the compare function */
654 xmlRelaxNGFacetCheck facet
; /* the facet check function */
655 xmlRelaxNGTypeFree freef
; /* the freeing function */
658 /************************************************************************
660 * Allocation functions *
662 ************************************************************************/
663 static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar
);
664 static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define
);
665 static void xmlRelaxNGNormExtSpace(xmlChar
* value
);
666 static void xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema
);
667 static int xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt
669 xmlRelaxNGValidStatePtr state1
,
670 xmlRelaxNGValidStatePtr state2
);
671 static void xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt
,
672 xmlRelaxNGValidStatePtr state
);
675 * xmlRelaxNGFreeDocument:
676 * @docu: a document structure
678 * Deallocate a RelaxNG document structure.
681 xmlRelaxNGFreeDocument(xmlRelaxNGDocumentPtr docu
)
686 if (docu
->href
!= NULL
)
688 if (docu
->doc
!= NULL
)
689 xmlFreeDoc(docu
->doc
);
690 if (docu
->schema
!= NULL
)
691 xmlRelaxNGFreeInnerSchema(docu
->schema
);
696 * xmlRelaxNGFreeDocumentList:
697 * @docu: a list of document structure
699 * Deallocate a RelaxNG document structures.
702 xmlRelaxNGFreeDocumentList(xmlRelaxNGDocumentPtr docu
)
704 xmlRelaxNGDocumentPtr next
;
706 while (docu
!= NULL
) {
708 xmlRelaxNGFreeDocument(docu
);
714 * xmlRelaxNGFreeInclude:
715 * @incl: a include structure
717 * Deallocate a RelaxNG include structure.
720 xmlRelaxNGFreeInclude(xmlRelaxNGIncludePtr incl
)
725 if (incl
->href
!= NULL
)
727 if (incl
->doc
!= NULL
)
728 xmlFreeDoc(incl
->doc
);
729 if (incl
->schema
!= NULL
)
730 xmlRelaxNGFree(incl
->schema
);
735 * xmlRelaxNGFreeIncludeList:
736 * @incl: a include structure list
738 * Deallocate a RelaxNG include structure.
741 xmlRelaxNGFreeIncludeList(xmlRelaxNGIncludePtr incl
)
743 xmlRelaxNGIncludePtr next
;
745 while (incl
!= NULL
) {
747 xmlRelaxNGFreeInclude(incl
);
753 * xmlRelaxNGNewRelaxNG:
754 * @ctxt: a Relax-NG validation context (optional)
756 * Allocate a new RelaxNG structure.
758 * Returns the newly allocated structure or NULL in case or error
761 xmlRelaxNGNewRelaxNG(xmlRelaxNGParserCtxtPtr ctxt
)
765 ret
= (xmlRelaxNGPtr
) xmlMalloc(sizeof(xmlRelaxNG
));
767 xmlRngPErrMemory(ctxt
, NULL
);
770 memset(ret
, 0, sizeof(xmlRelaxNG
));
776 * xmlRelaxNGFreeInnerSchema:
777 * @schema: a schema structure
779 * Deallocate a RelaxNG schema structure.
782 xmlRelaxNGFreeInnerSchema(xmlRelaxNGPtr schema
)
787 if (schema
->doc
!= NULL
)
788 xmlFreeDoc(schema
->doc
);
789 if (schema
->defTab
!= NULL
) {
792 for (i
= 0; i
< schema
->defNr
; i
++)
793 xmlRelaxNGFreeDefine(schema
->defTab
[i
]);
794 xmlFree(schema
->defTab
);
802 * @schema: a schema structure
804 * Deallocate a RelaxNG structure.
807 xmlRelaxNGFree(xmlRelaxNGPtr schema
)
812 if (schema
->topgrammar
!= NULL
)
813 xmlRelaxNGFreeGrammar(schema
->topgrammar
);
814 if (schema
->doc
!= NULL
)
815 xmlFreeDoc(schema
->doc
);
816 if (schema
->documents
!= NULL
)
817 xmlRelaxNGFreeDocumentList(schema
->documents
);
818 if (schema
->includes
!= NULL
)
819 xmlRelaxNGFreeIncludeList(schema
->includes
);
820 if (schema
->defTab
!= NULL
) {
823 for (i
= 0; i
< schema
->defNr
; i
++)
824 xmlRelaxNGFreeDefine(schema
->defTab
[i
]);
825 xmlFree(schema
->defTab
);
832 * xmlRelaxNGNewGrammar:
833 * @ctxt: a Relax-NG validation context (optional)
835 * Allocate a new RelaxNG grammar.
837 * Returns the newly allocated structure or NULL in case or error
839 static xmlRelaxNGGrammarPtr
840 xmlRelaxNGNewGrammar(xmlRelaxNGParserCtxtPtr ctxt
)
842 xmlRelaxNGGrammarPtr ret
;
844 ret
= (xmlRelaxNGGrammarPtr
) xmlMalloc(sizeof(xmlRelaxNGGrammar
));
846 xmlRngPErrMemory(ctxt
, NULL
);
849 memset(ret
, 0, sizeof(xmlRelaxNGGrammar
));
855 * xmlRelaxNGFreeGrammar:
856 * @grammar: a grammar structure
858 * Deallocate a RelaxNG grammar structure.
861 xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar
)
866 if (grammar
->children
!= NULL
) {
867 xmlRelaxNGFreeGrammar(grammar
->children
);
869 if (grammar
->next
!= NULL
) {
870 xmlRelaxNGFreeGrammar(grammar
->next
);
872 if (grammar
->refs
!= NULL
) {
873 xmlHashFree(grammar
->refs
, NULL
);
875 if (grammar
->defs
!= NULL
) {
876 xmlHashFree(grammar
->defs
, NULL
);
883 * xmlRelaxNGNewDefine:
884 * @ctxt: a Relax-NG validation context
885 * @node: the node in the input document.
887 * Allocate a new RelaxNG define.
889 * Returns the newly allocated structure or NULL in case or error
891 static xmlRelaxNGDefinePtr
892 xmlRelaxNGNewDefine(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
894 xmlRelaxNGDefinePtr ret
;
896 if (ctxt
->defMax
== 0) {
899 ctxt
->defTab
= (xmlRelaxNGDefinePtr
*)
900 xmlMalloc(ctxt
->defMax
* sizeof(xmlRelaxNGDefinePtr
));
901 if (ctxt
->defTab
== NULL
) {
902 xmlRngPErrMemory(ctxt
, "allocating define\n");
905 } else if (ctxt
->defMax
<= ctxt
->defNr
) {
906 xmlRelaxNGDefinePtr
*tmp
;
909 tmp
= (xmlRelaxNGDefinePtr
*) xmlRealloc(ctxt
->defTab
,
912 (xmlRelaxNGDefinePtr
));
914 xmlRngPErrMemory(ctxt
, "allocating define\n");
919 ret
= (xmlRelaxNGDefinePtr
) xmlMalloc(sizeof(xmlRelaxNGDefine
));
921 xmlRngPErrMemory(ctxt
, "allocating define\n");
924 memset(ret
, 0, sizeof(xmlRelaxNGDefine
));
925 ctxt
->defTab
[ctxt
->defNr
++] = ret
;
932 * xmlRelaxNGFreePartition:
933 * @partitions: a partition set structure
935 * Deallocate RelaxNG partition set structures.
938 xmlRelaxNGFreePartition(xmlRelaxNGPartitionPtr partitions
)
940 xmlRelaxNGInterleaveGroupPtr group
;
943 if (partitions
!= NULL
) {
944 if (partitions
->groups
!= NULL
) {
945 for (j
= 0; j
< partitions
->nbgroups
; j
++) {
946 group
= partitions
->groups
[j
];
948 if (group
->defs
!= NULL
)
949 xmlFree(group
->defs
);
950 if (group
->attrs
!= NULL
)
951 xmlFree(group
->attrs
);
955 xmlFree(partitions
->groups
);
957 if (partitions
->triage
!= NULL
) {
958 xmlHashFree(partitions
->triage
, NULL
);
965 * xmlRelaxNGFreeDefine:
966 * @define: a define structure
968 * Deallocate a RelaxNG define structure.
971 xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define
)
976 if ((define
->type
== XML_RELAXNG_VALUE
) && (define
->attrs
!= NULL
)) {
977 xmlRelaxNGTypeLibraryPtr lib
;
979 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
980 if ((lib
!= NULL
) && (lib
->freef
!= NULL
))
981 lib
->freef(lib
->data
, (void *) define
->attrs
);
983 if ((define
->data
!= NULL
) && (define
->type
== XML_RELAXNG_INTERLEAVE
))
984 xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr
) define
->data
);
985 if ((define
->data
!= NULL
) && (define
->type
== XML_RELAXNG_CHOICE
))
986 xmlHashFree((xmlHashTablePtr
) define
->data
, NULL
);
987 if (define
->name
!= NULL
)
988 xmlFree(define
->name
);
989 if (define
->ns
!= NULL
)
991 if (define
->value
!= NULL
)
992 xmlFree(define
->value
);
993 if (define
->contModel
!= NULL
)
994 xmlRegFreeRegexp(define
->contModel
);
999 * xmlRelaxNGNewStates:
1000 * @ctxt: a Relax-NG validation context
1001 * @size: the default size for the container
1003 * Allocate a new RelaxNG validation state container
1005 * Returns the newly allocated structure or NULL in case or error
1007 static xmlRelaxNGStatesPtr
1008 xmlRelaxNGNewStates(xmlRelaxNGValidCtxtPtr ctxt
, int size
)
1010 xmlRelaxNGStatesPtr ret
;
1012 if ((ctxt
!= NULL
) &&
1013 (ctxt
->freeStates
!= NULL
) && (ctxt
->freeStatesNr
> 0)) {
1014 ctxt
->freeStatesNr
--;
1015 ret
= ctxt
->freeStates
[ctxt
->freeStatesNr
];
1022 ret
= (xmlRelaxNGStatesPtr
) xmlMalloc(sizeof(xmlRelaxNGStates
) +
1025 sizeof(xmlRelaxNGValidStatePtr
));
1027 xmlRngVErrMemory(ctxt
, "allocating states\n");
1031 ret
->maxState
= size
;
1032 ret
->tabState
= (xmlRelaxNGValidStatePtr
*) xmlMalloc((size
) *
1034 (xmlRelaxNGValidStatePtr
));
1035 if (ret
->tabState
== NULL
) {
1036 xmlRngVErrMemory(ctxt
, "allocating states\n");
1044 * xmlRelaxNGAddStateUniq:
1045 * @ctxt: a Relax-NG validation context
1046 * @states: the states container
1047 * @state: the validation state
1049 * Add a RelaxNG validation state to the container without checking
1052 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1055 xmlRelaxNGAddStatesUniq(xmlRelaxNGValidCtxtPtr ctxt
,
1056 xmlRelaxNGStatesPtr states
,
1057 xmlRelaxNGValidStatePtr state
)
1059 if (state
== NULL
) {
1062 if (states
->nbState
>= states
->maxState
) {
1063 xmlRelaxNGValidStatePtr
*tmp
;
1066 size
= states
->maxState
* 2;
1067 tmp
= (xmlRelaxNGValidStatePtr
*) xmlRealloc(states
->tabState
,
1070 (xmlRelaxNGValidStatePtr
));
1072 xmlRngVErrMemory(ctxt
, "adding states\n");
1075 states
->tabState
= tmp
;
1076 states
->maxState
= size
;
1078 states
->tabState
[states
->nbState
++] = state
;
1083 * xmlRelaxNGAddState:
1084 * @ctxt: a Relax-NG validation context
1085 * @states: the states container
1086 * @state: the validation state
1088 * Add a RelaxNG validation state to the container
1090 * Return 1 in case of success and 0 if this is a duplicate and -1 on error
1093 xmlRelaxNGAddStates(xmlRelaxNGValidCtxtPtr ctxt
,
1094 xmlRelaxNGStatesPtr states
,
1095 xmlRelaxNGValidStatePtr state
)
1099 if (state
== NULL
|| states
== NULL
) {
1102 if (states
->nbState
>= states
->maxState
) {
1103 xmlRelaxNGValidStatePtr
*tmp
;
1106 size
= states
->maxState
* 2;
1107 tmp
= (xmlRelaxNGValidStatePtr
*) xmlRealloc(states
->tabState
,
1110 (xmlRelaxNGValidStatePtr
));
1112 xmlRngVErrMemory(ctxt
, "adding states\n");
1115 states
->tabState
= tmp
;
1116 states
->maxState
= size
;
1118 for (i
= 0; i
< states
->nbState
; i
++) {
1119 if (xmlRelaxNGEqualValidState(ctxt
, state
, states
->tabState
[i
])) {
1120 xmlRelaxNGFreeValidState(ctxt
, state
);
1124 states
->tabState
[states
->nbState
++] = state
;
1129 * xmlRelaxNGFreeStates:
1130 * @ctxt: a Relax-NG validation context
1131 * @states: the container
1133 * Free a RelaxNG validation state container
1136 xmlRelaxNGFreeStates(xmlRelaxNGValidCtxtPtr ctxt
,
1137 xmlRelaxNGStatesPtr states
)
1141 if ((ctxt
!= NULL
) && (ctxt
->freeStates
== NULL
)) {
1142 ctxt
->freeStatesMax
= 40;
1143 ctxt
->freeStatesNr
= 0;
1144 ctxt
->freeStates
= (xmlRelaxNGStatesPtr
*)
1145 xmlMalloc(ctxt
->freeStatesMax
* sizeof(xmlRelaxNGStatesPtr
));
1146 if (ctxt
->freeStates
== NULL
) {
1147 xmlRngVErrMemory(ctxt
, "storing states\n");
1149 } else if ((ctxt
!= NULL
)
1150 && (ctxt
->freeStatesNr
>= ctxt
->freeStatesMax
)) {
1151 xmlRelaxNGStatesPtr
*tmp
;
1153 tmp
= (xmlRelaxNGStatesPtr
*) xmlRealloc(ctxt
->freeStates
,
1154 2 * ctxt
->freeStatesMax
*
1156 (xmlRelaxNGStatesPtr
));
1158 xmlRngVErrMemory(ctxt
, "storing states\n");
1159 xmlFree(states
->tabState
);
1163 ctxt
->freeStates
= tmp
;
1164 ctxt
->freeStatesMax
*= 2;
1166 if ((ctxt
== NULL
) || (ctxt
->freeStates
== NULL
)) {
1167 xmlFree(states
->tabState
);
1170 ctxt
->freeStates
[ctxt
->freeStatesNr
++] = states
;
1175 * xmlRelaxNGNewValidState:
1176 * @ctxt: a Relax-NG validation context
1177 * @node: the current node or NULL for the document
1179 * Allocate a new RelaxNG validation state
1181 * Returns the newly allocated structure or NULL in case or error
1183 static xmlRelaxNGValidStatePtr
1184 xmlRelaxNGNewValidState(xmlRelaxNGValidCtxtPtr ctxt
, xmlNodePtr node
)
1186 xmlRelaxNGValidStatePtr ret
;
1188 xmlAttrPtr attrs
[MAX_ATTR
];
1190 xmlNodePtr root
= NULL
;
1193 root
= xmlDocGetRootElement(ctxt
->doc
);
1197 attr
= node
->properties
;
1198 while (attr
!= NULL
) {
1199 if (nbAttrs
< MAX_ATTR
)
1200 attrs
[nbAttrs
++] = attr
;
1206 if ((ctxt
->freeState
!= NULL
) && (ctxt
->freeState
->nbState
> 0)) {
1207 ctxt
->freeState
->nbState
--;
1208 ret
= ctxt
->freeState
->tabState
[ctxt
->freeState
->nbState
];
1211 (xmlRelaxNGValidStatePtr
)
1212 xmlMalloc(sizeof(xmlRelaxNGValidState
));
1214 xmlRngVErrMemory(ctxt
, "allocating states\n");
1217 memset(ret
, 0, sizeof(xmlRelaxNGValidState
));
1220 ret
->endvalue
= NULL
;
1222 ret
->node
= (xmlNodePtr
) ctxt
->doc
;
1226 ret
->seq
= node
->children
;
1230 if (ret
->attrs
== NULL
) {
1234 ret
->maxAttrs
= nbAttrs
;
1235 ret
->attrs
= (xmlAttrPtr
*) xmlMalloc(ret
->maxAttrs
*
1236 sizeof(xmlAttrPtr
));
1237 if (ret
->attrs
== NULL
) {
1238 xmlRngVErrMemory(ctxt
, "allocating states\n");
1241 } else if (ret
->maxAttrs
< nbAttrs
) {
1244 tmp
= (xmlAttrPtr
*) xmlRealloc(ret
->attrs
, nbAttrs
*
1245 sizeof(xmlAttrPtr
));
1247 xmlRngVErrMemory(ctxt
, "allocating states\n");
1251 ret
->maxAttrs
= nbAttrs
;
1253 ret
->nbAttrs
= nbAttrs
;
1254 if (nbAttrs
< MAX_ATTR
) {
1255 memcpy(ret
->attrs
, attrs
, sizeof(xmlAttrPtr
) * nbAttrs
);
1257 attr
= node
->properties
;
1259 while (attr
!= NULL
) {
1260 ret
->attrs
[nbAttrs
++] = attr
;
1265 ret
->nbAttrLeft
= ret
->nbAttrs
;
1270 * xmlRelaxNGCopyValidState:
1271 * @ctxt: a Relax-NG validation context
1272 * @state: a validation state
1274 * Copy the validation state
1276 * Returns the newly allocated structure or NULL in case or error
1278 static xmlRelaxNGValidStatePtr
1279 xmlRelaxNGCopyValidState(xmlRelaxNGValidCtxtPtr ctxt
,
1280 xmlRelaxNGValidStatePtr state
)
1282 xmlRelaxNGValidStatePtr ret
;
1283 unsigned int maxAttrs
;
1288 if ((ctxt
->freeState
!= NULL
) && (ctxt
->freeState
->nbState
> 0)) {
1289 ctxt
->freeState
->nbState
--;
1290 ret
= ctxt
->freeState
->tabState
[ctxt
->freeState
->nbState
];
1293 (xmlRelaxNGValidStatePtr
)
1294 xmlMalloc(sizeof(xmlRelaxNGValidState
));
1296 xmlRngVErrMemory(ctxt
, "allocating states\n");
1299 memset(ret
, 0, sizeof(xmlRelaxNGValidState
));
1302 maxAttrs
= ret
->maxAttrs
;
1303 memcpy(ret
, state
, sizeof(xmlRelaxNGValidState
));
1305 ret
->maxAttrs
= maxAttrs
;
1306 if (state
->nbAttrs
> 0) {
1307 if (ret
->attrs
== NULL
) {
1308 ret
->maxAttrs
= state
->maxAttrs
;
1309 ret
->attrs
= (xmlAttrPtr
*) xmlMalloc(ret
->maxAttrs
*
1310 sizeof(xmlAttrPtr
));
1311 if (ret
->attrs
== NULL
) {
1312 xmlRngVErrMemory(ctxt
, "allocating states\n");
1316 } else if (ret
->maxAttrs
< state
->nbAttrs
) {
1319 tmp
= (xmlAttrPtr
*) xmlRealloc(ret
->attrs
, state
->maxAttrs
*
1320 sizeof(xmlAttrPtr
));
1322 xmlRngVErrMemory(ctxt
, "allocating states\n");
1326 ret
->maxAttrs
= state
->maxAttrs
;
1329 memcpy(ret
->attrs
, state
->attrs
,
1330 state
->nbAttrs
* sizeof(xmlAttrPtr
));
1336 * xmlRelaxNGEqualValidState:
1337 * @ctxt: a Relax-NG validation context
1338 * @state1: a validation state
1339 * @state2: a validation state
1341 * Compare the validation states for equality
1343 * Returns 1 if equal, 0 otherwise
1346 xmlRelaxNGEqualValidState(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
1347 xmlRelaxNGValidStatePtr state1
,
1348 xmlRelaxNGValidStatePtr state2
)
1352 if ((state1
== NULL
) || (state2
== NULL
))
1354 if (state1
== state2
)
1356 if (state1
->node
!= state2
->node
)
1358 if (state1
->seq
!= state2
->seq
)
1360 if (state1
->nbAttrLeft
!= state2
->nbAttrLeft
)
1362 if (state1
->nbAttrs
!= state2
->nbAttrs
)
1364 if (state1
->endvalue
!= state2
->endvalue
)
1366 if ((state1
->value
!= state2
->value
) &&
1367 (!xmlStrEqual(state1
->value
, state2
->value
)))
1369 for (i
= 0; i
< state1
->nbAttrs
; i
++) {
1370 if (state1
->attrs
[i
] != state2
->attrs
[i
])
1377 * xmlRelaxNGFreeValidState:
1378 * @state: a validation state structure
1380 * Deallocate a RelaxNG validation state structure.
1383 xmlRelaxNGFreeValidState(xmlRelaxNGValidCtxtPtr ctxt
,
1384 xmlRelaxNGValidStatePtr state
)
1389 if ((ctxt
!= NULL
) && (ctxt
->freeState
== NULL
)) {
1390 ctxt
->freeState
= xmlRelaxNGNewStates(ctxt
, 40);
1392 if ((ctxt
== NULL
) || (ctxt
->freeState
== NULL
)) {
1393 if (state
->attrs
!= NULL
)
1394 xmlFree(state
->attrs
);
1397 xmlRelaxNGAddStatesUniq(ctxt
, ctxt
->freeState
, state
);
1401 /************************************************************************
1403 * Semi internal functions *
1405 ************************************************************************/
1408 * xmlRelaxParserSetFlag:
1409 * @ctxt: a RelaxNG parser context
1410 * @flags: a set of flags values
1412 * Semi private function used to pass information to a parser context
1413 * which are a combination of xmlRelaxNGParserFlag .
1415 * Returns 0 if success and -1 in case of error
1418 xmlRelaxParserSetFlag(xmlRelaxNGParserCtxtPtr ctxt
, int flags
)
1420 if (ctxt
== NULL
) return(-1);
1421 if (flags
& XML_RELAXNGP_FREE_DOC
) {
1422 ctxt
->crng
|= XML_RELAXNGP_FREE_DOC
;
1423 flags
-= XML_RELAXNGP_FREE_DOC
;
1425 if (flags
& XML_RELAXNGP_CRNG
) {
1426 ctxt
->crng
|= XML_RELAXNGP_CRNG
;
1427 flags
-= XML_RELAXNGP_CRNG
;
1429 if (flags
!= 0) return(-1);
1433 /************************************************************************
1435 * Document functions *
1437 ************************************************************************/
1438 static xmlDocPtr
xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
,
1442 * xmlRelaxNGIncludePush:
1443 * @ctxt: the parser context
1444 * @value: the element doc
1446 * Pushes a new include on top of the include stack
1448 * Returns 0 in case of error, the index in the stack otherwise
1451 xmlRelaxNGIncludePush(xmlRelaxNGParserCtxtPtr ctxt
,
1452 xmlRelaxNGIncludePtr value
)
1454 if (ctxt
->incTab
== NULL
) {
1458 (xmlRelaxNGIncludePtr
*) xmlMalloc(ctxt
->incMax
*
1459 sizeof(ctxt
->incTab
[0]));
1460 if (ctxt
->incTab
== NULL
) {
1461 xmlRngPErrMemory(ctxt
, "allocating include\n");
1465 if (ctxt
->incNr
>= ctxt
->incMax
) {
1468 (xmlRelaxNGIncludePtr
*) xmlRealloc(ctxt
->incTab
,
1470 sizeof(ctxt
->incTab
[0]));
1471 if (ctxt
->incTab
== NULL
) {
1472 xmlRngPErrMemory(ctxt
, "allocating include\n");
1476 ctxt
->incTab
[ctxt
->incNr
] = value
;
1478 return (ctxt
->incNr
++);
1482 * xmlRelaxNGIncludePop:
1483 * @ctxt: the parser context
1485 * Pops the top include from the include stack
1487 * Returns the include just removed
1489 static xmlRelaxNGIncludePtr
1490 xmlRelaxNGIncludePop(xmlRelaxNGParserCtxtPtr ctxt
)
1492 xmlRelaxNGIncludePtr ret
;
1494 if (ctxt
->incNr
<= 0)
1497 if (ctxt
->incNr
> 0)
1498 ctxt
->inc
= ctxt
->incTab
[ctxt
->incNr
- 1];
1501 ret
= ctxt
->incTab
[ctxt
->incNr
];
1502 ctxt
->incTab
[ctxt
->incNr
] = NULL
;
1507 * xmlRelaxNGRemoveRedefine:
1508 * @ctxt: the parser context
1509 * @URL: the normalized URL
1510 * @target: the included target
1511 * @name: the define name to eliminate
1513 * Applies the elimination algorithm of 4.7
1515 * Returns 0 in case of error, 1 in case of success.
1518 xmlRelaxNGRemoveRedefine(xmlRelaxNGParserCtxtPtr ctxt
,
1519 const xmlChar
* URL ATTRIBUTE_UNUSED
,
1520 xmlNodePtr target
, const xmlChar
* name
)
1523 xmlNodePtr tmp
, tmp2
;
1526 #ifdef DEBUG_INCLUDE
1528 xmlGenericError(xmlGenericErrorContext
,
1529 "Elimination of <include> start from %s\n", URL
);
1531 xmlGenericError(xmlGenericErrorContext
,
1532 "Elimination of <include> define %s from %s\n",
1536 while (tmp
!= NULL
) {
1538 if ((name
== NULL
) && (IS_RELAXNG(tmp
, "start"))) {
1542 } else if ((name
!= NULL
) && (IS_RELAXNG(tmp
, "define"))) {
1543 name2
= xmlGetProp(tmp
, BAD_CAST
"name");
1544 xmlRelaxNGNormExtSpace(name2
);
1545 if (name2
!= NULL
) {
1546 if (xmlStrEqual(name
, name2
)) {
1553 } else if (IS_RELAXNG(tmp
, "include")) {
1554 xmlChar
*href
= NULL
;
1555 xmlRelaxNGDocumentPtr inc
= tmp
->psvi
;
1557 if ((inc
!= NULL
) && (inc
->doc
!= NULL
) &&
1558 (inc
->doc
->children
!= NULL
)) {
1561 (inc
->doc
->children
->name
, BAD_CAST
"grammar")) {
1562 #ifdef DEBUG_INCLUDE
1563 href
= xmlGetProp(tmp
, BAD_CAST
"href");
1565 if (xmlRelaxNGRemoveRedefine(ctxt
, href
,
1566 xmlDocGetRootElement(inc
->doc
)->children
,
1570 #ifdef DEBUG_INCLUDE
1576 if (xmlRelaxNGRemoveRedefine(ctxt
, URL
, tmp
->children
, name
) == 1) {
1586 * xmlRelaxNGLoadInclude:
1587 * @ctxt: the parser context
1588 * @URL: the normalized URL
1589 * @node: the include node.
1590 * @ns: the namespace passed from the context.
1592 * First lookup if the document is already loaded into the parser context,
1593 * check against recursion. If not found the resource is loaded and
1594 * the content is preprocessed before being returned back to the caller.
1596 * Returns the xmlRelaxNGIncludePtr or NULL in case of error
1598 static xmlRelaxNGIncludePtr
1599 xmlRelaxNGLoadInclude(xmlRelaxNGParserCtxtPtr ctxt
, const xmlChar
* URL
,
1600 xmlNodePtr node
, const xmlChar
* ns
)
1602 xmlRelaxNGIncludePtr ret
= NULL
;
1605 xmlNodePtr root
, cur
;
1607 #ifdef DEBUG_INCLUDE
1608 xmlGenericError(xmlGenericErrorContext
,
1609 "xmlRelaxNGLoadInclude(%s)\n", URL
);
1613 * check against recursion in the stack
1615 for (i
= 0; i
< ctxt
->incNr
; i
++) {
1616 if (xmlStrEqual(ctxt
->incTab
[i
]->href
, URL
)) {
1617 xmlRngPErr(ctxt
, NULL
, XML_RNGP_INCLUDE_RECURSE
,
1618 "Detected an Include recursion for %s\n", URL
,
1627 doc
= xmlReadFile((const char *) URL
,NULL
,0);
1629 xmlRngPErr(ctxt
, node
, XML_RNGP_PARSE_ERROR
,
1630 "xmlRelaxNG: could not load %s\n", URL
, NULL
);
1633 #ifdef DEBUG_INCLUDE
1634 xmlGenericError(xmlGenericErrorContext
, "Parsed %s Okay\n", URL
);
1638 * Allocate the document structures and register it first.
1640 ret
= (xmlRelaxNGIncludePtr
) xmlMalloc(sizeof(xmlRelaxNGInclude
));
1642 xmlRngPErrMemory(ctxt
, "allocating include\n");
1646 memset(ret
, 0, sizeof(xmlRelaxNGInclude
));
1648 ret
->href
= xmlStrdup(URL
);
1649 ret
->next
= ctxt
->includes
;
1650 ctxt
->includes
= ret
;
1653 * transmit the ns if needed
1656 root
= xmlDocGetRootElement(doc
);
1658 if (xmlHasProp(root
, BAD_CAST
"ns") == NULL
) {
1659 xmlSetProp(root
, BAD_CAST
"ns", ns
);
1665 * push it on the stack
1667 xmlRelaxNGIncludePush(ctxt
, ret
);
1670 * Some preprocessing of the document content, this include recursing
1671 * in the include stack.
1673 #ifdef DEBUG_INCLUDE
1674 xmlGenericError(xmlGenericErrorContext
, "cleanup of %s\n", URL
);
1677 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
1684 * Pop up the include from the stack
1686 xmlRelaxNGIncludePop(ctxt
);
1688 #ifdef DEBUG_INCLUDE
1689 xmlGenericError(xmlGenericErrorContext
, "Checking of %s\n", URL
);
1692 * Check that the top element is a grammar
1694 root
= xmlDocGetRootElement(doc
);
1696 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY
,
1697 "xmlRelaxNG: included document is empty %s\n", URL
,
1701 if (!IS_RELAXNG(root
, "grammar")) {
1702 xmlRngPErr(ctxt
, node
, XML_RNGP_GRAMMAR_MISSING
,
1703 "xmlRelaxNG: included document %s root is not a grammar\n",
1709 * Elimination of redefined rules in the include.
1711 cur
= node
->children
;
1712 while (cur
!= NULL
) {
1713 if (IS_RELAXNG(cur
, "start")) {
1717 xmlRelaxNGRemoveRedefine(ctxt
, URL
, root
->children
, NULL
);
1719 xmlRngPErr(ctxt
, node
, XML_RNGP_START_MISSING
,
1720 "xmlRelaxNG: include %s has a start but not the included grammar\n",
1723 } else if (IS_RELAXNG(cur
, "define")) {
1726 name
= xmlGetProp(cur
, BAD_CAST
"name");
1728 xmlRngPErr(ctxt
, node
, XML_RNGP_NAME_MISSING
,
1729 "xmlRelaxNG: include %s has define without name\n",
1734 xmlRelaxNGNormExtSpace(name
);
1735 found
= xmlRelaxNGRemoveRedefine(ctxt
, URL
,
1736 root
->children
, name
);
1738 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_MISSING
,
1739 "xmlRelaxNG: include %s has a define %s but not the included grammar\n",
1745 if (IS_RELAXNG(cur
, "div") && cur
->children
!= NULL
) {
1746 cur
= cur
->children
;
1748 if (cur
->next
!= NULL
) {
1751 while (cur
->parent
!= node
&& cur
->parent
->next
== NULL
) {
1754 cur
= cur
->parent
!= node
? cur
->parent
->next
: NULL
;
1764 * xmlRelaxNGValidErrorPush:
1765 * @ctxt: the validation context
1766 * @err: the error code
1767 * @arg1: the first string argument
1768 * @arg2: the second string argument
1769 * @dup: arg need to be duplicated
1771 * Pushes a new error on top of the error stack
1773 * Returns 0 in case of error, the index in the stack otherwise
1776 xmlRelaxNGValidErrorPush(xmlRelaxNGValidCtxtPtr ctxt
,
1777 xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
1778 const xmlChar
* arg2
, int dup
)
1780 xmlRelaxNGValidErrorPtr cur
;
1783 xmlGenericError(xmlGenericErrorContext
,
1784 "Pushing error %d at %d on stack\n", err
, ctxt
->errNr
);
1786 if (ctxt
->errTab
== NULL
) {
1790 (xmlRelaxNGValidErrorPtr
) xmlMalloc(ctxt
->errMax
*
1792 (xmlRelaxNGValidError
));
1793 if (ctxt
->errTab
== NULL
) {
1794 xmlRngVErrMemory(ctxt
, "pushing error\n");
1799 if (ctxt
->errNr
>= ctxt
->errMax
) {
1802 (xmlRelaxNGValidErrorPtr
) xmlRealloc(ctxt
->errTab
,
1805 (xmlRelaxNGValidError
));
1806 if (ctxt
->errTab
== NULL
) {
1807 xmlRngVErrMemory(ctxt
, "pushing error\n");
1810 ctxt
->err
= &ctxt
->errTab
[ctxt
->errNr
- 1];
1812 if ((ctxt
->err
!= NULL
) && (ctxt
->state
!= NULL
) &&
1813 (ctxt
->err
->node
== ctxt
->state
->node
) && (ctxt
->err
->err
== err
))
1814 return (ctxt
->errNr
);
1815 cur
= &ctxt
->errTab
[ctxt
->errNr
];
1818 cur
->arg1
= xmlStrdup(arg1
);
1819 cur
->arg2
= xmlStrdup(arg2
);
1820 cur
->flags
= ERROR_IS_DUP
;
1826 if (ctxt
->state
!= NULL
) {
1827 cur
->node
= ctxt
->state
->node
;
1828 cur
->seq
= ctxt
->state
->seq
;
1834 return (ctxt
->errNr
++);
1838 * xmlRelaxNGValidErrorPop:
1839 * @ctxt: the validation context
1841 * Pops the top error from the error stack
1844 xmlRelaxNGValidErrorPop(xmlRelaxNGValidCtxtPtr ctxt
)
1846 xmlRelaxNGValidErrorPtr cur
;
1848 if (ctxt
->errNr
<= 0) {
1853 if (ctxt
->errNr
> 0)
1854 ctxt
->err
= &ctxt
->errTab
[ctxt
->errNr
- 1];
1857 cur
= &ctxt
->errTab
[ctxt
->errNr
];
1858 if (cur
->flags
& ERROR_IS_DUP
) {
1859 if (cur
->arg1
!= NULL
)
1860 xmlFree((xmlChar
*) cur
->arg1
);
1862 if (cur
->arg2
!= NULL
)
1863 xmlFree((xmlChar
*) cur
->arg2
);
1870 * xmlRelaxNGDocumentPush:
1871 * @ctxt: the parser context
1872 * @value: the element doc
1874 * Pushes a new doc on top of the doc stack
1876 * Returns 0 in case of error, the index in the stack otherwise
1879 xmlRelaxNGDocumentPush(xmlRelaxNGParserCtxtPtr ctxt
,
1880 xmlRelaxNGDocumentPtr value
)
1882 if (ctxt
->docTab
== NULL
) {
1886 (xmlRelaxNGDocumentPtr
*) xmlMalloc(ctxt
->docMax
*
1887 sizeof(ctxt
->docTab
[0]));
1888 if (ctxt
->docTab
== NULL
) {
1889 xmlRngPErrMemory(ctxt
, "adding document\n");
1893 if (ctxt
->docNr
>= ctxt
->docMax
) {
1896 (xmlRelaxNGDocumentPtr
*) xmlRealloc(ctxt
->docTab
,
1898 sizeof(ctxt
->docTab
[0]));
1899 if (ctxt
->docTab
== NULL
) {
1900 xmlRngPErrMemory(ctxt
, "adding document\n");
1904 ctxt
->docTab
[ctxt
->docNr
] = value
;
1906 return (ctxt
->docNr
++);
1910 * xmlRelaxNGDocumentPop:
1911 * @ctxt: the parser context
1913 * Pops the top doc from the doc stack
1915 * Returns the doc just removed
1917 static xmlRelaxNGDocumentPtr
1918 xmlRelaxNGDocumentPop(xmlRelaxNGParserCtxtPtr ctxt
)
1920 xmlRelaxNGDocumentPtr ret
;
1922 if (ctxt
->docNr
<= 0)
1925 if (ctxt
->docNr
> 0)
1926 ctxt
->doc
= ctxt
->docTab
[ctxt
->docNr
- 1];
1929 ret
= ctxt
->docTab
[ctxt
->docNr
];
1930 ctxt
->docTab
[ctxt
->docNr
] = NULL
;
1935 * xmlRelaxNGLoadExternalRef:
1936 * @ctxt: the parser context
1937 * @URL: the normalized URL
1938 * @ns: the inherited ns if any
1940 * First lookup if the document is already loaded into the parser context,
1941 * check against recursion. If not found the resource is loaded and
1942 * the content is preprocessed before being returned back to the caller.
1944 * Returns the xmlRelaxNGDocumentPtr or NULL in case of error
1946 static xmlRelaxNGDocumentPtr
1947 xmlRelaxNGLoadExternalRef(xmlRelaxNGParserCtxtPtr ctxt
,
1948 const xmlChar
* URL
, const xmlChar
* ns
)
1950 xmlRelaxNGDocumentPtr ret
= NULL
;
1956 * check against recursion in the stack
1958 for (i
= 0; i
< ctxt
->docNr
; i
++) {
1959 if (xmlStrEqual(ctxt
->docTab
[i
]->href
, URL
)) {
1960 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EXTERNALREF_RECURSE
,
1961 "Detected an externalRef recursion for %s\n", URL
,
1970 doc
= xmlReadFile((const char *) URL
,NULL
,0);
1972 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
1973 "xmlRelaxNG: could not load %s\n", URL
, NULL
);
1978 * Allocate the document structures and register it first.
1980 ret
= (xmlRelaxNGDocumentPtr
) xmlMalloc(sizeof(xmlRelaxNGDocument
));
1982 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_ERR_NO_MEMORY
,
1983 "xmlRelaxNG: allocate memory for doc %s\n", URL
, NULL
);
1987 memset(ret
, 0, sizeof(xmlRelaxNGDocument
));
1989 ret
->href
= xmlStrdup(URL
);
1990 ret
->next
= ctxt
->documents
;
1991 ret
->externalRef
= 1;
1992 ctxt
->documents
= ret
;
1995 * transmit the ns if needed
1998 root
= xmlDocGetRootElement(doc
);
2000 if (xmlHasProp(root
, BAD_CAST
"ns") == NULL
) {
2001 xmlSetProp(root
, BAD_CAST
"ns", ns
);
2007 * push it on the stack and register it in the hash table
2009 xmlRelaxNGDocumentPush(ctxt
, ret
);
2012 * Some preprocessing of the document content
2014 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
2020 xmlRelaxNGDocumentPop(ctxt
);
2025 /************************************************************************
2029 ************************************************************************/
2031 #define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
2032 #define VALID_ERR2(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 0);
2033 #define VALID_ERR3(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 0);
2034 #define VALID_ERR2P(a, b) xmlRelaxNGAddValidError(ctxt, a, b, NULL, 1);
2035 #define VALID_ERR3P(a, b, c) xmlRelaxNGAddValidError(ctxt, a, b, c, 1);
2038 xmlRelaxNGDefName(xmlRelaxNGDefinePtr def
)
2042 switch (def
->type
) {
2043 case XML_RELAXNG_EMPTY
:
2045 case XML_RELAXNG_NOT_ALLOWED
:
2046 return ("notAllowed");
2047 case XML_RELAXNG_EXCEPT
:
2049 case XML_RELAXNG_TEXT
:
2051 case XML_RELAXNG_ELEMENT
:
2053 case XML_RELAXNG_DATATYPE
:
2054 return ("datatype");
2055 case XML_RELAXNG_VALUE
:
2057 case XML_RELAXNG_LIST
:
2059 case XML_RELAXNG_ATTRIBUTE
:
2060 return ("attribute");
2061 case XML_RELAXNG_DEF
:
2063 case XML_RELAXNG_REF
:
2065 case XML_RELAXNG_EXTERNALREF
:
2066 return ("externalRef");
2067 case XML_RELAXNG_PARENTREF
:
2068 return ("parentRef");
2069 case XML_RELAXNG_OPTIONAL
:
2070 return ("optional");
2071 case XML_RELAXNG_ZEROORMORE
:
2072 return ("zeroOrMore");
2073 case XML_RELAXNG_ONEORMORE
:
2074 return ("oneOrMore");
2075 case XML_RELAXNG_CHOICE
:
2077 case XML_RELAXNG_GROUP
:
2079 case XML_RELAXNG_INTERLEAVE
:
2080 return ("interleave");
2081 case XML_RELAXNG_START
:
2083 case XML_RELAXNG_NOOP
:
2085 case XML_RELAXNG_PARAM
:
2092 * xmlRelaxNGGetErrorString:
2093 * @err: the error code
2094 * @arg1: the first string argument
2095 * @arg2: the second string argument
2097 * computes a formatted error string for the given error code and args
2099 * Returns the error string, it must be deallocated by the caller
2102 xmlRelaxNGGetErrorString(xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
2103 const xmlChar
* arg2
)
2115 case XML_RELAXNG_OK
:
2117 case XML_RELAXNG_ERR_MEMORY
:
2118 return (xmlCharStrdup("out of memory\n"));
2119 case XML_RELAXNG_ERR_TYPE
:
2120 snprintf(msg
, 1000, "failed to validate type %s\n", arg1
);
2122 case XML_RELAXNG_ERR_TYPEVAL
:
2123 snprintf(msg
, 1000, "Type %s doesn't allow value '%s'\n", arg1
,
2126 case XML_RELAXNG_ERR_DUPID
:
2127 snprintf(msg
, 1000, "ID %s redefined\n", arg1
);
2129 case XML_RELAXNG_ERR_TYPECMP
:
2130 snprintf(msg
, 1000, "failed to compare type %s\n", arg1
);
2132 case XML_RELAXNG_ERR_NOSTATE
:
2133 return (xmlCharStrdup("Internal error: no state\n"));
2134 case XML_RELAXNG_ERR_NODEFINE
:
2135 return (xmlCharStrdup("Internal error: no define\n"));
2136 case XML_RELAXNG_ERR_INTERNAL
:
2137 snprintf(msg
, 1000, "Internal error: %s\n", arg1
);
2139 case XML_RELAXNG_ERR_LISTEXTRA
:
2140 snprintf(msg
, 1000, "Extra data in list: %s\n", arg1
);
2142 case XML_RELAXNG_ERR_INTERNODATA
:
2143 return (xmlCharStrdup
2144 ("Internal: interleave block has no data\n"));
2145 case XML_RELAXNG_ERR_INTERSEQ
:
2146 return (xmlCharStrdup("Invalid sequence in interleave\n"));
2147 case XML_RELAXNG_ERR_INTEREXTRA
:
2148 snprintf(msg
, 1000, "Extra element %s in interleave\n", arg1
);
2150 case XML_RELAXNG_ERR_ELEMNAME
:
2151 snprintf(msg
, 1000, "Expecting element %s, got %s\n", arg1
,
2154 case XML_RELAXNG_ERR_ELEMNONS
:
2155 snprintf(msg
, 1000, "Expecting a namespace for element %s\n",
2158 case XML_RELAXNG_ERR_ELEMWRONGNS
:
2160 "Element %s has wrong namespace: expecting %s\n", arg1
,
2163 case XML_RELAXNG_ERR_ELEMWRONG
:
2164 snprintf(msg
, 1000, "Did not expect element %s there\n", arg1
);
2166 case XML_RELAXNG_ERR_TEXTWRONG
:
2168 "Did not expect text in element %s content\n", arg1
);
2170 case XML_RELAXNG_ERR_ELEMEXTRANS
:
2171 snprintf(msg
, 1000, "Expecting no namespace for element %s\n",
2174 case XML_RELAXNG_ERR_ELEMNOTEMPTY
:
2175 snprintf(msg
, 1000, "Expecting element %s to be empty\n", arg1
);
2177 case XML_RELAXNG_ERR_NOELEM
:
2178 snprintf(msg
, 1000, "Expecting an element %s, got nothing\n",
2181 case XML_RELAXNG_ERR_NOTELEM
:
2182 return (xmlCharStrdup("Expecting an element got text\n"));
2183 case XML_RELAXNG_ERR_ATTRVALID
:
2184 snprintf(msg
, 1000, "Element %s failed to validate attributes\n",
2187 case XML_RELAXNG_ERR_CONTENTVALID
:
2188 snprintf(msg
, 1000, "Element %s failed to validate content\n",
2191 case XML_RELAXNG_ERR_EXTRACONTENT
:
2192 snprintf(msg
, 1000, "Element %s has extra content: %s\n",
2195 case XML_RELAXNG_ERR_INVALIDATTR
:
2196 snprintf(msg
, 1000, "Invalid attribute %s for element %s\n",
2199 case XML_RELAXNG_ERR_LACKDATA
:
2200 snprintf(msg
, 1000, "Datatype element %s contains no data\n",
2203 case XML_RELAXNG_ERR_DATAELEM
:
2204 snprintf(msg
, 1000, "Datatype element %s has child elements\n",
2207 case XML_RELAXNG_ERR_VALELEM
:
2208 snprintf(msg
, 1000, "Value element %s has child elements\n",
2211 case XML_RELAXNG_ERR_LISTELEM
:
2212 snprintf(msg
, 1000, "List element %s has child elements\n",
2215 case XML_RELAXNG_ERR_DATATYPE
:
2216 snprintf(msg
, 1000, "Error validating datatype %s\n", arg1
);
2218 case XML_RELAXNG_ERR_VALUE
:
2219 snprintf(msg
, 1000, "Error validating value %s\n", arg1
);
2221 case XML_RELAXNG_ERR_LIST
:
2222 return (xmlCharStrdup("Error validating list\n"));
2223 case XML_RELAXNG_ERR_NOGRAMMAR
:
2224 return (xmlCharStrdup("No top grammar defined\n"));
2225 case XML_RELAXNG_ERR_EXTRADATA
:
2226 return (xmlCharStrdup("Extra data in the document\n"));
2228 return (xmlCharStrdup("Unknown error !\n"));
2231 snprintf(msg
, 1000, "Unknown error code %d\n", err
);
2234 result
= xmlCharStrdup(msg
);
2235 return (xmlEscapeFormatString(&result
));
2239 * xmlRelaxNGShowValidError:
2240 * @ctxt: the validation context
2241 * @err: the error number
2243 * @child: the node child generating the problem.
2244 * @arg1: the first argument
2245 * @arg2: the second argument
2247 * Show a validation error.
2250 xmlRelaxNGShowValidError(xmlRelaxNGValidCtxtPtr ctxt
,
2251 xmlRelaxNGValidErr err
, xmlNodePtr node
,
2252 xmlNodePtr child
, const xmlChar
* arg1
,
2253 const xmlChar
* arg2
)
2257 if (ctxt
->flags
& FLAGS_NOERROR
)
2261 xmlGenericError(xmlGenericErrorContext
, "Show error %d\n", err
);
2263 msg
= xmlRelaxNGGetErrorString(err
, arg1
, arg2
);
2267 if (ctxt
->errNo
== XML_RELAXNG_OK
)
2269 xmlRngVErr(ctxt
, (child
== NULL
? node
: child
), err
,
2270 (const char *) msg
, arg1
, arg2
);
2275 * xmlRelaxNGPopErrors:
2276 * @ctxt: the validation context
2277 * @level: the error level in the stack
2279 * pop and discard all errors until the given level is reached
2282 xmlRelaxNGPopErrors(xmlRelaxNGValidCtxtPtr ctxt
, int level
)
2285 xmlRelaxNGValidErrorPtr err
;
2288 xmlGenericError(xmlGenericErrorContext
,
2289 "Pop errors till level %d\n", level
);
2291 for (i
= level
; i
< ctxt
->errNr
; i
++) {
2292 err
= &ctxt
->errTab
[i
];
2293 if (err
->flags
& ERROR_IS_DUP
) {
2294 if (err
->arg1
!= NULL
)
2295 xmlFree((xmlChar
*) err
->arg1
);
2297 if (err
->arg2
!= NULL
)
2298 xmlFree((xmlChar
*) err
->arg2
);
2303 ctxt
->errNr
= level
;
2304 if (ctxt
->errNr
<= 0)
2309 * xmlRelaxNGDumpValidError:
2310 * @ctxt: the validation context
2312 * Show all validation error over a given index.
2315 xmlRelaxNGDumpValidError(xmlRelaxNGValidCtxtPtr ctxt
)
2318 xmlRelaxNGValidErrorPtr err
, dup
;
2321 xmlGenericError(xmlGenericErrorContext
,
2322 "Dumping error stack %d errors\n", ctxt
->errNr
);
2324 for (i
= 0, k
= 0; i
< ctxt
->errNr
; i
++) {
2325 err
= &ctxt
->errTab
[i
];
2326 if (k
< MAX_ERROR
) {
2327 for (j
= 0; j
< i
; j
++) {
2328 dup
= &ctxt
->errTab
[j
];
2329 if ((err
->err
== dup
->err
) && (err
->node
== dup
->node
) &&
2330 (xmlStrEqual(err
->arg1
, dup
->arg1
)) &&
2331 (xmlStrEqual(err
->arg2
, dup
->arg2
))) {
2335 xmlRelaxNGShowValidError(ctxt
, err
->err
, err
->node
, err
->seq
,
2336 err
->arg1
, err
->arg2
);
2340 if (err
->flags
& ERROR_IS_DUP
) {
2341 if (err
->arg1
!= NULL
)
2342 xmlFree((xmlChar
*) err
->arg1
);
2344 if (err
->arg2
!= NULL
)
2345 xmlFree((xmlChar
*) err
->arg2
);
2354 * xmlRelaxNGAddValidError:
2355 * @ctxt: the validation context
2356 * @err: the error number
2357 * @arg1: the first argument
2358 * @arg2: the second argument
2359 * @dup: need to dup the args
2361 * Register a validation error, either generating it if it's sure
2362 * or stacking it for later handling if unsure.
2365 xmlRelaxNGAddValidError(xmlRelaxNGValidCtxtPtr ctxt
,
2366 xmlRelaxNGValidErr err
, const xmlChar
* arg1
,
2367 const xmlChar
* arg2
, int dup
)
2371 if (ctxt
->flags
& FLAGS_NOERROR
)
2375 xmlGenericError(xmlGenericErrorContext
, "Adding error %d\n", err
);
2378 * generate the error directly
2380 if (((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) ||
2381 (ctxt
->flags
& FLAGS_NEGATIVE
)) {
2382 xmlNodePtr node
, seq
;
2385 * Flush first any stacked error which might be the
2386 * real cause of the problem.
2388 if (ctxt
->errNr
!= 0)
2389 xmlRelaxNGDumpValidError(ctxt
);
2390 if (ctxt
->state
!= NULL
) {
2391 node
= ctxt
->state
->node
;
2392 seq
= ctxt
->state
->seq
;
2396 if ((node
== NULL
) && (seq
== NULL
)) {
2399 xmlRelaxNGShowValidError(ctxt
, err
, node
, seq
, arg1
, arg2
);
2402 * Stack the error for later processing if needed
2405 xmlRelaxNGValidErrorPush(ctxt
, err
, arg1
, arg2
, dup
);
2410 /************************************************************************
2412 * Type library hooks *
2414 ************************************************************************/
2415 static xmlChar
*xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
,
2416 const xmlChar
* str
);
2419 * xmlRelaxNGSchemaTypeHave:
2420 * @data: data needed for the library
2421 * @type: the type name
2423 * Check if the given type is provided by
2424 * the W3C XMLSchema Datatype library.
2426 * Returns 1 if yes, 0 if no and -1 in case of error.
2429 xmlRelaxNGSchemaTypeHave(void *data ATTRIBUTE_UNUSED
, const xmlChar
* type
)
2431 xmlSchemaTypePtr typ
;
2435 typ
= xmlSchemaGetPredefinedType(type
,
2437 "http://www.w3.org/2001/XMLSchema");
2444 * xmlRelaxNGSchemaTypeCheck:
2445 * @data: data needed for the library
2446 * @type: the type name
2447 * @value: the value to check
2450 * Check if the given type and value are validated by
2451 * the W3C XMLSchema Datatype library.
2453 * Returns 1 if yes, 0 if no and -1 in case of error.
2456 xmlRelaxNGSchemaTypeCheck(void *data ATTRIBUTE_UNUSED
,
2457 const xmlChar
* type
,
2458 const xmlChar
* value
,
2459 void **result
, xmlNodePtr node
)
2461 xmlSchemaTypePtr typ
;
2464 if ((type
== NULL
) || (value
== NULL
))
2466 typ
= xmlSchemaGetPredefinedType(type
,
2468 "http://www.w3.org/2001/XMLSchema");
2471 ret
= xmlSchemaValPredefTypeNode(typ
, value
,
2472 (xmlSchemaValPtr
*) result
, node
);
2473 if (ret
== 2) /* special ID error code */
2483 * xmlRelaxNGSchemaFacetCheck:
2484 * @data: data needed for the library
2485 * @type: the type name
2486 * @facet: the facet name
2487 * @val: the facet value
2488 * @strval: the string value
2489 * @value: the value to check
2491 * Function provided by a type library to check a value facet
2493 * Returns 1 if yes, 0 if no and -1 in case of error.
2496 xmlRelaxNGSchemaFacetCheck(void *data ATTRIBUTE_UNUSED
,
2497 const xmlChar
* type
, const xmlChar
* facetname
,
2498 const xmlChar
* val
, const xmlChar
* strval
,
2501 xmlSchemaFacetPtr facet
;
2502 xmlSchemaTypePtr typ
;
2505 if ((type
== NULL
) || (strval
== NULL
))
2507 typ
= xmlSchemaGetPredefinedType(type
,
2509 "http://www.w3.org/2001/XMLSchema");
2513 facet
= xmlSchemaNewFacet();
2517 if (xmlStrEqual(facetname
, BAD_CAST
"minInclusive")) {
2518 facet
->type
= XML_SCHEMA_FACET_MININCLUSIVE
;
2519 } else if (xmlStrEqual(facetname
, BAD_CAST
"minExclusive")) {
2520 facet
->type
= XML_SCHEMA_FACET_MINEXCLUSIVE
;
2521 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxInclusive")) {
2522 facet
->type
= XML_SCHEMA_FACET_MAXINCLUSIVE
;
2523 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxExclusive")) {
2524 facet
->type
= XML_SCHEMA_FACET_MAXEXCLUSIVE
;
2525 } else if (xmlStrEqual(facetname
, BAD_CAST
"totalDigits")) {
2526 facet
->type
= XML_SCHEMA_FACET_TOTALDIGITS
;
2527 } else if (xmlStrEqual(facetname
, BAD_CAST
"fractionDigits")) {
2528 facet
->type
= XML_SCHEMA_FACET_FRACTIONDIGITS
;
2529 } else if (xmlStrEqual(facetname
, BAD_CAST
"pattern")) {
2530 facet
->type
= XML_SCHEMA_FACET_PATTERN
;
2531 } else if (xmlStrEqual(facetname
, BAD_CAST
"enumeration")) {
2532 facet
->type
= XML_SCHEMA_FACET_ENUMERATION
;
2533 } else if (xmlStrEqual(facetname
, BAD_CAST
"whiteSpace")) {
2534 facet
->type
= XML_SCHEMA_FACET_WHITESPACE
;
2535 } else if (xmlStrEqual(facetname
, BAD_CAST
"length")) {
2536 facet
->type
= XML_SCHEMA_FACET_LENGTH
;
2537 } else if (xmlStrEqual(facetname
, BAD_CAST
"maxLength")) {
2538 facet
->type
= XML_SCHEMA_FACET_MAXLENGTH
;
2539 } else if (xmlStrEqual(facetname
, BAD_CAST
"minLength")) {
2540 facet
->type
= XML_SCHEMA_FACET_MINLENGTH
;
2542 xmlSchemaFreeFacet(facet
);
2546 ret
= xmlSchemaCheckFacet(facet
, typ
, NULL
, type
);
2548 xmlSchemaFreeFacet(facet
);
2551 ret
= xmlSchemaValidateFacet(typ
, facet
, strval
, value
);
2552 xmlSchemaFreeFacet(facet
);
2559 * xmlRelaxNGSchemaFreeValue:
2560 * @data: data needed for the library
2561 * @value: the value to free
2563 * Function provided by a type library to free a Schemas value
2565 * Returns 1 if yes, 0 if no and -1 in case of error.
2568 xmlRelaxNGSchemaFreeValue(void *data ATTRIBUTE_UNUSED
, void *value
)
2570 xmlSchemaFreeValue(value
);
2574 * xmlRelaxNGSchemaTypeCompare:
2575 * @data: data needed for the library
2576 * @type: the type name
2577 * @value1: the first value
2578 * @value2: the second value
2580 * Compare two values for equality accordingly a type from the W3C XMLSchema
2583 * Returns 1 if equal, 0 if no and -1 in case of error.
2586 xmlRelaxNGSchemaTypeCompare(void *data ATTRIBUTE_UNUSED
,
2587 const xmlChar
* type
,
2588 const xmlChar
* value1
,
2591 const xmlChar
* value2
, xmlNodePtr ctxt2
)
2594 xmlSchemaTypePtr typ
;
2595 xmlSchemaValPtr res1
= NULL
, res2
= NULL
;
2597 if ((type
== NULL
) || (value1
== NULL
) || (value2
== NULL
))
2599 typ
= xmlSchemaGetPredefinedType(type
,
2601 "http://www.w3.org/2001/XMLSchema");
2604 if (comp1
== NULL
) {
2605 ret
= xmlSchemaValPredefTypeNode(typ
, value1
, &res1
, ctxt1
);
2611 res1
= (xmlSchemaValPtr
) comp1
;
2613 ret
= xmlSchemaValPredefTypeNode(typ
, value2
, &res2
, ctxt2
);
2615 if (res1
!= (xmlSchemaValPtr
) comp1
)
2616 xmlSchemaFreeValue(res1
);
2619 ret
= xmlSchemaCompareValues(res1
, res2
);
2620 if (res1
!= (xmlSchemaValPtr
) comp1
)
2621 xmlSchemaFreeValue(res1
);
2622 xmlSchemaFreeValue(res2
);
2631 * xmlRelaxNGDefaultTypeHave:
2632 * @data: data needed for the library
2633 * @type: the type name
2635 * Check if the given type is provided by
2636 * the default datatype library.
2638 * Returns 1 if yes, 0 if no and -1 in case of error.
2641 xmlRelaxNGDefaultTypeHave(void *data ATTRIBUTE_UNUSED
,
2642 const xmlChar
* type
)
2646 if (xmlStrEqual(type
, BAD_CAST
"string"))
2648 if (xmlStrEqual(type
, BAD_CAST
"token"))
2654 * xmlRelaxNGDefaultTypeCheck:
2655 * @data: data needed for the library
2656 * @type: the type name
2657 * @value: the value to check
2660 * Check if the given type and value are validated by
2661 * the default datatype library.
2663 * Returns 1 if yes, 0 if no and -1 in case of error.
2666 xmlRelaxNGDefaultTypeCheck(void *data ATTRIBUTE_UNUSED
,
2667 const xmlChar
* type ATTRIBUTE_UNUSED
,
2668 const xmlChar
* value ATTRIBUTE_UNUSED
,
2669 void **result ATTRIBUTE_UNUSED
,
2670 xmlNodePtr node ATTRIBUTE_UNUSED
)
2674 if (xmlStrEqual(type
, BAD_CAST
"string"))
2676 if (xmlStrEqual(type
, BAD_CAST
"token")) {
2684 * xmlRelaxNGDefaultTypeCompare:
2685 * @data: data needed for the library
2686 * @type: the type name
2687 * @value1: the first value
2688 * @value2: the second value
2690 * Compare two values accordingly a type from the default
2693 * Returns 1 if yes, 0 if no and -1 in case of error.
2696 xmlRelaxNGDefaultTypeCompare(void *data ATTRIBUTE_UNUSED
,
2697 const xmlChar
* type
,
2698 const xmlChar
* value1
,
2699 xmlNodePtr ctxt1 ATTRIBUTE_UNUSED
,
2700 void *comp1 ATTRIBUTE_UNUSED
,
2701 const xmlChar
* value2
,
2702 xmlNodePtr ctxt2 ATTRIBUTE_UNUSED
)
2706 if (xmlStrEqual(type
, BAD_CAST
"string")) {
2707 ret
= xmlStrEqual(value1
, value2
);
2708 } else if (xmlStrEqual(type
, BAD_CAST
"token")) {
2709 if (!xmlStrEqual(value1
, value2
)) {
2710 xmlChar
*nval
, *nvalue
;
2713 * TODO: trivial optimizations are possible by
2714 * computing at compile-time
2716 nval
= xmlRelaxNGNormalize(NULL
, value1
);
2717 nvalue
= xmlRelaxNGNormalize(NULL
, value2
);
2719 if ((nval
== NULL
) || (nvalue
== NULL
))
2721 else if (xmlStrEqual(nval
, nvalue
))
2735 static int xmlRelaxNGTypeInitialized
= 0;
2736 static xmlHashTablePtr xmlRelaxNGRegisteredTypes
= NULL
;
2739 * xmlRelaxNGFreeTypeLibrary:
2740 * @lib: the type library structure
2741 * @namespace: the URI bound to the library
2743 * Free the structure associated to the type library
2746 xmlRelaxNGFreeTypeLibrary(void *payload
,
2747 const xmlChar
* namespace ATTRIBUTE_UNUSED
)
2749 xmlRelaxNGTypeLibraryPtr lib
= (xmlRelaxNGTypeLibraryPtr
) payload
;
2752 if (lib
->namespace != NULL
)
2753 xmlFree((xmlChar
*) lib
->namespace);
2758 * xmlRelaxNGRegisterTypeLibrary:
2759 * @namespace: the URI bound to the library
2760 * @data: data associated to the library
2761 * @have: the provide function
2762 * @check: the checking function
2763 * @comp: the comparison function
2765 * Register a new type library
2767 * Returns 0 in case of success and -1 in case of error.
2770 xmlRelaxNGRegisterTypeLibrary(const xmlChar
* namespace, void *data
,
2771 xmlRelaxNGTypeHave have
,
2772 xmlRelaxNGTypeCheck check
,
2773 xmlRelaxNGTypeCompare comp
,
2774 xmlRelaxNGFacetCheck facet
,
2775 xmlRelaxNGTypeFree freef
)
2777 xmlRelaxNGTypeLibraryPtr lib
;
2780 if ((xmlRelaxNGRegisteredTypes
== NULL
) || (namespace == NULL
) ||
2781 (check
== NULL
) || (comp
== NULL
))
2783 if (xmlHashLookup(xmlRelaxNGRegisteredTypes
, namespace) != NULL
) {
2784 xmlGenericError(xmlGenericErrorContext
,
2785 "Relax-NG types library '%s' already registered\n",
2790 (xmlRelaxNGTypeLibraryPtr
)
2791 xmlMalloc(sizeof(xmlRelaxNGTypeLibrary
));
2793 xmlRngVErrMemory(NULL
, "adding types library\n");
2796 memset(lib
, 0, sizeof(xmlRelaxNGTypeLibrary
));
2797 lib
->namespace = xmlStrdup(namespace);
2804 ret
= xmlHashAddEntry(xmlRelaxNGRegisteredTypes
, namespace, lib
);
2806 xmlGenericError(xmlGenericErrorContext
,
2807 "Relax-NG types library failed to register '%s'\n",
2809 xmlRelaxNGFreeTypeLibrary(lib
, namespace);
2816 * xmlRelaxNGInitTypes:
2818 * Initialize the default type libraries.
2820 * Returns 0 in case of success and -1 in case of error.
2823 xmlRelaxNGInitTypes(void)
2825 if (xmlRelaxNGTypeInitialized
!= 0)
2827 xmlRelaxNGRegisteredTypes
= xmlHashCreate(10);
2828 if (xmlRelaxNGRegisteredTypes
== NULL
) {
2829 xmlGenericError(xmlGenericErrorContext
,
2830 "Failed to allocate sh table for Relax-NG types\n");
2833 xmlRelaxNGRegisterTypeLibrary(BAD_CAST
2834 "http://www.w3.org/2001/XMLSchema-datatypes",
2835 NULL
, xmlRelaxNGSchemaTypeHave
,
2836 xmlRelaxNGSchemaTypeCheck
,
2837 xmlRelaxNGSchemaTypeCompare
,
2838 xmlRelaxNGSchemaFacetCheck
,
2839 xmlRelaxNGSchemaFreeValue
);
2840 xmlRelaxNGRegisterTypeLibrary(xmlRelaxNGNs
, NULL
,
2841 xmlRelaxNGDefaultTypeHave
,
2842 xmlRelaxNGDefaultTypeCheck
,
2843 xmlRelaxNGDefaultTypeCompare
, NULL
,
2845 xmlRelaxNGTypeInitialized
= 1;
2850 * xmlRelaxNGCleanupTypes:
2852 * Cleanup the default Schemas type library associated to RelaxNG
2855 xmlRelaxNGCleanupTypes(void)
2857 xmlSchemaCleanupTypes();
2858 if (xmlRelaxNGTypeInitialized
== 0)
2860 xmlHashFree(xmlRelaxNGRegisteredTypes
, xmlRelaxNGFreeTypeLibrary
);
2861 xmlRelaxNGTypeInitialized
= 0;
2864 /************************************************************************
2866 * Compiling element content into regexp *
2868 * Sometime the element content can be compiled into a pure regexp, *
2869 * This allows a faster execution and streamability at that level *
2871 ************************************************************************/
2873 /* from automata.c but not exported */
2874 void xmlAutomataSetFlags(xmlAutomataPtr am
, int flags
);
2877 static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt
,
2878 xmlRelaxNGDefinePtr def
);
2881 * xmlRelaxNGIsCompilable:
2882 * @define: the definition to check
2884 * Check if a definition is nullable.
2886 * Returns 1 if yes, 0 if no and -1 in case of error
2889 xmlRelaxNGIsCompilable(xmlRelaxNGDefinePtr def
)
2896 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
2897 (def
->dflags
& IS_COMPILABLE
))
2899 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
2900 (def
->dflags
& IS_NOT_COMPILABLE
))
2902 switch (def
->type
) {
2903 case XML_RELAXNG_NOOP
:
2904 ret
= xmlRelaxNGIsCompilable(def
->content
);
2906 case XML_RELAXNG_TEXT
:
2907 case XML_RELAXNG_EMPTY
:
2910 case XML_RELAXNG_ELEMENT
:
2912 * Check if the element content is compilable
2914 if (((def
->dflags
& IS_NOT_COMPILABLE
) == 0) &&
2915 ((def
->dflags
& IS_COMPILABLE
) == 0)) {
2916 xmlRelaxNGDefinePtr list
;
2918 list
= def
->content
;
2919 while (list
!= NULL
) {
2920 ret
= xmlRelaxNGIsCompilable(list
);
2926 * Because the routine is recursive, we must guard against
2927 * discovering both COMPILABLE and NOT_COMPILABLE
2930 def
->dflags
&= ~IS_COMPILABLE
;
2931 def
->dflags
|= IS_NOT_COMPILABLE
;
2933 if ((ret
== 1) && !(def
->dflags
&= IS_NOT_COMPILABLE
))
2934 def
->dflags
|= IS_COMPILABLE
;
2935 #ifdef DEBUG_COMPILE
2937 xmlGenericError(xmlGenericErrorContext
,
2938 "element content for %s is compilable\n",
2940 } else if (ret
== 0) {
2941 xmlGenericError(xmlGenericErrorContext
,
2942 "element content for %s is not compilable\n",
2945 xmlGenericError(xmlGenericErrorContext
,
2946 "Problem in RelaxNGIsCompilable for element %s\n",
2952 * All elements return a compilable status unless they
2953 * are generic like anyName
2955 if ((def
->nameClass
!= NULL
) || (def
->name
== NULL
))
2960 case XML_RELAXNG_REF
:
2961 case XML_RELAXNG_EXTERNALREF
:
2962 case XML_RELAXNG_PARENTREF
:
2963 if (def
->depth
== -20) {
2966 xmlRelaxNGDefinePtr list
;
2969 list
= def
->content
;
2970 while (list
!= NULL
) {
2971 ret
= xmlRelaxNGIsCompilable(list
);
2978 case XML_RELAXNG_START
:
2979 case XML_RELAXNG_OPTIONAL
:
2980 case XML_RELAXNG_ZEROORMORE
:
2981 case XML_RELAXNG_ONEORMORE
:
2982 case XML_RELAXNG_CHOICE
:
2983 case XML_RELAXNG_GROUP
:
2984 case XML_RELAXNG_DEF
:{
2985 xmlRelaxNGDefinePtr list
;
2987 list
= def
->content
;
2988 while (list
!= NULL
) {
2989 ret
= xmlRelaxNGIsCompilable(list
);
2996 case XML_RELAXNG_EXCEPT
:
2997 case XML_RELAXNG_ATTRIBUTE
:
2998 case XML_RELAXNG_INTERLEAVE
:
2999 case XML_RELAXNG_DATATYPE
:
3000 case XML_RELAXNG_LIST
:
3001 case XML_RELAXNG_PARAM
:
3002 case XML_RELAXNG_VALUE
:
3003 case XML_RELAXNG_NOT_ALLOWED
:
3008 def
->dflags
|= IS_NOT_COMPILABLE
;
3010 def
->dflags
|= IS_COMPILABLE
;
3011 #ifdef DEBUG_COMPILE
3013 xmlGenericError(xmlGenericErrorContext
,
3014 "RelaxNGIsCompilable %s : true\n",
3015 xmlRelaxNGDefName(def
));
3016 } else if (ret
== 0) {
3017 xmlGenericError(xmlGenericErrorContext
,
3018 "RelaxNGIsCompilable %s : false\n",
3019 xmlRelaxNGDefName(def
));
3021 xmlGenericError(xmlGenericErrorContext
,
3022 "Problem in RelaxNGIsCompilable %s\n",
3023 xmlRelaxNGDefName(def
));
3030 * xmlRelaxNGCompile:
3031 * ctxt: the RelaxNG parser context
3032 * @define: the definition tree to compile
3034 * Compile the set of definitions, it works recursively, till the
3035 * element boundaries, where it tries to compile the content if possible
3037 * Returns 0 if success and -1 in case of error
3040 xmlRelaxNGCompile(xmlRelaxNGParserCtxtPtr ctxt
, xmlRelaxNGDefinePtr def
)
3043 xmlRelaxNGDefinePtr list
;
3045 if ((ctxt
== NULL
) || (def
== NULL
))
3048 switch (def
->type
) {
3049 case XML_RELAXNG_START
:
3050 if ((xmlRelaxNGIsCompilable(def
) == 1) && (def
->depth
!= -25)) {
3051 xmlAutomataPtr oldam
= ctxt
->am
;
3052 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3056 list
= def
->content
;
3057 ctxt
->am
= xmlNewAutomata();
3058 if (ctxt
->am
== NULL
)
3062 * assume identical strings but not same pointer are different
3063 * atoms, needed for non-determinism detection
3064 * That way if 2 elements with the same name are in a choice
3065 * branch the automata is found non-deterministic and
3066 * we fallback to the normal validation which does the right
3067 * thing of exploring both choices.
3069 xmlAutomataSetFlags(ctxt
->am
, 1);
3071 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
3072 while (list
!= NULL
) {
3073 xmlRelaxNGCompile(ctxt
, list
);
3076 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
3077 if (xmlAutomataIsDeterminist(ctxt
->am
))
3078 def
->contModel
= xmlAutomataCompile(ctxt
->am
);
3080 xmlFreeAutomata(ctxt
->am
);
3081 ctxt
->state
= oldstate
;
3085 case XML_RELAXNG_ELEMENT
:
3086 if ((ctxt
->am
!= NULL
) && (def
->name
!= NULL
)) {
3087 ctxt
->state
= xmlAutomataNewTransition2(ctxt
->am
,
3092 if ((def
->dflags
& IS_COMPILABLE
) && (def
->depth
!= -25)) {
3093 xmlAutomataPtr oldam
= ctxt
->am
;
3094 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3098 list
= def
->content
;
3099 ctxt
->am
= xmlNewAutomata();
3100 if (ctxt
->am
== NULL
)
3102 xmlAutomataSetFlags(ctxt
->am
, 1);
3103 ctxt
->state
= xmlAutomataGetInitState(ctxt
->am
);
3104 while (list
!= NULL
) {
3105 xmlRelaxNGCompile(ctxt
, list
);
3108 xmlAutomataSetFinalState(ctxt
->am
, ctxt
->state
);
3109 def
->contModel
= xmlAutomataCompile(ctxt
->am
);
3110 if (!xmlRegexpIsDeterminist(def
->contModel
)) {
3111 #ifdef DEBUG_COMPILE
3112 xmlGenericError(xmlGenericErrorContext
,
3113 "Content model not determinist %s\n",
3117 * we can only use the automata if it is determinist
3119 xmlRegFreeRegexp(def
->contModel
);
3120 def
->contModel
= NULL
;
3122 xmlFreeAutomata(ctxt
->am
);
3123 ctxt
->state
= oldstate
;
3126 xmlAutomataPtr oldam
= ctxt
->am
;
3129 * we can't build the content model for this element content
3130 * but it still might be possible to build it for some of its
3131 * children, recurse.
3133 ret
= xmlRelaxNGTryCompile(ctxt
, def
);
3137 case XML_RELAXNG_NOOP
:
3138 ret
= xmlRelaxNGCompile(ctxt
, def
->content
);
3140 case XML_RELAXNG_OPTIONAL
:{
3141 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3143 list
= def
->content
;
3144 while (list
!= NULL
) {
3145 xmlRelaxNGCompile(ctxt
, list
);
3148 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, ctxt
->state
);
3151 case XML_RELAXNG_ZEROORMORE
:{
3152 xmlAutomataStatePtr oldstate
;
3155 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3156 oldstate
= ctxt
->state
;
3157 list
= def
->content
;
3158 while (list
!= NULL
) {
3159 xmlRelaxNGCompile(ctxt
, list
);
3162 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldstate
);
3164 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3167 case XML_RELAXNG_ONEORMORE
:{
3168 xmlAutomataStatePtr oldstate
;
3170 list
= def
->content
;
3171 while (list
!= NULL
) {
3172 xmlRelaxNGCompile(ctxt
, list
);
3175 oldstate
= ctxt
->state
;
3176 list
= def
->content
;
3177 while (list
!= NULL
) {
3178 xmlRelaxNGCompile(ctxt
, list
);
3181 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, oldstate
);
3183 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3186 case XML_RELAXNG_CHOICE
:{
3187 xmlAutomataStatePtr target
= NULL
;
3188 xmlAutomataStatePtr oldstate
= ctxt
->state
;
3190 list
= def
->content
;
3191 while (list
!= NULL
) {
3192 ctxt
->state
= oldstate
;
3193 ret
= xmlRelaxNGCompile(ctxt
, list
);
3197 target
= ctxt
->state
;
3199 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
,
3204 ctxt
->state
= target
;
3208 case XML_RELAXNG_REF
:
3209 case XML_RELAXNG_EXTERNALREF
:
3210 case XML_RELAXNG_PARENTREF
:
3211 case XML_RELAXNG_GROUP
:
3212 case XML_RELAXNG_DEF
:
3213 list
= def
->content
;
3214 while (list
!= NULL
) {
3215 ret
= xmlRelaxNGCompile(ctxt
, list
);
3221 case XML_RELAXNG_TEXT
:{
3222 xmlAutomataStatePtr oldstate
;
3225 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3226 oldstate
= ctxt
->state
;
3227 xmlRelaxNGCompile(ctxt
, def
->content
);
3228 xmlAutomataNewTransition(ctxt
->am
, ctxt
->state
,
3229 ctxt
->state
, BAD_CAST
"#text",
3232 xmlAutomataNewEpsilon(ctxt
->am
, oldstate
, NULL
);
3235 case XML_RELAXNG_EMPTY
:
3237 xmlAutomataNewEpsilon(ctxt
->am
, ctxt
->state
, NULL
);
3239 case XML_RELAXNG_EXCEPT
:
3240 case XML_RELAXNG_ATTRIBUTE
:
3241 case XML_RELAXNG_INTERLEAVE
:
3242 case XML_RELAXNG_NOT_ALLOWED
:
3243 case XML_RELAXNG_DATATYPE
:
3244 case XML_RELAXNG_LIST
:
3245 case XML_RELAXNG_PARAM
:
3246 case XML_RELAXNG_VALUE
:
3247 /* This should not happen and generate an internal error */
3248 fprintf(stderr
, "RNG internal error trying to compile %s\n",
3249 xmlRelaxNGDefName(def
));
3256 * xmlRelaxNGTryCompile:
3257 * ctxt: the RelaxNG parser context
3258 * @define: the definition tree to compile
3260 * Try to compile the set of definitions, it works recursively,
3261 * possibly ignoring parts which cannot be compiled.
3263 * Returns 0 if success and -1 in case of error
3266 xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt
, xmlRelaxNGDefinePtr def
)
3269 xmlRelaxNGDefinePtr list
;
3271 if ((ctxt
== NULL
) || (def
== NULL
))
3274 if ((def
->type
== XML_RELAXNG_START
) ||
3275 (def
->type
== XML_RELAXNG_ELEMENT
)) {
3276 ret
= xmlRelaxNGIsCompilable(def
);
3277 if ((def
->dflags
& IS_COMPILABLE
) && (def
->depth
!= -25)) {
3279 ret
= xmlRelaxNGCompile(ctxt
, def
);
3280 #ifdef DEBUG_PROGRESSIVE
3282 if (def
->type
== XML_RELAXNG_START
)
3283 xmlGenericError(xmlGenericErrorContext
,
3284 "compiled the start\n");
3286 xmlGenericError(xmlGenericErrorContext
,
3287 "compiled element %s\n", def
->name
);
3289 if (def
->type
== XML_RELAXNG_START
)
3290 xmlGenericError(xmlGenericErrorContext
,
3291 "failed to compile the start\n");
3293 xmlGenericError(xmlGenericErrorContext
,
3294 "failed to compile element %s\n",
3301 switch (def
->type
) {
3302 case XML_RELAXNG_NOOP
:
3303 ret
= xmlRelaxNGTryCompile(ctxt
, def
->content
);
3305 case XML_RELAXNG_TEXT
:
3306 case XML_RELAXNG_DATATYPE
:
3307 case XML_RELAXNG_LIST
:
3308 case XML_RELAXNG_PARAM
:
3309 case XML_RELAXNG_VALUE
:
3310 case XML_RELAXNG_EMPTY
:
3311 case XML_RELAXNG_ELEMENT
:
3314 case XML_RELAXNG_OPTIONAL
:
3315 case XML_RELAXNG_ZEROORMORE
:
3316 case XML_RELAXNG_ONEORMORE
:
3317 case XML_RELAXNG_CHOICE
:
3318 case XML_RELAXNG_GROUP
:
3319 case XML_RELAXNG_DEF
:
3320 case XML_RELAXNG_START
:
3321 case XML_RELAXNG_REF
:
3322 case XML_RELAXNG_EXTERNALREF
:
3323 case XML_RELAXNG_PARENTREF
:
3324 list
= def
->content
;
3325 while (list
!= NULL
) {
3326 ret
= xmlRelaxNGTryCompile(ctxt
, list
);
3332 case XML_RELAXNG_EXCEPT
:
3333 case XML_RELAXNG_ATTRIBUTE
:
3334 case XML_RELAXNG_INTERLEAVE
:
3335 case XML_RELAXNG_NOT_ALLOWED
:
3342 /************************************************************************
3344 * Parsing functions *
3346 ************************************************************************/
3348 static xmlRelaxNGDefinePtr
xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
3349 ctxt
, xmlNodePtr node
);
3350 static xmlRelaxNGDefinePtr
xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr
3351 ctxt
, xmlNodePtr node
);
3352 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr
3353 ctxt
, xmlNodePtr nodes
,
3355 static xmlRelaxNGDefinePtr
xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr
3356 ctxt
, xmlNodePtr node
);
3357 static xmlRelaxNGPtr
xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
,
3359 static int xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
3361 static xmlRelaxNGDefinePtr
xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr
3362 ctxt
, xmlNodePtr node
,
3365 static xmlRelaxNGGrammarPtr
xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr
3366 ctxt
, xmlNodePtr nodes
);
3367 static int xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
3368 xmlRelaxNGDefinePtr define
,
3372 #define IS_BLANK_NODE(n) (xmlRelaxNGIsBlank((n)->content))
3375 * xmlRelaxNGIsNullable:
3376 * @define: the definition to verify
3378 * Check if a definition is nullable.
3380 * Returns 1 if yes, 0 if no and -1 in case of error
3383 xmlRelaxNGIsNullable(xmlRelaxNGDefinePtr define
)
3390 if (define
->dflags
& IS_NULLABLE
)
3392 if (define
->dflags
& IS_NOT_NULLABLE
)
3394 switch (define
->type
) {
3395 case XML_RELAXNG_EMPTY
:
3396 case XML_RELAXNG_TEXT
:
3399 case XML_RELAXNG_NOOP
:
3400 case XML_RELAXNG_DEF
:
3401 case XML_RELAXNG_REF
:
3402 case XML_RELAXNG_EXTERNALREF
:
3403 case XML_RELAXNG_PARENTREF
:
3404 case XML_RELAXNG_ONEORMORE
:
3405 ret
= xmlRelaxNGIsNullable(define
->content
);
3407 case XML_RELAXNG_EXCEPT
:
3408 case XML_RELAXNG_NOT_ALLOWED
:
3409 case XML_RELAXNG_ELEMENT
:
3410 case XML_RELAXNG_DATATYPE
:
3411 case XML_RELAXNG_PARAM
:
3412 case XML_RELAXNG_VALUE
:
3413 case XML_RELAXNG_LIST
:
3414 case XML_RELAXNG_ATTRIBUTE
:
3417 case XML_RELAXNG_CHOICE
:{
3418 xmlRelaxNGDefinePtr list
= define
->content
;
3420 while (list
!= NULL
) {
3421 ret
= xmlRelaxNGIsNullable(list
);
3429 case XML_RELAXNG_START
:
3430 case XML_RELAXNG_INTERLEAVE
:
3431 case XML_RELAXNG_GROUP
:{
3432 xmlRelaxNGDefinePtr list
= define
->content
;
3434 while (list
!= NULL
) {
3435 ret
= xmlRelaxNGIsNullable(list
);
3447 define
->dflags
|= IS_NOT_NULLABLE
;
3449 define
->dflags
|= IS_NULLABLE
;
3454 * xmlRelaxNGIsBlank:
3457 * Check if a string is ignorable c.f. 4.2. Whitespace
3459 * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
3462 xmlRelaxNGIsBlank(xmlChar
* str
)
3467 if (!(IS_BLANK_CH(*str
)))
3475 * xmlRelaxNGGetDataTypeLibrary:
3476 * @ctxt: a Relax-NG parser context
3477 * @node: the current data or value element
3479 * Applies algorithm from 4.3. datatypeLibrary attribute
3481 * Returns the datatypeLibrary value or NULL if not found
3484 xmlRelaxNGGetDataTypeLibrary(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
3487 xmlChar
*ret
, *escape
;
3492 if ((IS_RELAXNG(node
, "data")) || (IS_RELAXNG(node
, "value"))) {
3493 ret
= xmlGetProp(node
, BAD_CAST
"datatypeLibrary");
3499 escape
= xmlURIEscapeStr(ret
, BAD_CAST
":/#?");
3500 if (escape
== NULL
) {
3507 node
= node
->parent
;
3508 while ((node
!= NULL
) && (node
->type
== XML_ELEMENT_NODE
)) {
3509 ret
= xmlGetProp(node
, BAD_CAST
"datatypeLibrary");
3515 escape
= xmlURIEscapeStr(ret
, BAD_CAST
":/#?");
3516 if (escape
== NULL
) {
3522 node
= node
->parent
;
3528 * xmlRelaxNGParseValue:
3529 * @ctxt: a Relax-NG parser context
3530 * @node: the data node.
3532 * parse the content of a RelaxNG value node.
3534 * Returns the definition pointer or NULL in case of error
3536 static xmlRelaxNGDefinePtr
3537 xmlRelaxNGParseValue(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
3539 xmlRelaxNGDefinePtr def
= NULL
;
3540 xmlRelaxNGTypeLibraryPtr lib
= NULL
;
3545 def
= xmlRelaxNGNewDefine(ctxt
, node
);
3548 def
->type
= XML_RELAXNG_VALUE
;
3550 type
= xmlGetProp(node
, BAD_CAST
"type");
3552 xmlRelaxNGNormExtSpace(type
);
3553 if (xmlValidateNCName(type
, 0)) {
3554 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_VALUE
,
3555 "value type '%s' is not an NCName\n", type
, NULL
);
3557 library
= xmlRelaxNGGetDataTypeLibrary(ctxt
, node
);
3558 if (library
== NULL
)
3560 xmlStrdup(BAD_CAST
"http://relaxng.org/ns/structure/1.0");
3565 lib
= (xmlRelaxNGTypeLibraryPtr
)
3566 xmlHashLookup(xmlRelaxNGRegisteredTypes
, library
);
3568 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_TYPE_LIB
,
3569 "Use of unregistered type library '%s'\n", library
,
3574 if (lib
->have
== NULL
) {
3575 xmlRngPErr(ctxt
, node
, XML_RNGP_ERROR_TYPE_LIB
,
3576 "Internal error with type library '%s': no 'have'\n",
3579 success
= lib
->have(lib
->data
, def
->name
);
3581 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_NOT_FOUND
,
3582 "Error type '%s' is not exported by type library '%s'\n",
3583 def
->name
, library
);
3588 if (node
->children
== NULL
) {
3589 def
->value
= xmlStrdup(BAD_CAST
"");
3590 } else if (((node
->children
->type
!= XML_TEXT_NODE
) &&
3591 (node
->children
->type
!= XML_CDATA_SECTION_NODE
)) ||
3592 (node
->children
->next
!= NULL
)) {
3593 xmlRngPErr(ctxt
, node
, XML_RNGP_TEXT_EXPECTED
,
3594 "Expecting a single text value for <value>content\n",
3596 } else if (def
!= NULL
) {
3597 def
->value
= xmlNodeGetContent(node
);
3598 if (def
->value
== NULL
) {
3599 xmlRngPErr(ctxt
, node
, XML_RNGP_VALUE_NO_CONTENT
,
3600 "Element <value> has no content\n", NULL
, NULL
);
3601 } else if ((lib
!= NULL
) && (lib
->check
!= NULL
) && (success
== 1)) {
3605 lib
->check(lib
->data
, def
->name
, def
->value
, &val
, node
);
3607 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_VALUE
,
3608 "Value '%s' is not acceptable for type '%s'\n",
3609 def
->value
, def
->name
);
3620 * xmlRelaxNGParseData:
3621 * @ctxt: a Relax-NG parser context
3622 * @node: the data node.
3624 * parse the content of a RelaxNG data node.
3626 * Returns the definition pointer or NULL in case of error
3628 static xmlRelaxNGDefinePtr
3629 xmlRelaxNGParseData(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
3631 xmlRelaxNGDefinePtr def
= NULL
, except
;
3632 xmlRelaxNGDefinePtr param
, lastparam
= NULL
;
3633 xmlRelaxNGTypeLibraryPtr lib
;
3639 type
= xmlGetProp(node
, BAD_CAST
"type");
3641 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_MISSING
, "data has no type\n", NULL
,
3645 xmlRelaxNGNormExtSpace(type
);
3646 if (xmlValidateNCName(type
, 0)) {
3647 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_VALUE
,
3648 "data type '%s' is not an NCName\n", type
, NULL
);
3650 library
= xmlRelaxNGGetDataTypeLibrary(ctxt
, node
);
3651 if (library
== NULL
)
3653 xmlStrdup(BAD_CAST
"http://relaxng.org/ns/structure/1.0");
3655 def
= xmlRelaxNGNewDefine(ctxt
, node
);
3660 def
->type
= XML_RELAXNG_DATATYPE
;
3664 lib
= (xmlRelaxNGTypeLibraryPtr
)
3665 xmlHashLookup(xmlRelaxNGRegisteredTypes
, library
);
3667 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_TYPE_LIB
,
3668 "Use of unregistered type library '%s'\n", library
,
3673 if (lib
->have
== NULL
) {
3674 xmlRngPErr(ctxt
, node
, XML_RNGP_ERROR_TYPE_LIB
,
3675 "Internal error with type library '%s': no 'have'\n",
3678 tmp
= lib
->have(lib
->data
, def
->name
);
3680 xmlRngPErr(ctxt
, node
, XML_RNGP_TYPE_NOT_FOUND
,
3681 "Error type '%s' is not exported by type library '%s'\n",
3682 def
->name
, library
);
3687 "http://www.w3.org/2001/XMLSchema-datatypes"))
3688 && ((xmlStrEqual(def
->name
, BAD_CAST
"IDREF"))
3689 || (xmlStrEqual(def
->name
, BAD_CAST
"IDREFS")))) {
3694 content
= node
->children
;
3697 * Handle optional params
3699 while (content
!= NULL
) {
3700 if (!xmlStrEqual(content
->name
, BAD_CAST
"param"))
3702 if (xmlStrEqual(library
,
3703 BAD_CAST
"http://relaxng.org/ns/structure/1.0")) {
3704 xmlRngPErr(ctxt
, node
, XML_RNGP_PARAM_FORBIDDEN
,
3705 "Type library '%s' does not allow type parameters\n",
3707 content
= content
->next
;
3708 while ((content
!= NULL
) &&
3709 (xmlStrEqual(content
->name
, BAD_CAST
"param")))
3710 content
= content
->next
;
3712 param
= xmlRelaxNGNewDefine(ctxt
, node
);
3713 if (param
!= NULL
) {
3714 param
->type
= XML_RELAXNG_PARAM
;
3715 param
->name
= xmlGetProp(content
, BAD_CAST
"name");
3716 if (param
->name
== NULL
) {
3717 xmlRngPErr(ctxt
, node
, XML_RNGP_PARAM_NAME_MISSING
,
3718 "param has no name\n", NULL
, NULL
);
3720 param
->value
= xmlNodeGetContent(content
);
3721 if (lastparam
== NULL
) {
3722 def
->attrs
= lastparam
= param
;
3724 lastparam
->next
= param
;
3730 content
= content
->next
;
3734 * Handle optional except
3736 if ((content
!= NULL
)
3737 && (xmlStrEqual(content
->name
, BAD_CAST
"except"))) {
3739 xmlRelaxNGDefinePtr tmp2
, last
= NULL
;
3741 except
= xmlRelaxNGNewDefine(ctxt
, node
);
3742 if (except
== NULL
) {
3745 except
->type
= XML_RELAXNG_EXCEPT
;
3746 child
= content
->children
;
3747 def
->content
= except
;
3748 if (child
== NULL
) {
3749 xmlRngPErr(ctxt
, content
, XML_RNGP_EXCEPT_NO_CONTENT
,
3750 "except has no content\n", NULL
, NULL
);
3752 while (child
!= NULL
) {
3753 tmp2
= xmlRelaxNGParsePattern(ctxt
, child
);
3756 except
->content
= last
= tmp2
;
3762 child
= child
->next
;
3764 content
= content
->next
;
3767 * Check there is no unhandled data
3769 if (content
!= NULL
) {
3770 xmlRngPErr(ctxt
, content
, XML_RNGP_DATA_CONTENT
,
3771 "Element data has unexpected content %s\n",
3772 content
->name
, NULL
);
3778 static const xmlChar
*invalidName
= BAD_CAST
"\1";
3781 * xmlRelaxNGCompareNameClasses:
3782 * @defs1: the first element/attribute defs
3783 * @defs2: the second element/attribute defs
3784 * @name: the restriction on the name
3785 * @ns: the restriction on the namespace
3787 * Compare the 2 lists of element definitions. The comparison is
3788 * that if both lists do not accept the same QNames, it returns 1
3789 * If the 2 lists can accept the same QName the comparison returns 0
3791 * Returns 1 distinct, 0 if equal
3794 xmlRelaxNGCompareNameClasses(xmlRelaxNGDefinePtr def1
,
3795 xmlRelaxNGDefinePtr def2
)
3800 xmlRelaxNGValidCtxt ctxt
;
3802 memset(&ctxt
, 0, sizeof(xmlRelaxNGValidCtxt
));
3804 ctxt
.flags
= FLAGS_IGNORABLE
| FLAGS_NOERROR
;
3806 if ((def1
->type
== XML_RELAXNG_ELEMENT
) ||
3807 (def1
->type
== XML_RELAXNG_ATTRIBUTE
)) {
3808 if (def2
->type
== XML_RELAXNG_TEXT
)
3810 if (def1
->name
!= NULL
) {
3811 node
.name
= def1
->name
;
3813 node
.name
= invalidName
;
3815 if (def1
->ns
!= NULL
) {
3816 if (def1
->ns
[0] == 0) {
3825 if (xmlRelaxNGElementMatch(&ctxt
, def2
, &node
)) {
3826 if (def1
->nameClass
!= NULL
) {
3827 ret
= xmlRelaxNGCompareNameClasses(def1
->nameClass
, def2
);
3834 } else if (def1
->type
== XML_RELAXNG_TEXT
) {
3835 if (def2
->type
== XML_RELAXNG_TEXT
)
3838 } else if (def1
->type
== XML_RELAXNG_EXCEPT
) {
3839 ret
= xmlRelaxNGCompareNameClasses(def1
->content
, def2
);
3849 if ((def2
->type
== XML_RELAXNG_ELEMENT
) ||
3850 (def2
->type
== XML_RELAXNG_ATTRIBUTE
)) {
3851 if (def2
->name
!= NULL
) {
3852 node
.name
= def2
->name
;
3854 node
.name
= invalidName
;
3857 if (def2
->ns
!= NULL
) {
3858 if (def2
->ns
[0] == 0) {
3864 ns
.href
= invalidName
;
3866 if (xmlRelaxNGElementMatch(&ctxt
, def1
, &node
)) {
3867 if (def2
->nameClass
!= NULL
) {
3868 ret
= xmlRelaxNGCompareNameClasses(def2
->nameClass
, def1
);
3883 * xmlRelaxNGCompareElemDefLists:
3884 * @ctxt: a Relax-NG parser context
3885 * @defs1: the first list of element/attribute defs
3886 * @defs2: the second list of element/attribute defs
3888 * Compare the 2 lists of element or attribute definitions. The comparison
3889 * is that if both lists do not accept the same QNames, it returns 1
3890 * If the 2 lists can accept the same QName the comparison returns 0
3892 * Returns 1 distinct, 0 if equal
3895 xmlRelaxNGCompareElemDefLists(xmlRelaxNGParserCtxtPtr ctxt
3896 ATTRIBUTE_UNUSED
, xmlRelaxNGDefinePtr
* def1
,
3897 xmlRelaxNGDefinePtr
* def2
)
3899 xmlRelaxNGDefinePtr
*basedef2
= def2
;
3901 if ((def1
== NULL
) || (def2
== NULL
))
3903 if ((*def1
== NULL
) || (*def2
== NULL
))
3905 while (*def1
!= NULL
) {
3906 while ((*def2
) != NULL
) {
3907 if (xmlRelaxNGCompareNameClasses(*def1
, *def2
) == 0)
3918 * xmlRelaxNGGenerateAttributes:
3919 * @ctxt: a Relax-NG parser context
3920 * @def: the definition definition
3922 * Check if the definition can only generate attributes
3924 * Returns 1 if yes, 0 if no and -1 in case of error.
3927 xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt
,
3928 xmlRelaxNGDefinePtr def
)
3930 xmlRelaxNGDefinePtr parent
, cur
, tmp
;
3933 * Don't run that check in case of error. Infinite recursion
3936 if (ctxt
->nbErrors
!= 0)
3941 while (cur
!= NULL
) {
3942 if ((cur
->type
== XML_RELAXNG_ELEMENT
) ||
3943 (cur
->type
== XML_RELAXNG_TEXT
) ||
3944 (cur
->type
== XML_RELAXNG_DATATYPE
) ||
3945 (cur
->type
== XML_RELAXNG_PARAM
) ||
3946 (cur
->type
== XML_RELAXNG_LIST
) ||
3947 (cur
->type
== XML_RELAXNG_VALUE
) ||
3948 (cur
->type
== XML_RELAXNG_EMPTY
))
3950 if ((cur
->type
== XML_RELAXNG_CHOICE
) ||
3951 (cur
->type
== XML_RELAXNG_INTERLEAVE
) ||
3952 (cur
->type
== XML_RELAXNG_GROUP
) ||
3953 (cur
->type
== XML_RELAXNG_ONEORMORE
) ||
3954 (cur
->type
== XML_RELAXNG_ZEROORMORE
) ||
3955 (cur
->type
== XML_RELAXNG_OPTIONAL
) ||
3956 (cur
->type
== XML_RELAXNG_PARENTREF
) ||
3957 (cur
->type
== XML_RELAXNG_EXTERNALREF
) ||
3958 (cur
->type
== XML_RELAXNG_REF
) ||
3959 (cur
->type
== XML_RELAXNG_DEF
)) {
3960 if (cur
->content
!= NULL
) {
3964 while (tmp
!= NULL
) {
3965 tmp
->parent
= parent
;
3973 if (cur
->next
!= NULL
) {
3983 if (cur
->next
!= NULL
) {
3987 } while (cur
!= NULL
);
3993 * xmlRelaxNGGetElements:
3994 * @ctxt: a Relax-NG parser context
3995 * @def: the definition definition
3996 * @eora: gather elements (0), attributes (1) or elements and text (2)
3998 * Compute the list of top elements a definition can generate
4000 * Returns a list of elements or NULL if none was found.
4002 static xmlRelaxNGDefinePtr
*
4003 xmlRelaxNGGetElements(xmlRelaxNGParserCtxtPtr ctxt
,
4004 xmlRelaxNGDefinePtr def
, int eora
)
4006 xmlRelaxNGDefinePtr
*ret
= NULL
, parent
, cur
, tmp
;
4011 * Don't run that check in case of error. Infinite recursion
4014 if (ctxt
->nbErrors
!= 0)
4019 while (cur
!= NULL
) {
4020 if (((eora
== 0) && ((cur
->type
== XML_RELAXNG_ELEMENT
) ||
4021 (cur
->type
== XML_RELAXNG_TEXT
))) ||
4022 ((eora
== 1) && (cur
->type
== XML_RELAXNG_ATTRIBUTE
)) ||
4023 ((eora
== 2) && ((cur
->type
== XML_RELAXNG_DATATYPE
) ||
4024 (cur
->type
== XML_RELAXNG_ELEMENT
) ||
4025 (cur
->type
== XML_RELAXNG_LIST
) ||
4026 (cur
->type
== XML_RELAXNG_TEXT
) ||
4027 (cur
->type
== XML_RELAXNG_VALUE
)))) {
4030 ret
= (xmlRelaxNGDefinePtr
*)
4031 xmlMalloc((max
+ 1) * sizeof(xmlRelaxNGDefinePtr
));
4033 xmlRngPErrMemory(ctxt
, "getting element list\n");
4036 } else if (max
<= len
) {
4037 xmlRelaxNGDefinePtr
*temp
;
4040 temp
= xmlRealloc(ret
,
4041 (max
+ 1) * sizeof(xmlRelaxNGDefinePtr
));
4043 xmlRngPErrMemory(ctxt
, "getting element list\n");
4051 } else if ((cur
->type
== XML_RELAXNG_CHOICE
) ||
4052 (cur
->type
== XML_RELAXNG_INTERLEAVE
) ||
4053 (cur
->type
== XML_RELAXNG_GROUP
) ||
4054 (cur
->type
== XML_RELAXNG_ONEORMORE
) ||
4055 (cur
->type
== XML_RELAXNG_ZEROORMORE
) ||
4056 (cur
->type
== XML_RELAXNG_OPTIONAL
) ||
4057 (cur
->type
== XML_RELAXNG_PARENTREF
) ||
4058 (cur
->type
== XML_RELAXNG_REF
) ||
4059 (cur
->type
== XML_RELAXNG_DEF
) ||
4060 (cur
->type
== XML_RELAXNG_EXTERNALREF
)) {
4062 * Don't go within elements or attributes or string values.
4063 * Just gather the element top list
4065 if (cur
->content
!= NULL
) {
4069 while (tmp
!= NULL
) {
4070 tmp
->parent
= parent
;
4078 if (cur
->next
!= NULL
) {
4088 if (cur
->next
!= NULL
) {
4092 } while (cur
!= NULL
);
4098 * xmlRelaxNGCheckChoiceDeterminism:
4099 * @ctxt: a Relax-NG parser context
4100 * @def: the choice definition
4102 * Also used to find indeterministic pattern in choice
4105 xmlRelaxNGCheckChoiceDeterminism(xmlRelaxNGParserCtxtPtr ctxt
,
4106 xmlRelaxNGDefinePtr def
)
4108 xmlRelaxNGDefinePtr
**list
;
4109 xmlRelaxNGDefinePtr cur
;
4110 int nbchild
= 0, i
, j
, ret
;
4111 int is_nullable
= 0;
4112 int is_indeterminist
= 0;
4113 xmlHashTablePtr triage
= NULL
;
4116 if ((def
== NULL
) || (def
->type
!= XML_RELAXNG_CHOICE
))
4119 if (def
->dflags
& IS_PROCESSED
)
4123 * Don't run that check in case of error. Infinite recursion
4126 if (ctxt
->nbErrors
!= 0)
4129 is_nullable
= xmlRelaxNGIsNullable(def
);
4132 while (cur
!= NULL
) {
4137 list
= (xmlRelaxNGDefinePtr
**) xmlMalloc(nbchild
*
4138 sizeof(xmlRelaxNGDefinePtr
4141 xmlRngPErrMemory(ctxt
, "building choice\n");
4146 * a bit strong but safe
4148 if (is_nullable
== 0) {
4149 triage
= xmlHashCreate(10);
4154 while (cur
!= NULL
) {
4155 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 0);
4156 if ((list
[i
] == NULL
) || (list
[i
][0] == NULL
)) {
4158 } else if (is_triable
== 1) {
4159 xmlRelaxNGDefinePtr
*tmp
;
4163 while ((*tmp
!= NULL
) && (is_triable
== 1)) {
4164 if ((*tmp
)->type
== XML_RELAXNG_TEXT
) {
4165 res
= xmlHashAddEntry2(triage
,
4166 BAD_CAST
"#text", NULL
,
4170 } else if (((*tmp
)->type
== XML_RELAXNG_ELEMENT
) &&
4171 ((*tmp
)->name
!= NULL
)) {
4172 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4173 res
= xmlHashAddEntry2(triage
,
4177 res
= xmlHashAddEntry2(triage
,
4178 (*tmp
)->name
, (*tmp
)->ns
,
4182 } else if ((*tmp
)->type
== XML_RELAXNG_ELEMENT
) {
4183 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4184 res
= xmlHashAddEntry2(triage
,
4185 BAD_CAST
"#any", NULL
,
4188 res
= xmlHashAddEntry2(triage
,
4189 BAD_CAST
"#any", (*tmp
)->ns
,
4203 for (i
= 0; i
< nbchild
; i
++) {
4204 if (list
[i
] == NULL
)
4206 for (j
= 0; j
< i
; j
++) {
4207 if (list
[j
] == NULL
)
4209 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, list
[i
], list
[j
]);
4211 is_indeterminist
= 1;
4215 for (i
= 0; i
< nbchild
; i
++) {
4216 if (list
[i
] != NULL
)
4221 if (is_indeterminist
) {
4222 def
->dflags
|= IS_INDETERMINIST
;
4224 if (is_triable
== 1) {
4225 def
->dflags
|= IS_TRIABLE
;
4227 } else if (triage
!= NULL
) {
4228 xmlHashFree(triage
, NULL
);
4230 def
->dflags
|= IS_PROCESSED
;
4234 * xmlRelaxNGCheckGroupAttrs:
4235 * @ctxt: a Relax-NG parser context
4236 * @def: the group definition
4238 * Detects violations of rule 7.3
4241 xmlRelaxNGCheckGroupAttrs(xmlRelaxNGParserCtxtPtr ctxt
,
4242 xmlRelaxNGDefinePtr def
)
4244 xmlRelaxNGDefinePtr
**list
;
4245 xmlRelaxNGDefinePtr cur
;
4246 int nbchild
= 0, i
, j
, ret
;
4248 if ((def
== NULL
) ||
4249 ((def
->type
!= XML_RELAXNG_GROUP
) &&
4250 (def
->type
!= XML_RELAXNG_ELEMENT
)))
4253 if (def
->dflags
& IS_PROCESSED
)
4257 * Don't run that check in case of error. Infinite recursion
4260 if (ctxt
->nbErrors
!= 0)
4264 while (cur
!= NULL
) {
4269 while (cur
!= NULL
) {
4274 list
= (xmlRelaxNGDefinePtr
**) xmlMalloc(nbchild
*
4275 sizeof(xmlRelaxNGDefinePtr
4278 xmlRngPErrMemory(ctxt
, "building group\n");
4283 while (cur
!= NULL
) {
4284 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 1);
4289 while (cur
!= NULL
) {
4290 list
[i
] = xmlRelaxNGGetElements(ctxt
, cur
, 1);
4295 for (i
= 0; i
< nbchild
; i
++) {
4296 if (list
[i
] == NULL
)
4298 for (j
= 0; j
< i
; j
++) {
4299 if (list
[j
] == NULL
)
4301 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, list
[i
], list
[j
]);
4303 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_GROUP_ATTR_CONFLICT
,
4304 "Attributes conflicts in group\n", NULL
, NULL
);
4308 for (i
= 0; i
< nbchild
; i
++) {
4309 if (list
[i
] != NULL
)
4314 def
->dflags
|= IS_PROCESSED
;
4318 * xmlRelaxNGComputeInterleaves:
4319 * @def: the interleave definition
4320 * @ctxt: a Relax-NG parser context
4321 * @name: the definition name
4323 * A lot of work for preprocessing interleave definitions
4324 * is potentially needed to get a decent execution speed at runtime
4325 * - trying to get a total order on the element nodes generated
4326 * by the interleaves, order the list of interleave definitions
4327 * following that order.
4328 * - if <text/> is used to handle mixed content, it is better to
4329 * flag this in the define and simplify the runtime checking
4333 xmlRelaxNGComputeInterleaves(void *payload
, void *data
,
4334 const xmlChar
* name ATTRIBUTE_UNUSED
)
4336 xmlRelaxNGDefinePtr def
= (xmlRelaxNGDefinePtr
) payload
;
4337 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
4338 xmlRelaxNGDefinePtr cur
, *tmp
;
4340 xmlRelaxNGPartitionPtr partitions
= NULL
;
4341 xmlRelaxNGInterleaveGroupPtr
*groups
= NULL
;
4342 xmlRelaxNGInterleaveGroupPtr group
;
4347 int is_determinist
= 1;
4350 * Don't run that check in case of error. Infinite recursion
4353 if (ctxt
->nbErrors
!= 0)
4356 #ifdef DEBUG_INTERLEAVE
4357 xmlGenericError(xmlGenericErrorContext
,
4358 "xmlRelaxNGComputeInterleaves(%s)\n", name
);
4361 while (cur
!= NULL
) {
4366 #ifdef DEBUG_INTERLEAVE
4367 xmlGenericError(xmlGenericErrorContext
, " %d child\n", nbchild
);
4369 groups
= (xmlRelaxNGInterleaveGroupPtr
*)
4370 xmlMalloc(nbchild
* sizeof(xmlRelaxNGInterleaveGroupPtr
));
4374 while (cur
!= NULL
) {
4375 groups
[nbgroups
] = (xmlRelaxNGInterleaveGroupPtr
)
4376 xmlMalloc(sizeof(xmlRelaxNGInterleaveGroup
));
4377 if (groups
[nbgroups
] == NULL
)
4379 if (cur
->type
== XML_RELAXNG_TEXT
)
4381 groups
[nbgroups
]->rule
= cur
;
4382 groups
[nbgroups
]->defs
= xmlRelaxNGGetElements(ctxt
, cur
, 2);
4383 groups
[nbgroups
]->attrs
= xmlRelaxNGGetElements(ctxt
, cur
, 1);
4387 #ifdef DEBUG_INTERLEAVE
4388 xmlGenericError(xmlGenericErrorContext
, " %d groups\n", nbgroups
);
4392 * Let's check that all rules makes a partitions according to 7.4
4394 partitions
= (xmlRelaxNGPartitionPtr
)
4395 xmlMalloc(sizeof(xmlRelaxNGPartition
));
4396 if (partitions
== NULL
)
4398 memset(partitions
, 0, sizeof(xmlRelaxNGPartition
));
4399 partitions
->nbgroups
= nbgroups
;
4400 partitions
->triage
= xmlHashCreate(nbgroups
);
4401 for (i
= 0; i
< nbgroups
; i
++) {
4403 for (j
= i
+ 1; j
< nbgroups
; j
++) {
4404 if (groups
[j
] == NULL
)
4407 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, group
->defs
,
4410 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_ELEM_TEXT_CONFLICT
,
4411 "Element or text conflicts in interleave\n",
4414 ret
= xmlRelaxNGCompareElemDefLists(ctxt
, group
->attrs
,
4417 xmlRngPErr(ctxt
, def
->node
, XML_RNGP_ATTR_CONFLICT
,
4418 "Attributes conflicts in interleave\n", NULL
,
4423 if ((tmp
!= NULL
) && (*tmp
!= NULL
)) {
4424 while (*tmp
!= NULL
) {
4425 if ((*tmp
)->type
== XML_RELAXNG_TEXT
) {
4426 res
= xmlHashAddEntry2(partitions
->triage
,
4427 BAD_CAST
"#text", NULL
,
4428 (void *) (ptrdiff_t) (i
+ 1));
4430 is_determinist
= -1;
4431 } else if (((*tmp
)->type
== XML_RELAXNG_ELEMENT
) &&
4432 ((*tmp
)->name
!= NULL
)) {
4433 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4434 res
= xmlHashAddEntry2(partitions
->triage
,
4436 (void *) (ptrdiff_t) (i
+ 1));
4438 res
= xmlHashAddEntry2(partitions
->triage
,
4439 (*tmp
)->name
, (*tmp
)->ns
,
4440 (void *) (ptrdiff_t) (i
+ 1));
4442 is_determinist
= -1;
4443 } else if ((*tmp
)->type
== XML_RELAXNG_ELEMENT
) {
4444 if (((*tmp
)->ns
== NULL
) || ((*tmp
)->ns
[0] == 0))
4445 res
= xmlHashAddEntry2(partitions
->triage
,
4446 BAD_CAST
"#any", NULL
,
4447 (void *) (ptrdiff_t) (i
+ 1));
4449 res
= xmlHashAddEntry2(partitions
->triage
,
4450 BAD_CAST
"#any", (*tmp
)->ns
,
4451 (void *) (ptrdiff_t) (i
+ 1));
4452 if ((*tmp
)->nameClass
!= NULL
)
4455 is_determinist
= -1;
4457 is_determinist
= -1;
4465 partitions
->groups
= groups
;
4468 * and save the partition list back in the def
4470 def
->data
= partitions
;
4472 def
->dflags
|= IS_MIXED
;
4473 if (is_determinist
== 1)
4474 partitions
->flags
= IS_DETERMINIST
;
4475 if (is_determinist
== 2)
4476 partitions
->flags
= IS_DETERMINIST
| IS_NEEDCHECK
;
4480 xmlRngPErrMemory(ctxt
, "in interleave computation\n");
4481 if (groups
!= NULL
) {
4482 for (i
= 0; i
< nbgroups
; i
++)
4483 if (groups
[i
] != NULL
) {
4484 if (groups
[i
]->defs
!= NULL
)
4485 xmlFree(groups
[i
]->defs
);
4490 xmlRelaxNGFreePartition(partitions
);
4494 * xmlRelaxNGParseInterleave:
4495 * @ctxt: a Relax-NG parser context
4496 * @node: the data node.
4498 * parse the content of a RelaxNG interleave node.
4500 * Returns the definition pointer or NULL in case of error
4502 static xmlRelaxNGDefinePtr
4503 xmlRelaxNGParseInterleave(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4505 xmlRelaxNGDefinePtr def
= NULL
;
4506 xmlRelaxNGDefinePtr last
= NULL
, cur
;
4509 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4513 def
->type
= XML_RELAXNG_INTERLEAVE
;
4515 if (ctxt
->interleaves
== NULL
)
4516 ctxt
->interleaves
= xmlHashCreate(10);
4517 if (ctxt
->interleaves
== NULL
) {
4518 xmlRngPErrMemory(ctxt
, "create interleaves\n");
4522 snprintf(name
, 32, "interleave%d", ctxt
->nbInterleaves
++);
4523 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST name
, def
) < 0) {
4524 xmlRngPErr(ctxt
, node
, XML_RNGP_INTERLEAVE_ADD
,
4525 "Failed to add %s to hash table\n",
4526 (const xmlChar
*) name
, NULL
);
4529 child
= node
->children
;
4530 if (child
== NULL
) {
4531 xmlRngPErr(ctxt
, node
, XML_RNGP_INTERLEAVE_NO_CONTENT
,
4532 "Element interleave is empty\n", NULL
, NULL
);
4534 while (child
!= NULL
) {
4535 if (IS_RELAXNG(child
, "element")) {
4536 cur
= xmlRelaxNGParseElement(ctxt
, child
);
4538 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
4543 def
->content
= last
= cur
;
4549 child
= child
->next
;
4556 * xmlRelaxNGParseInclude:
4557 * @ctxt: a Relax-NG parser context
4558 * @node: the include node
4560 * Integrate the content of an include node in the current grammar
4562 * Returns 0 in case of success or -1 in case of error
4565 xmlRelaxNGParseInclude(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4567 xmlRelaxNGIncludePtr incl
;
4573 xmlRngPErr(ctxt
, node
, XML_RNGP_INCLUDE_EMPTY
,
4574 "Include node has no data\n", NULL
, NULL
);
4577 root
= xmlDocGetRootElement(incl
->doc
);
4579 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY
, "Include document is empty\n",
4583 if (!xmlStrEqual(root
->name
, BAD_CAST
"grammar")) {
4584 xmlRngPErr(ctxt
, node
, XML_RNGP_GRAMMAR_MISSING
,
4585 "Include document root is not a grammar\n", NULL
, NULL
);
4590 * Merge the definition from both the include and the internal list
4592 if (root
->children
!= NULL
) {
4593 tmp
= xmlRelaxNGParseGrammarContent(ctxt
, root
->children
);
4597 if (node
->children
!= NULL
) {
4598 tmp
= xmlRelaxNGParseGrammarContent(ctxt
, node
->children
);
4606 * xmlRelaxNGParseDefine:
4607 * @ctxt: a Relax-NG parser context
4608 * @node: the define node
4610 * parse the content of a RelaxNG define element node.
4612 * Returns 0 in case of success or -1 in case of error
4615 xmlRelaxNGParseDefine(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4619 xmlRelaxNGDefinePtr def
;
4620 const xmlChar
*olddefine
;
4622 name
= xmlGetProp(node
, BAD_CAST
"name");
4624 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_NAME_MISSING
,
4625 "define has no name\n", NULL
, NULL
);
4627 xmlRelaxNGNormExtSpace(name
);
4628 if (xmlValidateNCName(name
, 0)) {
4629 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_DEFINE_NAME
,
4630 "define name '%s' is not an NCName\n", name
, NULL
);
4632 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4637 def
->type
= XML_RELAXNG_DEF
;
4639 if (node
->children
== NULL
) {
4640 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_EMPTY
,
4641 "define has no children\n", NULL
, NULL
);
4643 olddefine
= ctxt
->define
;
4644 ctxt
->define
= name
;
4646 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4647 ctxt
->define
= olddefine
;
4649 if (ctxt
->grammar
->defs
== NULL
)
4650 ctxt
->grammar
->defs
= xmlHashCreate(10);
4651 if (ctxt
->grammar
->defs
== NULL
) {
4652 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_CREATE_FAILED
,
4653 "Could not create definition hash\n", NULL
, NULL
);
4656 tmp
= xmlHashAddEntry(ctxt
->grammar
->defs
, name
, def
);
4658 xmlRelaxNGDefinePtr prev
;
4660 prev
= xmlHashLookup(ctxt
->grammar
->defs
, name
);
4662 xmlRngPErr(ctxt
, node
, XML_RNGP_DEFINE_CREATE_FAILED
,
4663 "Internal error on define aggregation of %s\n",
4667 while (prev
->nextHash
!= NULL
)
4668 prev
= prev
->nextHash
;
4669 prev
->nextHash
= def
;
4678 * xmlRelaxNGParseImportRef:
4679 * @payload: the parser context
4680 * @data: the current grammar
4681 * @name: the reference name
4683 * Import import one references into the current grammar
4686 xmlRelaxNGParseImportRef(void *payload
, void *data
, const xmlChar
*name
) {
4687 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
4688 xmlRelaxNGDefinePtr def
= (xmlRelaxNGDefinePtr
) payload
;
4691 def
->dflags
|= IS_EXTERNAL_REF
;
4693 tmp
= xmlHashAddEntry(ctxt
->grammar
->refs
, name
, def
);
4695 xmlRelaxNGDefinePtr prev
;
4697 prev
= (xmlRelaxNGDefinePtr
)
4698 xmlHashLookup(ctxt
->grammar
->refs
, def
->name
);
4700 if (def
->name
!= NULL
) {
4701 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4702 "Error refs definitions '%s'\n",
4705 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4706 "Error refs definitions\n",
4710 def
->nextHash
= prev
->nextHash
;
4711 prev
->nextHash
= def
;
4717 * xmlRelaxNGParseImportRefs:
4718 * @ctxt: the parser context
4719 * @grammar: the sub grammar
4721 * Import references from the subgrammar into the current grammar
4723 * Returns 0 in case of success, -1 in case of failure
4726 xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt
,
4727 xmlRelaxNGGrammarPtr grammar
) {
4728 if ((ctxt
== NULL
) || (grammar
== NULL
) || (ctxt
->grammar
== NULL
))
4730 if (grammar
->refs
== NULL
)
4732 if (ctxt
->grammar
->refs
== NULL
)
4733 ctxt
->grammar
->refs
= xmlHashCreate(10);
4734 if (ctxt
->grammar
->refs
== NULL
) {
4735 xmlRngPErr(ctxt
, NULL
, XML_RNGP_REF_CREATE_FAILED
,
4736 "Could not create references hash\n", NULL
, NULL
);
4739 xmlHashScan(grammar
->refs
, xmlRelaxNGParseImportRef
, ctxt
);
4744 * xmlRelaxNGProcessExternalRef:
4745 * @ctxt: the parser context
4746 * @node: the externalRef node
4748 * Process and compile an externalRef node
4750 * Returns the xmlRelaxNGDefinePtr or NULL in case of error
4752 static xmlRelaxNGDefinePtr
4753 xmlRelaxNGProcessExternalRef(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4755 xmlRelaxNGDocumentPtr docu
;
4756 xmlNodePtr root
, tmp
;
4758 int newNs
= 0, oldflags
;
4759 xmlRelaxNGDefinePtr def
;
4763 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4766 def
->type
= XML_RELAXNG_EXTERNALREF
;
4768 if (docu
->content
== NULL
) {
4770 * Then do the parsing for good
4772 root
= xmlDocGetRootElement(docu
->doc
);
4774 xmlRngPErr(ctxt
, node
, XML_RNGP_EXTERNALREF_EMTPY
,
4775 "xmlRelaxNGParse: %s is empty\n", ctxt
->URL
,
4780 * ns transmission rules
4782 ns
= xmlGetProp(root
, BAD_CAST
"ns");
4785 while ((tmp
!= NULL
) && (tmp
->type
== XML_ELEMENT_NODE
)) {
4786 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
4793 xmlSetProp(root
, BAD_CAST
"ns", ns
);
4802 * Parsing to get a precompiled schemas.
4804 oldflags
= ctxt
->flags
;
4805 ctxt
->flags
|= XML_RELAXNG_IN_EXTERNALREF
;
4806 docu
->schema
= xmlRelaxNGParseDocument(ctxt
, root
);
4807 ctxt
->flags
= oldflags
;
4808 if ((docu
->schema
!= NULL
) &&
4809 (docu
->schema
->topgrammar
!= NULL
)) {
4810 docu
->content
= docu
->schema
->topgrammar
->start
;
4811 if (docu
->schema
->topgrammar
->refs
)
4812 xmlRelaxNGParseImportRefs(ctxt
, docu
->schema
->topgrammar
);
4816 * the externalRef may be reused in a different ns context
4819 xmlUnsetProp(root
, BAD_CAST
"ns");
4822 def
->content
= docu
->content
;
4830 * xmlRelaxNGParsePattern:
4831 * @ctxt: a Relax-NG parser context
4832 * @node: the pattern node.
4834 * parse the content of a RelaxNG pattern node.
4836 * Returns the definition pointer or NULL in case of error or if no
4837 * pattern is generated.
4839 static xmlRelaxNGDefinePtr
4840 xmlRelaxNGParsePattern(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
4842 xmlRelaxNGDefinePtr def
= NULL
;
4847 if (IS_RELAXNG(node
, "element")) {
4848 def
= xmlRelaxNGParseElement(ctxt
, node
);
4849 } else if (IS_RELAXNG(node
, "attribute")) {
4850 def
= xmlRelaxNGParseAttribute(ctxt
, node
);
4851 } else if (IS_RELAXNG(node
, "empty")) {
4852 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4855 def
->type
= XML_RELAXNG_EMPTY
;
4856 if (node
->children
!= NULL
) {
4857 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_NOT_EMPTY
,
4858 "empty: had a child node\n", NULL
, NULL
);
4860 } else if (IS_RELAXNG(node
, "text")) {
4861 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4864 def
->type
= XML_RELAXNG_TEXT
;
4865 if (node
->children
!= NULL
) {
4866 xmlRngPErr(ctxt
, node
, XML_RNGP_TEXT_HAS_CHILD
,
4867 "text: had a child node\n", NULL
, NULL
);
4869 } else if (IS_RELAXNG(node
, "zeroOrMore")) {
4870 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4873 def
->type
= XML_RELAXNG_ZEROORMORE
;
4874 if (node
->children
== NULL
) {
4875 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4876 "Element %s is empty\n", node
->name
, NULL
);
4879 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4881 } else if (IS_RELAXNG(node
, "oneOrMore")) {
4882 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4885 def
->type
= XML_RELAXNG_ONEORMORE
;
4886 if (node
->children
== NULL
) {
4887 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4888 "Element %s is empty\n", node
->name
, NULL
);
4891 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4893 } else if (IS_RELAXNG(node
, "optional")) {
4894 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4897 def
->type
= XML_RELAXNG_OPTIONAL
;
4898 if (node
->children
== NULL
) {
4899 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4900 "Element %s is empty\n", node
->name
, NULL
);
4903 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 1);
4905 } else if (IS_RELAXNG(node
, "choice")) {
4906 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4909 def
->type
= XML_RELAXNG_CHOICE
;
4910 if (node
->children
== NULL
) {
4911 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4912 "Element %s is empty\n", node
->name
, NULL
);
4915 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4917 } else if (IS_RELAXNG(node
, "group")) {
4918 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4921 def
->type
= XML_RELAXNG_GROUP
;
4922 if (node
->children
== NULL
) {
4923 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4924 "Element %s is empty\n", node
->name
, NULL
);
4927 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4929 } else if (IS_RELAXNG(node
, "ref")) {
4930 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4933 def
->type
= XML_RELAXNG_REF
;
4934 def
->name
= xmlGetProp(node
, BAD_CAST
"name");
4935 if (def
->name
== NULL
) {
4936 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NO_NAME
, "ref has no name\n",
4939 xmlRelaxNGNormExtSpace(def
->name
);
4940 if (xmlValidateNCName(def
->name
, 0)) {
4941 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NAME_INVALID
,
4942 "ref name '%s' is not an NCName\n", def
->name
,
4946 if (node
->children
!= NULL
) {
4947 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_NOT_EMPTY
, "ref is not empty\n",
4950 if (ctxt
->grammar
->refs
== NULL
)
4951 ctxt
->grammar
->refs
= xmlHashCreate(10);
4952 if (ctxt
->grammar
->refs
== NULL
) {
4953 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4954 "Could not create references hash\n", NULL
, NULL
);
4959 tmp
= xmlHashAddEntry(ctxt
->grammar
->refs
, def
->name
, def
);
4961 xmlRelaxNGDefinePtr prev
;
4963 prev
= (xmlRelaxNGDefinePtr
)
4964 xmlHashLookup(ctxt
->grammar
->refs
, def
->name
);
4966 if (def
->name
!= NULL
) {
4967 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4968 "Error refs definitions '%s'\n",
4971 xmlRngPErr(ctxt
, node
, XML_RNGP_REF_CREATE_FAILED
,
4972 "Error refs definitions\n",
4977 def
->nextHash
= prev
->nextHash
;
4978 prev
->nextHash
= def
;
4982 } else if (IS_RELAXNG(node
, "data")) {
4983 def
= xmlRelaxNGParseData(ctxt
, node
);
4984 } else if (IS_RELAXNG(node
, "value")) {
4985 def
= xmlRelaxNGParseValue(ctxt
, node
);
4986 } else if (IS_RELAXNG(node
, "list")) {
4987 def
= xmlRelaxNGNewDefine(ctxt
, node
);
4990 def
->type
= XML_RELAXNG_LIST
;
4991 if (node
->children
== NULL
) {
4992 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
,
4993 "Element %s is empty\n", node
->name
, NULL
);
4996 xmlRelaxNGParsePatterns(ctxt
, node
->children
, 0);
4998 } else if (IS_RELAXNG(node
, "interleave")) {
4999 def
= xmlRelaxNGParseInterleave(ctxt
, node
);
5000 } else if (IS_RELAXNG(node
, "externalRef")) {
5001 def
= xmlRelaxNGProcessExternalRef(ctxt
, node
);
5002 } else if (IS_RELAXNG(node
, "notAllowed")) {
5003 def
= xmlRelaxNGNewDefine(ctxt
, node
);
5006 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
5007 if (node
->children
!= NULL
) {
5008 xmlRngPErr(ctxt
, node
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
5009 "xmlRelaxNGParse: notAllowed element is not empty\n",
5012 } else if (IS_RELAXNG(node
, "grammar")) {
5013 xmlRelaxNGGrammarPtr grammar
, old
;
5014 xmlRelaxNGGrammarPtr oldparent
;
5016 #ifdef DEBUG_GRAMMAR
5017 xmlGenericError(xmlGenericErrorContext
,
5018 "Found <grammar> pattern\n");
5021 oldparent
= ctxt
->parentgrammar
;
5022 old
= ctxt
->grammar
;
5023 ctxt
->parentgrammar
= old
;
5024 grammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
5026 ctxt
->grammar
= old
;
5027 ctxt
->parentgrammar
= oldparent
;
5029 if (grammar
!= NULL
) {
5030 grammar
->next
= old
->next
;
5031 old
->next
= grammar
;
5035 if (grammar
!= NULL
)
5036 def
= grammar
->start
;
5039 } else if (IS_RELAXNG(node
, "parentRef")) {
5040 if (ctxt
->parentgrammar
== NULL
) {
5041 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NO_PARENT
,
5042 "Use of parentRef without a parent grammar\n", NULL
,
5046 def
= xmlRelaxNGNewDefine(ctxt
, node
);
5049 def
->type
= XML_RELAXNG_PARENTREF
;
5050 def
->name
= xmlGetProp(node
, BAD_CAST
"name");
5051 if (def
->name
== NULL
) {
5052 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NO_NAME
,
5053 "parentRef has no name\n", NULL
, NULL
);
5055 xmlRelaxNGNormExtSpace(def
->name
);
5056 if (xmlValidateNCName(def
->name
, 0)) {
5057 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NAME_INVALID
,
5058 "parentRef name '%s' is not an NCName\n",
5062 if (node
->children
!= NULL
) {
5063 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_NOT_EMPTY
,
5064 "parentRef is not empty\n", NULL
, NULL
);
5066 if (ctxt
->parentgrammar
->refs
== NULL
)
5067 ctxt
->parentgrammar
->refs
= xmlHashCreate(10);
5068 if (ctxt
->parentgrammar
->refs
== NULL
) {
5069 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_CREATE_FAILED
,
5070 "Could not create references hash\n", NULL
, NULL
);
5072 } else if (def
->name
!= NULL
) {
5076 xmlHashAddEntry(ctxt
->parentgrammar
->refs
, def
->name
, def
);
5078 xmlRelaxNGDefinePtr prev
;
5080 prev
= (xmlRelaxNGDefinePtr
)
5081 xmlHashLookup(ctxt
->parentgrammar
->refs
, def
->name
);
5083 xmlRngPErr(ctxt
, node
, XML_RNGP_PARENTREF_CREATE_FAILED
,
5084 "Internal error parentRef definitions '%s'\n",
5088 def
->nextHash
= prev
->nextHash
;
5089 prev
->nextHash
= def
;
5093 } else if (IS_RELAXNG(node
, "mixed")) {
5094 if (node
->children
== NULL
) {
5095 xmlRngPErr(ctxt
, node
, XML_RNGP_EMPTY_CONSTRUCT
, "Mixed is empty\n",
5099 def
= xmlRelaxNGParseInterleave(ctxt
, node
);
5101 xmlRelaxNGDefinePtr tmp
;
5103 if ((def
->content
!= NULL
) && (def
->content
->next
!= NULL
)) {
5104 tmp
= xmlRelaxNGNewDefine(ctxt
, node
);
5106 tmp
->type
= XML_RELAXNG_GROUP
;
5107 tmp
->content
= def
->content
;
5112 tmp
= xmlRelaxNGNewDefine(ctxt
, node
);
5115 tmp
->type
= XML_RELAXNG_TEXT
;
5116 tmp
->next
= def
->content
;
5121 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_CONSTRUCT
,
5122 "Unexpected node %s is not a pattern\n", node
->name
,
5130 * xmlRelaxNGParseAttribute:
5131 * @ctxt: a Relax-NG parser context
5132 * @node: the element node
5134 * parse the content of a RelaxNG attribute node.
5136 * Returns the definition pointer or NULL in case of error.
5138 static xmlRelaxNGDefinePtr
5139 xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5141 xmlRelaxNGDefinePtr ret
, cur
;
5145 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5148 ret
->type
= XML_RELAXNG_ATTRIBUTE
;
5149 ret
->parent
= ctxt
->def
;
5150 child
= node
->children
;
5151 if (child
== NULL
) {
5152 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_EMPTY
,
5153 "xmlRelaxNGParseattribute: attribute has no children\n",
5157 old_flags
= ctxt
->flags
;
5158 ctxt
->flags
|= XML_RELAXNG_IN_ATTRIBUTE
;
5159 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5161 child
= child
->next
;
5163 if (child
!= NULL
) {
5164 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5166 switch (cur
->type
) {
5167 case XML_RELAXNG_EMPTY
:
5168 case XML_RELAXNG_NOT_ALLOWED
:
5169 case XML_RELAXNG_TEXT
:
5170 case XML_RELAXNG_ELEMENT
:
5171 case XML_RELAXNG_DATATYPE
:
5172 case XML_RELAXNG_VALUE
:
5173 case XML_RELAXNG_LIST
:
5174 case XML_RELAXNG_REF
:
5175 case XML_RELAXNG_PARENTREF
:
5176 case XML_RELAXNG_EXTERNALREF
:
5177 case XML_RELAXNG_DEF
:
5178 case XML_RELAXNG_ONEORMORE
:
5179 case XML_RELAXNG_ZEROORMORE
:
5180 case XML_RELAXNG_OPTIONAL
:
5181 case XML_RELAXNG_CHOICE
:
5182 case XML_RELAXNG_GROUP
:
5183 case XML_RELAXNG_INTERLEAVE
:
5184 case XML_RELAXNG_ATTRIBUTE
:
5188 case XML_RELAXNG_START
:
5189 case XML_RELAXNG_PARAM
:
5190 case XML_RELAXNG_EXCEPT
:
5191 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_CONTENT
,
5192 "attribute has invalid content\n", NULL
,
5195 case XML_RELAXNG_NOOP
:
5196 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_NOOP
,
5197 "RNG Internal error, noop found in attribute\n",
5202 child
= child
->next
;
5204 if (child
!= NULL
) {
5205 xmlRngPErr(ctxt
, node
, XML_RNGP_ATTRIBUTE_CHILDREN
,
5206 "attribute has multiple children\n", NULL
, NULL
);
5208 ctxt
->flags
= old_flags
;
5213 * xmlRelaxNGParseExceptNameClass:
5214 * @ctxt: a Relax-NG parser context
5215 * @node: the except node
5216 * @attr: 1 if within an attribute, 0 if within an element
5218 * parse the content of a RelaxNG nameClass node.
5220 * Returns the definition pointer or NULL in case of error.
5222 static xmlRelaxNGDefinePtr
5223 xmlRelaxNGParseExceptNameClass(xmlRelaxNGParserCtxtPtr ctxt
,
5224 xmlNodePtr node
, int attr
)
5226 xmlRelaxNGDefinePtr ret
, cur
, last
= NULL
;
5229 if (!IS_RELAXNG(node
, "except")) {
5230 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_MISSING
,
5231 "Expecting an except node\n", NULL
, NULL
);
5234 if (node
->next
!= NULL
) {
5235 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_MULTIPLE
,
5236 "exceptNameClass allows only a single except node\n",
5239 if (node
->children
== NULL
) {
5240 xmlRngPErr(ctxt
, node
, XML_RNGP_EXCEPT_EMPTY
, "except has no content\n",
5245 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5248 ret
->type
= XML_RELAXNG_EXCEPT
;
5249 child
= node
->children
;
5250 while (child
!= NULL
) {
5251 cur
= xmlRelaxNGNewDefine(ctxt
, child
);
5255 cur
->type
= XML_RELAXNG_ATTRIBUTE
;
5257 cur
->type
= XML_RELAXNG_ELEMENT
;
5259 if (xmlRelaxNGParseNameClass(ctxt
, child
, cur
) != NULL
) {
5267 child
= child
->next
;
5274 * xmlRelaxNGParseNameClass:
5275 * @ctxt: a Relax-NG parser context
5276 * @node: the nameClass node
5277 * @def: the current definition
5279 * parse the content of a RelaxNG nameClass node.
5281 * Returns the definition pointer or NULL in case of error.
5283 static xmlRelaxNGDefinePtr
5284 xmlRelaxNGParseNameClass(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
,
5285 xmlRelaxNGDefinePtr def
)
5287 xmlRelaxNGDefinePtr ret
, tmp
;
5291 if ((IS_RELAXNG(node
, "name")) || (IS_RELAXNG(node
, "anyName")) ||
5292 (IS_RELAXNG(node
, "nsName"))) {
5293 if ((def
->type
!= XML_RELAXNG_ELEMENT
) &&
5294 (def
->type
!= XML_RELAXNG_ATTRIBUTE
)) {
5295 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5299 if (ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
)
5300 ret
->type
= XML_RELAXNG_ATTRIBUTE
;
5302 ret
->type
= XML_RELAXNG_ELEMENT
;
5305 if (IS_RELAXNG(node
, "name")) {
5306 val
= xmlNodeGetContent(node
);
5307 xmlRelaxNGNormExtSpace(val
);
5308 if (xmlValidateNCName(val
, 0)) {
5309 if (node
->parent
!= NULL
)
5310 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NAME
,
5311 "Element %s name '%s' is not an NCName\n",
5312 node
->parent
->name
, val
);
5314 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NAME
,
5315 "name '%s' is not an NCName\n",
5319 val
= xmlGetProp(node
, BAD_CAST
"ns");
5321 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5323 (xmlStrEqual(val
, BAD_CAST
"http://www.w3.org/2000/xmlns"))) {
5324 xmlRngPErr(ctxt
, node
, XML_RNGP_XML_NS
,
5325 "Attribute with namespace '%s' is not allowed\n",
5328 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5330 (val
[0] == 0) && (xmlStrEqual(ret
->name
, BAD_CAST
"xmlns"))) {
5331 xmlRngPErr(ctxt
, node
, XML_RNGP_XMLNS_NAME
,
5332 "Attribute with QName 'xmlns' is not allowed\n",
5335 } else if (IS_RELAXNG(node
, "anyName")) {
5338 if (node
->children
!= NULL
) {
5340 xmlRelaxNGParseExceptNameClass(ctxt
, node
->children
,
5342 XML_RELAXNG_ATTRIBUTE
));
5344 } else if (IS_RELAXNG(node
, "nsName")) {
5346 ret
->ns
= xmlGetProp(node
, BAD_CAST
"ns");
5347 if (ret
->ns
== NULL
) {
5348 xmlRngPErr(ctxt
, node
, XML_RNGP_NSNAME_NO_NS
,
5349 "nsName has no ns attribute\n", NULL
, NULL
);
5351 if ((ctxt
->flags
& XML_RELAXNG_IN_ATTRIBUTE
) &&
5352 (ret
->ns
!= NULL
) &&
5354 (ret
->ns
, BAD_CAST
"http://www.w3.org/2000/xmlns"))) {
5355 xmlRngPErr(ctxt
, node
, XML_RNGP_XML_NS
,
5356 "Attribute with namespace '%s' is not allowed\n",
5359 if (node
->children
!= NULL
) {
5361 xmlRelaxNGParseExceptNameClass(ctxt
, node
->children
,
5363 XML_RELAXNG_ATTRIBUTE
));
5365 } else if (IS_RELAXNG(node
, "choice")) {
5367 xmlRelaxNGDefinePtr last
= NULL
;
5369 if (def
->type
== XML_RELAXNG_CHOICE
) {
5372 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5376 ret
->type
= XML_RELAXNG_CHOICE
;
5379 if (node
->children
== NULL
) {
5380 xmlRngPErr(ctxt
, node
, XML_RNGP_CHOICE_EMPTY
,
5381 "Element choice is empty\n", NULL
, NULL
);
5384 child
= node
->children
;
5385 while (child
!= NULL
) {
5386 tmp
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5395 child
= child
->next
;
5399 xmlRngPErr(ctxt
, node
, XML_RNGP_CHOICE_CONTENT
,
5400 "expecting name, anyName, nsName or choice : got %s\n",
5401 (node
== NULL
? (const xmlChar
*) "nothing" : node
->name
),
5406 if (def
->nameClass
== NULL
) {
5407 def
->nameClass
= ret
;
5409 tmp
= def
->nameClass
;
5410 while (tmp
->next
!= NULL
) {
5420 * xmlRelaxNGParseElement:
5421 * @ctxt: a Relax-NG parser context
5422 * @node: the element node
5424 * parse the content of a RelaxNG element node.
5426 * Returns the definition pointer or NULL in case of error.
5428 static xmlRelaxNGDefinePtr
5429 xmlRelaxNGParseElement(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
5431 xmlRelaxNGDefinePtr ret
, cur
, last
;
5433 const xmlChar
*olddefine
;
5435 ret
= xmlRelaxNGNewDefine(ctxt
, node
);
5438 ret
->type
= XML_RELAXNG_ELEMENT
;
5439 ret
->parent
= ctxt
->def
;
5440 child
= node
->children
;
5441 if (child
== NULL
) {
5442 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_EMPTY
,
5443 "xmlRelaxNGParseElement: element has no children\n",
5447 cur
= xmlRelaxNGParseNameClass(ctxt
, child
, ret
);
5449 child
= child
->next
;
5451 if (child
== NULL
) {
5452 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_NO_CONTENT
,
5453 "xmlRelaxNGParseElement: element has no content\n",
5457 olddefine
= ctxt
->define
;
5458 ctxt
->define
= NULL
;
5460 while (child
!= NULL
) {
5461 cur
= xmlRelaxNGParsePattern(ctxt
, child
);
5464 switch (cur
->type
) {
5465 case XML_RELAXNG_EMPTY
:
5466 case XML_RELAXNG_NOT_ALLOWED
:
5467 case XML_RELAXNG_TEXT
:
5468 case XML_RELAXNG_ELEMENT
:
5469 case XML_RELAXNG_DATATYPE
:
5470 case XML_RELAXNG_VALUE
:
5471 case XML_RELAXNG_LIST
:
5472 case XML_RELAXNG_REF
:
5473 case XML_RELAXNG_PARENTREF
:
5474 case XML_RELAXNG_EXTERNALREF
:
5475 case XML_RELAXNG_DEF
:
5476 case XML_RELAXNG_ZEROORMORE
:
5477 case XML_RELAXNG_ONEORMORE
:
5478 case XML_RELAXNG_OPTIONAL
:
5479 case XML_RELAXNG_CHOICE
:
5480 case XML_RELAXNG_GROUP
:
5481 case XML_RELAXNG_INTERLEAVE
:
5483 ret
->content
= last
= cur
;
5485 if ((last
->type
== XML_RELAXNG_ELEMENT
) &&
5486 (ret
->content
== last
)) {
5487 ret
->content
= xmlRelaxNGNewDefine(ctxt
, node
);
5488 if (ret
->content
!= NULL
) {
5489 ret
->content
->type
= XML_RELAXNG_GROUP
;
5490 ret
->content
->content
= last
;
5492 ret
->content
= last
;
5499 case XML_RELAXNG_ATTRIBUTE
:
5500 cur
->next
= ret
->attrs
;
5503 case XML_RELAXNG_START
:
5504 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5505 "RNG Internal error, start found in element\n",
5508 case XML_RELAXNG_PARAM
:
5509 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5510 "RNG Internal error, param found in element\n",
5513 case XML_RELAXNG_EXCEPT
:
5514 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5515 "RNG Internal error, except found in element\n",
5518 case XML_RELAXNG_NOOP
:
5519 xmlRngPErr(ctxt
, node
, XML_RNGP_ELEMENT_CONTENT
,
5520 "RNG Internal error, noop found in element\n",
5525 child
= child
->next
;
5527 ctxt
->define
= olddefine
;
5532 * xmlRelaxNGParsePatterns:
5533 * @ctxt: a Relax-NG parser context
5534 * @nodes: list of nodes
5535 * @group: use an implicit <group> for elements
5537 * parse the content of a RelaxNG start node.
5539 * Returns the definition pointer or NULL in case of error.
5541 static xmlRelaxNGDefinePtr
5542 xmlRelaxNGParsePatterns(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
,
5545 xmlRelaxNGDefinePtr def
= NULL
, last
= NULL
, cur
, parent
;
5548 while (nodes
!= NULL
) {
5549 if (IS_RELAXNG(nodes
, "element")) {
5550 cur
= xmlRelaxNGParseElement(ctxt
, nodes
);
5556 if ((group
== 1) && (def
->type
== XML_RELAXNG_ELEMENT
) &&
5558 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5561 def
->type
= XML_RELAXNG_GROUP
;
5562 def
->content
= last
;
5567 cur
->parent
= parent
;
5569 cur
= xmlRelaxNGParsePattern(ctxt
, nodes
);
5579 nodes
= nodes
->next
;
5585 * xmlRelaxNGParseStart:
5586 * @ctxt: a Relax-NG parser context
5587 * @nodes: start children nodes
5589 * parse the content of a RelaxNG start node.
5591 * Returns 0 in case of success, -1 in case of error
5594 xmlRelaxNGParseStart(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
5597 xmlRelaxNGDefinePtr def
= NULL
, last
;
5599 if (nodes
== NULL
) {
5600 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
, "start has no children\n",
5604 if (IS_RELAXNG(nodes
, "empty")) {
5605 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5608 def
->type
= XML_RELAXNG_EMPTY
;
5609 if (nodes
->children
!= NULL
) {
5610 xmlRngPErr(ctxt
, nodes
, XML_RNGP_EMPTY_CONTENT
,
5611 "element empty is not empty\n", NULL
, NULL
);
5613 } else if (IS_RELAXNG(nodes
, "notAllowed")) {
5614 def
= xmlRelaxNGNewDefine(ctxt
, nodes
);
5617 def
->type
= XML_RELAXNG_NOT_ALLOWED
;
5618 if (nodes
->children
!= NULL
) {
5619 xmlRngPErr(ctxt
, nodes
, XML_RNGP_NOTALLOWED_NOT_EMPTY
,
5620 "element notAllowed is not empty\n", NULL
, NULL
);
5623 def
= xmlRelaxNGParsePatterns(ctxt
, nodes
, 1);
5625 if (ctxt
->grammar
->start
!= NULL
) {
5626 last
= ctxt
->grammar
->start
;
5627 while (last
->next
!= NULL
)
5631 ctxt
->grammar
->start
= def
;
5633 nodes
= nodes
->next
;
5634 if (nodes
!= NULL
) {
5635 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_CONTENT
,
5636 "start more than one children\n", NULL
, NULL
);
5643 * xmlRelaxNGParseGrammarContent:
5644 * @ctxt: a Relax-NG parser context
5645 * @nodes: grammar children nodes
5647 * parse the content of a RelaxNG grammar node.
5649 * Returns 0 in case of success, -1 in case of error
5652 xmlRelaxNGParseGrammarContent(xmlRelaxNGParserCtxtPtr ctxt
,
5657 if (nodes
== NULL
) {
5658 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_EMPTY
,
5659 "grammar has no children\n", NULL
, NULL
);
5662 while (nodes
!= NULL
) {
5663 if (IS_RELAXNG(nodes
, "start")) {
5664 if (nodes
->children
== NULL
) {
5665 xmlRngPErr(ctxt
, nodes
, XML_RNGP_START_EMPTY
,
5666 "start has no children\n", NULL
, NULL
);
5668 tmp
= xmlRelaxNGParseStart(ctxt
, nodes
->children
);
5672 } else if (IS_RELAXNG(nodes
, "define")) {
5673 tmp
= xmlRelaxNGParseDefine(ctxt
, nodes
);
5676 } else if (IS_RELAXNG(nodes
, "include")) {
5677 tmp
= xmlRelaxNGParseInclude(ctxt
, nodes
);
5681 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
5682 "grammar has unexpected child %s\n", nodes
->name
,
5686 nodes
= nodes
->next
;
5692 * xmlRelaxNGCheckReference:
5694 * @ctxt: a Relax-NG parser context
5695 * @name: the name associated to the defines
5697 * Applies the 4.17. combine attribute rule for all the define
5698 * element of a given grammar using the same name.
5701 xmlRelaxNGCheckReference(void *payload
, void *data
, const xmlChar
* name
)
5703 xmlRelaxNGDefinePtr ref
= (xmlRelaxNGDefinePtr
) payload
;
5704 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
5705 xmlRelaxNGGrammarPtr grammar
;
5706 xmlRelaxNGDefinePtr def
, cur
;
5709 * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
5711 if (ref
->dflags
& IS_EXTERNAL_REF
)
5714 grammar
= ctxt
->grammar
;
5715 if (grammar
== NULL
) {
5716 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5717 "Internal error: no grammar in CheckReference %s\n",
5721 if (ref
->content
!= NULL
) {
5722 xmlRngPErr(ctxt
, ref
->node
, XML_ERR_INTERNAL_ERROR
,
5723 "Internal error: reference has content in CheckReference %s\n",
5727 if (grammar
->defs
!= NULL
) {
5728 def
= xmlHashLookup(grammar
->defs
, name
);
5731 while (cur
!= NULL
) {
5733 cur
= cur
->nextHash
;
5736 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5737 "Reference %s has no matching definition\n", name
,
5741 xmlRngPErr(ctxt
, ref
->node
, XML_RNGP_REF_NO_DEF
,
5742 "Reference %s has no matching definition\n", name
,
5748 * xmlRelaxNGCheckCombine:
5749 * @define: the define(s) list
5750 * @ctxt: a Relax-NG parser context
5751 * @name: the name associated to the defines
5753 * Applies the 4.17. combine attribute rule for all the define
5754 * element of a given grammar using the same name.
5757 xmlRelaxNGCheckCombine(void *payload
, void *data
, const xmlChar
* name
)
5759 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) payload
;
5760 xmlRelaxNGParserCtxtPtr ctxt
= (xmlRelaxNGParserCtxtPtr
) data
;
5762 int choiceOrInterleave
= -1;
5764 xmlRelaxNGDefinePtr cur
, last
, tmp
, tmp2
;
5766 if (define
->nextHash
== NULL
)
5769 while (cur
!= NULL
) {
5770 combine
= xmlGetProp(cur
->node
, BAD_CAST
"combine");
5771 if (combine
!= NULL
) {
5772 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5773 if (choiceOrInterleave
== -1)
5774 choiceOrInterleave
= 1;
5775 else if (choiceOrInterleave
== 0) {
5776 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5777 "Defines for %s use both 'choice' and 'interleave'\n",
5780 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5781 if (choiceOrInterleave
== -1)
5782 choiceOrInterleave
= 0;
5783 else if (choiceOrInterleave
== 1) {
5784 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_DEF_CHOICE_AND_INTERLEAVE
,
5785 "Defines for %s use both 'choice' and 'interleave'\n",
5789 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5790 "Defines for %s use unknown combine value '%s''\n",
5798 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_NEED_COMBINE
,
5799 "Some defines for %s needs the combine attribute\n",
5804 cur
= cur
->nextHash
;
5807 xmlGenericError(xmlGenericErrorContext
,
5808 "xmlRelaxNGCheckCombine(): merging %s defines: %d\n",
5809 name
, choiceOrInterleave
);
5811 if (choiceOrInterleave
== -1)
5812 choiceOrInterleave
= 0;
5813 cur
= xmlRelaxNGNewDefine(ctxt
, define
->node
);
5816 if (choiceOrInterleave
== 0)
5817 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5819 cur
->type
= XML_RELAXNG_CHOICE
;
5822 while (tmp
!= NULL
) {
5823 if (tmp
->content
!= NULL
) {
5824 if (tmp
->content
->next
!= NULL
) {
5826 * we need first to create a wrapper.
5828 tmp2
= xmlRelaxNGNewDefine(ctxt
, tmp
->content
->node
);
5831 tmp2
->type
= XML_RELAXNG_GROUP
;
5832 tmp2
->content
= tmp
->content
;
5834 tmp2
= tmp
->content
;
5837 cur
->content
= tmp2
;
5844 tmp
= tmp
->nextHash
;
5846 define
->content
= cur
;
5847 if (choiceOrInterleave
== 0) {
5848 if (ctxt
->interleaves
== NULL
)
5849 ctxt
->interleaves
= xmlHashCreate(10);
5850 if (ctxt
->interleaves
== NULL
) {
5851 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5852 "Failed to create interleaves hash table\n", NULL
,
5857 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5858 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5860 xmlRngPErr(ctxt
, define
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5861 "Failed to add %s to hash table\n",
5862 (const xmlChar
*) tmpname
, NULL
);
5869 * xmlRelaxNGCombineStart:
5870 * @ctxt: a Relax-NG parser context
5871 * @grammar: the grammar
5873 * Applies the 4.17. combine rule for all the start
5874 * element of a given grammar.
5877 xmlRelaxNGCombineStart(xmlRelaxNGParserCtxtPtr ctxt
,
5878 xmlRelaxNGGrammarPtr grammar
)
5880 xmlRelaxNGDefinePtr starts
;
5882 int choiceOrInterleave
= -1;
5884 xmlRelaxNGDefinePtr cur
;
5886 starts
= grammar
->start
;
5887 if ((starts
== NULL
) || (starts
->next
== NULL
))
5890 while (cur
!= NULL
) {
5891 if ((cur
->node
== NULL
) || (cur
->node
->parent
== NULL
) ||
5892 (!xmlStrEqual(cur
->node
->parent
->name
, BAD_CAST
"start"))) {
5894 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_MISSING
,
5895 "Internal error: start element not found\n", NULL
,
5898 combine
= xmlGetProp(cur
->node
->parent
, BAD_CAST
"combine");
5901 if (combine
!= NULL
) {
5902 if (xmlStrEqual(combine
, BAD_CAST
"choice")) {
5903 if (choiceOrInterleave
== -1)
5904 choiceOrInterleave
= 1;
5905 else if (choiceOrInterleave
== 0) {
5906 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5907 "<start> use both 'choice' and 'interleave'\n",
5910 } else if (xmlStrEqual(combine
, BAD_CAST
"interleave")) {
5911 if (choiceOrInterleave
== -1)
5912 choiceOrInterleave
= 0;
5913 else if (choiceOrInterleave
== 1) {
5914 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_START_CHOICE_AND_INTERLEAVE
,
5915 "<start> use both 'choice' and 'interleave'\n",
5919 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_UNKNOWN_COMBINE
,
5920 "<start> uses unknown combine value '%s''\n",
5928 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NEED_COMBINE
,
5929 "Some <start> element miss the combine attribute\n",
5937 xmlGenericError(xmlGenericErrorContext
,
5938 "xmlRelaxNGCombineStart(): merging <start>: %d\n",
5939 choiceOrInterleave
);
5941 if (choiceOrInterleave
== -1)
5942 choiceOrInterleave
= 0;
5943 cur
= xmlRelaxNGNewDefine(ctxt
, starts
->node
);
5946 if (choiceOrInterleave
== 0)
5947 cur
->type
= XML_RELAXNG_INTERLEAVE
;
5949 cur
->type
= XML_RELAXNG_CHOICE
;
5950 cur
->content
= grammar
->start
;
5951 grammar
->start
= cur
;
5952 if (choiceOrInterleave
== 0) {
5953 if (ctxt
->interleaves
== NULL
)
5954 ctxt
->interleaves
= xmlHashCreate(10);
5955 if (ctxt
->interleaves
== NULL
) {
5956 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5957 "Failed to create interleaves hash table\n", NULL
,
5962 snprintf(tmpname
, 32, "interleave%d", ctxt
->nbInterleaves
++);
5963 if (xmlHashAddEntry(ctxt
->interleaves
, BAD_CAST tmpname
, cur
) <
5965 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_INTERLEAVE_CREATE_FAILED
,
5966 "Failed to add %s to hash table\n",
5967 (const xmlChar
*) tmpname
, NULL
);
5974 * xmlRelaxNGCheckCycles:
5975 * @ctxt: a Relax-NG parser context
5976 * @nodes: grammar children nodes
5977 * @depth: the counter
5981 * Returns 0 if check passed, and -1 in case of error
5984 xmlRelaxNGCheckCycles(xmlRelaxNGParserCtxtPtr ctxt
,
5985 xmlRelaxNGDefinePtr cur
, int depth
)
5989 while ((ret
== 0) && (cur
!= NULL
)) {
5990 if ((cur
->type
== XML_RELAXNG_REF
) ||
5991 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
5992 if (cur
->depth
== -1) {
5994 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
5996 } else if (depth
== cur
->depth
) {
5997 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_CYCLE
,
5998 "Detected a cycle in %s references\n",
6002 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6003 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
+ 1);
6005 ret
= xmlRelaxNGCheckCycles(ctxt
, cur
->content
, depth
);
6013 * xmlRelaxNGTryUnlink:
6014 * @ctxt: a Relax-NG parser context
6015 * @cur: the definition to unlink
6016 * @parent: the parent definition
6017 * @prev: the previous sibling definition
6019 * Try to unlink a definition. If not possible make it a NOOP
6021 * Returns the new prev definition
6023 static xmlRelaxNGDefinePtr
6024 xmlRelaxNGTryUnlink(xmlRelaxNGParserCtxtPtr ctxt ATTRIBUTE_UNUSED
,
6025 xmlRelaxNGDefinePtr cur
,
6026 xmlRelaxNGDefinePtr parent
, xmlRelaxNGDefinePtr prev
)
6029 prev
->next
= cur
->next
;
6031 if (parent
!= NULL
) {
6032 if (parent
->content
== cur
)
6033 parent
->content
= cur
->next
;
6034 else if (parent
->attrs
== cur
)
6035 parent
->attrs
= cur
->next
;
6036 else if (parent
->nameClass
== cur
)
6037 parent
->nameClass
= cur
->next
;
6039 cur
->type
= XML_RELAXNG_NOOP
;
6047 * xmlRelaxNGSimplify:
6048 * @ctxt: a Relax-NG parser context
6049 * @nodes: grammar children nodes
6051 * Check for simplification of empty and notAllowed
6054 xmlRelaxNGSimplify(xmlRelaxNGParserCtxtPtr ctxt
,
6055 xmlRelaxNGDefinePtr cur
, xmlRelaxNGDefinePtr parent
)
6057 xmlRelaxNGDefinePtr prev
= NULL
;
6059 while (cur
!= NULL
) {
6060 if ((cur
->type
== XML_RELAXNG_REF
) ||
6061 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6062 if (cur
->depth
!= -3) {
6064 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6066 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6067 cur
->parent
= parent
;
6068 if ((parent
!= NULL
) &&
6069 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6070 (parent
->type
== XML_RELAXNG_LIST
) ||
6071 (parent
->type
== XML_RELAXNG_GROUP
) ||
6072 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6073 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6074 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6075 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6078 if ((parent
!= NULL
) && (parent
->type
== XML_RELAXNG_CHOICE
)) {
6079 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6082 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6083 cur
->parent
= parent
;
6084 if ((parent
!= NULL
) &&
6085 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6086 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6087 parent
->type
= XML_RELAXNG_EMPTY
;
6090 if ((parent
!= NULL
) &&
6091 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6092 (parent
->type
== XML_RELAXNG_INTERLEAVE
))) {
6093 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6097 cur
->parent
= parent
;
6098 if (cur
->content
!= NULL
)
6099 xmlRelaxNGSimplify(ctxt
, cur
->content
, cur
);
6100 if ((cur
->type
!= XML_RELAXNG_VALUE
) && (cur
->attrs
!= NULL
))
6101 xmlRelaxNGSimplify(ctxt
, cur
->attrs
, cur
);
6102 if (cur
->nameClass
!= NULL
)
6103 xmlRelaxNGSimplify(ctxt
, cur
->nameClass
, cur
);
6105 * On Elements, try to move attribute only generating rules on
6108 if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6110 xmlRelaxNGDefinePtr tmp
, pre
;
6112 while (cur
->content
!= NULL
) {
6114 xmlRelaxNGGenerateAttributes(ctxt
, cur
->content
);
6115 if (attronly
== 1) {
6117 * migrate cur->content to attrs
6120 cur
->content
= tmp
->next
;
6121 tmp
->next
= cur
->attrs
;
6125 * cur->content can generate elements or text
6131 while ((pre
!= NULL
) && (pre
->next
!= NULL
)) {
6133 attronly
= xmlRelaxNGGenerateAttributes(ctxt
, tmp
);
6134 if (attronly
== 1) {
6136 * migrate tmp to attrs
6138 pre
->next
= tmp
->next
;
6139 tmp
->next
= cur
->attrs
;
6147 * This may result in a simplification
6149 if ((cur
->type
== XML_RELAXNG_GROUP
) ||
6150 (cur
->type
== XML_RELAXNG_INTERLEAVE
)) {
6151 if (cur
->content
== NULL
)
6152 cur
->type
= XML_RELAXNG_EMPTY
;
6153 else if (cur
->content
->next
== NULL
) {
6154 if ((parent
== NULL
) && (prev
== NULL
)) {
6155 cur
->type
= XML_RELAXNG_NOOP
;
6156 } else if (prev
== NULL
) {
6157 parent
->content
= cur
->content
;
6158 cur
->content
->next
= cur
->next
;
6161 cur
->content
->next
= cur
->next
;
6162 prev
->next
= cur
->content
;
6168 * the current node may have been transformed back
6170 if ((cur
->type
== XML_RELAXNG_EXCEPT
) &&
6171 (cur
->content
!= NULL
) &&
6172 (cur
->content
->type
== XML_RELAXNG_NOT_ALLOWED
)) {
6173 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6174 } else if (cur
->type
== XML_RELAXNG_NOT_ALLOWED
) {
6175 if ((parent
!= NULL
) &&
6176 ((parent
->type
== XML_RELAXNG_ATTRIBUTE
) ||
6177 (parent
->type
== XML_RELAXNG_LIST
) ||
6178 (parent
->type
== XML_RELAXNG_GROUP
) ||
6179 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6180 (parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6181 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6182 parent
->type
= XML_RELAXNG_NOT_ALLOWED
;
6185 if ((parent
!= NULL
) &&
6186 (parent
->type
== XML_RELAXNG_CHOICE
)) {
6187 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6190 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6191 if ((parent
!= NULL
) &&
6192 ((parent
->type
== XML_RELAXNG_ONEORMORE
) ||
6193 (parent
->type
== XML_RELAXNG_ZEROORMORE
))) {
6194 parent
->type
= XML_RELAXNG_EMPTY
;
6197 if ((parent
!= NULL
) &&
6198 ((parent
->type
== XML_RELAXNG_GROUP
) ||
6199 (parent
->type
== XML_RELAXNG_INTERLEAVE
) ||
6200 (parent
->type
== XML_RELAXNG_CHOICE
))) {
6201 prev
= xmlRelaxNGTryUnlink(ctxt
, cur
, parent
, prev
);
6213 * xmlRelaxNGGroupContentType:
6214 * @ct1: the first content type
6215 * @ct2: the second content type
6217 * Try to group 2 content types
6219 * Returns the content type
6221 static xmlRelaxNGContentType
6222 xmlRelaxNGGroupContentType(xmlRelaxNGContentType ct1
,
6223 xmlRelaxNGContentType ct2
)
6225 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6226 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6227 return (XML_RELAXNG_CONTENT_ERROR
);
6228 if (ct1
== XML_RELAXNG_CONTENT_EMPTY
)
6230 if (ct2
== XML_RELAXNG_CONTENT_EMPTY
)
6232 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) &&
6233 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6234 return (XML_RELAXNG_CONTENT_COMPLEX
);
6235 return (XML_RELAXNG_CONTENT_ERROR
);
6239 * xmlRelaxNGMaxContentType:
6240 * @ct1: the first content type
6241 * @ct2: the second content type
6243 * Compute the max content-type
6245 * Returns the content type
6247 static xmlRelaxNGContentType
6248 xmlRelaxNGMaxContentType(xmlRelaxNGContentType ct1
,
6249 xmlRelaxNGContentType ct2
)
6251 if ((ct1
== XML_RELAXNG_CONTENT_ERROR
) ||
6252 (ct2
== XML_RELAXNG_CONTENT_ERROR
))
6253 return (XML_RELAXNG_CONTENT_ERROR
);
6254 if ((ct1
== XML_RELAXNG_CONTENT_SIMPLE
) ||
6255 (ct2
== XML_RELAXNG_CONTENT_SIMPLE
))
6256 return (XML_RELAXNG_CONTENT_SIMPLE
);
6257 if ((ct1
== XML_RELAXNG_CONTENT_COMPLEX
) ||
6258 (ct2
== XML_RELAXNG_CONTENT_COMPLEX
))
6259 return (XML_RELAXNG_CONTENT_COMPLEX
);
6260 return (XML_RELAXNG_CONTENT_EMPTY
);
6264 * xmlRelaxNGCheckRules:
6265 * @ctxt: a Relax-NG parser context
6266 * @cur: the current definition
6267 * @flags: some accumulated flags
6268 * @ptype: the parent type
6270 * Check for rules in section 7.1 and 7.2
6272 * Returns the content type of @cur
6274 static xmlRelaxNGContentType
6275 xmlRelaxNGCheckRules(xmlRelaxNGParserCtxtPtr ctxt
,
6276 xmlRelaxNGDefinePtr cur
, int flags
,
6277 xmlRelaxNGType ptype
)
6280 xmlRelaxNGContentType ret
, tmp
, val
= XML_RELAXNG_CONTENT_EMPTY
;
6282 while (cur
!= NULL
) {
6283 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6284 if ((cur
->type
== XML_RELAXNG_REF
) ||
6285 (cur
->type
== XML_RELAXNG_PARENTREF
)) {
6287 * This should actually be caught by list//element(ref) at the
6288 * element boundaries, c.f. Bug #159968 local refs are dropped
6292 if (flags
& XML_RELAXNG_IN_LIST
) {
6293 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_REF
,
6294 "Found forbidden pattern list//ref\n", NULL
,
6298 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6299 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_REF
,
6300 "Found forbidden pattern data/except//ref\n",
6303 if (cur
->content
== NULL
) {
6304 if (cur
->type
== XML_RELAXNG_PARENTREF
)
6305 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6306 "Internal found no define for parent refs\n",
6309 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_REF_NO_DEF
,
6310 "Internal found no define for ref %s\n",
6311 (cur
->name
? cur
->name
: BAD_CAST
"null"), NULL
);
6313 if (cur
->depth
> -4) {
6315 ret
= xmlRelaxNGCheckRules(ctxt
, cur
->content
,
6317 cur
->depth
= ret
- 15;
6318 } else if (cur
->depth
== -4) {
6319 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6321 ret
= (xmlRelaxNGContentType
) (cur
->depth
+ 15);
6323 } else if (cur
->type
== XML_RELAXNG_ELEMENT
) {
6325 * The 7.3 Attribute derivation rule for groups is plugged there
6327 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6328 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6329 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ELEM
,
6330 "Found forbidden pattern data/except//element(ref)\n",
6333 if (flags
& XML_RELAXNG_IN_LIST
) {
6334 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ELEM
,
6335 "Found forbidden pattern list//element(ref)\n",
6338 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6339 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6340 "Found forbidden pattern attribute//element(ref)\n",
6343 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6344 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ELEM
,
6345 "Found forbidden pattern attribute//element(ref)\n",
6349 * reset since in the simple form elements are only child
6354 xmlRelaxNGCheckRules(ctxt
, cur
->attrs
, nflags
, cur
->type
);
6355 if (ret
!= XML_RELAXNG_CONTENT_EMPTY
) {
6356 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_EMPTY
,
6357 "Element %s attributes have a content type error\n",
6361 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6363 if (ret
== XML_RELAXNG_CONTENT_ERROR
) {
6364 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ELEM_CONTENT_ERROR
,
6365 "Element %s has a content type error\n",
6368 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6370 } else if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
6371 if (flags
& XML_RELAXNG_IN_ATTRIBUTE
) {
6372 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ATTR_ATTR
,
6373 "Found forbidden pattern attribute//attribute\n",
6376 if (flags
& XML_RELAXNG_IN_LIST
) {
6377 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_ATTR
,
6378 "Found forbidden pattern list//attribute\n",
6381 if (flags
& XML_RELAXNG_IN_OOMGROUP
) {
6382 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_GROUP_ATTR
,
6383 "Found forbidden pattern oneOrMore//group//attribute\n",
6386 if (flags
& XML_RELAXNG_IN_OOMINTERLEAVE
) {
6387 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_ONEMORE_INTERLEAVE_ATTR
,
6388 "Found forbidden pattern oneOrMore//interleave//attribute\n",
6391 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6392 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ATTR
,
6393 "Found forbidden pattern data/except//attribute\n",
6396 if (flags
& XML_RELAXNG_IN_START
) {
6397 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ATTR
,
6398 "Found forbidden pattern start//attribute\n",
6401 if ((!(flags
& XML_RELAXNG_IN_ONEORMORE
))
6402 && cur
->name
== NULL
6403 /* following is checking alternative name class readiness
6404 in case it went the "choice" route */
6405 && cur
->nameClass
== NULL
) {
6406 if (cur
->ns
== NULL
) {
6407 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_ANYNAME_ATTR_ANCESTOR
,
6408 "Found anyName attribute without oneOrMore ancestor\n",
6411 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_NSNAME_ATTR_ANCESTOR
,
6412 "Found nsName attribute without oneOrMore ancestor\n",
6416 nflags
= flags
| XML_RELAXNG_IN_ATTRIBUTE
;
6417 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
, cur
->type
);
6418 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6419 } else if ((cur
->type
== XML_RELAXNG_ONEORMORE
) ||
6420 (cur
->type
== XML_RELAXNG_ZEROORMORE
)) {
6421 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6422 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_ONEMORE
,
6423 "Found forbidden pattern data/except//oneOrMore\n",
6426 if (flags
& XML_RELAXNG_IN_START
) {
6427 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_ONEMORE
,
6428 "Found forbidden pattern start//oneOrMore\n",
6431 nflags
= flags
| XML_RELAXNG_IN_ONEORMORE
;
6433 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6435 ret
= xmlRelaxNGGroupContentType(ret
, ret
);
6436 } else if (cur
->type
== XML_RELAXNG_LIST
) {
6437 if (flags
& XML_RELAXNG_IN_LIST
) {
6438 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_LIST
,
6439 "Found forbidden pattern list//list\n", NULL
,
6442 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6443 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_LIST
,
6444 "Found forbidden pattern data/except//list\n",
6447 if (flags
& XML_RELAXNG_IN_START
) {
6448 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_LIST
,
6449 "Found forbidden pattern start//list\n", NULL
,
6452 nflags
= flags
| XML_RELAXNG_IN_LIST
;
6454 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6456 } else if (cur
->type
== XML_RELAXNG_GROUP
) {
6457 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6458 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_GROUP
,
6459 "Found forbidden pattern data/except//group\n",
6462 if (flags
& XML_RELAXNG_IN_START
) {
6463 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_GROUP
,
6464 "Found forbidden pattern start//group\n", NULL
,
6467 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6468 nflags
= flags
| XML_RELAXNG_IN_OOMGROUP
;
6472 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6475 * The 7.3 Attribute derivation rule for groups is plugged there
6477 xmlRelaxNGCheckGroupAttrs(ctxt
, cur
);
6478 } else if (cur
->type
== XML_RELAXNG_INTERLEAVE
) {
6479 if (flags
& XML_RELAXNG_IN_LIST
) {
6480 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_INTERLEAVE
,
6481 "Found forbidden pattern list//interleave\n",
6484 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6485 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6486 "Found forbidden pattern data/except//interleave\n",
6489 if (flags
& XML_RELAXNG_IN_START
) {
6490 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_INTERLEAVE
,
6491 "Found forbidden pattern start//interleave\n",
6494 if (flags
& XML_RELAXNG_IN_ONEORMORE
)
6495 nflags
= flags
| XML_RELAXNG_IN_OOMINTERLEAVE
;
6499 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6501 } else if (cur
->type
== XML_RELAXNG_EXCEPT
) {
6502 if ((cur
->parent
!= NULL
) &&
6503 (cur
->parent
->type
== XML_RELAXNG_DATATYPE
))
6504 nflags
= flags
| XML_RELAXNG_IN_DATAEXCEPT
;
6508 xmlRelaxNGCheckRules(ctxt
, cur
->content
, nflags
,
6510 } else if (cur
->type
== XML_RELAXNG_DATATYPE
) {
6511 if (flags
& XML_RELAXNG_IN_START
) {
6512 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_DATA
,
6513 "Found forbidden pattern start//data\n", NULL
,
6516 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6517 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6518 } else if (cur
->type
== XML_RELAXNG_VALUE
) {
6519 if (flags
& XML_RELAXNG_IN_START
) {
6520 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_VALUE
,
6521 "Found forbidden pattern start//value\n", NULL
,
6524 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6525 ret
= XML_RELAXNG_CONTENT_SIMPLE
;
6526 } else if (cur
->type
== XML_RELAXNG_TEXT
) {
6527 if (flags
& XML_RELAXNG_IN_LIST
) {
6528 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_LIST_TEXT
,
6529 "Found forbidden pattern list//text\n", NULL
,
6532 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6533 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_TEXT
,
6534 "Found forbidden pattern data/except//text\n",
6537 if (flags
& XML_RELAXNG_IN_START
) {
6538 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_TEXT
,
6539 "Found forbidden pattern start//text\n", NULL
,
6542 ret
= XML_RELAXNG_CONTENT_COMPLEX
;
6543 } else if (cur
->type
== XML_RELAXNG_EMPTY
) {
6544 if (flags
& XML_RELAXNG_IN_DATAEXCEPT
) {
6545 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_DATA_EXCEPT_EMPTY
,
6546 "Found forbidden pattern data/except//empty\n",
6549 if (flags
& XML_RELAXNG_IN_START
) {
6550 xmlRngPErr(ctxt
, cur
->node
, XML_RNGP_PAT_START_EMPTY
,
6551 "Found forbidden pattern start//empty\n", NULL
,
6554 ret
= XML_RELAXNG_CONTENT_EMPTY
;
6555 } else if (cur
->type
== XML_RELAXNG_CHOICE
) {
6556 xmlRelaxNGCheckChoiceDeterminism(ctxt
, cur
);
6558 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6561 xmlRelaxNGCheckRules(ctxt
, cur
->content
, flags
, cur
->type
);
6564 if (ptype
== XML_RELAXNG_GROUP
) {
6565 val
= xmlRelaxNGGroupContentType(val
, ret
);
6566 } else if (ptype
== XML_RELAXNG_INTERLEAVE
) {
6568 * TODO: scan complain that tmp is never used, seems on purpose
6569 * need double-checking
6571 tmp
= xmlRelaxNGGroupContentType(val
, ret
);
6572 if (tmp
!= XML_RELAXNG_CONTENT_ERROR
)
6573 tmp
= xmlRelaxNGMaxContentType(val
, ret
);
6574 } else if (ptype
== XML_RELAXNG_CHOICE
) {
6575 val
= xmlRelaxNGMaxContentType(val
, ret
);
6576 } else if (ptype
== XML_RELAXNG_LIST
) {
6577 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6578 } else if (ptype
== XML_RELAXNG_EXCEPT
) {
6579 if (ret
== XML_RELAXNG_CONTENT_ERROR
)
6580 val
= XML_RELAXNG_CONTENT_ERROR
;
6582 val
= XML_RELAXNG_CONTENT_SIMPLE
;
6584 val
= xmlRelaxNGGroupContentType(val
, ret
);
6592 * xmlRelaxNGParseGrammar:
6593 * @ctxt: a Relax-NG parser context
6594 * @nodes: grammar children nodes
6596 * parse a Relax-NG <grammar> node
6598 * Returns the internal xmlRelaxNGGrammarPtr built or
6599 * NULL in case of error
6601 static xmlRelaxNGGrammarPtr
6602 xmlRelaxNGParseGrammar(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr nodes
)
6604 xmlRelaxNGGrammarPtr ret
, tmp
, old
;
6606 #ifdef DEBUG_GRAMMAR
6607 xmlGenericError(xmlGenericErrorContext
, "Parsing a new grammar\n");
6610 ret
= xmlRelaxNGNewGrammar(ctxt
);
6615 * Link the new grammar in the tree
6617 ret
->parent
= ctxt
->grammar
;
6618 if (ctxt
->grammar
!= NULL
) {
6619 tmp
= ctxt
->grammar
->children
;
6621 ctxt
->grammar
->children
= ret
;
6623 while (tmp
->next
!= NULL
)
6629 old
= ctxt
->grammar
;
6630 ctxt
->grammar
= ret
;
6631 xmlRelaxNGParseGrammarContent(ctxt
, nodes
);
6632 ctxt
->grammar
= ret
;
6633 if (ctxt
->grammar
== NULL
) {
6634 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_CONTENT
,
6635 "Failed to parse <grammar> content\n", NULL
, NULL
);
6636 } else if (ctxt
->grammar
->start
== NULL
) {
6637 xmlRngPErr(ctxt
, nodes
, XML_RNGP_GRAMMAR_NO_START
,
6638 "Element <grammar> has no <start>\n", NULL
, NULL
);
6642 * Apply 4.17 merging rules to defines and starts
6644 xmlRelaxNGCombineStart(ctxt
, ret
);
6645 if (ret
->defs
!= NULL
) {
6646 xmlHashScan(ret
->defs
, xmlRelaxNGCheckCombine
, ctxt
);
6650 * link together defines and refs in this grammar
6652 if (ret
->refs
!= NULL
) {
6653 xmlHashScan(ret
->refs
, xmlRelaxNGCheckReference
, ctxt
);
6659 ctxt
->grammar
= old
;
6664 * xmlRelaxNGParseDocument:
6665 * @ctxt: a Relax-NG parser context
6666 * @node: the root node of the RelaxNG schema
6668 * parse a Relax-NG definition resource and build an internal
6669 * xmlRelaxNG structure which can be used to validate instances.
6671 * Returns the internal XML RelaxNG structure built or
6672 * NULL in case of error
6674 static xmlRelaxNGPtr
6675 xmlRelaxNGParseDocument(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6677 xmlRelaxNGPtr schema
= NULL
;
6678 const xmlChar
*olddefine
;
6679 xmlRelaxNGGrammarPtr old
;
6681 if ((ctxt
== NULL
) || (node
== NULL
))
6684 schema
= xmlRelaxNGNewRelaxNG(ctxt
);
6688 olddefine
= ctxt
->define
;
6689 ctxt
->define
= NULL
;
6690 if (IS_RELAXNG(node
, "grammar")) {
6691 schema
->topgrammar
= xmlRelaxNGParseGrammar(ctxt
, node
->children
);
6692 if (schema
->topgrammar
== NULL
) {
6693 xmlRelaxNGFree(schema
);
6697 xmlRelaxNGGrammarPtr tmp
, ret
;
6699 schema
->topgrammar
= ret
= xmlRelaxNGNewGrammar(ctxt
);
6700 if (schema
->topgrammar
== NULL
) {
6701 xmlRelaxNGFree(schema
);
6705 * Link the new grammar in the tree
6707 ret
->parent
= ctxt
->grammar
;
6708 if (ctxt
->grammar
!= NULL
) {
6709 tmp
= ctxt
->grammar
->children
;
6711 ctxt
->grammar
->children
= ret
;
6713 while (tmp
->next
!= NULL
)
6718 old
= ctxt
->grammar
;
6719 ctxt
->grammar
= ret
;
6720 xmlRelaxNGParseStart(ctxt
, node
);
6722 ctxt
->grammar
= old
;
6724 ctxt
->define
= olddefine
;
6725 if (schema
->topgrammar
->start
!= NULL
) {
6726 xmlRelaxNGCheckCycles(ctxt
, schema
->topgrammar
->start
, 0);
6727 if ((ctxt
->flags
& XML_RELAXNG_IN_EXTERNALREF
) == 0) {
6728 xmlRelaxNGSimplify(ctxt
, schema
->topgrammar
->start
, NULL
);
6729 while ((schema
->topgrammar
->start
!= NULL
) &&
6730 (schema
->topgrammar
->start
->type
== XML_RELAXNG_NOOP
) &&
6731 (schema
->topgrammar
->start
->next
!= NULL
))
6732 schema
->topgrammar
->start
=
6733 schema
->topgrammar
->start
->content
;
6734 xmlRelaxNGCheckRules(ctxt
, schema
->topgrammar
->start
,
6735 XML_RELAXNG_IN_START
, XML_RELAXNG_NOOP
);
6740 xmlGenericError(xmlGenericErrorContext
,
6741 "xmlRelaxNGParseDocument() failed\n");
6747 /************************************************************************
6749 * Reading RelaxNGs *
6751 ************************************************************************/
6754 * xmlRelaxNGNewParserCtxt:
6755 * @URL: the location of the schema
6757 * Create an XML RelaxNGs parse context for that file/resource expected
6758 * to contain an XML RelaxNGs file.
6760 * Returns the parser context or NULL in case of error
6762 xmlRelaxNGParserCtxtPtr
6763 xmlRelaxNGNewParserCtxt(const char *URL
)
6765 xmlRelaxNGParserCtxtPtr ret
;
6771 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6773 xmlRngPErrMemory(NULL
, "building parser\n");
6776 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6777 ret
->URL
= xmlStrdup((const xmlChar
*) URL
);
6778 ret
->error
= xmlGenericError
;
6779 ret
->userData
= xmlGenericErrorContext
;
6784 * xmlRelaxNGNewMemParserCtxt:
6785 * @buffer: a pointer to a char array containing the schemas
6786 * @size: the size of the array
6788 * Create an XML RelaxNGs parse context for that memory buffer expected
6789 * to contain an XML RelaxNGs file.
6791 * Returns the parser context or NULL in case of error
6793 xmlRelaxNGParserCtxtPtr
6794 xmlRelaxNGNewMemParserCtxt(const char *buffer
, int size
)
6796 xmlRelaxNGParserCtxtPtr ret
;
6798 if ((buffer
== NULL
) || (size
<= 0))
6802 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6804 xmlRngPErrMemory(NULL
, "building parser\n");
6807 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6808 ret
->buffer
= buffer
;
6810 ret
->error
= xmlGenericError
;
6811 ret
->userData
= xmlGenericErrorContext
;
6816 * xmlRelaxNGNewDocParserCtxt:
6817 * @doc: a preparsed document tree
6819 * Create an XML RelaxNGs parser context for that document.
6820 * Note: since the process of compiling a RelaxNG schemas modifies the
6821 * document, the @doc parameter is duplicated internally.
6823 * Returns the parser context or NULL in case of error
6825 xmlRelaxNGParserCtxtPtr
6826 xmlRelaxNGNewDocParserCtxt(xmlDocPtr doc
)
6828 xmlRelaxNGParserCtxtPtr ret
;
6833 copy
= xmlCopyDoc(doc
, 1);
6838 (xmlRelaxNGParserCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGParserCtxt
));
6840 xmlRngPErrMemory(NULL
, "building parser\n");
6843 memset(ret
, 0, sizeof(xmlRelaxNGParserCtxt
));
6844 ret
->document
= copy
;
6846 ret
->userData
= xmlGenericErrorContext
;
6851 * xmlRelaxNGFreeParserCtxt:
6852 * @ctxt: the schema parser context
6854 * Free the resources associated to the schema parser context
6857 xmlRelaxNGFreeParserCtxt(xmlRelaxNGParserCtxtPtr ctxt
)
6861 if (ctxt
->URL
!= NULL
)
6863 if (ctxt
->doc
!= NULL
)
6864 xmlRelaxNGFreeDocument(ctxt
->doc
);
6865 if (ctxt
->interleaves
!= NULL
)
6866 xmlHashFree(ctxt
->interleaves
, NULL
);
6867 if (ctxt
->documents
!= NULL
)
6868 xmlRelaxNGFreeDocumentList(ctxt
->documents
);
6869 if (ctxt
->includes
!= NULL
)
6870 xmlRelaxNGFreeIncludeList(ctxt
->includes
);
6871 if (ctxt
->docTab
!= NULL
)
6872 xmlFree(ctxt
->docTab
);
6873 if (ctxt
->incTab
!= NULL
)
6874 xmlFree(ctxt
->incTab
);
6875 if (ctxt
->defTab
!= NULL
) {
6878 for (i
= 0; i
< ctxt
->defNr
; i
++)
6879 xmlRelaxNGFreeDefine(ctxt
->defTab
[i
]);
6880 xmlFree(ctxt
->defTab
);
6882 if ((ctxt
->document
!= NULL
) && (ctxt
->freedoc
))
6883 xmlFreeDoc(ctxt
->document
);
6888 * xmlRelaxNGNormExtSpace:
6891 * Removes the leading and ending spaces of the value
6892 * The string is modified "in situ"
6895 xmlRelaxNGNormExtSpace(xmlChar
* value
)
6897 xmlChar
*start
= value
;
6898 xmlChar
*cur
= value
;
6903 while (IS_BLANK_CH(*cur
))
6907 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6912 while (IS_BLANK_CH(*cur
))
6921 while ((*cur
!= 0) && (!IS_BLANK_CH(*cur
)))
6927 /* don't try to normalize the inner spaces */
6928 while (IS_BLANK_CH(*cur
))
6940 * xmlRelaxNGCleanupAttributes:
6941 * @ctxt: a Relax-NG parser context
6942 * @node: a Relax-NG node
6944 * Check all the attributes on the given node
6947 xmlRelaxNGCleanupAttributes(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr node
)
6949 xmlAttrPtr cur
, next
;
6951 cur
= node
->properties
;
6952 while (cur
!= NULL
) {
6954 if ((cur
->ns
== NULL
) ||
6955 (xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
6956 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
6957 if ((!xmlStrEqual(node
->name
, BAD_CAST
"element")) &&
6958 (!xmlStrEqual(node
->name
, BAD_CAST
"attribute")) &&
6959 (!xmlStrEqual(node
->name
, BAD_CAST
"ref")) &&
6960 (!xmlStrEqual(node
->name
, BAD_CAST
"parentRef")) &&
6961 (!xmlStrEqual(node
->name
, BAD_CAST
"param")) &&
6962 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6963 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6964 "Attribute %s is not allowed on %s\n",
6965 cur
->name
, node
->name
);
6967 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"type")) {
6968 if ((!xmlStrEqual(node
->name
, BAD_CAST
"value")) &&
6969 (!xmlStrEqual(node
->name
, BAD_CAST
"data"))) {
6970 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6971 "Attribute %s is not allowed on %s\n",
6972 cur
->name
, node
->name
);
6974 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"href")) {
6975 if ((!xmlStrEqual(node
->name
, BAD_CAST
"externalRef")) &&
6976 (!xmlStrEqual(node
->name
, BAD_CAST
"include"))) {
6977 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6978 "Attribute %s is not allowed on %s\n",
6979 cur
->name
, node
->name
);
6981 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"combine")) {
6982 if ((!xmlStrEqual(node
->name
, BAD_CAST
"start")) &&
6983 (!xmlStrEqual(node
->name
, BAD_CAST
"define"))) {
6984 xmlRngPErr(ctxt
, node
, XML_RNGP_FORBIDDEN_ATTRIBUTE
,
6985 "Attribute %s is not allowed on %s\n",
6986 cur
->name
, node
->name
);
6988 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"datatypeLibrary")) {
6992 val
= xmlNodeListGetString(node
->doc
, cur
->children
, 1);
6995 uri
= xmlParseURI((const char *) val
);
6997 xmlRngPErr(ctxt
, node
, XML_RNGP_INVALID_URI
,
6998 "Attribute %s contains invalid URI %s\n",
7001 if (uri
->scheme
== NULL
) {
7002 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_NOT_ABSOLUTE
,
7003 "Attribute %s URI %s is not absolute\n",
7006 if (uri
->fragment
!= NULL
) {
7007 xmlRngPErr(ctxt
, node
, XML_RNGP_URI_FRAGMENT
,
7008 "Attribute %s URI %s has a fragment ID\n",
7016 } else if (!xmlStrEqual(cur
->name
, BAD_CAST
"ns")) {
7017 xmlRngPErr(ctxt
, node
, XML_RNGP_UNKNOWN_ATTRIBUTE
,
7018 "Unknown attribute %s on %s\n", cur
->name
,
7027 * xmlRelaxNGCleanupTree:
7028 * @ctxt: a Relax-NG parser context
7029 * @root: an xmlNodePtr subtree
7031 * Cleanup the subtree from unwanted nodes for parsing, resolve
7032 * Include and externalRef lookups.
7035 xmlRelaxNGCleanupTree(xmlRelaxNGParserCtxtPtr ctxt
, xmlNodePtr root
)
7037 xmlNodePtr cur
, delete;
7041 while (cur
!= NULL
) {
7042 if (delete != NULL
) {
7043 xmlUnlinkNode(delete);
7044 xmlFreeNode(delete);
7047 if (cur
->type
== XML_ELEMENT_NODE
) {
7049 * Simplification 4.1. Annotations
7051 if ((cur
->ns
== NULL
) ||
7052 (!xmlStrEqual(cur
->ns
->href
, xmlRelaxNGNs
))) {
7053 if ((cur
->parent
!= NULL
) &&
7054 (cur
->parent
->type
== XML_ELEMENT_NODE
) &&
7055 ((xmlStrEqual(cur
->parent
->name
, BAD_CAST
"name")) ||
7056 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value")) ||
7057 (xmlStrEqual(cur
->parent
->name
, BAD_CAST
"param")))) {
7058 xmlRngPErr(ctxt
, cur
, XML_RNGP_FOREIGN_ELEMENT
,
7059 "element %s doesn't allow foreign elements\n",
7060 cur
->parent
->name
, NULL
);
7065 xmlRelaxNGCleanupAttributes(ctxt
, cur
);
7066 if (xmlStrEqual(cur
->name
, BAD_CAST
"externalRef")) {
7067 xmlChar
*href
, *ns
, *base
, *URL
;
7068 xmlRelaxNGDocumentPtr docu
;
7072 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7075 while ((tmp
!= NULL
) &&
7076 (tmp
->type
== XML_ELEMENT_NODE
)) {
7077 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7083 href
= xmlGetProp(cur
, BAD_CAST
"href");
7085 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7086 "xmlRelaxNGParse: externalRef has no href attribute\n",
7093 uri
= xmlParseURI((const char *) href
);
7095 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7096 "Incorrect URI for externalRef %s\n",
7105 if (uri
->fragment
!= NULL
) {
7106 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7107 "Fragment forbidden in URI for externalRef %s\n",
7118 base
= xmlNodeGetBase(cur
->doc
, cur
);
7119 URL
= xmlBuildURI(href
, base
);
7121 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7122 "Failed to compute URL for externalRef %s\n",
7137 docu
= xmlRelaxNGLoadExternalRef(ctxt
, URL
, ns
);
7139 xmlRngPErr(ctxt
, cur
, XML_RNGP_EXTERNAL_REF_FAILURE
,
7140 "Failed to load externalRef %s\n", URL
,
7152 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"include")) {
7153 xmlChar
*href
, *ns
, *base
, *URL
;
7154 xmlRelaxNGIncludePtr incl
;
7157 href
= xmlGetProp(cur
, BAD_CAST
"href");
7159 xmlRngPErr(ctxt
, cur
, XML_RNGP_MISSING_HREF
,
7160 "xmlRelaxNGParse: include has no href attribute\n",
7165 base
= xmlNodeGetBase(cur
->doc
, cur
);
7166 URL
= xmlBuildURI(href
, base
);
7168 xmlRngPErr(ctxt
, cur
, XML_RNGP_HREF_ERROR
,
7169 "Failed to compute URL for include %s\n",
7182 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7185 while ((tmp
!= NULL
) &&
7186 (tmp
->type
== XML_ELEMENT_NODE
)) {
7187 ns
= xmlGetProp(tmp
, BAD_CAST
"ns");
7193 incl
= xmlRelaxNGLoadInclude(ctxt
, URL
, cur
, ns
);
7197 xmlRngPErr(ctxt
, cur
, XML_RNGP_INCLUDE_FAILURE
,
7198 "Failed to load include %s\n", URL
,
7206 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"element")) ||
7207 (xmlStrEqual(cur
->name
, BAD_CAST
"attribute")))
7210 xmlNodePtr text
= NULL
;
7213 * Simplification 4.8. name attribute of element
7214 * and attribute elements
7216 name
= xmlGetProp(cur
, BAD_CAST
"name");
7218 if (cur
->children
== NULL
) {
7220 xmlNewChild(cur
, cur
->ns
, BAD_CAST
"name",
7225 node
= xmlNewDocNode(cur
->doc
, cur
->ns
,
7226 BAD_CAST
"name", NULL
);
7228 xmlAddPrevSibling(cur
->children
, node
);
7229 text
= xmlNewText(name
);
7230 xmlAddChild(node
, text
);
7235 xmlRngPErr(ctxt
, cur
, XML_RNGP_CREATE_FAILURE
,
7236 "Failed to create a name %s element\n",
7239 xmlUnsetProp(cur
, BAD_CAST
"name");
7241 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7244 xmlSetProp(text
, BAD_CAST
"ns", ns
);
7245 /* xmlUnsetProp(cur, BAD_CAST "ns"); */
7248 } else if (xmlStrEqual(cur
->name
,
7249 BAD_CAST
"attribute")) {
7250 xmlSetProp(text
, BAD_CAST
"ns", BAD_CAST
"");
7253 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"name")) ||
7254 (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) ||
7255 (xmlStrEqual(cur
->name
, BAD_CAST
"value"))) {
7257 * Simplification 4.8. name attribute of element
7258 * and attribute elements
7260 if (xmlHasProp(cur
, BAD_CAST
"ns") == NULL
) {
7265 while ((node
!= NULL
) &&
7266 (node
->type
== XML_ELEMENT_NODE
)) {
7267 ns
= xmlGetProp(node
, BAD_CAST
"ns");
7271 node
= node
->parent
;
7274 xmlSetProp(cur
, BAD_CAST
"ns", BAD_CAST
"");
7276 xmlSetProp(cur
, BAD_CAST
"ns", ns
);
7280 if (xmlStrEqual(cur
->name
, BAD_CAST
"name")) {
7281 xmlChar
*name
, *local
, *prefix
;
7284 * Simplification: 4.10. QNames
7286 name
= xmlNodeGetContent(cur
);
7288 local
= xmlSplitQName2(name
, &prefix
);
7289 if (local
!= NULL
) {
7292 ns
= xmlSearchNs(cur
->doc
, cur
, prefix
);
7294 xmlRngPErr(ctxt
, cur
,
7295 XML_RNGP_PREFIX_UNDEFINED
,
7296 "xmlRelaxNGParse: no namespace for prefix %s\n",
7299 xmlSetProp(cur
, BAD_CAST
"ns",
7301 xmlNodeSetContent(cur
, local
);
7312 if (xmlStrEqual(cur
->name
, BAD_CAST
"nsName")) {
7313 if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7314 xmlRngPErr(ctxt
, cur
,
7315 XML_RNGP_PAT_NSNAME_EXCEPT_NSNAME
,
7316 "Found nsName/except//nsName forbidden construct\n",
7320 } else if ((xmlStrEqual(cur
->name
, BAD_CAST
"except")) &&
7322 int oldflags
= ctxt
->flags
;
7327 if ((cur
->parent
!= NULL
) &&
7329 (cur
->parent
->name
, BAD_CAST
"anyName"))) {
7330 ctxt
->flags
|= XML_RELAXNG_IN_ANYEXCEPT
;
7331 xmlRelaxNGCleanupTree(ctxt
, cur
);
7332 ctxt
->flags
= oldflags
;
7334 } else if ((cur
->parent
!= NULL
) &&
7336 (cur
->parent
->name
, BAD_CAST
"nsName"))) {
7337 ctxt
->flags
|= XML_RELAXNG_IN_NSEXCEPT
;
7338 xmlRelaxNGCleanupTree(ctxt
, cur
);
7339 ctxt
->flags
= oldflags
;
7342 } else if (xmlStrEqual(cur
->name
, BAD_CAST
"anyName")) {
7346 if (ctxt
->flags
& XML_RELAXNG_IN_ANYEXCEPT
) {
7347 xmlRngPErr(ctxt
, cur
,
7348 XML_RNGP_PAT_ANYNAME_EXCEPT_ANYNAME
,
7349 "Found anyName/except//anyName forbidden construct\n",
7351 } else if (ctxt
->flags
& XML_RELAXNG_IN_NSEXCEPT
) {
7352 xmlRngPErr(ctxt
, cur
,
7353 XML_RNGP_PAT_NSNAME_EXCEPT_ANYNAME
,
7354 "Found nsName/except//anyName forbidden construct\n",
7359 * This is not an else since "include" is transformed
7362 if (xmlStrEqual(cur
->name
, BAD_CAST
"div")) {
7364 xmlNodePtr child
, ins
, tmp
;
7367 * implements rule 4.11
7370 ns
= xmlGetProp(cur
, BAD_CAST
"ns");
7372 child
= cur
->children
;
7374 while (child
!= NULL
) {
7376 if (!xmlHasProp(child
, BAD_CAST
"ns")) {
7377 xmlSetProp(child
, BAD_CAST
"ns", ns
);
7381 xmlUnlinkNode(child
);
7382 ins
= xmlAddNextSibling(ins
, child
);
7388 * Since we are about to delete cur, if its nsDef is non-NULL we
7389 * need to preserve it (it contains the ns definitions for the
7390 * children we just moved). We'll just stick it on to the end
7391 * of cur->parent's list, since it's never going to be re-serialized
7394 if ((cur
->nsDef
!= NULL
) && (cur
->parent
!= NULL
)) {
7395 xmlNsPtr parDef
= (xmlNsPtr
)&cur
->parent
->nsDef
;
7396 while (parDef
->next
!= NULL
)
7397 parDef
= parDef
->next
;
7398 parDef
->next
= cur
->nsDef
;
7407 * Simplification 4.2 whitespaces
7409 else if ((cur
->type
== XML_TEXT_NODE
) ||
7410 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
7411 if (IS_BLANK_NODE(cur
)) {
7412 if ((cur
->parent
!= NULL
) &&
7413 (cur
->parent
->type
== XML_ELEMENT_NODE
)) {
7414 if ((!xmlStrEqual(cur
->parent
->name
, BAD_CAST
"value"))
7417 (cur
->parent
->name
, BAD_CAST
"param")))
7432 if (cur
->children
!= NULL
) {
7433 if ((cur
->children
->type
!= XML_ENTITY_DECL
) &&
7434 (cur
->children
->type
!= XML_ENTITY_REF_NODE
) &&
7435 (cur
->children
->type
!= XML_ENTITY_NODE
)) {
7436 cur
= cur
->children
;
7441 if (cur
->next
!= NULL
) {
7454 if (cur
->next
!= NULL
) {
7458 } while (cur
!= NULL
);
7460 if (delete != NULL
) {
7461 xmlUnlinkNode(delete);
7462 xmlFreeNode(delete);
7468 * xmlRelaxNGCleanupDoc:
7469 * @ctxt: a Relax-NG parser context
7470 * @doc: an xmldocPtr document pointer
7472 * Cleanup the document from unwanted nodes for parsing, resolve
7473 * Include and externalRef lookups.
7475 * Returns the cleaned up document or NULL in case of error
7478 xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt
, xmlDocPtr doc
)
7485 root
= xmlDocGetRootElement(doc
);
7487 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
, XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7491 xmlRelaxNGCleanupTree(ctxt
, root
);
7497 * @ctxt: a Relax-NG parser context
7499 * parse a schema definition resource and build an internal
7500 * XML Schema structure which can be used to validate instances.
7502 * Returns the internal XML RelaxNG structure built from the resource or
7503 * NULL in case of error
7506 xmlRelaxNGParse(xmlRelaxNGParserCtxtPtr ctxt
)
7508 xmlRelaxNGPtr ret
= NULL
;
7512 xmlRelaxNGInitTypes();
7518 * First step is to parse the input document into an DOM/Infoset
7520 if (ctxt
->URL
!= NULL
) {
7521 doc
= xmlReadFile((const char *) ctxt
->URL
,NULL
,0);
7523 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7524 "xmlRelaxNGParse: could not load %s\n", ctxt
->URL
,
7528 } else if (ctxt
->buffer
!= NULL
) {
7529 doc
= xmlReadMemory(ctxt
->buffer
, ctxt
->size
,NULL
,NULL
,0);
7531 xmlRngPErr(ctxt
, NULL
, XML_RNGP_PARSE_ERROR
,
7532 "xmlRelaxNGParse: could not parse schemas\n", NULL
,
7536 doc
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7537 ctxt
->URL
= xmlStrdup(BAD_CAST
"in_memory_buffer");
7538 } else if (ctxt
->document
!= NULL
) {
7539 doc
= ctxt
->document
;
7541 xmlRngPErr(ctxt
, NULL
, XML_RNGP_EMPTY
,
7542 "xmlRelaxNGParse: nothing to parse\n", NULL
, NULL
);
7545 ctxt
->document
= doc
;
7548 * Some preprocessing of the document content
7550 doc
= xmlRelaxNGCleanupDoc(ctxt
, doc
);
7552 xmlFreeDoc(ctxt
->document
);
7553 ctxt
->document
= NULL
;
7558 * Then do the parsing for good
7560 root
= xmlDocGetRootElement(doc
);
7562 xmlRngPErr(ctxt
, (xmlNodePtr
) doc
,
7563 XML_RNGP_EMPTY
, "xmlRelaxNGParse: %s is empty\n",
7564 (ctxt
->URL
? ctxt
->URL
: BAD_CAST
"schemas"), NULL
);
7566 xmlFreeDoc(ctxt
->document
);
7567 ctxt
->document
= NULL
;
7570 ret
= xmlRelaxNGParseDocument(ctxt
, root
);
7572 xmlFreeDoc(ctxt
->document
);
7573 ctxt
->document
= NULL
;
7578 * Check the ref/defines links
7581 * try to preprocess interleaves
7583 if (ctxt
->interleaves
!= NULL
) {
7584 xmlHashScan(ctxt
->interleaves
, xmlRelaxNGComputeInterleaves
, ctxt
);
7588 * if there was a parsing error return NULL
7590 if (ctxt
->nbErrors
> 0) {
7591 xmlRelaxNGFree(ret
);
7592 ctxt
->document
= NULL
;
7598 * try to compile (parts of) the schemas
7600 if ((ret
->topgrammar
!= NULL
) && (ret
->topgrammar
->start
!= NULL
)) {
7601 if (ret
->topgrammar
->start
->type
!= XML_RELAXNG_START
) {
7602 xmlRelaxNGDefinePtr def
;
7604 def
= xmlRelaxNGNewDefine(ctxt
, NULL
);
7606 def
->type
= XML_RELAXNG_START
;
7607 def
->content
= ret
->topgrammar
->start
;
7608 ret
->topgrammar
->start
= def
;
7611 xmlRelaxNGTryCompile(ctxt
, ret
->topgrammar
->start
);
7615 * Transfer the pointer for cleanup at the schema level.
7618 ctxt
->document
= NULL
;
7619 ret
->documents
= ctxt
->documents
;
7620 ctxt
->documents
= NULL
;
7622 ret
->includes
= ctxt
->includes
;
7623 ctxt
->includes
= NULL
;
7624 ret
->defNr
= ctxt
->defNr
;
7625 ret
->defTab
= ctxt
->defTab
;
7626 ctxt
->defTab
= NULL
;
7627 if (ctxt
->idref
== 1)
7634 * xmlRelaxNGSetParserErrors:
7635 * @ctxt: a Relax-NG validation context
7636 * @err: the error callback
7637 * @warn: the warning callback
7638 * @ctx: contextual data for the callbacks
7640 * Set the callback functions used to handle errors for a validation context
7643 xmlRelaxNGSetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7644 xmlRelaxNGValidityErrorFunc err
,
7645 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
7650 ctxt
->warning
= warn
;
7651 ctxt
->serror
= NULL
;
7652 ctxt
->userData
= ctx
;
7656 * xmlRelaxNGGetParserErrors:
7657 * @ctxt: a Relax-NG validation context
7658 * @err: the error callback result
7659 * @warn: the warning callback result
7660 * @ctx: contextual data for the callbacks result
7662 * Get the callback information used to handle errors for a validation context
7664 * Returns -1 in case of failure, 0 otherwise.
7667 xmlRelaxNGGetParserErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7668 xmlRelaxNGValidityErrorFunc
* err
,
7669 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
7676 *warn
= ctxt
->warning
;
7678 *ctx
= ctxt
->userData
;
7683 * xmlRelaxNGSetParserStructuredErrors:
7684 * @ctxt: a Relax-NG parser context
7685 * @serror: the error callback
7686 * @ctx: contextual data for the callbacks
7688 * Set the callback functions used to handle errors for a parsing context
7691 xmlRelaxNGSetParserStructuredErrors(xmlRelaxNGParserCtxtPtr ctxt
,
7692 xmlStructuredErrorFunc serror
,
7697 ctxt
->serror
= serror
;
7699 ctxt
->warning
= NULL
;
7700 ctxt
->userData
= ctx
;
7703 #ifdef LIBXML_OUTPUT_ENABLED
7705 /************************************************************************
7707 * Dump back a compiled form *
7709 ************************************************************************/
7710 static void xmlRelaxNGDumpDefine(FILE * output
,
7711 xmlRelaxNGDefinePtr define
);
7714 * xmlRelaxNGDumpDefines:
7715 * @output: the file output
7716 * @defines: a list of define structures
7718 * Dump a RelaxNG structure back
7721 xmlRelaxNGDumpDefines(FILE * output
, xmlRelaxNGDefinePtr defines
)
7723 while (defines
!= NULL
) {
7724 xmlRelaxNGDumpDefine(output
, defines
);
7725 defines
= defines
->next
;
7730 * xmlRelaxNGDumpDefine:
7731 * @output: the file output
7732 * @define: a define structure
7734 * Dump a RelaxNG structure back
7737 xmlRelaxNGDumpDefine(FILE * output
, xmlRelaxNGDefinePtr define
)
7741 switch (define
->type
) {
7742 case XML_RELAXNG_EMPTY
:
7743 fprintf(output
, "<empty/>\n");
7745 case XML_RELAXNG_NOT_ALLOWED
:
7746 fprintf(output
, "<notAllowed/>\n");
7748 case XML_RELAXNG_TEXT
:
7749 fprintf(output
, "<text/>\n");
7751 case XML_RELAXNG_ELEMENT
:
7752 fprintf(output
, "<element>\n");
7753 if (define
->name
!= NULL
) {
7754 fprintf(output
, "<name");
7755 if (define
->ns
!= NULL
)
7756 fprintf(output
, " ns=\"%s\"", define
->ns
);
7757 fprintf(output
, ">%s</name>\n", define
->name
);
7759 xmlRelaxNGDumpDefines(output
, define
->attrs
);
7760 xmlRelaxNGDumpDefines(output
, define
->content
);
7761 fprintf(output
, "</element>\n");
7763 case XML_RELAXNG_LIST
:
7764 fprintf(output
, "<list>\n");
7765 xmlRelaxNGDumpDefines(output
, define
->content
);
7766 fprintf(output
, "</list>\n");
7768 case XML_RELAXNG_ONEORMORE
:
7769 fprintf(output
, "<oneOrMore>\n");
7770 xmlRelaxNGDumpDefines(output
, define
->content
);
7771 fprintf(output
, "</oneOrMore>\n");
7773 case XML_RELAXNG_ZEROORMORE
:
7774 fprintf(output
, "<zeroOrMore>\n");
7775 xmlRelaxNGDumpDefines(output
, define
->content
);
7776 fprintf(output
, "</zeroOrMore>\n");
7778 case XML_RELAXNG_CHOICE
:
7779 fprintf(output
, "<choice>\n");
7780 xmlRelaxNGDumpDefines(output
, define
->content
);
7781 fprintf(output
, "</choice>\n");
7783 case XML_RELAXNG_GROUP
:
7784 fprintf(output
, "<group>\n");
7785 xmlRelaxNGDumpDefines(output
, define
->content
);
7786 fprintf(output
, "</group>\n");
7788 case XML_RELAXNG_INTERLEAVE
:
7789 fprintf(output
, "<interleave>\n");
7790 xmlRelaxNGDumpDefines(output
, define
->content
);
7791 fprintf(output
, "</interleave>\n");
7793 case XML_RELAXNG_OPTIONAL
:
7794 fprintf(output
, "<optional>\n");
7795 xmlRelaxNGDumpDefines(output
, define
->content
);
7796 fprintf(output
, "</optional>\n");
7798 case XML_RELAXNG_ATTRIBUTE
:
7799 fprintf(output
, "<attribute>\n");
7800 xmlRelaxNGDumpDefines(output
, define
->content
);
7801 fprintf(output
, "</attribute>\n");
7803 case XML_RELAXNG_DEF
:
7804 fprintf(output
, "<define");
7805 if (define
->name
!= NULL
)
7806 fprintf(output
, " name=\"%s\"", define
->name
);
7807 fprintf(output
, ">\n");
7808 xmlRelaxNGDumpDefines(output
, define
->content
);
7809 fprintf(output
, "</define>\n");
7811 case XML_RELAXNG_REF
:
7812 fprintf(output
, "<ref");
7813 if (define
->name
!= NULL
)
7814 fprintf(output
, " name=\"%s\"", define
->name
);
7815 fprintf(output
, ">\n");
7816 xmlRelaxNGDumpDefines(output
, define
->content
);
7817 fprintf(output
, "</ref>\n");
7819 case XML_RELAXNG_PARENTREF
:
7820 fprintf(output
, "<parentRef");
7821 if (define
->name
!= NULL
)
7822 fprintf(output
, " name=\"%s\"", define
->name
);
7823 fprintf(output
, ">\n");
7824 xmlRelaxNGDumpDefines(output
, define
->content
);
7825 fprintf(output
, "</parentRef>\n");
7827 case XML_RELAXNG_EXTERNALREF
:
7828 fprintf(output
, "<externalRef>");
7829 xmlRelaxNGDumpDefines(output
, define
->content
);
7830 fprintf(output
, "</externalRef>\n");
7832 case XML_RELAXNG_DATATYPE
:
7833 case XML_RELAXNG_VALUE
:
7835 case XML_RELAXNG_START
:
7836 case XML_RELAXNG_EXCEPT
:
7837 case XML_RELAXNG_PARAM
:
7839 case XML_RELAXNG_NOOP
:
7840 xmlRelaxNGDumpDefines(output
, define
->content
);
7846 * xmlRelaxNGDumpGrammar:
7847 * @output: the file output
7848 * @grammar: a grammar structure
7849 * @top: is this a top grammar
7851 * Dump a RelaxNG structure back
7854 xmlRelaxNGDumpGrammar(FILE * output
, xmlRelaxNGGrammarPtr grammar
, int top
)
7856 if (grammar
== NULL
)
7859 fprintf(output
, "<grammar");
7861 fprintf(output
, " xmlns=\"http://relaxng.org/ns/structure/1.0\"");
7862 switch (grammar
->combine
) {
7863 case XML_RELAXNG_COMBINE_UNDEFINED
:
7865 case XML_RELAXNG_COMBINE_CHOICE
:
7866 fprintf(output
, " combine=\"choice\"");
7868 case XML_RELAXNG_COMBINE_INTERLEAVE
:
7869 fprintf(output
, " combine=\"interleave\"");
7872 fprintf(output
, " <!-- invalid combine value -->");
7874 fprintf(output
, ">\n");
7875 if (grammar
->start
== NULL
) {
7876 fprintf(output
, " <!-- grammar had no start -->");
7878 fprintf(output
, "<start>\n");
7879 xmlRelaxNGDumpDefine(output
, grammar
->start
);
7880 fprintf(output
, "</start>\n");
7882 /* TODO ? Dump the defines ? */
7883 fprintf(output
, "</grammar>\n");
7888 * @output: the file output
7889 * @schema: a schema structure
7891 * Dump a RelaxNG structure back
7894 xmlRelaxNGDump(FILE * output
, xmlRelaxNGPtr schema
)
7898 if (schema
== NULL
) {
7899 fprintf(output
, "RelaxNG empty or failed to compile\n");
7902 fprintf(output
, "RelaxNG: ");
7903 if (schema
->doc
== NULL
) {
7904 fprintf(output
, "no document\n");
7905 } else if (schema
->doc
->URL
!= NULL
) {
7906 fprintf(output
, "%s\n", schema
->doc
->URL
);
7908 fprintf(output
, "\n");
7910 if (schema
->topgrammar
== NULL
) {
7911 fprintf(output
, "RelaxNG has no top grammar\n");
7914 xmlRelaxNGDumpGrammar(output
, schema
->topgrammar
, 1);
7918 * xmlRelaxNGDumpTree:
7919 * @output: the file output
7920 * @schema: a schema structure
7922 * Dump the transformed RelaxNG tree.
7925 xmlRelaxNGDumpTree(FILE * output
, xmlRelaxNGPtr schema
)
7929 if (schema
== NULL
) {
7930 fprintf(output
, "RelaxNG empty or failed to compile\n");
7933 if (schema
->doc
== NULL
) {
7934 fprintf(output
, "no document\n");
7936 xmlDocDump(output
, schema
->doc
);
7939 #endif /* LIBXML_OUTPUT_ENABLED */
7941 /************************************************************************
7943 * Validation of compiled content *
7945 ************************************************************************/
7946 static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
7947 xmlRelaxNGDefinePtr define
);
7950 * xmlRelaxNGValidateCompiledCallback:
7951 * @exec: the regular expression instance
7952 * @token: the token which matched
7953 * @transdata: callback data, the define for the subelement if available
7954 @ @inputdata: callback data, the Relax NG validation context
7956 * Handle the callback and if needed validate the element children.
7959 xmlRelaxNGValidateCompiledCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED
,
7960 const xmlChar
* token
,
7961 void *transdata
, void *inputdata
)
7963 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
7964 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
7967 #ifdef DEBUG_COMPILE
7968 xmlGenericError(xmlGenericErrorContext
,
7969 "Compiled callback for: '%s'\n", token
);
7972 fprintf(stderr
, "callback on %s missing context\n", token
);
7975 if (define
== NULL
) {
7976 if (token
[0] == '#')
7978 fprintf(stderr
, "callback on %s missing define\n", token
);
7979 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7980 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7983 if ((ctxt
== NULL
) || (define
== NULL
)) {
7984 fprintf(stderr
, "callback on %s missing info\n", token
);
7985 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
7986 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7988 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
7989 fprintf(stderr
, "callback on %s define is not element\n", token
);
7990 if (ctxt
->errNo
== XML_RELAXNG_OK
)
7991 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
7994 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
);
8000 * xmlRelaxNGValidateCompiledContent:
8001 * @ctxt: the RelaxNG validation context
8002 * @regexp: the regular expression as compiled
8003 * @content: list of children to test against the regexp
8005 * Validate the content model of an element or start using the regexp
8007 * Returns 0 in case of success, -1 in case of error.
8010 xmlRelaxNGValidateCompiledContent(xmlRelaxNGValidCtxtPtr ctxt
,
8011 xmlRegexpPtr regexp
, xmlNodePtr content
)
8013 xmlRegExecCtxtPtr exec
;
8018 if ((ctxt
== NULL
) || (regexp
== NULL
))
8020 oldperr
= ctxt
->perr
;
8021 exec
= xmlRegNewExecCtxt(regexp
,
8022 xmlRelaxNGValidateCompiledCallback
, ctxt
);
8025 while (cur
!= NULL
) {
8026 ctxt
->state
->seq
= cur
;
8027 switch (cur
->type
) {
8029 case XML_CDATA_SECTION_NODE
:
8030 if (xmlIsBlankNode(cur
))
8032 ret
= xmlRegExecPushString(exec
, BAD_CAST
"#text", ctxt
);
8034 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
,
8038 case XML_ELEMENT_NODE
:
8039 if (cur
->ns
!= NULL
) {
8040 ret
= xmlRegExecPushString2(exec
, cur
->name
,
8041 cur
->ns
->href
, ctxt
);
8043 ret
= xmlRegExecPushString(exec
, cur
->name
, ctxt
);
8046 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, cur
->name
);
8055 * Switch to next element
8059 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8062 ctxt
->state
->seq
= NULL
;
8063 } else if (ret
== 0) {
8065 * TODO: get some of the names needed to exit the current state of exec
8067 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8069 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8070 xmlRelaxNGDumpValidError(ctxt
);
8074 xmlRegFreeExecCtxt(exec
);
8076 * There might be content model errors outside of the pure
8077 * regexp validation, e.g. for attribute values.
8079 if ((ret
== 0) && (ctxt
->perr
!= 0)) {
8082 ctxt
->perr
= oldperr
;
8086 /************************************************************************
8088 * Progressive validation of when possible *
8090 ************************************************************************/
8091 static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
8092 xmlRelaxNGDefinePtr defines
);
8093 static int xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
,
8095 static void xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
);
8098 * xmlRelaxNGElemPush:
8099 * @ctxt: the validation context
8100 * @exec: the regexp runtime for the new content model
8102 * Push a new regexp for the current node content model on the stack
8104 * Returns 0 in case of success and -1 in case of error.
8107 xmlRelaxNGElemPush(xmlRelaxNGValidCtxtPtr ctxt
, xmlRegExecCtxtPtr exec
)
8109 if (ctxt
->elemTab
== NULL
) {
8111 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlMalloc(ctxt
->elemMax
*
8113 (xmlRegExecCtxtPtr
));
8114 if (ctxt
->elemTab
== NULL
) {
8115 xmlRngVErrMemory(ctxt
, "validating\n");
8119 if (ctxt
->elemNr
>= ctxt
->elemMax
) {
8121 ctxt
->elemTab
= (xmlRegExecCtxtPtr
*) xmlRealloc(ctxt
->elemTab
,
8124 (xmlRegExecCtxtPtr
));
8125 if (ctxt
->elemTab
== NULL
) {
8126 xmlRngVErrMemory(ctxt
, "validating\n");
8130 ctxt
->elemTab
[ctxt
->elemNr
++] = exec
;
8136 * xmlRelaxNGElemPop:
8137 * @ctxt: the validation context
8139 * Pop the regexp of the current node content model from the stack
8141 * Returns the exec or NULL if empty
8143 static xmlRegExecCtxtPtr
8144 xmlRelaxNGElemPop(xmlRelaxNGValidCtxtPtr ctxt
)
8146 xmlRegExecCtxtPtr ret
;
8148 if (ctxt
->elemNr
<= 0)
8151 ret
= ctxt
->elemTab
[ctxt
->elemNr
];
8152 ctxt
->elemTab
[ctxt
->elemNr
] = NULL
;
8153 if (ctxt
->elemNr
> 0)
8154 ctxt
->elem
= ctxt
->elemTab
[ctxt
->elemNr
- 1];
8161 * xmlRelaxNGValidateProgressiveCallback:
8162 * @exec: the regular expression instance
8163 * @token: the token which matched
8164 * @transdata: callback data, the define for the subelement if available
8165 @ @inputdata: callback data, the Relax NG validation context
8167 * Handle the callback and if needed validate the element children.
8168 * some of the in/out information are passed via the context in @inputdata.
8171 xmlRelaxNGValidateProgressiveCallback(xmlRegExecCtxtPtr exec
8173 const xmlChar
* token
,
8174 void *transdata
, void *inputdata
)
8176 xmlRelaxNGValidCtxtPtr ctxt
= (xmlRelaxNGValidCtxtPtr
) inputdata
;
8177 xmlRelaxNGDefinePtr define
= (xmlRelaxNGDefinePtr
) transdata
;
8178 xmlRelaxNGValidStatePtr state
, oldstate
;
8180 int ret
= 0, oldflags
;
8182 #ifdef DEBUG_PROGRESSIVE
8183 xmlGenericError(xmlGenericErrorContext
,
8184 "Progressive callback for: '%s'\n", token
);
8187 fprintf(stderr
, "callback on %s missing context\n", token
);
8192 if (define
== NULL
) {
8193 if (token
[0] == '#')
8195 fprintf(stderr
, "callback on %s missing define\n", token
);
8196 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8197 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8201 if ((ctxt
== NULL
) || (define
== NULL
)) {
8202 fprintf(stderr
, "callback on %s missing info\n", token
);
8203 if ((ctxt
!= NULL
) && (ctxt
->errNo
== XML_RELAXNG_OK
))
8204 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8207 } else if (define
->type
!= XML_RELAXNG_ELEMENT
) {
8208 fprintf(stderr
, "callback on %s define is not element\n", token
);
8209 if (ctxt
->errNo
== XML_RELAXNG_OK
)
8210 ctxt
->errNo
= XML_RELAXNG_ERR_INTERNAL
;
8214 if (node
->type
!= XML_ELEMENT_NODE
) {
8215 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
8216 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8217 xmlRelaxNGDumpValidError(ctxt
);
8221 if (define
->contModel
== NULL
) {
8223 * this node cannot be validated in a streamable fashion
8225 #ifdef DEBUG_PROGRESSIVE
8226 xmlGenericError(xmlGenericErrorContext
,
8227 "Element '%s' validation is not streamable\n",
8231 ctxt
->pdef
= define
;
8234 exec
= xmlRegNewExecCtxt(define
->contModel
,
8235 xmlRelaxNGValidateProgressiveCallback
, ctxt
);
8240 xmlRelaxNGElemPush(ctxt
, exec
);
8243 * Validate the attributes part of the content.
8245 state
= xmlRelaxNGNewValidState(ctxt
, node
);
8246 if (state
== NULL
) {
8250 oldstate
= ctxt
->state
;
8251 ctxt
->state
= state
;
8252 if (define
->attrs
!= NULL
) {
8253 ret
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
8256 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
8259 if (ctxt
->state
!= NULL
) {
8260 ctxt
->state
->seq
= NULL
;
8261 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
8265 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8266 } else if (ctxt
->states
!= NULL
) {
8269 oldflags
= ctxt
->flags
;
8271 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8272 state
= ctxt
->states
->tabState
[i
];
8273 ctxt
->state
= state
;
8274 ctxt
->state
->seq
= NULL
;
8276 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
8283 * validation error, log the message for the "best" one
8285 ctxt
->flags
|= FLAGS_IGNORABLE
;
8286 xmlRelaxNGLogBestError(ctxt
);
8288 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
8289 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[i
]);
8291 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
8292 ctxt
->states
= NULL
;
8293 if ((ret
== 0) && (tmp
== -1))
8295 ctxt
->flags
= oldflags
;
8297 if (ctxt
->pstate
== -1) {
8298 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
8299 xmlRelaxNGDumpValidError(ctxt
);
8302 ctxt
->state
= oldstate
;
8306 * xmlRelaxNGValidatePushElement:
8307 * @ctxt: the validation context
8308 * @doc: a document instance
8309 * @elem: an element instance
8311 * Push a new element start on the RelaxNG validation stack.
8313 * returns 1 if no validation problem was found or 0 if validating the
8314 * element requires a full node, and -1 in case of error.
8317 xmlRelaxNGValidatePushElement(xmlRelaxNGValidCtxtPtr ctxt
,
8318 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8323 if ((ctxt
== NULL
) || (elem
== NULL
))
8326 #ifdef DEBUG_PROGRESSIVE
8327 xmlGenericError(xmlGenericErrorContext
, "PushElem %s\n", elem
->name
);
8329 if (ctxt
->elem
== 0) {
8330 xmlRelaxNGPtr schema
;
8331 xmlRelaxNGGrammarPtr grammar
;
8332 xmlRegExecCtxtPtr exec
;
8333 xmlRelaxNGDefinePtr define
;
8335 schema
= ctxt
->schema
;
8336 if (schema
== NULL
) {
8337 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8340 grammar
= schema
->topgrammar
;
8341 if ((grammar
== NULL
) || (grammar
->start
== NULL
)) {
8342 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
8345 define
= grammar
->start
;
8346 if (define
->contModel
== NULL
) {
8347 ctxt
->pdef
= define
;
8350 exec
= xmlRegNewExecCtxt(define
->contModel
,
8351 xmlRelaxNGValidateProgressiveCallback
,
8356 xmlRelaxNGElemPush(ctxt
, exec
);
8360 if (elem
->ns
!= NULL
) {
8362 xmlRegExecPushString2(ctxt
->elem
, elem
->name
, elem
->ns
->href
,
8365 ret
= xmlRegExecPushString(ctxt
->elem
, elem
->name
, ctxt
);
8368 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, elem
->name
);
8370 if (ctxt
->pstate
== 0)
8372 else if (ctxt
->pstate
< 0)
8377 #ifdef DEBUG_PROGRESSIVE
8379 xmlGenericError(xmlGenericErrorContext
, "PushElem %s failed\n",
8386 * xmlRelaxNGValidatePushCData:
8387 * @ctxt: the RelaxNG validation context
8388 * @data: some character data read
8389 * @len: the length of the data
8391 * check the CData parsed for validation in the current stack
8393 * returns 1 if no validation problem was found or -1 otherwise
8396 xmlRelaxNGValidatePushCData(xmlRelaxNGValidCtxtPtr ctxt
,
8397 const xmlChar
* data
, int len ATTRIBUTE_UNUSED
)
8401 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (data
== NULL
))
8404 #ifdef DEBUG_PROGRESSIVE
8405 xmlGenericError(xmlGenericErrorContext
, "CDATA %s %d\n", data
, len
);
8408 while (*data
!= 0) {
8409 if (!IS_BLANK_CH(*data
))
8416 ret
= xmlRegExecPushString(ctxt
->elem
, BAD_CAST
"#text", ctxt
);
8418 VALID_ERR2(XML_RELAXNG_ERR_TEXTWRONG
, BAD_CAST
" TODO ");
8419 #ifdef DEBUG_PROGRESSIVE
8420 xmlGenericError(xmlGenericErrorContext
, "CDATA failed\n");
8429 * xmlRelaxNGValidatePopElement:
8430 * @ctxt: the RelaxNG validation context
8431 * @doc: a document instance
8432 * @elem: an element instance
8434 * Pop the element end from the RelaxNG validation stack.
8436 * returns 1 if no validation problem was found or 0 otherwise
8439 xmlRelaxNGValidatePopElement(xmlRelaxNGValidCtxtPtr ctxt
,
8440 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8444 xmlRegExecCtxtPtr exec
;
8446 if ((ctxt
== NULL
) || (ctxt
->elem
== NULL
) || (elem
== NULL
))
8448 #ifdef DEBUG_PROGRESSIVE
8449 xmlGenericError(xmlGenericErrorContext
, "PopElem %s\n", elem
->name
);
8452 * verify that we reached a terminal state of the content model.
8454 exec
= xmlRelaxNGElemPop(ctxt
);
8455 ret
= xmlRegExecPushString(exec
, NULL
, NULL
);
8458 * TODO: get some of the names needed to exit the current state of exec
8460 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, BAD_CAST
"");
8462 } else if (ret
< 0) {
8467 xmlRegFreeExecCtxt(exec
);
8468 #ifdef DEBUG_PROGRESSIVE
8470 xmlGenericError(xmlGenericErrorContext
, "PopElem %s failed\n",
8477 * xmlRelaxNGValidateFullElement:
8478 * @ctxt: the validation context
8479 * @doc: a document instance
8480 * @elem: an element instance
8482 * Validate a full subtree when xmlRelaxNGValidatePushElement() returned
8483 * 0 and the content of the node has been expanded.
8485 * returns 1 if no validation problem was found or -1 in case of error.
8488 xmlRelaxNGValidateFullElement(xmlRelaxNGValidCtxtPtr ctxt
,
8489 xmlDocPtr doc ATTRIBUTE_UNUSED
,
8493 xmlRelaxNGValidStatePtr state
;
8495 if ((ctxt
== NULL
) || (ctxt
->pdef
== NULL
) || (elem
== NULL
))
8497 #ifdef DEBUG_PROGRESSIVE
8498 xmlGenericError(xmlGenericErrorContext
, "FullElem %s\n", elem
->name
);
8500 state
= xmlRelaxNGNewValidState(ctxt
, elem
->parent
);
8501 if (state
== NULL
) {
8505 ctxt
->state
= state
;
8506 ctxt
->errNo
= XML_RELAXNG_OK
;
8507 ret
= xmlRelaxNGValidateDefinition(ctxt
, ctxt
->pdef
);
8508 if ((ret
!= 0) || (ctxt
->errNo
!= XML_RELAXNG_OK
))
8512 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
8514 #ifdef DEBUG_PROGRESSIVE
8516 xmlGenericError(xmlGenericErrorContext
, "FullElem %s failed\n",
8522 /************************************************************************
8524 * Generic interpreted validation implementation *
8526 ************************************************************************/
8527 static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8528 xmlRelaxNGDefinePtr define
);
8531 * xmlRelaxNGSkipIgnored:
8532 * @ctxt: a schema validation context
8533 * @node: the top node.
8535 * Skip ignorable nodes in that context
8537 * Returns the new sibling or NULL in case of error.
8540 xmlRelaxNGSkipIgnored(xmlRelaxNGValidCtxtPtr ctxt ATTRIBUTE_UNUSED
,
8544 * TODO complete and handle entities
8546 while ((node
!= NULL
) &&
8547 ((node
->type
== XML_COMMENT_NODE
) ||
8548 (node
->type
== XML_PI_NODE
) ||
8549 (node
->type
== XML_XINCLUDE_START
) ||
8550 (node
->type
== XML_XINCLUDE_END
) ||
8551 (((node
->type
== XML_TEXT_NODE
) ||
8552 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
8553 ((ctxt
->flags
& FLAGS_MIXED_CONTENT
) ||
8554 (IS_BLANK_NODE(node
)))))) {
8561 * xmlRelaxNGNormalize:
8562 * @ctxt: a schema validation context
8563 * @str: the string to normalize
8565 * Implements the normalizeWhiteSpace( s ) function from
8566 * section 6.2.9 of the spec
8568 * Returns the new string or NULL in case of error.
8571 xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt
, const xmlChar
* str
)
8584 ret
= (xmlChar
*) xmlMallocAtomic((len
+ 1) * sizeof(xmlChar
));
8586 xmlRngVErrMemory(ctxt
, "validating\n");
8590 while (IS_BLANK_CH(*str
))
8593 if (IS_BLANK_CH(*str
)) {
8594 while (IS_BLANK_CH(*str
))
8607 * xmlRelaxNGValidateDatatype:
8608 * @ctxt: a Relax-NG validation context
8609 * @value: the string value
8610 * @type: the datatype definition
8613 * Validate the given value against the datatype
8615 * Returns 0 if the validation succeeded or an error code.
8618 xmlRelaxNGValidateDatatype(xmlRelaxNGValidCtxtPtr ctxt
,
8619 const xmlChar
* value
,
8620 xmlRelaxNGDefinePtr define
, xmlNodePtr node
)
8623 xmlRelaxNGTypeLibraryPtr lib
;
8624 void *result
= NULL
;
8625 xmlRelaxNGDefinePtr cur
;
8627 if ((define
== NULL
) || (define
->data
== NULL
)) {
8630 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8631 if (lib
->check
!= NULL
) {
8632 if ((define
->attrs
!= NULL
) &&
8633 (define
->attrs
->type
== XML_RELAXNG_PARAM
)) {
8635 lib
->check(lib
->data
, define
->name
, value
, &result
, node
);
8637 ret
= lib
->check(lib
->data
, define
->name
, value
, NULL
, node
);
8642 VALID_ERR2(XML_RELAXNG_ERR_TYPE
, define
->name
);
8643 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8644 lib
->freef(lib
->data
, result
);
8646 } else if (ret
== 1) {
8648 } else if (ret
== 2) {
8649 VALID_ERR2P(XML_RELAXNG_ERR_DUPID
, value
);
8651 VALID_ERR3P(XML_RELAXNG_ERR_TYPEVAL
, define
->name
, value
);
8654 cur
= define
->attrs
;
8655 while ((ret
== 0) && (cur
!= NULL
) && (cur
->type
== XML_RELAXNG_PARAM
)) {
8656 if (lib
->facet
!= NULL
) {
8657 tmp
= lib
->facet(lib
->data
, define
->name
, cur
->name
,
8658 cur
->value
, value
, result
);
8664 if ((ret
== 0) && (define
->content
!= NULL
)) {
8665 const xmlChar
*oldvalue
, *oldendvalue
;
8667 oldvalue
= ctxt
->state
->value
;
8668 oldendvalue
= ctxt
->state
->endvalue
;
8669 ctxt
->state
->value
= (xmlChar
*) value
;
8670 ctxt
->state
->endvalue
= NULL
;
8671 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8672 ctxt
->state
->value
= (xmlChar
*) oldvalue
;
8673 ctxt
->state
->endvalue
= (xmlChar
*) oldendvalue
;
8675 if ((result
!= NULL
) && (lib
!= NULL
) && (lib
->freef
!= NULL
))
8676 lib
->freef(lib
->data
, result
);
8681 * xmlRelaxNGNextValue:
8682 * @ctxt: a Relax-NG validation context
8684 * Skip to the next value when validating within a list
8686 * Returns 0 if the operation succeeded or an error code.
8689 xmlRelaxNGNextValue(xmlRelaxNGValidCtxtPtr ctxt
)
8693 cur
= ctxt
->state
->value
;
8694 if ((cur
== NULL
) || (ctxt
->state
->endvalue
== NULL
)) {
8695 ctxt
->state
->value
= NULL
;
8696 ctxt
->state
->endvalue
= NULL
;
8701 while ((cur
!= ctxt
->state
->endvalue
) && (*cur
== 0))
8703 if (cur
== ctxt
->state
->endvalue
)
8704 ctxt
->state
->value
= NULL
;
8706 ctxt
->state
->value
= cur
;
8711 * xmlRelaxNGValidateValueList:
8712 * @ctxt: a Relax-NG validation context
8713 * @defines: the list of definitions to verify
8715 * Validate the given set of definitions for the current value
8717 * Returns 0 if the validation succeeded or an error code.
8720 xmlRelaxNGValidateValueList(xmlRelaxNGValidCtxtPtr ctxt
,
8721 xmlRelaxNGDefinePtr defines
)
8725 while (defines
!= NULL
) {
8726 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
8729 defines
= defines
->next
;
8735 * xmlRelaxNGValidateValue:
8736 * @ctxt: a Relax-NG validation context
8737 * @define: the definition to verify
8739 * Validate the given definition for the current value
8741 * Returns 0 if the validation succeeded or an error code.
8744 xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt
,
8745 xmlRelaxNGDefinePtr define
)
8747 int ret
= 0, oldflags
;
8750 value
= ctxt
->state
->value
;
8751 switch (define
->type
) {
8752 case XML_RELAXNG_EMPTY
:{
8753 if ((value
!= NULL
) && (value
[0] != 0)) {
8756 while (IS_BLANK_CH(value
[idx
]))
8758 if (value
[idx
] != 0)
8763 case XML_RELAXNG_TEXT
:
8765 case XML_RELAXNG_VALUE
:{
8766 if (!xmlStrEqual(value
, define
->value
)) {
8767 if (define
->name
!= NULL
) {
8768 xmlRelaxNGTypeLibraryPtr lib
;
8770 lib
= (xmlRelaxNGTypeLibraryPtr
) define
->data
;
8771 if ((lib
!= NULL
) && (lib
->comp
!= NULL
)) {
8772 ret
= lib
->comp(lib
->data
, define
->name
,
8773 define
->value
, define
->node
,
8774 (void *) define
->attrs
,
8775 value
, ctxt
->state
->node
);
8779 VALID_ERR2(XML_RELAXNG_ERR_TYPECMP
,
8782 } else if (ret
== 1) {
8788 xmlChar
*nval
, *nvalue
;
8791 * TODO: trivial optimizations are possible by
8792 * computing at compile-time
8794 nval
= xmlRelaxNGNormalize(ctxt
, define
->value
);
8795 nvalue
= xmlRelaxNGNormalize(ctxt
, value
);
8797 if ((nval
== NULL
) || (nvalue
== NULL
) ||
8798 (!xmlStrEqual(nval
, nvalue
)))
8807 xmlRelaxNGNextValue(ctxt
);
8810 case XML_RELAXNG_DATATYPE
:{
8811 ret
= xmlRelaxNGValidateDatatype(ctxt
, value
, define
,
8814 xmlRelaxNGNextValue(ctxt
);
8818 case XML_RELAXNG_CHOICE
:{
8819 xmlRelaxNGDefinePtr list
= define
->content
;
8822 oldflags
= ctxt
->flags
;
8823 ctxt
->flags
|= FLAGS_IGNORABLE
;
8825 oldvalue
= ctxt
->state
->value
;
8826 while (list
!= NULL
) {
8827 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8831 ctxt
->state
->value
= oldvalue
;
8834 ctxt
->flags
= oldflags
;
8836 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
8837 xmlRelaxNGDumpValidError(ctxt
);
8839 if (ctxt
->errNr
> 0)
8840 xmlRelaxNGPopErrors(ctxt
, 0);
8844 case XML_RELAXNG_LIST
:{
8845 xmlRelaxNGDefinePtr list
= define
->content
;
8846 xmlChar
*oldvalue
, *oldend
, *val
, *cur
;
8852 oldvalue
= ctxt
->state
->value
;
8853 oldend
= ctxt
->state
->endvalue
;
8855 val
= xmlStrdup(oldvalue
);
8857 val
= xmlStrdup(BAD_CAST
"");
8860 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
8865 if (IS_BLANK_CH(*cur
)) {
8871 while (IS_BLANK_CH(*cur
))
8877 xmlGenericError(xmlGenericErrorContext
,
8878 "list value: '%s' found %d items\n",
8879 oldvalue
, nb_values
);
8882 ctxt
->state
->endvalue
= cur
;
8884 while ((*cur
== 0) && (cur
!= ctxt
->state
->endvalue
))
8887 ctxt
->state
->value
= cur
;
8889 while (list
!= NULL
) {
8890 if (ctxt
->state
->value
== ctxt
->state
->endvalue
)
8891 ctxt
->state
->value
= NULL
;
8892 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8895 xmlGenericError(xmlGenericErrorContext
,
8896 "Failed to validate value: '%s' with %d rule\n",
8897 ctxt
->state
->value
, nb_values
);
8907 if ((ret
== 0) && (ctxt
->state
->value
!= NULL
) &&
8908 (ctxt
->state
->value
!= ctxt
->state
->endvalue
)) {
8909 VALID_ERR2(XML_RELAXNG_ERR_LISTEXTRA
,
8910 ctxt
->state
->value
);
8914 ctxt
->state
->value
= oldvalue
;
8915 ctxt
->state
->endvalue
= oldend
;
8918 case XML_RELAXNG_ONEORMORE
:
8919 ret
= xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8923 /* Falls through. */
8924 case XML_RELAXNG_ZEROORMORE
:{
8925 xmlChar
*cur
, *temp
;
8927 if ((ctxt
->state
->value
== NULL
) ||
8928 (*ctxt
->state
->value
== 0)) {
8932 oldflags
= ctxt
->flags
;
8933 ctxt
->flags
|= FLAGS_IGNORABLE
;
8934 cur
= ctxt
->state
->value
;
8936 while ((cur
!= NULL
) && (cur
!= ctxt
->state
->endvalue
) &&
8940 xmlRelaxNGValidateValueList(ctxt
, define
->content
);
8942 ctxt
->state
->value
= temp
;
8946 cur
= ctxt
->state
->value
;
8948 ctxt
->flags
= oldflags
;
8949 if (ctxt
->errNr
> 0)
8950 xmlRelaxNGPopErrors(ctxt
, 0);
8953 case XML_RELAXNG_OPTIONAL
:{
8956 if ((ctxt
->state
->value
== NULL
) ||
8957 (*ctxt
->state
->value
== 0)) {
8961 oldflags
= ctxt
->flags
;
8962 ctxt
->flags
|= FLAGS_IGNORABLE
;
8963 temp
= ctxt
->state
->value
;
8964 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
8965 ctxt
->flags
= oldflags
;
8967 ctxt
->state
->value
= temp
;
8968 if (ctxt
->errNr
> 0)
8969 xmlRelaxNGPopErrors(ctxt
, 0);
8973 if (ctxt
->errNr
> 0)
8974 xmlRelaxNGPopErrors(ctxt
, 0);
8977 case XML_RELAXNG_EXCEPT
:{
8978 xmlRelaxNGDefinePtr list
;
8980 list
= define
->content
;
8981 while (list
!= NULL
) {
8982 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
8992 case XML_RELAXNG_DEF
:
8993 case XML_RELAXNG_GROUP
:{
8994 xmlRelaxNGDefinePtr list
;
8996 list
= define
->content
;
8997 while (list
!= NULL
) {
8998 ret
= xmlRelaxNGValidateValue(ctxt
, list
);
9008 case XML_RELAXNG_REF
:
9009 case XML_RELAXNG_PARENTREF
:
9010 if (define
->content
== NULL
) {
9011 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
9014 ret
= xmlRelaxNGValidateValue(ctxt
, define
->content
);
9024 * xmlRelaxNGValidateValueContent:
9025 * @ctxt: a Relax-NG validation context
9026 * @defines: the list of definitions to verify
9028 * Validate the given definitions for the current value
9030 * Returns 0 if the validation succeeded or an error code.
9033 xmlRelaxNGValidateValueContent(xmlRelaxNGValidCtxtPtr ctxt
,
9034 xmlRelaxNGDefinePtr defines
)
9038 while (defines
!= NULL
) {
9039 ret
= xmlRelaxNGValidateValue(ctxt
, defines
);
9042 defines
= defines
->next
;
9048 * xmlRelaxNGAttributeMatch:
9049 * @ctxt: a Relax-NG validation context
9050 * @define: the definition to check
9051 * @prop: the attribute
9053 * Check if the attribute matches the definition nameClass
9055 * Returns 1 if the attribute matches, 0 if no, or -1 in case of error
9058 xmlRelaxNGAttributeMatch(xmlRelaxNGValidCtxtPtr ctxt
,
9059 xmlRelaxNGDefinePtr define
, xmlAttrPtr prop
)
9063 if (define
->name
!= NULL
) {
9064 if (!xmlStrEqual(define
->name
, prop
->name
))
9067 if (define
->ns
!= NULL
) {
9068 if (define
->ns
[0] == 0) {
9069 if (prop
->ns
!= NULL
)
9072 if ((prop
->ns
== NULL
) ||
9073 (!xmlStrEqual(define
->ns
, prop
->ns
->href
)))
9077 if (define
->nameClass
== NULL
)
9079 define
= define
->nameClass
;
9080 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9081 xmlRelaxNGDefinePtr list
;
9083 list
= define
->content
;
9084 while (list
!= NULL
) {
9085 ret
= xmlRelaxNGAttributeMatch(ctxt
, list
, prop
);
9092 } else if (define
->type
== XML_RELAXNG_CHOICE
) {
9093 xmlRelaxNGDefinePtr list
;
9095 list
= define
->nameClass
;
9096 while (list
!= NULL
) {
9097 ret
= xmlRelaxNGAttributeMatch(ctxt
, list
, prop
);
9111 * xmlRelaxNGValidateAttribute:
9112 * @ctxt: a Relax-NG validation context
9113 * @define: the definition to verify
9115 * Validate the given attribute definition for that node
9117 * Returns 0 if the validation succeeded or an error code.
9120 xmlRelaxNGValidateAttribute(xmlRelaxNGValidCtxtPtr ctxt
,
9121 xmlRelaxNGDefinePtr define
)
9124 xmlChar
*value
, *oldvalue
;
9125 xmlAttrPtr prop
= NULL
, tmp
;
9128 if (ctxt
->state
->nbAttrLeft
<= 0)
9130 if (define
->name
!= NULL
) {
9131 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9132 tmp
= ctxt
->state
->attrs
[i
];
9133 if ((tmp
!= NULL
) && (xmlStrEqual(define
->name
, tmp
->name
))) {
9134 if ((((define
->ns
== NULL
) || (define
->ns
[0] == 0)) &&
9135 (tmp
->ns
== NULL
)) ||
9136 ((tmp
->ns
!= NULL
) &&
9137 (xmlStrEqual(define
->ns
, tmp
->ns
->href
)))) {
9144 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9145 oldvalue
= ctxt
->state
->value
;
9146 oldseq
= ctxt
->state
->seq
;
9147 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9148 ctxt
->state
->value
= value
;
9149 ctxt
->state
->endvalue
= NULL
;
9150 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9151 if (ctxt
->state
->value
!= NULL
)
9152 value
= ctxt
->state
->value
;
9155 ctxt
->state
->value
= oldvalue
;
9156 ctxt
->state
->seq
= oldseq
;
9159 * flag the attribute as processed
9161 ctxt
->state
->attrs
[i
] = NULL
;
9162 ctxt
->state
->nbAttrLeft
--;
9168 xmlGenericError(xmlGenericErrorContext
,
9169 "xmlRelaxNGValidateAttribute(%s): %d\n",
9173 for (i
= 0; i
< ctxt
->state
->nbAttrs
; i
++) {
9174 tmp
= ctxt
->state
->attrs
[i
];
9175 if ((tmp
!= NULL
) &&
9176 (xmlRelaxNGAttributeMatch(ctxt
, define
, tmp
) == 1)) {
9182 value
= xmlNodeListGetString(prop
->doc
, prop
->children
, 1);
9183 oldvalue
= ctxt
->state
->value
;
9184 oldseq
= ctxt
->state
->seq
;
9185 ctxt
->state
->seq
= (xmlNodePtr
) prop
;
9186 ctxt
->state
->value
= value
;
9187 ret
= xmlRelaxNGValidateValueContent(ctxt
, define
->content
);
9188 if (ctxt
->state
->value
!= NULL
)
9189 value
= ctxt
->state
->value
;
9192 ctxt
->state
->value
= oldvalue
;
9193 ctxt
->state
->seq
= oldseq
;
9196 * flag the attribute as processed
9198 ctxt
->state
->attrs
[i
] = NULL
;
9199 ctxt
->state
->nbAttrLeft
--;
9205 if (define
->ns
!= NULL
) {
9206 xmlGenericError(xmlGenericErrorContext
,
9207 "xmlRelaxNGValidateAttribute(nsName ns = %s): %d\n",
9210 xmlGenericError(xmlGenericErrorContext
,
9211 "xmlRelaxNGValidateAttribute(anyName): %d\n",
9221 * xmlRelaxNGValidateAttributeList:
9222 * @ctxt: a Relax-NG validation context
9223 * @define: the list of definition to verify
9225 * Validate the given node against the list of attribute definitions
9227 * Returns 0 if the validation succeeded or an error code.
9230 xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt
,
9231 xmlRelaxNGDefinePtr defines
)
9235 xmlRelaxNGDefinePtr cur
;
9238 while (cur
!= NULL
) {
9239 if (cur
->type
== XML_RELAXNG_ATTRIBUTE
) {
9240 if (xmlRelaxNGValidateAttribute(ctxt
, cur
) != 0)
9249 while (cur
!= NULL
) {
9250 if (cur
->type
!= XML_RELAXNG_ATTRIBUTE
) {
9251 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9252 res
= xmlRelaxNGValidateDefinition(ctxt
, cur
);
9256 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9259 if (res
== -1) /* continues on -2 */
9269 * xmlRelaxNGNodeMatchesList:
9271 * @list: a NULL terminated array of definitions
9273 * Check if a node can be matched by one of the definitions
9275 * Returns 1 if matches 0 otherwise
9278 xmlRelaxNGNodeMatchesList(xmlNodePtr node
, xmlRelaxNGDefinePtr
* list
)
9280 xmlRelaxNGDefinePtr cur
;
9283 if ((node
== NULL
) || (list
== NULL
))
9287 while (cur
!= NULL
) {
9288 if ((node
->type
== XML_ELEMENT_NODE
) &&
9289 (cur
->type
== XML_RELAXNG_ELEMENT
)) {
9290 tmp
= xmlRelaxNGElementMatch(NULL
, cur
, node
);
9293 } else if (((node
->type
== XML_TEXT_NODE
) ||
9294 (node
->type
== XML_CDATA_SECTION_NODE
)) &&
9295 ((cur
->type
== XML_RELAXNG_DATATYPE
) ||
9296 (cur
->type
== XML_RELAXNG_LIST
) ||
9297 (cur
->type
== XML_RELAXNG_TEXT
) ||
9298 (cur
->type
== XML_RELAXNG_VALUE
))) {
9307 * xmlRelaxNGValidateInterleave:
9308 * @ctxt: a Relax-NG validation context
9309 * @define: the definition to verify
9311 * Validate an interleave definition for a node.
9313 * Returns 0 if the validation succeeded or an error code.
9316 xmlRelaxNGValidateInterleave(xmlRelaxNGValidCtxtPtr ctxt
,
9317 xmlRelaxNGDefinePtr define
)
9319 int ret
= 0, i
, nbgroups
;
9320 int errNr
= ctxt
->errNr
;
9323 xmlRelaxNGValidStatePtr oldstate
;
9324 xmlRelaxNGPartitionPtr partitions
;
9325 xmlRelaxNGInterleaveGroupPtr group
= NULL
;
9326 xmlNodePtr cur
, start
, last
= NULL
, lastchg
= NULL
, lastelem
;
9327 xmlNodePtr
*list
= NULL
, *lasts
= NULL
;
9329 if (define
->data
!= NULL
) {
9330 partitions
= (xmlRelaxNGPartitionPtr
) define
->data
;
9331 nbgroups
= partitions
->nbgroups
;
9333 VALID_ERR(XML_RELAXNG_ERR_INTERNODATA
);
9337 * Optimizations for MIXED
9339 oldflags
= ctxt
->flags
;
9340 if (define
->dflags
& IS_MIXED
) {
9341 ctxt
->flags
|= FLAGS_MIXED_CONTENT
;
9342 if (nbgroups
== 2) {
9344 * this is a pure <mixed> case
9346 if (ctxt
->state
!= NULL
)
9347 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9349 if (partitions
->groups
[0]->rule
->type
== XML_RELAXNG_TEXT
)
9350 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9351 partitions
->groups
[1]->
9354 ret
= xmlRelaxNGValidateDefinition(ctxt
,
9355 partitions
->groups
[0]->
9358 if (ctxt
->state
!= NULL
)
9359 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
,
9363 ctxt
->flags
= oldflags
;
9369 * Build arrays to store the first and last node of the chain
9370 * pertaining to each group
9372 list
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9374 xmlRngVErrMemory(ctxt
, "validating\n");
9377 memset(list
, 0, nbgroups
* sizeof(xmlNodePtr
));
9378 lasts
= (xmlNodePtr
*) xmlMalloc(nbgroups
* sizeof(xmlNodePtr
));
9379 if (lasts
== NULL
) {
9380 xmlRngVErrMemory(ctxt
, "validating\n");
9383 memset(lasts
, 0, nbgroups
* sizeof(xmlNodePtr
));
9386 * Walk the sequence of children finding the right group and
9387 * sorting them in sequences.
9389 cur
= ctxt
->state
->seq
;
9390 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9392 while (cur
!= NULL
) {
9393 ctxt
->state
->seq
= cur
;
9394 if ((partitions
->triage
!= NULL
) &&
9395 (partitions
->flags
& IS_DETERMINIST
)) {
9398 if ((cur
->type
== XML_TEXT_NODE
) ||
9399 (cur
->type
== XML_CDATA_SECTION_NODE
)) {
9400 tmp
= xmlHashLookup2(partitions
->triage
, BAD_CAST
"#text",
9402 } else if (cur
->type
== XML_ELEMENT_NODE
) {
9403 if (cur
->ns
!= NULL
) {
9404 tmp
= xmlHashLookup2(partitions
->triage
, cur
->name
,
9407 tmp
= xmlHashLookup2(partitions
->triage
,
9412 xmlHashLookup2(partitions
->triage
, cur
->name
,
9416 xmlHashLookup2(partitions
->triage
, BAD_CAST
"#any",
9423 i
= ((ptrdiff_t) tmp
) - 1;
9424 if (partitions
->flags
& IS_NEEDCHECK
) {
9425 group
= partitions
->groups
[i
];
9426 if (!xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9431 for (i
= 0; i
< nbgroups
; i
++) {
9432 group
= partitions
->groups
[i
];
9435 if (xmlRelaxNGNodeMatchesList(cur
, group
->defs
))
9440 * We break as soon as an element not matched is found
9442 if (i
>= nbgroups
) {
9445 if (lasts
[i
] != NULL
) {
9446 lasts
[i
]->next
= cur
;
9452 if (cur
->next
!= NULL
)
9453 lastchg
= cur
->next
;
9456 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
->next
);
9459 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9464 oldstate
= ctxt
->state
;
9465 for (i
= 0; i
< nbgroups
; i
++) {
9466 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
, oldstate
);
9467 if (ctxt
->state
== NULL
) {
9471 group
= partitions
->groups
[i
];
9472 if (lasts
[i
] != NULL
) {
9473 last
= lasts
[i
]->next
;
9474 lasts
[i
]->next
= NULL
;
9476 ctxt
->state
->seq
= list
[i
];
9477 ret
= xmlRelaxNGValidateDefinition(ctxt
, group
->rule
);
9480 if (ctxt
->state
!= NULL
) {
9481 cur
= ctxt
->state
->seq
;
9482 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9483 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9484 oldstate
= ctxt
->state
;
9487 /* there's a nasty violation of context-free unambiguities,
9488 since in open-name-class context, interleave in the
9489 production shall finish without caring about anything
9490 else that is OK to follow in that case -- it would
9491 otherwise get marked as "extra content" and would
9492 hence fail the validation, hence this perhaps
9493 dirty attempt to rectify such a situation */
9494 && (define
->parent
->type
!= XML_RELAXNG_DEF
9495 || !xmlStrEqual(define
->parent
->name
,
9496 (const xmlChar
*) "open-name-class"))) {
9497 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9499 ctxt
->state
= oldstate
;
9502 } else if (ctxt
->states
!= NULL
) {
9509 * PBM: what happen if there is attributes checks in the interleaves
9512 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9513 cur
= ctxt
->states
->tabState
[j
]->seq
;
9514 cur
= xmlRelaxNGSkipIgnored(ctxt
, cur
);
9517 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9521 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9522 /* try to keep the latest one to mach old heuristic */
9523 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9528 } else if (found
== 0) {
9529 if (lowattr
== -1) {
9530 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9533 if (ctxt
->states
->tabState
[j
]->nbAttrLeft
<= lowattr
) {
9534 /* try to keep the latest one to mach old heuristic */
9535 lowattr
= ctxt
->states
->tabState
[j
]->nbAttrLeft
;
9541 * BIG PBM: here we pick only one restarting point :-(
9543 if (ctxt
->states
->nbState
> 0) {
9544 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
9546 oldstate
= ctxt
->states
->tabState
[best
];
9547 ctxt
->states
->tabState
[best
] = NULL
;
9550 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1];
9551 ctxt
->states
->tabState
[ctxt
->states
->nbState
- 1] = NULL
;
9552 ctxt
->states
->nbState
--;
9555 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
9556 xmlRelaxNGFreeValidState(ctxt
, ctxt
->states
->tabState
[j
]);
9558 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
9559 ctxt
->states
= NULL
;
9562 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
,
9563 (const xmlChar
*) "noname");
9565 VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA
, cur
->name
);
9568 ctxt
->state
= oldstate
;
9575 if (lasts
[i
] != NULL
) {
9576 lasts
[i
]->next
= last
;
9579 if (ctxt
->state
!= NULL
)
9580 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
9581 ctxt
->state
= oldstate
;
9582 ctxt
->state
->seq
= lastelem
;
9584 VALID_ERR(XML_RELAXNG_ERR_INTERSEQ
);
9590 ctxt
->flags
= oldflags
;
9592 * builds the next links chain from the prev one
9595 while (cur
!= NULL
) {
9596 if ((cur
== start
) || (cur
->prev
== NULL
))
9598 cur
->prev
->next
= cur
;
9602 if (ctxt
->errNr
> errNr
)
9603 xmlRelaxNGPopErrors(ctxt
, errNr
);
9612 * xmlRelaxNGValidateDefinitionList:
9613 * @ctxt: a Relax-NG validation context
9614 * @define: the list of definition to verify
9616 * Validate the given node content against the (list) of definitions
9618 * Returns 0 if the validation succeeded or an error code.
9621 xmlRelaxNGValidateDefinitionList(xmlRelaxNGValidCtxtPtr ctxt
,
9622 xmlRelaxNGDefinePtr defines
)
9627 if (defines
== NULL
) {
9628 VALID_ERR2(XML_RELAXNG_ERR_INTERNAL
,
9629 BAD_CAST
"NULL definition list");
9632 while (defines
!= NULL
) {
9633 if ((ctxt
->state
!= NULL
) || (ctxt
->states
!= NULL
)) {
9634 res
= xmlRelaxNGValidateDefinition(ctxt
, defines
);
9638 VALID_ERR(XML_RELAXNG_ERR_NOSTATE
);
9641 if (res
== -1) /* continues on -2 */
9643 defines
= defines
->next
;
9650 * xmlRelaxNGElementMatch:
9651 * @ctxt: a Relax-NG validation context
9652 * @define: the definition to check
9653 * @elem: the element
9655 * Check if the element matches the definition nameClass
9657 * Returns 1 if the element matches, 0 if no, or -1 in case of error
9660 xmlRelaxNGElementMatch(xmlRelaxNGValidCtxtPtr ctxt
,
9661 xmlRelaxNGDefinePtr define
, xmlNodePtr elem
)
9663 int ret
= 0, oldflags
= 0;
9665 if (define
->name
!= NULL
) {
9666 if (!xmlStrEqual(elem
->name
, define
->name
)) {
9667 VALID_ERR3(XML_RELAXNG_ERR_ELEMNAME
, define
->name
, elem
->name
);
9671 if ((define
->ns
!= NULL
) && (define
->ns
[0] != 0)) {
9672 if (elem
->ns
== NULL
) {
9673 VALID_ERR2(XML_RELAXNG_ERR_ELEMNONS
, elem
->name
);
9675 } else if (!xmlStrEqual(elem
->ns
->href
, define
->ns
)) {
9676 VALID_ERR3(XML_RELAXNG_ERR_ELEMWRONGNS
,
9677 elem
->name
, define
->ns
);
9680 } else if ((elem
->ns
!= NULL
) && (define
->ns
!= NULL
) &&
9681 (define
->name
== NULL
)) {
9682 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, elem
->name
);
9684 } else if ((elem
->ns
!= NULL
) && (define
->name
!= NULL
)) {
9685 VALID_ERR2(XML_RELAXNG_ERR_ELEMEXTRANS
, define
->name
);
9689 if (define
->nameClass
== NULL
)
9692 define
= define
->nameClass
;
9693 if (define
->type
== XML_RELAXNG_EXCEPT
) {
9694 xmlRelaxNGDefinePtr list
;
9697 oldflags
= ctxt
->flags
;
9698 ctxt
->flags
|= FLAGS_IGNORABLE
;
9701 list
= define
->content
;
9702 while (list
!= NULL
) {
9703 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9706 ctxt
->flags
= oldflags
;
9711 ctxt
->flags
= oldflags
;
9718 ctxt
->flags
= oldflags
;
9720 } else if (define
->type
== XML_RELAXNG_CHOICE
) {
9721 xmlRelaxNGDefinePtr list
;
9724 oldflags
= ctxt
->flags
;
9725 ctxt
->flags
|= FLAGS_IGNORABLE
;
9728 list
= define
->nameClass
;
9729 while (list
!= NULL
) {
9730 ret
= xmlRelaxNGElementMatch(ctxt
, list
, elem
);
9733 ctxt
->flags
= oldflags
;
9738 ctxt
->flags
= oldflags
;
9745 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9746 xmlRelaxNGDumpValidError(ctxt
);
9748 if (ctxt
->errNr
> 0)
9749 xmlRelaxNGPopErrors(ctxt
, 0);
9754 ctxt
->flags
= oldflags
;
9763 * xmlRelaxNGBestState:
9764 * @ctxt: a Relax-NG validation context
9766 * Find the "best" state in the ctxt->states list of states to report
9767 * errors about. I.e. a state with no element left in the child list
9768 * or the one with the less attributes left.
9769 * This is called only if a validation error was detected
9771 * Returns the index of the "best" state or -1 in case of error
9774 xmlRelaxNGBestState(xmlRelaxNGValidCtxtPtr ctxt
)
9776 xmlRelaxNGValidStatePtr state
;
9779 int value
= 1000000;
9781 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9782 (ctxt
->states
->nbState
<= 0))
9785 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
9786 state
= ctxt
->states
->tabState
[i
];
9789 if (state
->seq
!= NULL
) {
9790 if ((best
== -1) || (value
> 100000)) {
9795 tmp
= state
->nbAttrLeft
;
9796 if ((best
== -1) || (value
> tmp
)) {
9806 * xmlRelaxNGLogBestError:
9807 * @ctxt: a Relax-NG validation context
9809 * Find the "best" state in the ctxt->states list of states to report
9810 * errors about and log it.
9813 xmlRelaxNGLogBestError(xmlRelaxNGValidCtxtPtr ctxt
)
9817 if ((ctxt
== NULL
) || (ctxt
->states
== NULL
) ||
9818 (ctxt
->states
->nbState
<= 0))
9821 best
= xmlRelaxNGBestState(ctxt
);
9822 if ((best
>= 0) && (best
< ctxt
->states
->nbState
)) {
9823 ctxt
->state
= ctxt
->states
->tabState
[best
];
9825 xmlRelaxNGValidateElementEnd(ctxt
, 1);
9830 * xmlRelaxNGValidateElementEnd:
9831 * @ctxt: a Relax-NG validation context
9832 * @dolog: indicate that error logging should be done
9834 * Validate the end of the element, implements check that
9835 * there is nothing left not consumed in the element content
9836 * or in the attribute list.
9838 * Returns 0 if the validation succeeded or an error code.
9841 xmlRelaxNGValidateElementEnd(xmlRelaxNGValidCtxtPtr ctxt
, int dolog
)
9844 xmlRelaxNGValidStatePtr state
;
9846 state
= ctxt
->state
;
9847 if (state
->seq
!= NULL
) {
9848 state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, state
->seq
);
9849 if (state
->seq
!= NULL
) {
9851 VALID_ERR3(XML_RELAXNG_ERR_EXTRACONTENT
,
9852 state
->node
->name
, state
->seq
->name
);
9857 for (i
= 0; i
< state
->nbAttrs
; i
++) {
9858 if (state
->attrs
[i
] != NULL
) {
9860 VALID_ERR3(XML_RELAXNG_ERR_INVALIDATTR
,
9861 state
->attrs
[i
]->name
, state
->node
->name
);
9870 * xmlRelaxNGValidateState:
9871 * @ctxt: a Relax-NG validation context
9872 * @define: the definition to verify
9874 * Validate the current state against the definition
9876 * Returns 0 if the validation succeeded or an error code.
9879 xmlRelaxNGValidateState(xmlRelaxNGValidCtxtPtr ctxt
,
9880 xmlRelaxNGDefinePtr define
)
9883 int ret
= 0, i
, tmp
, oldflags
, errNr
;
9884 xmlRelaxNGValidStatePtr oldstate
= NULL
, state
;
9886 if (define
== NULL
) {
9887 VALID_ERR(XML_RELAXNG_ERR_NODEFINE
);
9891 if (ctxt
->state
!= NULL
) {
9892 node
= ctxt
->state
->seq
;
9897 for (i
= 0; i
< ctxt
->depth
; i
++)
9898 xmlGenericError(xmlGenericErrorContext
, " ");
9899 xmlGenericError(xmlGenericErrorContext
,
9900 "Start validating %s ", xmlRelaxNGDefName(define
));
9901 if (define
->name
!= NULL
)
9902 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
9903 if ((node
!= NULL
) && (node
->name
!= NULL
))
9904 xmlGenericError(xmlGenericErrorContext
, "on %s\n", node
->name
);
9906 xmlGenericError(xmlGenericErrorContext
, "\n");
9909 switch (define
->type
) {
9910 case XML_RELAXNG_EMPTY
:
9913 case XML_RELAXNG_NOT_ALLOWED
:
9916 case XML_RELAXNG_TEXT
:
9917 while ((node
!= NULL
) &&
9918 ((node
->type
== XML_TEXT_NODE
) ||
9919 (node
->type
== XML_COMMENT_NODE
) ||
9920 (node
->type
== XML_PI_NODE
) ||
9921 (node
->type
== XML_CDATA_SECTION_NODE
)))
9923 ctxt
->state
->seq
= node
;
9925 case XML_RELAXNG_ELEMENT
:
9926 errNr
= ctxt
->errNr
;
9927 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
9929 VALID_ERR2(XML_RELAXNG_ERR_NOELEM
, define
->name
);
9931 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9932 xmlRelaxNGDumpValidError(ctxt
);
9935 if (node
->type
!= XML_ELEMENT_NODE
) {
9936 VALID_ERR(XML_RELAXNG_ERR_NOTELEM
);
9938 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9939 xmlRelaxNGDumpValidError(ctxt
);
9943 * This node was already validated successfully against
9946 if (node
->psvi
== define
) {
9947 ctxt
->state
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
9948 if (ctxt
->errNr
> errNr
)
9949 xmlRelaxNGPopErrors(ctxt
, errNr
);
9950 if (ctxt
->errNr
!= 0) {
9951 while ((ctxt
->err
!= NULL
) &&
9952 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
)
9953 && (xmlStrEqual(ctxt
->err
->arg2
, node
->name
)))
9956 XML_RELAXNG_ERR_ELEMEXTRANS
)
9957 && (xmlStrEqual(ctxt
->err
->arg1
, node
->name
)))
9958 || (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
)
9959 || (ctxt
->err
->err
==
9960 XML_RELAXNG_ERR_NOTELEM
)))
9961 xmlRelaxNGValidErrorPop(ctxt
);
9966 ret
= xmlRelaxNGElementMatch(ctxt
, define
, node
);
9969 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9970 xmlRelaxNGDumpValidError(ctxt
);
9974 if (ctxt
->errNr
!= 0) {
9975 if (ctxt
->errNr
> errNr
)
9976 xmlRelaxNGPopErrors(ctxt
, errNr
);
9977 while ((ctxt
->err
!= NULL
) &&
9978 (((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMNAME
) &&
9979 (xmlStrEqual(ctxt
->err
->arg2
, node
->name
))) ||
9980 ((ctxt
->err
->err
== XML_RELAXNG_ERR_ELEMEXTRANS
) &&
9981 (xmlStrEqual(ctxt
->err
->arg1
, node
->name
))) ||
9982 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOELEM
) ||
9983 (ctxt
->err
->err
== XML_RELAXNG_ERR_NOTELEM
)))
9984 xmlRelaxNGValidErrorPop(ctxt
);
9986 errNr
= ctxt
->errNr
;
9988 oldflags
= ctxt
->flags
;
9989 if (ctxt
->flags
& FLAGS_MIXED_CONTENT
) {
9990 ctxt
->flags
-= FLAGS_MIXED_CONTENT
;
9992 state
= xmlRelaxNGNewValidState(ctxt
, node
);
9993 if (state
== NULL
) {
9995 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0)
9996 xmlRelaxNGDumpValidError(ctxt
);
10000 oldstate
= ctxt
->state
;
10001 ctxt
->state
= state
;
10002 if (define
->attrs
!= NULL
) {
10003 tmp
= xmlRelaxNGValidateAttributeList(ctxt
, define
->attrs
);
10006 VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID
, node
->name
);
10009 if (define
->contModel
!= NULL
) {
10010 xmlRelaxNGValidStatePtr nstate
, tmpstate
= ctxt
->state
;
10011 xmlRelaxNGStatesPtr tmpstates
= ctxt
->states
;
10014 nstate
= xmlRelaxNGNewValidState(ctxt
, node
);
10015 ctxt
->state
= nstate
;
10016 ctxt
->states
= NULL
;
10018 tmp
= xmlRelaxNGValidateCompiledContent(ctxt
,
10021 nseq
= ctxt
->state
->seq
;
10022 ctxt
->state
= tmpstate
;
10023 ctxt
->states
= tmpstates
;
10024 xmlRelaxNGFreeValidState(ctxt
, nstate
);
10026 #ifdef DEBUG_COMPILE
10027 xmlGenericError(xmlGenericErrorContext
,
10028 "Validating content of '%s' : %d\n",
10029 define
->name
, tmp
);
10034 if (ctxt
->states
!= NULL
) {
10037 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10038 state
= ctxt
->states
->tabState
[i
];
10039 ctxt
->state
= state
;
10040 ctxt
->state
->seq
= nseq
;
10042 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
10049 * validation error, log the message for the "best" one
10051 ctxt
->flags
|= FLAGS_IGNORABLE
;
10052 xmlRelaxNGLogBestError(ctxt
);
10054 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10055 xmlRelaxNGFreeValidState(ctxt
,
10059 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10060 ctxt
->flags
= oldflags
;
10061 ctxt
->states
= NULL
;
10062 if ((ret
== 0) && (tmp
== -1))
10065 state
= ctxt
->state
;
10066 if (ctxt
->state
!= NULL
)
10067 ctxt
->state
->seq
= nseq
;
10069 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
10070 xmlRelaxNGFreeValidState(ctxt
, state
);
10073 if (define
->content
!= NULL
) {
10074 tmp
= xmlRelaxNGValidateDefinitionList(ctxt
,
10079 if (ctxt
->state
== NULL
) {
10080 ctxt
->state
= oldstate
;
10081 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
10083 ctxt
->state
= NULL
;
10085 VALID_ERR2(XML_RELAXNG_ERR_CONTENTVALID
,
10091 if (ctxt
->states
!= NULL
) {
10094 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10095 state
= ctxt
->states
->tabState
[i
];
10096 ctxt
->state
= state
;
10098 if (xmlRelaxNGValidateElementEnd(ctxt
, 0) == 0) {
10105 * validation error, log the message for the "best" one
10107 ctxt
->flags
|= FLAGS_IGNORABLE
;
10108 xmlRelaxNGLogBestError(ctxt
);
10110 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10111 xmlRelaxNGFreeValidState(ctxt
,
10112 ctxt
->states
->tabState
[i
]);
10113 ctxt
->states
->tabState
[i
] = NULL
;
10115 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10116 ctxt
->flags
= oldflags
;
10117 ctxt
->states
= NULL
;
10118 if ((ret
== 0) && (tmp
== -1))
10121 state
= ctxt
->state
;
10123 ret
= xmlRelaxNGValidateElementEnd(ctxt
, 1);
10124 xmlRelaxNGFreeValidState(ctxt
, state
);
10128 node
->psvi
= define
;
10130 ctxt
->flags
= oldflags
;
10131 ctxt
->state
= oldstate
;
10132 if (oldstate
!= NULL
)
10133 oldstate
->seq
= xmlRelaxNGSkipIgnored(ctxt
, node
->next
);
10135 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10136 xmlRelaxNGDumpValidError(ctxt
);
10144 if (ctxt
->errNr
> errNr
)
10145 xmlRelaxNGPopErrors(ctxt
, errNr
);
10149 xmlGenericError(xmlGenericErrorContext
,
10150 "xmlRelaxNGValidateDefinition(): validated %s : %d",
10152 if (oldstate
== NULL
)
10153 xmlGenericError(xmlGenericErrorContext
, ": no state\n");
10154 else if (oldstate
->seq
== NULL
)
10155 xmlGenericError(xmlGenericErrorContext
, ": done\n");
10156 else if (oldstate
->seq
->type
== XML_ELEMENT_NODE
)
10157 xmlGenericError(xmlGenericErrorContext
, ": next elem %s\n",
10158 oldstate
->seq
->name
);
10160 xmlGenericError(xmlGenericErrorContext
, ": next %s %d\n",
10161 oldstate
->seq
->name
, oldstate
->seq
->type
);
10164 case XML_RELAXNG_OPTIONAL
:{
10165 errNr
= ctxt
->errNr
;
10166 oldflags
= ctxt
->flags
;
10167 ctxt
->flags
|= FLAGS_IGNORABLE
;
10168 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10170 xmlRelaxNGValidateDefinitionList(ctxt
,
10173 if (ctxt
->state
!= NULL
)
10174 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10175 ctxt
->state
= oldstate
;
10176 ctxt
->flags
= oldflags
;
10178 if (ctxt
->errNr
> errNr
)
10179 xmlRelaxNGPopErrors(ctxt
, errNr
);
10182 if (ctxt
->states
!= NULL
) {
10183 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10185 ctxt
->states
= xmlRelaxNGNewStates(ctxt
, 1);
10186 if (ctxt
->states
== NULL
) {
10187 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10188 ctxt
->flags
= oldflags
;
10190 if (ctxt
->errNr
> errNr
)
10191 xmlRelaxNGPopErrors(ctxt
, errNr
);
10194 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, oldstate
);
10195 xmlRelaxNGAddStates(ctxt
, ctxt
->states
, ctxt
->state
);
10196 ctxt
->state
= NULL
;
10198 ctxt
->flags
= oldflags
;
10200 if (ctxt
->errNr
> errNr
)
10201 xmlRelaxNGPopErrors(ctxt
, errNr
);
10204 case XML_RELAXNG_ONEORMORE
:
10205 errNr
= ctxt
->errNr
;
10206 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10210 if (ctxt
->errNr
> errNr
)
10211 xmlRelaxNGPopErrors(ctxt
, errNr
);
10212 /* Falls through. */
10213 case XML_RELAXNG_ZEROORMORE
:{
10215 xmlRelaxNGStatesPtr states
= NULL
, res
= NULL
;
10218 errNr
= ctxt
->errNr
;
10219 res
= xmlRelaxNGNewStates(ctxt
, 1);
10225 * All the input states are also exit states
10227 if (ctxt
->state
!= NULL
) {
10228 xmlRelaxNGAddStates(ctxt
, res
,
10229 xmlRelaxNGCopyValidState(ctxt
,
10233 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10234 xmlRelaxNGAddStates(ctxt
, res
,
10235 xmlRelaxNGCopyValidState(ctxt
,
10236 ctxt
->states
->tabState
[j
]));
10239 oldflags
= ctxt
->flags
;
10240 ctxt
->flags
|= FLAGS_IGNORABLE
;
10243 base
= res
->nbState
;
10245 if (ctxt
->states
!= NULL
) {
10246 states
= ctxt
->states
;
10247 for (i
= 0; i
< states
->nbState
; i
++) {
10248 ctxt
->state
= states
->tabState
[i
];
10249 ctxt
->states
= NULL
;
10250 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10254 if (ctxt
->state
!= NULL
) {
10255 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10257 ctxt
->state
= NULL
;
10260 } else if (ctxt
->states
!= NULL
) {
10261 for (j
= 0; j
< ctxt
->states
->nbState
;
10264 xmlRelaxNGAddStates(ctxt
, res
,
10265 ctxt
->states
->tabState
[j
]);
10269 xmlRelaxNGFreeStates(ctxt
,
10271 ctxt
->states
= NULL
;
10274 if (ctxt
->state
!= NULL
) {
10275 xmlRelaxNGFreeValidState(ctxt
,
10277 ctxt
->state
= NULL
;
10282 ret
= xmlRelaxNGValidateDefinitionList(ctxt
,
10286 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10287 ctxt
->state
= NULL
;
10289 base
= res
->nbState
;
10290 if (ctxt
->state
!= NULL
) {
10291 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10293 ctxt
->state
= NULL
;
10296 } else if (ctxt
->states
!= NULL
) {
10297 for (j
= 0; j
< ctxt
->states
->nbState
; j
++) {
10298 tmp
= xmlRelaxNGAddStates(ctxt
, res
,
10299 ctxt
->states
->tabState
[j
]);
10303 if (states
== NULL
) {
10304 states
= ctxt
->states
;
10306 xmlRelaxNGFreeStates(ctxt
,
10309 ctxt
->states
= NULL
;
10315 * Collect all the new nodes added at that step
10316 * and make them the new node set
10318 if (res
->nbState
- base
== 1) {
10319 ctxt
->state
= xmlRelaxNGCopyValidState(ctxt
,
10324 if (states
== NULL
) {
10325 xmlRelaxNGNewStates(ctxt
,
10326 res
->nbState
- base
);
10327 states
= ctxt
->states
;
10328 if (states
== NULL
) {
10333 states
->nbState
= 0;
10334 for (i
= base
; i
< res
->nbState
; i
++)
10335 xmlRelaxNGAddStates(ctxt
, states
,
10336 xmlRelaxNGCopyValidState
10337 (ctxt
, res
->tabState
[i
]));
10338 ctxt
->states
= states
;
10341 } while (progress
== 1);
10342 if (states
!= NULL
) {
10343 xmlRelaxNGFreeStates(ctxt
, states
);
10345 ctxt
->states
= res
;
10346 ctxt
->flags
= oldflags
;
10349 * errors may have to be propagated back...
10351 if (ctxt
->errNr
> errNr
)
10352 xmlRelaxNGPopErrors(ctxt
, errNr
);
10357 case XML_RELAXNG_CHOICE
:{
10358 xmlRelaxNGDefinePtr list
= NULL
;
10359 xmlRelaxNGStatesPtr states
= NULL
;
10361 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10363 errNr
= ctxt
->errNr
;
10364 if ((define
->dflags
& IS_TRIABLE
) && (define
->data
!= NULL
) &&
10367 * node == NULL can't be optimized since IS_TRIABLE
10368 * doesn't account for choice which may lead to
10371 xmlHashTablePtr triage
=
10372 (xmlHashTablePtr
) define
->data
;
10375 * Something we can optimize cleanly there is only one
10376 * possible branch out !
10378 if ((node
->type
== XML_TEXT_NODE
) ||
10379 (node
->type
== XML_CDATA_SECTION_NODE
)) {
10381 xmlHashLookup2(triage
, BAD_CAST
"#text", NULL
);
10382 } else if (node
->type
== XML_ELEMENT_NODE
) {
10383 if (node
->ns
!= NULL
) {
10384 list
= xmlHashLookup2(triage
, node
->name
,
10388 xmlHashLookup2(triage
, BAD_CAST
"#any",
10392 xmlHashLookup2(triage
, node
->name
, NULL
);
10395 xmlHashLookup2(triage
, BAD_CAST
"#any",
10398 if (list
== NULL
) {
10400 VALID_ERR2(XML_RELAXNG_ERR_ELEMWRONG
, node
->name
);
10403 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10409 list
= define
->content
;
10410 oldflags
= ctxt
->flags
;
10411 ctxt
->flags
|= FLAGS_IGNORABLE
;
10413 while (list
!= NULL
) {
10414 oldstate
= xmlRelaxNGCopyValidState(ctxt
, ctxt
->state
);
10415 ret
= xmlRelaxNGValidateDefinition(ctxt
, list
);
10417 if (states
== NULL
) {
10418 states
= xmlRelaxNGNewStates(ctxt
, 1);
10420 if (ctxt
->state
!= NULL
) {
10421 xmlRelaxNGAddStates(ctxt
, states
, ctxt
->state
);
10422 } else if (ctxt
->states
!= NULL
) {
10423 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10424 xmlRelaxNGAddStates(ctxt
, states
,
10428 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10429 ctxt
->states
= NULL
;
10432 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10434 ctxt
->state
= oldstate
;
10437 if (states
!= NULL
) {
10438 xmlRelaxNGFreeValidState(ctxt
, oldstate
);
10439 ctxt
->states
= states
;
10440 ctxt
->state
= NULL
;
10443 ctxt
->states
= NULL
;
10445 ctxt
->flags
= oldflags
;
10447 if ((ctxt
->flags
& FLAGS_IGNORABLE
) == 0) {
10448 xmlRelaxNGDumpValidError(ctxt
);
10451 if (ctxt
->errNr
> errNr
)
10452 xmlRelaxNGPopErrors(ctxt
, errNr
);
10456 case XML_RELAXNG_DEF
:
10457 case XML_RELAXNG_GROUP
:
10458 ret
= xmlRelaxNGValidateDefinitionList(ctxt
, define
->content
);
10460 case XML_RELAXNG_INTERLEAVE
:
10461 ret
= xmlRelaxNGValidateInterleave(ctxt
, define
);
10463 case XML_RELAXNG_ATTRIBUTE
:
10464 ret
= xmlRelaxNGValidateAttribute(ctxt
, define
);
10466 case XML_RELAXNG_START
:
10467 case XML_RELAXNG_NOOP
:
10468 case XML_RELAXNG_REF
:
10469 case XML_RELAXNG_EXTERNALREF
:
10470 case XML_RELAXNG_PARENTREF
:
10471 ret
= xmlRelaxNGValidateDefinition(ctxt
, define
->content
);
10473 case XML_RELAXNG_DATATYPE
:{
10475 xmlChar
*content
= NULL
;
10478 while (child
!= NULL
) {
10479 if (child
->type
== XML_ELEMENT_NODE
) {
10480 VALID_ERR2(XML_RELAXNG_ERR_DATAELEM
,
10481 node
->parent
->name
);
10484 } else if ((child
->type
== XML_TEXT_NODE
) ||
10485 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10486 content
= xmlStrcat(content
, child
->content
);
10488 /* TODO: handle entities ... */
10489 child
= child
->next
;
10492 if (content
!= NULL
)
10496 if (content
== NULL
) {
10497 content
= xmlStrdup(BAD_CAST
"");
10498 if (content
== NULL
) {
10499 xmlRngVErrMemory(ctxt
, "validating\n");
10504 ret
= xmlRelaxNGValidateDatatype(ctxt
, content
, define
,
10507 VALID_ERR2(XML_RELAXNG_ERR_DATATYPE
, define
->name
);
10508 } else if (ret
== 0) {
10509 ctxt
->state
->seq
= NULL
;
10511 if (content
!= NULL
)
10515 case XML_RELAXNG_VALUE
:{
10516 xmlChar
*content
= NULL
;
10521 while (child
!= NULL
) {
10522 if (child
->type
== XML_ELEMENT_NODE
) {
10523 VALID_ERR2(XML_RELAXNG_ERR_VALELEM
,
10524 node
->parent
->name
);
10527 } else if ((child
->type
== XML_TEXT_NODE
) ||
10528 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10529 content
= xmlStrcat(content
, child
->content
);
10531 /* TODO: handle entities ... */
10532 child
= child
->next
;
10535 if (content
!= NULL
)
10539 if (content
== NULL
) {
10540 content
= xmlStrdup(BAD_CAST
"");
10541 if (content
== NULL
) {
10542 xmlRngVErrMemory(ctxt
, "validating\n");
10547 oldvalue
= ctxt
->state
->value
;
10548 ctxt
->state
->value
= content
;
10549 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10550 ctxt
->state
->value
= oldvalue
;
10552 VALID_ERR2(XML_RELAXNG_ERR_VALUE
, define
->name
);
10553 } else if (ret
== 0) {
10554 ctxt
->state
->seq
= NULL
;
10556 if (content
!= NULL
)
10560 case XML_RELAXNG_LIST
:{
10563 xmlChar
*oldvalue
, *oldendvalue
;
10567 * Make sure it's only text nodes
10572 while (child
!= NULL
) {
10573 if (child
->type
== XML_ELEMENT_NODE
) {
10574 VALID_ERR2(XML_RELAXNG_ERR_LISTELEM
,
10575 node
->parent
->name
);
10578 } else if ((child
->type
== XML_TEXT_NODE
) ||
10579 (child
->type
== XML_CDATA_SECTION_NODE
)) {
10580 content
= xmlStrcat(content
, child
->content
);
10582 /* TODO: handle entities ... */
10583 child
= child
->next
;
10586 if (content
!= NULL
)
10590 if (content
== NULL
) {
10591 content
= xmlStrdup(BAD_CAST
"");
10592 if (content
== NULL
) {
10593 xmlRngVErrMemory(ctxt
, "validating\n");
10598 len
= xmlStrlen(content
);
10599 oldvalue
= ctxt
->state
->value
;
10600 oldendvalue
= ctxt
->state
->endvalue
;
10601 ctxt
->state
->value
= content
;
10602 ctxt
->state
->endvalue
= content
+ len
;
10603 ret
= xmlRelaxNGValidateValue(ctxt
, define
);
10604 ctxt
->state
->value
= oldvalue
;
10605 ctxt
->state
->endvalue
= oldendvalue
;
10607 VALID_ERR(XML_RELAXNG_ERR_LIST
);
10608 } else if ((ret
== 0) && (node
!= NULL
)) {
10609 ctxt
->state
->seq
= node
->next
;
10611 if (content
!= NULL
)
10615 case XML_RELAXNG_EXCEPT
:
10616 case XML_RELAXNG_PARAM
:
10622 for (i
= 0; i
< ctxt
->depth
; i
++)
10623 xmlGenericError(xmlGenericErrorContext
, " ");
10624 xmlGenericError(xmlGenericErrorContext
,
10625 "Validating %s ", xmlRelaxNGDefName(define
));
10626 if (define
->name
!= NULL
)
10627 xmlGenericError(xmlGenericErrorContext
, "%s ", define
->name
);
10629 xmlGenericError(xmlGenericErrorContext
, "succeeded\n");
10631 xmlGenericError(xmlGenericErrorContext
, "failed\n");
10637 * xmlRelaxNGValidateDefinition:
10638 * @ctxt: a Relax-NG validation context
10639 * @define: the definition to verify
10641 * Validate the current node lists against the definition
10643 * Returns 0 if the validation succeeded or an error code.
10646 xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt
,
10647 xmlRelaxNGDefinePtr define
)
10649 xmlRelaxNGStatesPtr states
, res
;
10650 int i
, j
, k
, ret
, oldflags
;
10653 * We should NOT have both ctxt->state and ctxt->states
10655 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10656 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10657 ctxt
->state
= NULL
;
10660 if ((ctxt
->states
== NULL
) || (ctxt
->states
->nbState
== 1)) {
10661 if (ctxt
->states
!= NULL
) {
10662 ctxt
->state
= ctxt
->states
->tabState
[0];
10663 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10664 ctxt
->states
= NULL
;
10666 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10667 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10668 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10669 ctxt
->state
= NULL
;
10671 if ((ctxt
->states
!= NULL
) && (ctxt
->states
->nbState
== 1)) {
10672 ctxt
->state
= ctxt
->states
->tabState
[0];
10673 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10674 ctxt
->states
= NULL
;
10679 states
= ctxt
->states
;
10680 ctxt
->states
= NULL
;
10683 oldflags
= ctxt
->flags
;
10684 ctxt
->flags
|= FLAGS_IGNORABLE
;
10685 for (i
= 0; i
< states
->nbState
; i
++) {
10686 ctxt
->state
= states
->tabState
[i
];
10687 ctxt
->states
= NULL
;
10688 ret
= xmlRelaxNGValidateState(ctxt
, define
);
10690 * We should NOT have both ctxt->state and ctxt->states
10692 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10693 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10694 ctxt
->state
= NULL
;
10697 if (ctxt
->states
== NULL
) {
10699 /* add the state to the container */
10700 xmlRelaxNGAddStates(ctxt
, res
, ctxt
->state
);
10701 ctxt
->state
= NULL
;
10703 /* add the state directly in states */
10704 states
->tabState
[j
++] = ctxt
->state
;
10705 ctxt
->state
= NULL
;
10709 /* make it the new container and copy other results */
10710 res
= ctxt
->states
;
10711 ctxt
->states
= NULL
;
10712 for (k
= 0; k
< j
; k
++)
10713 xmlRelaxNGAddStates(ctxt
, res
,
10714 states
->tabState
[k
]);
10716 /* add all the new results to res and reff the container */
10717 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10718 xmlRelaxNGAddStates(ctxt
, res
,
10719 ctxt
->states
->tabState
[k
]);
10720 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10721 ctxt
->states
= NULL
;
10725 if (ctxt
->state
!= NULL
) {
10726 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10727 ctxt
->state
= NULL
;
10728 } else if (ctxt
->states
!= NULL
) {
10729 for (k
= 0; k
< ctxt
->states
->nbState
; k
++)
10730 xmlRelaxNGFreeValidState(ctxt
,
10731 ctxt
->states
->tabState
[k
]);
10732 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10733 ctxt
->states
= NULL
;
10737 ctxt
->flags
= oldflags
;
10739 xmlRelaxNGFreeStates(ctxt
, states
);
10740 ctxt
->states
= res
;
10742 } else if (j
> 1) {
10743 states
->nbState
= j
;
10744 ctxt
->states
= states
;
10746 } else if (j
== 1) {
10747 ctxt
->state
= states
->tabState
[0];
10748 xmlRelaxNGFreeStates(ctxt
, states
);
10752 xmlRelaxNGFreeStates(ctxt
, states
);
10753 if (ctxt
->states
!= NULL
) {
10754 xmlRelaxNGFreeStates(ctxt
, ctxt
->states
);
10755 ctxt
->states
= NULL
;
10758 if ((ctxt
->state
!= NULL
) && (ctxt
->states
!= NULL
)) {
10759 TODO
xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10760 ctxt
->state
= NULL
;
10766 * xmlRelaxNGValidateDocument:
10767 * @ctxt: a Relax-NG validation context
10768 * @doc: the document
10770 * Validate the given document
10772 * Returns 0 if the validation succeeded or an error code.
10775 xmlRelaxNGValidateDocument(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
10778 xmlRelaxNGPtr schema
;
10779 xmlRelaxNGGrammarPtr grammar
;
10780 xmlRelaxNGValidStatePtr state
;
10783 if ((ctxt
== NULL
) || (ctxt
->schema
== NULL
) || (doc
== NULL
))
10786 ctxt
->errNo
= XML_RELAXNG_OK
;
10787 schema
= ctxt
->schema
;
10788 grammar
= schema
->topgrammar
;
10789 if (grammar
== NULL
) {
10790 VALID_ERR(XML_RELAXNG_ERR_NOGRAMMAR
);
10793 state
= xmlRelaxNGNewValidState(ctxt
, NULL
);
10794 ctxt
->state
= state
;
10795 ret
= xmlRelaxNGValidateDefinition(ctxt
, grammar
->start
);
10796 if ((ctxt
->state
!= NULL
) && (state
->seq
!= NULL
)) {
10797 state
= ctxt
->state
;
10799 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10800 if (node
!= NULL
) {
10802 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10806 } else if (ctxt
->states
!= NULL
) {
10810 for (i
= 0; i
< ctxt
->states
->nbState
; i
++) {
10811 state
= ctxt
->states
->tabState
[i
];
10813 node
= xmlRelaxNGSkipIgnored(ctxt
, node
);
10816 xmlRelaxNGFreeValidState(ctxt
, state
);
10820 VALID_ERR(XML_RELAXNG_ERR_EXTRADATA
);
10825 if (ctxt
->state
!= NULL
) {
10826 xmlRelaxNGFreeValidState(ctxt
, ctxt
->state
);
10827 ctxt
->state
= NULL
;
10830 xmlRelaxNGDumpValidError(ctxt
);
10832 else if (ctxt
->errNr
!= 0) {
10833 ctxt
->error(ctxt
->userData
,
10834 "%d Extra error messages left on stack !\n",
10836 xmlRelaxNGDumpValidError(ctxt
);
10839 #ifdef LIBXML_VALID_ENABLED
10840 if (ctxt
->idref
== 1) {
10841 xmlValidCtxt vctxt
;
10843 memset(&vctxt
, 0, sizeof(xmlValidCtxt
));
10845 vctxt
.error
= ctxt
->error
;
10846 vctxt
.warning
= ctxt
->warning
;
10847 vctxt
.userData
= ctxt
->userData
;
10849 if (xmlValidateDocumentFinal(&vctxt
, doc
) != 1)
10852 #endif /* LIBXML_VALID_ENABLED */
10853 if ((ret
== 0) && (ctxt
->errNo
!= XML_RELAXNG_OK
))
10860 * xmlRelaxNGCleanPSVI:
10861 * @node: an input element or document
10863 * Call this routine to speed up XPath computation on static documents.
10864 * This stamps all the element nodes with the document order
10865 * Like for line information, the order is kept in the element->content
10866 * field, the value stored is actually - the node number (starting at -1)
10867 * to be able to differentiate from line numbers.
10869 * Returns the number of elements found in the document or -1 in case
10873 xmlRelaxNGCleanPSVI(xmlNodePtr node
) {
10876 if ((node
== NULL
) ||
10877 ((node
->type
!= XML_ELEMENT_NODE
) &&
10878 (node
->type
!= XML_DOCUMENT_NODE
) &&
10879 (node
->type
!= XML_HTML_DOCUMENT_NODE
)))
10881 if (node
->type
== XML_ELEMENT_NODE
)
10884 cur
= node
->children
;
10885 while (cur
!= NULL
) {
10886 if (cur
->type
== XML_ELEMENT_NODE
) {
10888 if (cur
->children
!= NULL
) {
10889 cur
= cur
->children
;
10893 if (cur
->next
!= NULL
) {
10905 if (cur
->next
!= NULL
) {
10909 } while (cur
!= NULL
);
10913 /************************************************************************
10915 * Validation interfaces *
10917 ************************************************************************/
10920 * xmlRelaxNGNewValidCtxt:
10921 * @schema: a precompiled XML RelaxNGs
10923 * Create an XML RelaxNGs validation context based on the given schema
10925 * Returns the validation context or NULL in case of error
10927 xmlRelaxNGValidCtxtPtr
10928 xmlRelaxNGNewValidCtxt(xmlRelaxNGPtr schema
)
10930 xmlRelaxNGValidCtxtPtr ret
;
10932 ret
= (xmlRelaxNGValidCtxtPtr
) xmlMalloc(sizeof(xmlRelaxNGValidCtxt
));
10934 xmlRngVErrMemory(NULL
, "building context\n");
10937 memset(ret
, 0, sizeof(xmlRelaxNGValidCtxt
));
10938 ret
->schema
= schema
;
10939 ret
->error
= xmlGenericError
;
10940 ret
->userData
= xmlGenericErrorContext
;
10944 ret
->errTab
= NULL
;
10945 if (schema
!= NULL
)
10946 ret
->idref
= schema
->idref
;
10947 ret
->states
= NULL
;
10948 ret
->freeState
= NULL
;
10949 ret
->freeStates
= NULL
;
10950 ret
->errNo
= XML_RELAXNG_OK
;
10955 * xmlRelaxNGFreeValidCtxt:
10956 * @ctxt: the schema validation context
10958 * Free the resources associated to the schema validation context
10961 xmlRelaxNGFreeValidCtxt(xmlRelaxNGValidCtxtPtr ctxt
)
10967 if (ctxt
->states
!= NULL
)
10968 xmlRelaxNGFreeStates(NULL
, ctxt
->states
);
10969 if (ctxt
->freeState
!= NULL
) {
10970 for (k
= 0; k
< ctxt
->freeState
->nbState
; k
++) {
10971 xmlRelaxNGFreeValidState(NULL
, ctxt
->freeState
->tabState
[k
]);
10973 xmlRelaxNGFreeStates(NULL
, ctxt
->freeState
);
10975 if (ctxt
->freeStates
!= NULL
) {
10976 for (k
= 0; k
< ctxt
->freeStatesNr
; k
++) {
10977 xmlRelaxNGFreeStates(NULL
, ctxt
->freeStates
[k
]);
10979 xmlFree(ctxt
->freeStates
);
10981 if (ctxt
->errTab
!= NULL
)
10982 xmlFree(ctxt
->errTab
);
10983 if (ctxt
->elemTab
!= NULL
) {
10984 xmlRegExecCtxtPtr exec
;
10986 exec
= xmlRelaxNGElemPop(ctxt
);
10987 while (exec
!= NULL
) {
10988 xmlRegFreeExecCtxt(exec
);
10989 exec
= xmlRelaxNGElemPop(ctxt
);
10991 xmlFree(ctxt
->elemTab
);
10997 * xmlRelaxNGSetValidErrors:
10998 * @ctxt: a Relax-NG validation context
10999 * @err: the error function
11000 * @warn: the warning function
11001 * @ctx: the functions context
11003 * Set the error and warning callback information
11006 xmlRelaxNGSetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
11007 xmlRelaxNGValidityErrorFunc err
,
11008 xmlRelaxNGValidityWarningFunc warn
, void *ctx
)
11013 ctxt
->warning
= warn
;
11014 ctxt
->userData
= ctx
;
11015 ctxt
->serror
= NULL
;
11019 * xmlRelaxNGSetValidStructuredErrors:
11020 * @ctxt: a Relax-NG validation context
11021 * @serror: the structured error function
11022 * @ctx: the functions context
11024 * Set the structured error callback
11027 xmlRelaxNGSetValidStructuredErrors(xmlRelaxNGValidCtxtPtr ctxt
,
11028 xmlStructuredErrorFunc serror
, void *ctx
)
11032 ctxt
->serror
= serror
;
11033 ctxt
->error
= NULL
;
11034 ctxt
->warning
= NULL
;
11035 ctxt
->userData
= ctx
;
11039 * xmlRelaxNGGetValidErrors:
11040 * @ctxt: a Relax-NG validation context
11041 * @err: the error function result
11042 * @warn: the warning function result
11043 * @ctx: the functions context result
11045 * Get the error and warning callback information
11047 * Returns -1 in case of error and 0 otherwise
11050 xmlRelaxNGGetValidErrors(xmlRelaxNGValidCtxtPtr ctxt
,
11051 xmlRelaxNGValidityErrorFunc
* err
,
11052 xmlRelaxNGValidityWarningFunc
* warn
, void **ctx
)
11057 *err
= ctxt
->error
;
11059 *warn
= ctxt
->warning
;
11061 *ctx
= ctxt
->userData
;
11066 * xmlRelaxNGValidateDoc:
11067 * @ctxt: a Relax-NG validation context
11068 * @doc: a parsed document tree
11070 * Validate a document tree in memory.
11072 * Returns 0 if the document is valid, a positive error code
11073 * number otherwise and -1 in case of internal or API error.
11076 xmlRelaxNGValidateDoc(xmlRelaxNGValidCtxtPtr ctxt
, xmlDocPtr doc
)
11080 if ((ctxt
== NULL
) || (doc
== NULL
))
11085 ret
= xmlRelaxNGValidateDocument(ctxt
, doc
);
11087 * Remove all left PSVI
11089 xmlRelaxNGCleanPSVI((xmlNodePtr
) doc
);
11092 * TODO: build error codes
11099 #define bottom_relaxng
11100 #include "elfgcchack.h"
11101 #endif /* LIBXML_SCHEMAS_ENABLED */