another optimization, for choice this time cleanups. Daniel
* relaxng.c: another optimization, for choice this time
* result/relaxng/spec1* result/relaxng/tutor12_1*
result/relaxng/tutor3_7: cleanups.
Daniel
diff --git a/relaxng.c b/relaxng.c
index bd2b0d6..51330f0 100644
--- a/relaxng.c
+++ b/relaxng.c
@@ -131,6 +131,8 @@
#define IS_NOT_NULLABLE 2
#define IS_INDETERMINIST 4
#define IS_MIXED 8
+#define IS_TRIABLE 16
+#define IS_PROCESSED 32
struct _xmlRelaxNGDefine {
xmlRelaxNGType type; /* the type of definition */
@@ -146,7 +148,7 @@
xmlRelaxNGDefinePtr nameClass;/* the nameClass definition if any */
xmlRelaxNGDefinePtr nextHash;/* next define in defs/refs hash tables */
short depth; /* used for the cycle detection */
- short flags; /* define related flags */
+ short dflags; /* define related flags */
};
/**
@@ -780,6 +782,9 @@
if ((define->data != NULL) &&
(define->type == XML_RELAXNG_INTERLEAVE))
xmlRelaxNGFreePartition((xmlRelaxNGPartitionPtr) define->data);
+ if ((define->data != NULL) &&
+ (define->type == XML_RELAXNG_CHOICE))
+ xmlHashFree((xmlHashTablePtr) define->data, NULL);
if (define->name != NULL)
xmlFree(define->name);
if (define->ns != NULL)
@@ -1052,9 +1057,6 @@
}
}
ret->nbAttrLeft = ret->nbAttrs;
- if (ret->node == NULL) {
- printf("pbm!\n");
- }
return (ret);
}
@@ -1121,9 +1123,6 @@
}
memcpy(ret->attrs, state->attrs, state->nbAttrs * sizeof(xmlAttrPtr));
}
- if (ret->node == NULL) {
- printf("pbm!\n");
- }
return(ret);
}
@@ -2645,9 +2644,9 @@
if (define == NULL)
return(-1);
- if (define->flags & IS_NULLABLE)
+ if (define->dflags & IS_NULLABLE)
return(1);
- if (define->flags & IS_NOT_NULLABLE)
+ if (define->dflags & IS_NOT_NULLABLE)
return(0);
switch (define->type) {
case XML_RELAXNG_EMPTY:
@@ -2699,9 +2698,9 @@
}
done:
if (ret == 0)
- define->flags |= IS_NOT_NULLABLE;
+ define->dflags |= IS_NOT_NULLABLE;
if (ret == 1)
- define->flags |= IS_NULLABLE;
+ define->dflags |= IS_NULLABLE;
return(ret);
}
@@ -3286,11 +3285,16 @@
int nbchild = 0, i, j, ret;
int is_nullable = 0;
int is_indeterminist = 0;
+ xmlHashTablePtr triage = NULL;
+ int is_triable = 1;
if ((def == NULL) ||
(def->type != XML_RELAXNG_CHOICE))
return;
+ if (def->dflags & IS_PROCESSED)
+ return;
+
/*
* Don't run that check in case of error. Infinite recursion
* becomes possible.
@@ -3316,9 +3320,60 @@
return;
}
i = 0;
+ /*
+ * a bit strong but safe
+ */
+ if (is_nullable == 0) {
+ triage = xmlHashCreate(10);
+ } else {
+ is_triable = 0;
+ }
cur = def->content;
while (cur != NULL) {
list[i] = xmlRelaxNGGetElements(ctxt, cur, 0);
+ if ((list[i] == NULL) || (list[i][0] == NULL)) {
+ is_triable = 0;
+ } else if (is_triable == 1) {
+ xmlRelaxNGDefinePtr *tmp;
+ int res;
+
+ tmp = list[i];
+ while ((*tmp != NULL) && (is_triable == 1)) {
+ if ((*tmp)->type == XML_RELAXNG_TEXT) {
+ res = xmlHashAddEntry2(triage,
+ BAD_CAST "#text", NULL,
+ (void *)cur);
+ if (res != 0)
+ is_triable = -1;
+ } else if (((*tmp)->type == XML_RELAXNG_ELEMENT) &&
+ ((*tmp)->name != NULL)) {
+ if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
+ res = xmlHashAddEntry2(triage,
+ (*tmp)->name, NULL,
+ (void *)cur);
+ else
+ res = xmlHashAddEntry2(triage,
+ (*tmp)->name, (*tmp)->ns,
+ (void *)cur);
+ if (res != 0)
+ is_triable = -1;
+ } else if ((*tmp)->type == XML_RELAXNG_ELEMENT) {
+ if (((*tmp)->ns == NULL) || ((*tmp)->ns[0] == 0))
+ res = xmlHashAddEntry2(triage,
+ BAD_CAST "#any", NULL,
+ (void *)cur);
+ else
+ res = xmlHashAddEntry2(triage,
+ BAD_CAST "#any", (*tmp)->ns,
+ (void *)cur);
+ if (res != 0)
+ is_triable = -1;
+ } else {
+ is_triable = -1;
+ }
+ tmp++;
+ }
+ }
i++;
cur = cur->next;
}
@@ -3342,8 +3397,15 @@
xmlFree(list);
if (is_indeterminist) {
- def->flags |= IS_INDETERMINIST;
+ def->dflags |= IS_INDETERMINIST;
}
+ if (is_triable == 1) {
+ def->dflags |= IS_TRIABLE;
+ def->data = triage;
+ } else if (triage != NULL) {
+ xmlHashFree(triage, NULL);
+ }
+ def->dflags |= IS_PROCESSED;
}
/**
@@ -3365,6 +3427,9 @@
(def->type != XML_RELAXNG_ELEMENT)))
return;
+ if (def->dflags & IS_PROCESSED)
+ return;
+
/*
* Don't run that check in case of error. Infinite recursion
* becomes possible.
@@ -3427,6 +3492,7 @@
}
xmlFree(list);
+ def->dflags |= IS_PROCESSED;
}
/**
@@ -3584,7 +3650,7 @@
*/
def->data = partitions;
if (is_mixed != 0)
- def->flags |= IS_MIXED;
+ def->dflags |= IS_MIXED;
if (is_determinist == 1)
partitions->flags = IS_DETERMINIST;
if (is_determinist == 2)
@@ -7589,7 +7655,7 @@
* Optimizations for MIXED
*/
oldflags = ctxt->flags;
- if (define->flags & IS_MIXED) {
+ if (define->dflags & IS_MIXED) {
ctxt->flags |= FLAGS_MIXED_CONTENT;
if (nbgroups == 2) {
/*
@@ -8328,14 +8394,49 @@
break;
}
case XML_RELAXNG_CHOICE: {
- xmlRelaxNGDefinePtr list = define->content;
+ xmlRelaxNGDefinePtr list;
xmlRelaxNGStatesPtr states = NULL;
+ node = xmlRelaxNGSkipIgnored(ctxt, node);
+ if ((define->dflags & IS_TRIABLE) && (define->data != NULL)) {
+ xmlHashTablePtr triage = (xmlHashTablePtr) define->data;
+
+ /*
+ * Something we can optimize cleanly there is only one
+ * possble branch out !
+ */
+ if (node == NULL) {
+ ret = -1;
+ break;
+ }
+ if ((node->type == XML_TEXT_NODE) ||
+ (node->type == XML_CDATA_SECTION_NODE)) {
+ list = xmlHashLookup2(triage, BAD_CAST "#text", NULL);
+ } else if (node->type == XML_ELEMENT_NODE) {
+ if (node->ns != NULL) {
+ list = xmlHashLookup2(triage, node->name,
+ node->ns->href);
+ if (list == NULL)
+ list = xmlHashLookup2(triage, BAD_CAST "#any",
+ node->ns->href);
+ } else
+ list = xmlHashLookup2(triage, node->name, NULL);
+ if (list == NULL)
+ list = xmlHashLookup2(triage, BAD_CAST "#any", NULL);
+ }
+ if (list == NULL) {
+ ret = -1;
+ break;
+ }
+ ret = xmlRelaxNGValidateDefinition(ctxt, list);
+ break;
+ }
+
+ list = define->content;
oldflags = ctxt->flags;
errNr = ctxt->errNr;
ctxt->flags |= FLAGS_IGNORABLE;
- node = xmlRelaxNGSkipIgnored(ctxt, node);
while (list != NULL) {
oldstate = xmlRelaxNGCopyValidState(ctxt, ctxt->state);