static const xmlChar *xmlRelaxNGNs = (const xmlChar *)
"http://relaxng.org/ns/structure/1.0";
-#define IS_RELAXNG(node, type) \
+#define IS_RELAXNG(node, typ) \
((node != NULL) && (node->ns != NULL) && \
- (xmlStrEqual(node->name, (const xmlChar *) type)) && \
+ (node->type == XML_ELEMENT_NODE) && \
+ (xmlStrEqual(node->name, (const xmlChar *) typ)) && \
(xmlStrEqual(node->ns->href, xmlRelaxNGNs)))
#define DEBUG_LIST 1
-#define DEBUG_INCLUDE 1
+#define DEBUG_INCLUDE 1
#define DEBUG_ERROR 1
#define MAX_ERROR 5
-#define TODO \
+#define TODO \
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
#define IS_PROCESSED (1 << 5)
#define IS_COMPILABLE (1 << 6)
#define IS_NOT_COMPILABLE (1 << 7)
+#define IS_EXTERNAL_REF (1 << 8)
struct _xmlRelaxNGDefine {
xmlRelaxNGType type; /* the type of definition */
xmlDocPtr doc; /* the associated XML document */
xmlRelaxNGDefinePtr content; /* the definitions */
xmlRelaxNGPtr schema; /* the schema */
+ int externalRef; /* 1 if an external ref */
};
/************************************************************************
* *
- * Some factorized error routines *
+ * Some factorized error routines *
* *
************************************************************************/
}
/************************************************************************
- * *
- * Preliminary type checking interfaces *
- * *
+ * *
+ * Preliminary type checking interfaces *
+ * *
************************************************************************/
/**
};
/************************************************************************
- * *
- * Allocation functions *
- * *
+ * *
+ * Allocation functions *
+ * *
************************************************************************/
static void xmlRelaxNGFreeGrammar(xmlRelaxNGGrammarPtr grammar);
static void xmlRelaxNGFreeDefine(xmlRelaxNGDefinePtr define);
xmlRelaxNGStatesPtr ret;
if ((ctxt != NULL) &&
- (ctxt->freeState != NULL) && (ctxt->freeStatesNr > 0)) {
+ (ctxt->freeStates != NULL) && (ctxt->freeStatesNr > 0)) {
ctxt->freeStatesNr--;
ret = ctxt->freeStates[ctxt->freeStatesNr];
ret->nbState = 0;
{
int i;
- if (state == NULL) {
+ if (state == NULL || states == NULL) {
return (-1);
}
if (states->nbState >= states->maxState) {
}
/************************************************************************
- * *
- * Semi internal functions *
- * *
+ * *
+ * Semi internal functions *
+ * *
************************************************************************/
/**
}
/************************************************************************
- * *
- * Document functions *
- * *
+ * *
+ * Document functions *
+ * *
************************************************************************/
static xmlDocPtr xmlRelaxNGCleanupDoc(xmlRelaxNGParserCtxtPtr ctxt,
xmlDocPtr doc);
href = xmlGetProp(tmp, BAD_CAST "href");
#endif
if (xmlRelaxNGRemoveRedefine(ctxt, href,
- inc->doc->children->
- children, name) == 1) {
+ xmlDocGetRootElement(inc->doc)->children,
+ name) == 1) {
found = 1;
}
#ifdef DEBUG_INCLUDE
ret->doc = doc;
ret->href = xmlStrdup(URL);
ret->next = ctxt->documents;
+ ret->externalRef = 1;
ctxt->documents = ret;
/*
}
/************************************************************************
- * *
- * Error functions *
- * *
+ * *
+ * Error functions *
+ * *
************************************************************************/
#define VALID_ERR(a) xmlRelaxNGAddValidError(ctxt, a, NULL, NULL, 0);
* generate the error directly
*/
if (((ctxt->flags & FLAGS_IGNORABLE) == 0) ||
- (ctxt->flags & FLAGS_NEGATIVE)) {
+ (ctxt->flags & FLAGS_NEGATIVE)) {
xmlNodePtr node, seq;
/*
} else {
node = seq = NULL;
}
+ if ((node == NULL) && (seq == NULL)) {
+ node = ctxt->pnode;
+ }
xmlRelaxNGShowValidError(ctxt, err, node, seq, arg1, arg2);
}
/*
/************************************************************************
- * *
- * Type library hooks *
- * *
+ * *
+ * Type library hooks *
+ * *
************************************************************************/
static xmlChar *xmlRelaxNGNormalize(xmlRelaxNGValidCtxtPtr ctxt,
const xmlChar * str);
}
ret = xmlSchemaValPredefTypeNode(typ, value2, &res2, ctxt2);
if (ret != 0) {
- if ((comp1 == NULL) && (res1 != NULL))
+ if (res1 != (xmlSchemaValPtr) comp1)
xmlSchemaFreeValue(res1);
return (-1);
}
- if (res1 == NULL) {
- return (-1);
- }
ret = xmlSchemaCompareValues(res1, res2);
if (res1 != (xmlSchemaValPtr) comp1)
xmlSchemaFreeValue(res1);
}
/************************************************************************
- * *
- * Compiling element content into regexp *
- * *
+ * *
+ * Compiling element content into regexp *
+ * *
* Sometime the element content can be compiled into a pure regexp, *
* This allows a faster execution and streamability at that level *
- * *
+ * *
************************************************************************/
+/* from automata.c but not exported */
+void xmlAutomataSetFlags(xmlAutomataPtr am, int flags);
+
+
static int xmlRelaxNGTryCompile(xmlRelaxNGParserCtxtPtr ctxt,
xmlRelaxNGDefinePtr def);
ctxt->am = xmlNewAutomata();
if (ctxt->am == NULL)
return (-1);
+
+ /*
+ * assume identical strings but not same pointer are different
+ * atoms, needed for non-determinism detection
+ * That way if 2 elements with the same name are in a choice
+ * branch the automata is found non-deterministic and
+ * we fallback to the normal validation which does the right
+ * thing of exploring both choices.
+ */
+ xmlAutomataSetFlags(ctxt->am, 1);
+
ctxt->state = xmlAutomataGetInitState(ctxt->am);
while (list != NULL) {
xmlRelaxNGCompile(ctxt, list);
list = list->next;
}
xmlAutomataSetFinalState(ctxt->am, ctxt->state);
- def->contModel = xmlAutomataCompile(ctxt->am);
- xmlRegexpIsDeterminist(def->contModel);
+ if (xmlAutomataIsDeterminist(ctxt->am))
+ def->contModel = xmlAutomataCompile(ctxt->am);
xmlFreeAutomata(ctxt->am);
ctxt->state = oldstate;
ctxt->am = xmlNewAutomata();
if (ctxt->am == NULL)
return (-1);
+ xmlAutomataSetFlags(ctxt->am, 1);
ctxt->state = xmlAutomataGetInitState(ctxt->am);
while (list != NULL) {
xmlRelaxNGCompile(ctxt, list);
xmlAutomataSetFinalState(ctxt->am, ctxt->state);
def->contModel = xmlAutomataCompile(ctxt->am);
if (!xmlRegexpIsDeterminist(def->contModel)) {
+#ifdef DEBUG_COMPILE
+ xmlGenericError(xmlGenericErrorContext,
+ "Content model not determinist %s\n",
+ def->name);
+#endif
/*
* we can only use the automata if it is determinist
*/
case XML_RELAXNG_OPTIONAL:{
xmlAutomataStatePtr oldstate = ctxt->state;
- xmlRelaxNGCompile(ctxt, def->content);
+ list = def->content;
+ while (list != NULL) {
+ xmlRelaxNGCompile(ctxt, list);
+ list = list->next;
+ }
xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
break;
}
}
/************************************************************************
- * *
- * Parsing functions *
- * *
+ * *
+ * Parsing functions *
+ * *
************************************************************************/
static xmlRelaxNGDefinePtr xmlRelaxNGParseAttribute(xmlRelaxNGParserCtxtPtr
{
xmlChar *ret, *escape;
+ if (node == NULL)
+ return(NULL);
+
if ((IS_RELAXNG(node, "data")) || (IS_RELAXNG(node, "value"))) {
ret = xmlGetProp(node, BAD_CAST "datatypeLibrary");
if (ret != NULL) {
return (0);
return (1);
} else if (def1->type == XML_RELAXNG_EXCEPT) {
- TODO ret = 0;
+ ret = xmlRelaxNGCompareNameClasses(def1->content, def2);
+ if (ret == 0)
+ ret = 1;
+ else if (ret == 1)
+ ret = 0;
} else {
TODO ret = 0;
}
}
/**
+ * xmlRelaxNGParseImportRef:
+ * @payload: the parser context
+ * @data: the current grammar
+ * @name: the reference name
+ *
+ * Import import one references into the current grammar
+ */
+static void
+xmlRelaxNGParseImportRef(void *payload, void *data, xmlChar *name) {
+ xmlRelaxNGParserCtxtPtr ctxt = (xmlRelaxNGParserCtxtPtr) data;
+ xmlRelaxNGDefinePtr def = (xmlRelaxNGDefinePtr) payload;
+ int tmp;
+
+ def->dflags |= IS_EXTERNAL_REF;
+
+ tmp = xmlHashAddEntry(ctxt->grammar->refs, name, def);
+ if (tmp < 0) {
+ xmlRelaxNGDefinePtr prev;
+
+ prev = (xmlRelaxNGDefinePtr)
+ xmlHashLookup(ctxt->grammar->refs, def->name);
+ if (prev == NULL) {
+ if (def->name != NULL) {
+ xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
+ "Error refs definitions '%s'\n",
+ def->name, NULL);
+ } else {
+ xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
+ "Error refs definitions\n",
+ NULL, NULL);
+ }
+ } else {
+ def->nextHash = prev->nextHash;
+ prev->nextHash = def;
+ }
+ }
+}
+
+/**
+ * xmlRelaxNGParseImportRefs:
+ * @ctxt: the parser context
+ * @grammar: the sub grammar
+ *
+ * Import references from the subgrammar into the current grammar
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+static int
+xmlRelaxNGParseImportRefs(xmlRelaxNGParserCtxtPtr ctxt,
+ xmlRelaxNGGrammarPtr grammar) {
+ if ((ctxt == NULL) || (grammar == NULL) || (ctxt->grammar == NULL))
+ return(-1);
+ if (grammar->refs == NULL)
+ return(0);
+ if (ctxt->grammar->refs == NULL)
+ ctxt->grammar->refs = xmlHashCreate(10);
+ if (ctxt->grammar->refs == NULL) {
+ xmlRngPErr(ctxt, NULL, XML_RNGP_REF_CREATE_FAILED,
+ "Could not create references hash\n", NULL, NULL);
+ return(-1);
+ }
+ xmlHashScan(grammar->refs, xmlRelaxNGParseImportRef, ctxt);
+ return(0);
+}
+
+/**
* xmlRelaxNGProcessExternalRef:
* @ctxt: the parser context
* @node: the externlRef node
if ((docu->schema != NULL) &&
(docu->schema->topgrammar != NULL)) {
docu->content = docu->schema->topgrammar->start;
+ if (docu->schema->topgrammar->refs)
+ xmlRelaxNGParseImportRefs(ctxt, docu->schema->topgrammar);
}
/*
} else {
xmlRngPErr(ctxt, node, XML_RNGP_CHOICE_CONTENT,
"expecting name, anyName, nsName or choice : got %s\n",
- node->name, NULL);
+ (node == NULL ? (const xmlChar *) "nothing" : node->name),
+ NULL);
return (NULL);
}
if (ret != def) {
xmlRelaxNGGrammarPtr grammar;
xmlRelaxNGDefinePtr def, cur;
+ /*
+ * Those rules don't apply to imported ref from xmlRelaxNGParseImportRef
+ */
+ if (ref->dflags & IS_EXTERNAL_REF)
+ return;
+
grammar = ctxt->grammar;
if (grammar == NULL) {
xmlRngPErr(ctxt, ref->node, XML_ERR_INTERNAL_ERROR,
xmlRelaxNGDefinePtr cur, int flags,
xmlRelaxNGType ptype)
{
- int nflags = flags;
+ int nflags;
xmlRelaxNGContentType ret, tmp, val = XML_RELAXNG_CONTENT_EMPTY;
while (cur != NULL) {
"Found forbidden pattern data/except//ref\n",
NULL, NULL);
}
+ if (cur->content == NULL) {
+ if (cur->type == XML_RELAXNG_PARENTREF)
+ xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
+ "Internal found no define for parent refs\n",
+ NULL, NULL);
+ else
+ xmlRngPErr(ctxt, cur->node, XML_RNGP_REF_NO_DEF,
+ "Internal found no define for ref %s\n",
+ (cur->name ? cur->name: BAD_CAST "null"), NULL);
+ }
if (cur->depth > -4) {
cur->depth = -4;
ret = xmlRelaxNGCheckRules(ctxt, cur->content,
if (ptype == XML_RELAXNG_GROUP) {
val = xmlRelaxNGGroupContentType(val, ret);
} else if (ptype == XML_RELAXNG_INTERLEAVE) {
+ /*
+ * TODO: scan complain that tmp is never used, seems on purpose
+ * need double-checking
+ */
tmp = xmlRelaxNGGroupContentType(val, ret);
if (tmp != XML_RELAXNG_CONTENT_ERROR)
tmp = xmlRelaxNGMaxContentType(val, ret);
}
/*
- * Apply 4.17 mergingd rules to defines and starts
+ * Apply 4.17 merging rules to defines and starts
*/
xmlRelaxNGCombineStart(ctxt, ret);
if (ret->defs != NULL) {
ctxt);
}
+
+ /* @@@@ */
+
ctxt->grammar = old;
return (ret);
}
ctxt->define = NULL;
if (IS_RELAXNG(node, "grammar")) {
schema->topgrammar = xmlRelaxNGParseGrammar(ctxt, node->children);
+ if (schema->topgrammar == NULL) {
+ xmlRelaxNGFree(schema);
+ return (NULL);
+ }
} else {
xmlRelaxNGGrammarPtr tmp, ret;
schema->topgrammar = ret = xmlRelaxNGNewGrammar(ctxt);
if (schema->topgrammar == NULL) {
- return (schema);
+ xmlRelaxNGFree(schema);
+ return (NULL);
}
/*
* Link the new grammar in the tree
}
/************************************************************************
- * *
- * Reading RelaxNGs *
- * *
+ * *
+ * Reading RelaxNGs *
+ * *
************************************************************************/
/**
}
}
/*
- * Thisd is not an else since "include" is transformed
+ * This is not an else since "include" is transformed
* into a div
*/
if (xmlStrEqual(cur->name, BAD_CAST "div")) {
if (ns != NULL)
xmlFree(ns);
/*
- * Since we are about to delete cur, if it's nsDef is non-NULL we
+ * Since we are about to delete cur, if its nsDef is non-NULL we
* need to preserve it (it contains the ns definitions for the
* children we just moved). We'll just stick it on to the end
* of cur->parent's list, since it's never going to be re-serialized
* (bug 143738).
*/
- if (cur->nsDef != NULL) {
+ if ((cur->nsDef != NULL) && (cur->parent != NULL)) {
xmlNsPtr parDef = (xmlNsPtr)&cur->parent->nsDef;
while (parDef->next != NULL)
parDef = parDef->next;
else if ((cur->type == XML_TEXT_NODE) ||
(cur->type == XML_CDATA_SECTION_NODE)) {
if (IS_BLANK_NODE(cur)) {
- if (cur->parent->type == XML_ELEMENT_NODE) {
+ if ((cur->parent != NULL) &&
+ (cur->parent->type == XML_ELEMENT_NODE)) {
if ((!xmlStrEqual(cur->parent->name, BAD_CAST "value"))
&&
(!xmlStrEqual
xmlRngPErr(ctxt, (xmlNodePtr) doc,
XML_RNGP_EMPTY, "xmlRelaxNGParse: %s is empty\n",
(ctxt->URL ? ctxt->URL : BAD_CAST "schemas"), NULL);
-
+
xmlFreeDoc(ctxt->document);
ctxt->document = NULL;
return (NULL);
#ifdef LIBXML_OUTPUT_ENABLED
/************************************************************************
- * *
- * Dump back a compiled form *
- * *
+ * *
+ * Dump back a compiled form *
+ * *
************************************************************************/
static void xmlRelaxNGDumpDefine(FILE * output,
xmlRelaxNGDefinePtr define);
* xmlRelaxNGDumpGrammar:
* @output: the file output
* @grammar: a grammar structure
- * @top: is this a top grammar
+ * @top: is this a top grammar
*
* Dump a RelaxNG structure back
*/
#endif /* LIBXML_OUTPUT_ENABLED */
/************************************************************************
- * *
- * Validation of compiled content *
- * *
+ * *
+ * Validation of compiled content *
+ * *
************************************************************************/
static int xmlRelaxNGValidateDefinition(xmlRelaxNGValidCtxtPtr ctxt,
xmlRelaxNGDefinePtr define);
}
/************************************************************************
- * *
- * Progressive validation of when possible *
- * *
+ * *
+ * Progressive validation of when possible *
+ * *
************************************************************************/
static int xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
xmlRelaxNGDefinePtr defines);
* xmlRelaxNGValidatePushCData:
* @ctxt: the RelaxNG validation context
* @data: some character data read
- * @len: the lenght of the data
+ * @len: the length of the data
*
* check the CData parsed for validation in the current stack
*
ret = -1;
else
ret = 1;
- xmlRelaxNGFreeValidState(ctxt, state);
+ xmlRelaxNGFreeValidState(ctxt, ctxt->state);
ctxt->state = NULL;
#ifdef DEBUG_PROGRESSIVE
if (ret < 0)
}
/************************************************************************
- * *
- * Generic interpreted validation implementation *
- * *
+ * *
+ * Generic interpreted validation implementation *
+ * *
************************************************************************/
static int xmlRelaxNGValidateValue(xmlRelaxNGValidCtxtPtr ctxt,
xmlRelaxNGDefinePtr define);
case XML_RELAXNG_ZEROORMORE:{
xmlChar *cur, *temp;
+ if ((ctxt->state->value == NULL) ||
+ (*ctxt->state->value == 0)) {
+ ret = 0;
+ break;
+ }
oldflags = ctxt->flags;
ctxt->flags |= FLAGS_IGNORABLE;
cur = ctxt->state->value;
xmlRelaxNGPopErrors(ctxt, 0);
break;
}
+ case XML_RELAXNG_OPTIONAL:{
+ xmlChar *temp;
+
+ if ((ctxt->state->value == NULL) ||
+ (*ctxt->state->value == 0)) {
+ ret = 0;
+ break;
+ }
+ oldflags = ctxt->flags;
+ ctxt->flags |= FLAGS_IGNORABLE;
+ temp = ctxt->state->value;
+ ret = xmlRelaxNGValidateValue(ctxt, define->content);
+ ctxt->flags = oldflags;
+ if (ret != 0) {
+ ctxt->state->value = temp;
+ if (ctxt->errNr > 0)
+ xmlRelaxNGPopErrors(ctxt, 0);
+ ret = 0;
+ break;
+ }
+ if (ctxt->errNr > 0)
+ xmlRelaxNGPopErrors(ctxt, 0);
+ break;
+ }
case XML_RELAXNG_EXCEPT:{
xmlRelaxNGDefinePtr list;
}
case XML_RELAXNG_REF:
case XML_RELAXNG_PARENTREF:
- ret = xmlRelaxNGValidateValue(ctxt, define->content);
+ if (define->content == NULL) {
+ VALID_ERR(XML_RELAXNG_ERR_NODEFINE);
+ ret = -1;
+ } else {
+ ret = xmlRelaxNGValidateValue(ctxt, define->content);
+ }
break;
default:
TODO ret = -1;
return (ret);
list = list->next;
}
+ } else if (define->type == XML_RELAXNG_CHOICE) {
+ xmlRelaxNGDefinePtr list;
+
+ list = define->nameClass;
+ while (list != NULL) {
+ ret = xmlRelaxNGAttributeMatch(ctxt, list, prop);
+ if (ret == 1)
+ return (1);
+ if (ret < 0)
+ return (ret);
+ list = list->next;
+ }
+ return (0);
} else {
TODO}
return (1);
oldstate = ctxt->state;
for (i = 0; i < nbgroups; i++) {
ctxt->state = xmlRelaxNGCopyValidState(ctxt, oldstate);
+ if (ctxt->state == NULL) {
+ ret = -1;
+ break;
+ }
group = partitions->groups[i];
if (lasts[i] != NULL) {
last = lasts[i]->next;
oldstate =
ctxt->states->tabState[ctxt->states->nbState - 1];
ctxt->states->tabState[ctxt->states->nbState - 1] = NULL;
+ ctxt->states->nbState--;
}
}
for (j = 0; j < ctxt->states->nbState ; j++) {
xmlRelaxNGFreeStates(ctxt, ctxt->states);
ctxt->states = NULL;
if (found == 0) {
- VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
+ if (cur == NULL) {
+ VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA,
+ (const xmlChar *) "noname");
+ } else {
+ VALID_ERR2(XML_RELAXNG_ERR_INTEREXTRA, cur->name);
+ }
ret = -1;
ctxt->state = oldstate;
goto done;
ctxt->depth++;
switch (define->type) {
case XML_RELAXNG_EMPTY:
- node = xmlRelaxNGSkipIgnored(ctxt, node);
+ xmlRelaxNGSkipIgnored(ctxt, node);
ret = 0;
break;
case XML_RELAXNG_NOT_ALLOWED:
ret = -1;
} else {
state = ctxt->state;
- ctxt->state->seq = nseq;
+ if (ctxt->state != NULL)
+ ctxt->state->seq = nseq;
if (ret == 0)
ret = xmlRelaxNGValidateElementEnd(ctxt, 1);
xmlRelaxNGFreeValidState(ctxt, state);
}
for (i = 0; i < ctxt->states->nbState; i++) {
xmlRelaxNGFreeValidState(ctxt,
- ctxt->states->
- tabState[i]);
+ ctxt->states->tabState[i]);
+ ctxt->states->tabState[i] = NULL;
}
xmlRelaxNGFreeStates(ctxt, ctxt->states);
ctxt->flags = oldflags;
} else {
for (j = 0; j < ctxt->states->nbState; j++) {
xmlRelaxNGAddStates(ctxt, res,
- xmlRelaxNGCopyValidState(ctxt,
- ctxt->
- states->
- tabState
- [j]));
+ xmlRelaxNGCopyValidState(ctxt,
+ ctxt->states->tabState[j]));
}
}
oldflags = ctxt->flags;
j++) {
tmp =
xmlRelaxNGAddStates(ctxt, res,
- ctxt->
- states->
- tabState
- [j]);
+ ctxt->states->tabState[j]);
if (tmp == 1)
progress = 1;
}
} else if (ctxt->states != NULL) {
for (j = 0; j < ctxt->states->nbState; j++) {
tmp = xmlRelaxNGAddStates(ctxt, res,
- ctxt->
- states->
- tabState[j]);
+ ctxt->states->tabState[j]);
if (tmp == 1)
progress = 1;
}
for (i = base; i < res->nbState; i++)
xmlRelaxNGAddStates(ctxt, states,
xmlRelaxNGCopyValidState
- (ctxt,
- res->tabState[i]));
+ (ctxt, res->tabState[i]));
ctxt->states = states;
}
}
return (ret);
}
+/**
+ * xmlRelaxNGCleanPSVI:
+ * @node: an input element or document
+ *
+ * Call this routine to speed up XPath computation on static documents.
+ * This stamps all the element nodes with the document order
+ * Like for line information, the order is kept in the element->content
+ * field, the value stored is actually - the node number (starting at -1)
+ * to be able to differentiate from line numbers.
+ *
+ * Returns the number of elements found in the document or -1 in case
+ * of error.
+ */
+static void
+xmlRelaxNGCleanPSVI(xmlNodePtr node) {
+ xmlNodePtr cur;
+
+ if ((node == NULL) ||
+ ((node->type != XML_ELEMENT_NODE) &&
+ (node->type != XML_DOCUMENT_NODE) &&
+ (node->type != XML_HTML_DOCUMENT_NODE)))
+ return;
+ if (node->type == XML_ELEMENT_NODE)
+ node->psvi = NULL;
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ cur->psvi = NULL;
+ if (cur->children != NULL) {
+ cur = cur->children;
+ continue;
+ }
+ }
+ if (cur->next != NULL) {
+ cur = cur->next;
+ continue;
+ }
+ do {
+ cur = cur->parent;
+ if (cur == NULL)
+ break;
+ if (cur == node) {
+ cur = NULL;
+ break;
+ }
+ if (cur->next != NULL) {
+ cur = cur->next;
+ break;
+ }
+ } while (cur != NULL);
+ }
+ return;
+}
/************************************************************************
- * *
- * Validation interfaces *
- * *
+ * *
+ * Validation interfaces *
+ * *
************************************************************************/
/**
ret = xmlRelaxNGValidateDocument(ctxt, doc);
/*
+ * Remove all left PSVI
+ */
+ xmlRelaxNGCleanPSVI((xmlNodePtr) doc);
+
+ /*
* TODO: build error codes
*/
if (ret == -1)