Some changes/fixes to the streaming evaluation. A bit of support for
* pattern.c: Some changes/fixes to the streaming evaluation.
* xmlschemas.c: A bit of support for parsing the schema for
schema. Fixed attribute derivation when the use is
"prohibited" and was "optional". Fixed an attribute construction
bug, a left-over from the time, where <complexContent>,
<extension>, etc. where created as structs.
diff --git a/pattern.c b/pattern.c
index 7bd8bb0..292a2ca 100644
--- a/pattern.c
+++ b/pattern.c
@@ -38,7 +38,6 @@
#ifdef LIBXML_PATTERN_ENABLED
/* #define DEBUG_STREAMING */
-#define SUPPORT_IDC
#define ERROR(a, b, c, d)
#define ERROR5(a, b, c, d, e)
@@ -48,10 +47,18 @@
#define XML_STREAM_STEP_ROOT 4
#define XML_STREAM_STEP_ATTR 8
+/*
+* TODO: This is used on _xmlStreamCtxt, so don't use any values
+* from xmlPatternFlags.
+*/
+#define XML_STREAM_DESC 1<<16
+
#define XML_PATTERN_NOTPATTERN (XML_PATTERN_XPATH | \
XML_PATTERN_XSSEL | \
XML_PATTERN_XSFIELD)
-#define XML_PATTERN_XSD (XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD)
+
+#define XML_STREAM_XS_IDC(item) (item->flags & \
+ (XML_PATTERN_XSSEL | XML_PATTERN_XSFIELD))
typedef struct _xmlStreamStep xmlStreamStep;
typedef xmlStreamStep *xmlStreamStepPtr;
@@ -68,6 +75,7 @@
int nbStep; /* number of steps in the automata */
int maxStep; /* allocated number of steps */
xmlStreamStepPtr steps; /* the array of steps */
+ int flags;
};
struct _xmlStreamCtxt {
@@ -78,6 +86,7 @@
int level; /* how deep are we ? */
int *states; /* the array of step indexes */
int flags; /* validation options */
+ int blockLevel;
};
static void xmlFreeStreamComp(xmlStreamCompPtr comp);
@@ -879,6 +888,7 @@
if (name == NULL) {
if (CUR == '*') {
PUSH(XML_OP_ATTR, NULL, NULL);
+ NEXT;
} else {
ERROR(NULL, NULL, NULL,
"xmlCompileAttributeTest : Name expected\n");
@@ -1122,7 +1132,7 @@
static void
xmlCompilePathPattern(xmlPatParserContextPtr ctxt) {
SKIP_BLANKS;
- if (CUR == '/') {
+ if ((CUR == '/') && (NXT(1) != '/')) {
ctxt->comp->flags |= PAT_FROM_ROOT;
} else if ((CUR == '.') || (ctxt->comp->flags & XML_PATTERN_NOTPATTERN)) {
ctxt->comp->flags |= PAT_FROM_CUR;
@@ -1429,8 +1439,27 @@
break;
case XML_OP_ANCESTOR:
flags |= XML_STREAM_STEP_DESC;
+ /*
+ * Mark the expression as having "//".
+ */
+ if ((stream->flags & XML_STREAM_DESC) == 0)
+ stream->flags |= XML_STREAM_DESC;
break;
}
+ }
+ if ((! root) && (comp->flags & XML_PATTERN_NOTPATTERN) == 0) {
+ /*
+ * If this should behave like a real pattern, we will mark
+ * the first step as having "//", to be reentrant on every
+ * tree level.
+ */
+ if ((stream->flags & XML_STREAM_DESC) == 0)
+ stream->flags |= XML_STREAM_DESC;
+
+ if (stream->nbStep > 0) {
+ if ((stream->steps[0].flags & XML_STREAM_STEP_DESC) == 0)
+ stream->steps[0].flags |= XML_STREAM_STEP_DESC;
+ }
}
stream->steps[s].flags |= XML_STREAM_STEP_FINAL;
if (root)
@@ -1475,6 +1504,7 @@
cur->maxState = 4;
cur->level = 0;
cur->comp = stream;
+ cur->blockLevel = -1;
return(cur);
}
@@ -1568,6 +1598,7 @@
if ((name == NULL) && (ns == NULL)) {
stream->nbState = 0;
stream->level = 0;
+ stream->blockLevel = -1;
if (comp->steps[0].flags & XML_STREAM_STEP_ROOT) {
tmp = xmlStreamCtxtAddState(stream, 0, 0);
if (tmp < 0)
@@ -1596,47 +1627,68 @@
stream->level++;
goto stream_next;
}
- if ((stream->flags & XML_PATTERN_NOTPATTERN) != 0) {
- tmp = stream->level;
- for (i = 0; i < comp->nbStep; i++) {
- if (comp->steps[i].flags & XML_STREAM_STEP_DESC) {
- tmp = -2;
- break;
- }
- }
- if (comp->nbStep <= tmp) {
- stream->level++;
- goto stream_next;
- }
-
+ if (stream->blockLevel != -1) {
+ /*
+ * Skip blocked expressions.
+ */
+ stream->level++;
+ goto stream_next;
}
/*
* Check evolution of existing states
*/
+ i = 0;
m = stream->nbState;
- for (i = 0;i < m;i++) {
- match = 0;
- step = stream->states[2 * i];
- /* dead states */
- if (step < 0) continue;
- /* skip new states just added */
- if (stream->states[(2 * i) + 1] > stream->level)
- continue;
- /* skip continuations */
- desc = comp->steps[step].flags & XML_STREAM_STEP_DESC;
- if ((stream->states[(2 * i) + 1] < stream->level) && (!desc))
- continue;
+ while (i < m) {
+ if ((comp->flags & XML_STREAM_DESC) == 0) {
+ /*
+ * If there is no "//", then only the last
+ * added state is of interest.
+ */
+ step = stream->states[2 * (stream->nbState -1)];
+ /*
+ * TODO: Security check, should not happen, remove it.
+ */
+ if (stream->states[(2 * (stream->nbState -1)) + 1] <
+ stream->level) {
+ return (-1);
+ }
+ desc = 0;
+ /* loop-stopper */
+ i = m;
+ } else {
+ /*
+ * If there are "//", then we need to process every "//"
+ * occuring in the states, plus any other state for this
+ * level.
+ */
+ step = stream->states[2 * i];
- /* discard old states */
- /* something needed about old level discarded */
+ /* TODO: should not happen anymore: dead states */
+ if (step < 0)
+ goto next_state;
+ tmp = stream->states[(2 * i) + 1];
+
+ /* skip new states just added */
+ if (tmp > stream->level)
+ goto next_state;
+
+ /* skip states at ancestor levels, except if "//" */
+ desc = comp->steps[step].flags & XML_STREAM_STEP_DESC;
+ if ((tmp < stream->level) && (!desc))
+ goto next_state;
+ }
/*
* Check for correct node-type.
*/
- if ((comp->steps[step].flags & XML_STREAM_STEP_ATTR) &&
- (nodeType != XML_ATTRIBUTE_NODE))
- continue;
-
+ if ((nodeType == XML_ATTRIBUTE_NODE) &&
+ ((comp->steps[0].flags & XML_STREAM_STEP_ATTR) == 0))
+ goto next_state;
+ /*
+ * Compare local/namespace-name.
+ */
+ match = 0;
if (comp->dict) {
if (comp->steps[step].name == NULL) {
if (comp->steps[step].ns == NULL)
@@ -1677,76 +1729,105 @@
}
}
}
+ if (((comp->flags & XML_STREAM_DESC) == 0) &&
+ ((! match) || final)) {
+ /*
+ * Mark this expression as blocked for any evaluation at
+ * deeper levels. Note that this includes "/foo"
+ * expressions if the *pattern* behaviour is used.
+ */
+ stream->blockLevel = stream->level +1;
+ }
+next_state:
+ i++;
}
- /*
- * Check creating a new state.
- */
stream->level++;
-
+
/*
- * Check the start only if this is a "desc" evaluation
- * or if we are at the first level of evaluation.
+ * Re/enter the expression.
*/
+ if (comp->steps[0].flags & XML_STREAM_STEP_ROOT)
+ goto stream_next;
+
desc = comp->steps[0].flags & XML_STREAM_STEP_DESC;
- if ( ((comp->steps[0].flags & XML_STREAM_STEP_ROOT) == 0) &&
- ( ((stream->flags & XML_PATTERN_XSD) == 0) ||
- ( (desc || (stream->level == 1)) )
- )
- ) {
-
-/*
-#ifdef SUPPORT_IDC
-
-
- if ((desc || (stream->level == 1)) &&
- (!(comp->steps[0].flags & XML_STREAM_STEP_ROOT))) {
-
- *
- * Workaround for missing "self::node()" on "@foo".
- *
- if (comp->steps[0].flags & XML_STREAM_STEP_ATTR) {
- xmlStreamCtxtAddState(stream, 0, stream->level);
- goto stream_next;
- }
-#else
+ if (stream->flags & XML_PATTERN_NOTPATTERN) {
+ /*
+ * Re/enter the expression if it is a "descendant" one,
+ * or if we are at the 1st level of evaluation.
+ */
- if (!(comp->steps[0].flags & XML_STREAM_STEP_ROOT)) {
-#endif
- */
- if (comp->steps[0].name == NULL) {
- if (comp->steps[0].ns == NULL)
- match = 1;
- else {
- if (comp->dict)
- match = (comp->steps[0].ns == ns);
- else
- match = xmlStrEqual(comp->steps[0].ns, ns);
- }
- } else {
- if ((stream->flags & XML_PATTERN_XSD) && (!desc)) {
+ if (stream->level == 1) {
+ if (XML_STREAM_XS_IDC(stream)) {
/*
- * Workaround for missing "self::node() on "foo".
- */
- xmlStreamCtxtAddState(stream, 0, stream->level);
+ * XS-IDC: The missing "self::node()" will always
+ * match the first given node.
+ */
goto stream_next;
- } else {
- if (comp->dict) {
- match = ((comp->steps[0].name == name) &&
- (comp->steps[0].ns == ns));
- } else {
- match = ((xmlStrEqual(comp->steps[0].name, name)) &&
- (xmlStrEqual(comp->steps[0].ns, ns)));
- }
- }
- }
- if (match) {
- if (comp->steps[0].flags & XML_STREAM_STEP_FINAL)
- ret = 1;
- else
- xmlStreamCtxtAddState(stream, 1, stream->level);
- }
+ } else
+ goto compare;
+ }
+ /*
+ * A "//" is always reentrant.
+ */
+ if (desc)
+ goto compare;
+
+ /*
+ * XS-IDC: Process the 2nd level, since the missing
+ * "self::node()" is responsible for the 2nd level being
+ * the real start level.
+ */
+ if ((stream->level == 2) && XML_STREAM_XS_IDC(stream))
+ goto compare;
+
+ goto stream_next;
}
+
+compare:
+ /*
+ * Check expected node-type.
+ */
+ if ((nodeType == XML_ATTRIBUTE_NODE) &&
+ ((comp->steps[0].flags & XML_STREAM_STEP_ATTR) == 0))
+ goto stream_next;
+ /*
+ * Compare local/namespace-name.
+ */
+ match = 0;
+ if (comp->steps[0].name == NULL) {
+ if (comp->steps[0].ns == NULL)
+ match = 1;
+ else {
+ if (comp->dict)
+ match = (comp->steps[0].ns == ns);
+ else
+ match = xmlStrEqual(comp->steps[0].ns, ns);
+ }
+ } else {
+ if (comp->dict)
+ match = ((comp->steps[0].name == name) &&
+ (comp->steps[0].ns == ns));
+ else
+ match = ((xmlStrEqual(comp->steps[0].name, name)) &&
+ (xmlStrEqual(comp->steps[0].ns, ns)));
+ }
+ if (match) {
+ final = comp->steps[0].flags & XML_STREAM_STEP_FINAL;
+ if (final)
+ ret = 1;
+ else
+ xmlStreamCtxtAddState(stream, 1, stream->level);
+ }
+ if (((comp->flags & XML_STREAM_DESC) == 0) &&
+ ((! match) || final)) {
+ /*
+ * Mark this expression as blocked for any evaluation at
+ * deeper levels.
+ */
+ stream->blockLevel = stream->level;
+ }
+
stream_next:
stream = stream->next;
} /* while stream != NULL */
@@ -1811,26 +1892,32 @@
*/
int
xmlStreamPop(xmlStreamCtxtPtr stream) {
- int i, m;
+ int i, lev;
int ret;
if (stream == NULL)
return(-1);
ret = 0;
while (stream != NULL) {
+ /*
+ * Reset block-level.
+ */
+ if (stream->blockLevel == stream->level)
+ stream->blockLevel = -1;
+
stream->level--;
if (stream->level < 0)
- ret = -1;
-
+ ret = -1;
/*
* Check evolution of existing states
- */
- m = stream->nbState;
- for (i = 0;i < m;i++) {
- if (stream->states[(2 * i)] < 0) break;
+ */
+ for (i = stream->nbState -1; i >= 0; i--) {
/* discard obsoleted states */
- if (stream->states[(2 * i) + 1] > stream->level)
- stream->states[(2 * i)] = -1;
+ lev = stream->states[(2 * i) + 1];
+ if (lev > stream->level)
+ stream->nbState--;
+ if (lev <= stream->level)
+ break;
}
stream = stream->next;
}