more work on RelaxNG streaming validation trying to improve the subset
* relaxng.c xmllint.c: more work on RelaxNG streaming validation
trying to improve the subset compiled, and more testing.
* doc/downloads.html doc/xml.html doc/xmlmem.html: some updates on the
documentation
* test/relaxng/tutor11_1_3.xml: fixes the DTD path
* result/relaxng/*.err: fix some of the outputs
Daniel
diff --git a/relaxng.c b/relaxng.c
index cb3c130..b7a0711 100644
--- a/relaxng.c
+++ b/relaxng.c
@@ -3617,6 +3617,78 @@
}
/**
+ * xmlRelaxNGGenerateAttributes:
+ * @ctxt: a Relax-NG parser context
+ * @def: the definition definition
+ *
+ * Check if the definition can only generate attributes
+ *
+ * Returns 1 if yes, 0 if no and -1 in case of error.
+ */
+static int
+xmlRelaxNGGenerateAttributes(xmlRelaxNGParserCtxtPtr ctxt,
+ xmlRelaxNGDefinePtr def) {
+ xmlRelaxNGDefinePtr parent, cur, tmp;
+
+ /*
+ * Don't run that check in case of error. Infinite recursion
+ * becomes possible.
+ */
+ if (ctxt->nbErrors != 0)
+ return(-1);
+
+ parent = NULL;
+ cur = def;
+ while (cur != NULL) {
+ if ((cur->type == XML_RELAXNG_ELEMENT) ||
+ (cur->type == XML_RELAXNG_TEXT) ||
+ (cur->type == XML_RELAXNG_DATATYPE) ||
+ (cur->type == XML_RELAXNG_PARAM) ||
+ (cur->type == XML_RELAXNG_LIST) ||
+ (cur->type == XML_RELAXNG_VALUE) ||
+ (cur->type == XML_RELAXNG_EMPTY))
+ return(0);
+ if ((cur->type == XML_RELAXNG_CHOICE) ||
+ (cur->type == XML_RELAXNG_INTERLEAVE) ||
+ (cur->type == XML_RELAXNG_GROUP) ||
+ (cur->type == XML_RELAXNG_ONEORMORE) ||
+ (cur->type == XML_RELAXNG_ZEROORMORE) ||
+ (cur->type == XML_RELAXNG_OPTIONAL) ||
+ (cur->type == XML_RELAXNG_PARENTREF) ||
+ (cur->type == XML_RELAXNG_EXTERNALREF) ||
+ (cur->type == XML_RELAXNG_REF) ||
+ (cur->type == XML_RELAXNG_DEF)) {
+ if (cur->content != NULL) {
+ parent = cur;
+ cur = cur->content;
+ tmp = cur;
+ while (tmp != NULL) {
+ tmp->parent = parent;
+ tmp = tmp->next;
+ }
+ continue;
+ }
+ }
+ if (cur == def)
+ break;
+ if (cur->next != NULL) {
+ cur = cur->next;
+ continue;
+ }
+ do {
+ cur = cur->parent;
+ if (cur == NULL) break;
+ if (cur == def) return(1);
+ if (cur->next != NULL) {
+ cur = cur->next;
+ break;
+ }
+ } while (cur != NULL);
+ }
+ return(1);
+}
+
+/**
* xmlRelaxNGGetElements:
* @ctxt: a Relax-NG parser context
* @def: the definition definition
@@ -5122,6 +5194,7 @@
}
break;
case XML_RELAXNG_ATTRIBUTE:
+ /* HERE !!! */
cur->next = ret->attrs;
ret->attrs = cur;
break;
@@ -5741,6 +5814,47 @@
if (cur->nameClass != NULL)
xmlRelaxNGSimplify(ctxt, cur->nameClass, cur);
/*
+ * On Elements, try to move attribute only generating rules on
+ * the attrs rules.
+ */
+ if (cur->type == XML_RELAXNG_ELEMENT) {
+ int attronly;
+ xmlRelaxNGDefinePtr tmp, pre;
+
+ while (cur->content != NULL) {
+ attronly = xmlRelaxNGGenerateAttributes(ctxt, cur->content);
+ if (attronly == 1) {
+ /*
+ * migrate cur->content to attrs
+ */
+ tmp = cur->content;
+ cur->content = tmp->next;
+ tmp->next = cur->attrs;
+ cur->attrs = tmp;
+ } else {
+ /*
+ * cur->content can generate elements or text
+ */
+ break;
+ }
+ }
+ pre = cur->content;
+ while ((pre != NULL) && (pre->next != NULL)) {
+ tmp = pre->next;
+ attronly = xmlRelaxNGGenerateAttributes(ctxt, tmp);
+ if (attronly == 1) {
+ /*
+ * migrate tmp to attrs
+ */
+ pre->next = tmp->next;
+ tmp->next = cur->attrs;
+ cur->attrs = tmp;
+ } else {
+ pre = tmp;
+ }
+ }
+ }
+ /*
* This may result in a simplification
*/
if ((cur->type == XML_RELAXNG_GROUP) ||
@@ -7106,18 +7220,18 @@
/*
* try to compile (parts of) the schemas
*/
- if ((ctxt->grammar != NULL) && (ctxt->grammar->start != NULL)) {
- if (ctxt->grammar->start->type != XML_RELAXNG_START) {
+ if ((ret->topgrammar != NULL) && (ret->topgrammar->start != NULL)) {
+ if (ret->topgrammar->start->type != XML_RELAXNG_START) {
xmlRelaxNGDefinePtr def;
def = xmlRelaxNGNewDefine(ctxt, NULL);
if (def != NULL) {
def->type = XML_RELAXNG_START;
- def->content = ctxt->grammar->start;
- ctxt->grammar->start = def;
+ def->content = ret->topgrammar->start;
+ ret->topgrammar->start = def;
}
}
- xmlRelaxNGTryCompile(ctxt, ctxt->grammar->start);
+ xmlRelaxNGTryCompile(ctxt, ret->topgrammar->start);
}
/*
@@ -7603,9 +7717,9 @@
void *inputdata) {
xmlRelaxNGValidCtxtPtr ctxt = (xmlRelaxNGValidCtxtPtr) inputdata;
xmlRelaxNGDefinePtr define = (xmlRelaxNGDefinePtr) transdata;
- xmlRelaxNGValidStatePtr state;
+ xmlRelaxNGValidStatePtr state, oldstate;
xmlNodePtr node = ctxt->pnode;
- int ret;
+ int ret, oldflags;
#ifdef DEBUG_PROGRESSIVE
xmlGenericError(xmlGenericErrorContext,
@@ -7674,6 +7788,7 @@
ctxt->pstate = -1;
return;
}
+ oldstate = ctxt->state;
ctxt->state = state;
if (define->attrs != NULL) {
ret = xmlRelaxNGValidateAttributeList(ctxt, define->attrs);
@@ -7682,13 +7797,40 @@
VALID_ERR2(XML_RELAXNG_ERR_ATTRVALID, node->name);
}
}
- ctxt->state->seq = NULL;
- ret = xmlRelaxNGValidateElementEnd(ctxt);
- if (ret != 0) {
- ctxt->pstate = -1;
+ if (ctxt->state != NULL) {
+ ctxt->state->seq = NULL;
+ ret = xmlRelaxNGValidateElementEnd(ctxt);
+ if (ret != 0) {
+ ctxt->pstate = -1;
+ }
+ xmlRelaxNGFreeValidState(ctxt, ctxt->state);
+ } else if (ctxt->states != NULL) {
+ int tmp = -1, i;
+
+ oldflags = ctxt->flags;
+ ctxt->flags |= FLAGS_IGNORABLE;
+
+ for (i = 0; i < ctxt->states->nbState; i++) {
+ state = ctxt->states->tabState[i];
+ ctxt->state = state;
+ ctxt->state->seq = NULL;
+
+ if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
+ tmp = 0;
+ xmlRelaxNGFreeValidState(ctxt, state);
+ }
+ xmlRelaxNGFreeStates(ctxt, ctxt->states);
+ ctxt->states = NULL;
+ if ((ret == 0) && (tmp == -1))
+ ctxt->pstate = -1;
+ ctxt->flags = oldflags;
}
- xmlRelaxNGFreeValidState(ctxt, state);
- ctxt->state = NULL;
+ if (ctxt->pstate == -1) {
+ if ((ctxt->flags & FLAGS_IGNORABLE) == 0) {
+ xmlRelaxNGDumpValidError(ctxt);
+ }
+ }
+ ctxt->state = oldstate;
}
/**
@@ -8551,12 +8693,38 @@
static int
xmlRelaxNGValidateAttributeList(xmlRelaxNGValidCtxtPtr ctxt,
xmlRelaxNGDefinePtr defines) {
- int ret = 0;
- while (defines != NULL) {
- if (xmlRelaxNGValidateAttribute(ctxt, defines) != 0)
- ret = -1;
- defines = defines->next;
+ int ret = 0, res;
+ int needmore = 0;
+ xmlRelaxNGDefinePtr cur;
+
+ cur = defines;
+ while (cur != NULL) {
+ if (cur->type == XML_RELAXNG_ATTRIBUTE) {
+ if (xmlRelaxNGValidateAttribute(ctxt, cur) != 0)
+ ret = -1;
+ } else
+ needmore = 1;
+ cur = cur->next;
}
+ if (!needmore)
+ return(ret);
+ cur = defines;
+ while (cur != NULL) {
+ if (cur->type != XML_RELAXNG_ATTRIBUTE) {
+ if ((ctxt->state != NULL) || (ctxt->states != NULL)) {
+ res = xmlRelaxNGValidateDefinition(ctxt, cur);
+ if (res < 0)
+ ret = -1;
+ } else {
+ VALID_ERR(XML_RELAXNG_ERR_NOSTATE);
+ return(-1);
+ }
+ if (res == -1) /* continues on -2 */
+ break;
+ }
+ cur = cur->next;
+ }
+
return(ret);
}
@@ -9162,22 +9330,55 @@
}
}
if (define->contModel != NULL) {
+ xmlRelaxNGValidStatePtr nstate, tmpstate = ctxt->state;
+ xmlRelaxNGStatesPtr tmpstates = ctxt->states;
+ xmlNodePtr nseq;
+
+ nstate = xmlRelaxNGNewValidState(ctxt, node);
+ ctxt->state = nstate;
+ ctxt->states = NULL;
+
tmp = xmlRelaxNGValidateCompiledContent(ctxt,
define->contModel,
ctxt->state->seq);
+ nseq = ctxt->state->seq;
+ ctxt->state = tmpstate;
+ ctxt->states = tmpstates;
+ xmlRelaxNGFreeValidState(ctxt, nstate);
+
#ifdef DEBUG_COMPILE
xmlGenericError(xmlGenericErrorContext,
"Validating content of '%s' : %d\n", define->name, tmp);
#endif
- state = ctxt->state;
- if (tmp == 0) {
- tmp = xmlRelaxNGValidateElementEnd(ctxt);
- if (tmp != 0)
- ret = -1;
- } else {
+ if (tmp != 0)
ret = -1;
- }
- xmlRelaxNGFreeValidState(ctxt, state);
+
+ if (ctxt->states != NULL) {
+ tmp = -1;
+
+ ctxt->flags |= FLAGS_IGNORABLE;
+
+ for (i = 0; i < ctxt->states->nbState; i++) {
+ state = ctxt->states->tabState[i];
+ ctxt->state = state;
+ ctxt->state->seq = nseq;
+
+ if (xmlRelaxNGValidateElementEnd(ctxt) == 0)
+ tmp = 0;
+ xmlRelaxNGFreeValidState(ctxt, state);
+ }
+ xmlRelaxNGFreeStates(ctxt, ctxt->states);
+ ctxt->flags = oldflags;
+ ctxt->states = NULL;
+ if ((ret == 0) && (tmp == -1))
+ ret = -1;
+ } else {
+ state = ctxt->state;
+ ctxt->state->seq = nseq;
+ if (ret == 0)
+ ret = xmlRelaxNGValidateElementEnd(ctxt);
+ xmlRelaxNGFreeValidState(ctxt, state);
+ }
} else {
if (define->content != NULL) {
tmp = xmlRelaxNGValidateDefinitionList(ctxt,