Commit 9ca11bfc authored by Kasimier T. Buchcik's avatar Kasimier T. Buchcik
Browse files

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.
parent 9ea5565f
Tue Jun 14 21:19:16 CEST 2005 Kasimier Buchcik <libxml2-cvs@cazic.net>
* 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.
Tue Jun 14 12:35:12 CEST 2005 Daniel Veillard <daniel@veillard.com>
* libxml-2.0.pc.in: removed a redundant include path
......
......@@ -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 @@ struct _xmlStreamComp {
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 @@ struct _xmlStreamCtxt {
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 @@ xmlCompileAttributeTest(xmlPatParserContextPtr ctxt) {
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 @@ error:
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,9 +1439,28 @@ xmlStreamCompile(xmlPatternPtr comp) {
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)
stream->steps[0].flags |= XML_STREAM_STEP_ROOT;
......@@ -1475,6 +1504,7 @@ xmlNewStreamCtxt(xmlStreamCompPtr stream) {
cur->maxState = 4;
cur->level = 0;
cur->comp = stream;
cur->blockLevel = -1;
return(cur);
}
......@@ -1568,6 +1598,7 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream,
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 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream,
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) {
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;
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];
/* 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;
/* 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,43 +1729,72 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream,
}
}
}
}
if (((comp->flags & XML_STREAM_DESC) == 0) &&
((! match) || final)) {
/*
* Check creating a new state.
* 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++;
}
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.
*/
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)) )
)
) {
if (comp->steps[0].flags & XML_STREAM_STEP_ROOT)
goto stream_next;
/*
#ifdef SUPPORT_IDC
desc = comp->steps[0].flags & XML_STREAM_STEP_DESC;
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 (stream->level == 1) {
if (XML_STREAM_XS_IDC(stream)) {
/*
* XS-IDC: The missing "self::node()" will always
* match the first given node.
*/
goto stream_next;
} else
goto compare;
}
/*
* A "//" is always reentrant.
*/
if (desc)
goto compare;
if ((desc || (stream->level == 1)) &&
(!(comp->steps[0].flags & XML_STREAM_STEP_ROOT))) {
/*
* 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;
*
* 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 (!(comp->steps[0].flags & XML_STREAM_STEP_ROOT)) {
#endif
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;
......@@ -1724,29 +1805,29 @@ xmlStreamPushInternal(xmlStreamCtxtPtr stream,
match = xmlStrEqual(comp->steps[0].ns, ns);
}
} else {
if ((stream->flags & XML_PATTERN_XSD) && (!desc)) {
/*
* Workaround for missing "self::node() on "foo".
*/
xmlStreamCtxtAddState(stream, 0, stream->level);
goto stream_next;
} else {
if (comp->dict) {
if (comp->dict)
match = ((comp->steps[0].name == name) &&
(comp->steps[0].ns == ns));
} else {
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)
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 @@ xmlStreamPushAttr(xmlStreamCtxtPtr stream,
*/
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;
/*
* 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;
}
......
......@@ -256,6 +256,7 @@ struct _xmlSchemaParserCtxt {
int sizeLocalImports;
int nbLocalImports;
xmlHashTablePtr substGroups;
int isS4S;
};
#define XML_SCHEMAS_ATTR_UNKNOWN 1
......@@ -6914,10 +6915,10 @@ xmlSchemaCheckCSelectorXPath(xmlSchemaParserCtxtPtr ctxt,
*/
if (isField)
selector->xpathComp = (void *) xmlPatterncompile(selector->xpath,
NULL, 1, nsArray);
NULL, XML_PATTERN_XSFIELD, nsArray);
else
selector->xpathComp = (void *) xmlPatterncompile(selector->xpath,
NULL, 1, nsArray);
NULL, XML_PATTERN_XSSEL, nsArray);
if (nsArray != NULL)
xmlFree((xmlChar **) nsArray);
......@@ -8046,10 +8047,21 @@ xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
NULL, node,
"name", NULL);
return (NULL);
} else if (xmlSchemaPValAttrNode(ctxt,
} else {
if (xmlSchemaPValAttrNode(ctxt,
NULL, NULL, attr,
xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &attrValue) != 0) {
xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &attrValue) != 0)
return (NULL);
/*
* Skip built-in types.
*/
if (ctxt->isS4S) {
xmlSchemaTypePtr biType;
biType = xmlSchemaGetPredefinedType(attrValue, xmlSchemaNs);
if (biType != NULL)
return (biType);
}
}
}
......@@ -9020,7 +9032,7 @@ xmlSchemaParseForImpInc(xmlSchemaParserCtxtPtr pctxt,
xmlNodePtr node)
{
const xmlChar *oldURL, **oldLocImps, *oldTNS;
int oldFlags, oldNumLocImps, oldSizeLocImps;
int oldFlags, oldNumLocImps, oldSizeLocImps, oldIsS4S;
/*
* Save and reset the context & schema.
......@@ -9035,9 +9047,17 @@ xmlSchemaParseForImpInc(xmlSchemaParserCtxtPtr pctxt,
oldSizeLocImps = pctxt->sizeLocalImports;
pctxt->sizeLocalImports = 0;
oldFlags = schema->flags;
oldIsS4S = pctxt->isS4S;
xmlSchemaClearSchemaDefaults(schema);
oldTNS = schema->targetNamespace;
schema->targetNamespace = targetNamespace;
if ((targetNamespace != NULL) &&
xmlStrEqual(targetNamespace, xmlSchemaNs)) {
/*
* We are parsing the schema for schema!
*/
pctxt->isS4S = 1;
}
/*
* Parse the schema.
*/
......@@ -9054,6 +9074,7 @@ xmlSchemaParseForImpInc(xmlSchemaParserCtxtPtr pctxt,
pctxt->nbLocalImports = oldNumLocImps;
pctxt->sizeLocalImports = oldSizeLocImps;
pctxt->URL = oldURL;
pctxt->isS4S = oldIsS4S;
}
/**
......@@ -10568,15 +10589,13 @@ xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
return (NULL);
nberrors = ctxt->nberrors;
ctxt->nberrors = 0;
ctxt->isS4S = 0;
if (IS_SCHEMA(node, "schema")) {
xmlSchemaImportPtr import;
schema = xmlSchemaNewSchema(ctxt);
if (schema == NULL)
return (NULL);
/*
* Disable build of list of items.
*/
attr = xmlSchemaGetPropNode(node, "targetNamespace");
if (attr != NULL) {
xmlSchemaPValAttrNode(ctxt, NULL, NULL, attr,
......@@ -10585,6 +10604,12 @@ xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
* TODO: Should we proceed with an invalid target namespace?
*/
schema->targetNamespace = xmlDictLookup(ctxt->dict, val, -1);
if (xmlStrEqual(schema->targetNamespace, xmlSchemaNs)) {
/*
* We are parsing the schema for schema!
*/
ctxt->isS4S = 1;
}
} else {
schema->targetNamespace = NULL;
}
......@@ -12474,18 +12499,7 @@ xmlSchemaBuildAttributeValidation(xmlSchemaParserCtxtPtr pctxt,
}
}
}
if ((type->subtypes != NULL) &&
((type->subtypes->type == XML_SCHEMA_TYPE_COMPLEX_CONTENT) ||
(type->subtypes->type == XML_SCHEMA_TYPE_SIMPLE_CONTENT))) {
/*
* type --> (<simpleContent>|<complexContent>)
* --> (<restriction>|<extension>) --> attributes
*/
attrs = type->subtypes->subtypes->attributes;
} else {
/* Short hand form of the complexType. */
attrs = type->attributes;
}
/*
* Handle attribute wildcards.
*/
......@@ -12661,6 +12675,13 @@ xmlSchemaBuildAttributeValidation(xmlSchemaParserCtxtPtr pctxt,
found = 1;
if ((cur->attr->occurs ==
XML_SCHEMAS_ATTR_USE_PROHIBITED) &&
(base->attr->occurs ==
XML_SCHEMAS_ATTR_USE_OPTIONAL)) {
/*
* NOOP.
*/
} else if ((cur->attr->occurs ==
XML_SCHEMAS_ATTR_USE_OPTIONAL) &&
(base->attr->occurs ==
XML_SCHEMAS_ATTR_USE_REQUIRED)) {
......@@ -18085,7 +18106,7 @@ xmlSchemaAssembleByLocation(xmlSchemaValidCtxtPtr vctxt,
{
const xmlChar *targetNs, *oldtns;
xmlDocPtr doc, olddoc;
int oldflags, ret = 0;
int oldflags, ret = 0, oldIsS4S;
xmlNodePtr docElem;
xmlSchemaParserCtxtPtr pctxt;
......@@ -18137,9 +18158,17 @@ xmlSchemaAssembleByLocation(xmlSchemaValidCtxtPtr vctxt,
oldflags = schema->flags;
oldtns = schema->targetNamespace;
olddoc = schema->doc;
oldIsS4S = vctxt->pctxt->isS4S;
xmlSchemaClearSchemaDefaults(schema);
schema->targetNamespace = targetNs;
if ((targetNs != NULL) &&
xmlStrEqual(targetNs, xmlSchemaNs)) {
/*
* We are parsing the schema for schema!
*/
vctxt->pctxt->isS4S = 1;
}
/* schema->nbCurItems = 0; */
pctxt->schema = schema;
pctxt->ctxtType = NULL;
......@@ -18170,6 +18199,7 @@ finally:
/*
* Restore the context & schema.
*/
vctxt->pctxt->isS4S = oldIsS4S;
schema->flags = oldflags;
schema->targetNamespace = oldtns;
schema->doc = olddoc;
......@@ -18904,7 +18934,7 @@ xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt,
}
} else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) {
/*
* An IDC key node was found.
* An IDC key node was found by the IDC field.
*/
#if DEBUG_IDC
xmlGenericError(xmlGenericErrorContext,
......@@ -22770,10 +22800,10 @@ xmlSchemaValidateElem(xmlSchemaValidCtxtPtr vctxt)
vctxt->inode->localName,
vctxt->inode->nsName);
if (vctxt->inode->decl == NULL) {
VERROR(XML_SCHEMAV_CVC_ELT_1, NULL,
ret = XML_SCHEMAV_CVC_ELT_1;
VERROR(ret, NULL,
"No matching global declaration available "
"for the validation root");
ret = vctxt->err;
goto exit;
}
}
......@@ -22823,6 +22853,9 @@ xmlSchemaValidateElem(xmlSchemaValidCtxtPtr vctxt)
}
goto exit;
}
/*
* Validate against the type definition.
*/
type_validation:
if (vctxt->inode->typeDef == NULL) {
......@@ -22840,7 +22873,7 @@ type_validation:
goto exit;
}
/*
* Evaluate IDCs. Do it here, since new matchers are registered
* Evaluate IDCs. Do it here, since new IDC matchers are registered
* during validation against the declaration. This must be done
* _before_ attribute validation.
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment