summaryrefslogtreecommitdiff
path: root/xmlschemas.c
diff options
context:
space:
mode:
Diffstat (limited to 'xmlschemas.c')
-rw-r--r--xmlschemas.c242
1 files changed, 230 insertions, 12 deletions
diff --git a/xmlschemas.c b/xmlschemas.c
index 192cfe8..25f9400 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -183,6 +183,12 @@ static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt,
xmlSchemaPtr schema,
xmlNodePtr node);
+static int
+xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt,
+ xmlSchemaTypePtr type,
+ const xmlChar * value,
+ int fireErrors);
+
/************************************************************************
* *
* Datatype error handlers *
@@ -1492,7 +1498,7 @@ xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
if (val == NULL)
return (NULL);
- if (!strchr(val, ':')) {
+ if (!strchr((char *) val, ':')) {
ns = xmlSearchNs(node->doc, node, 0);
if (ns) {
*namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
@@ -1996,7 +2002,7 @@ static xmlSchemaAttributePtr
xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
xmlNodePtr node)
{
- const xmlChar *name, *refNs = NULL, *ref = NULL;
+ const xmlChar *name, *refNs = NULL, *ref = NULL, *attrVal;
xmlSchemaAttributePtr ret;
xmlNodePtr child = NULL;
char buf[100];
@@ -2025,6 +2031,23 @@ xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
if (ret == NULL) {
return (NULL);
}
+
+ /* Read the "use" attribute. */
+ attrVal = xmlSchemaGetProp(ctxt, node, "use");
+ if (attrVal != NULL) {
+ if (xmlStrEqual(attrVal, BAD_CAST "optional"))
+ ret->occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL;
+ else if (xmlStrEqual(attrVal, BAD_CAST "prohibited"))
+ ret->occurs = XML_SCHEMAS_ATTR_USE_PROHIBITED;
+ else if (xmlStrEqual(attrVal, BAD_CAST "required"))
+ ret->occurs = XML_SCHEMAS_ATTR_USE_REQUIRED;
+ else
+ xmlSchemaPErr(ctxt, node,
+ XML_SCHEMAP_INVALID_ATTR_USE,
+ "attribute %s has an invalid value for \"use\"\n", name, NULL);
+ } else
+ ret->occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL;
+
ret->ref = ref;
ret->refNs = refNs;
if ((ret->targetNamespace != NULL) &&
@@ -2279,7 +2302,7 @@ xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
if (type == NULL)
return (NULL);
type->node = node;
- type->type = XML_SCHEMA_TYPE_LIST;
+ type->type = XML_SCHEMA_TYPE_UNION;
type->id = xmlSchemaGetProp(ctxt, node, "id");
type->ref = xmlSchemaGetProp(ctxt, node, "memberTypes");
@@ -4358,6 +4381,58 @@ xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem,
}
}
+static void
+xmlSchemaParseUnionRefCheck(xmlSchemaTypePtr typeDecl,
+ xmlSchemaParserCtxtPtr ctxt)
+{
+ const xmlChar *cur, *end, *prefix, *ncName, *namespace;
+ xmlChar *tmp;
+ xmlSchemaTypePtr subtype;
+ xmlNsPtr ns;
+ int len;
+
+ if ((typeDecl->type != XML_SCHEMA_TYPE_UNION) || (typeDecl->ref == NULL))
+ return;
+
+ cur = typeDecl->ref;
+ do {
+ while (IS_BLANK_CH(*cur))
+ cur++;
+ end = cur;
+ while ((*end != 0) && (!(IS_BLANK_CH(*end))))
+ end++;
+ if (end == cur)
+ break;
+ tmp = xmlStrndup(cur, end - cur);
+ ncName = xmlSplitQName3(tmp, &len);
+ if (ncName != NULL) {
+ prefix = xmlDictLookup(ctxt->dict, tmp, len);
+ } else {
+ prefix = NULL;
+ ncName = tmp;
+ }
+ ns = xmlSearchNs(typeDecl->node->doc, typeDecl->node, prefix);
+ if (ns == NULL) {
+ xmlSchemaPErr(ctxt, typeDecl->node, XML_SCHEMAP_PREFIX_UNDEFINED,
+ "Union %s: the namespace of member type %s is undefined\n",
+ typeDecl->name, (const xmlChar *) tmp);
+ namespace = NULL;
+ } else {
+ namespace = xmlDictLookup(ctxt->dict, ns->href, -1);
+ }
+ /* Lookup the referenced type */
+ subtype = xmlSchemaGetType(ctxt->schema, ncName, namespace);
+ if (subtype == NULL) {
+ xmlSchemaPErr(ctxt, typeDecl->node, XML_SCHEMAP_UNKNOWN_MEMBER_TYPE,
+ "Union %s references an unknown member type >%s<\n",
+ typeDecl->name, (const xmlChar *) tmp);
+ }
+ xmlFree(tmp);
+ cur = end;
+ } while (*cur != 0);
+
+}
+
/**
* xmlSchemaTypeFixup:
* @typeDecl: the schema type definition
@@ -4473,7 +4548,16 @@ xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
typeDecl->base, name);
return;
}
+ if (typeDecl->recurse) {
+ xmlSchemaPErr(ctxt, typeDecl->node,
+ XML_SCHEMAP_UNKNOWN_BASE_TYPE,
+ "Schemas: extension type %s is recursive\n",
+ name, NULL);
+ return;
+ }
+ typeDecl->recurse = 1;
xmlSchemaTypeFixup(base, ctxt, NULL);
+ typeDecl->recurse = 0;
if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) {
/* 2.1 */
typeDecl->contentType = base->contentType;
@@ -4553,6 +4637,7 @@ xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl,
case XML_SCHEMA_TYPE_NOTATION:
case XML_SCHEMA_TYPE_LIST:
case XML_SCHEMA_TYPE_UNION:
+ xmlSchemaParseUnionRefCheck(typeDecl, ctxt);
case XML_SCHEMA_FACET_MININCLUSIVE:
case XML_SCHEMA_FACET_MINEXCLUSIVE:
case XML_SCHEMA_FACET_MAXINCLUSIVE:
@@ -5060,12 +5145,13 @@ xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
}
/**
- * xmlSchemaValidateFacets:
+ * xmlSchemaValidateFacetsInternal:
* @ctxt: a schema validation context
* @base: the base type
* @facets: the list of facets to check
* @value: the lexical repr of the value to validate
* @val: the precomputed value
+ * @fireErrors: if 0, only internal errors will be fired; otherwise all errors will be fired.
*
* Check a value against all facet conditions
*
@@ -5073,9 +5159,9 @@ xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
* number otherwise and -1 in case of internal or API error.
*/
static int
-xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
+xmlSchemaValidateFacetsInternal(xmlSchemaValidCtxtPtr ctxt,
xmlSchemaTypePtr base,
- xmlSchemaFacetPtr facets, const xmlChar * value)
+ xmlSchemaFacetPtr facets, const xmlChar * value, int fireErrors)
{
int ret = 0;
int tmp = 0;
@@ -5101,7 +5187,8 @@ xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
if (tmp != 0) {
ret = tmp;
- xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_FACET, "Failed to validate type with facet %s\n", (const xmlChar *) xmlSchemaFacetTypeToString(type), NULL);
+ if (fireErrors)
+ xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_FACET, "Failed to validate type with facet %s\n", (const xmlChar *) xmlSchemaFacetTypeToString(type), NULL);
}
if (facet != NULL)
facet = facet->next;
@@ -5109,6 +5196,27 @@ xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
return (ret);
}
+/**
+ * xmlSchemaValidateFacets:
+ * @ctxt: a schema validation context
+ * @base: the base type
+ * @facets: the list of facets to check
+ * @value: the lexical repr of the value to validate
+ * @val: the precomputed value
+ *
+ * Check a value against all facet conditions
+ *
+ * Returns 0 if the element is schemas valid, a positive error code
+ * number otherwise and -1 in case of internal or API error.
+ */
+static int
+xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
+ xmlSchemaTypePtr base,
+ xmlSchemaFacetPtr facets, const xmlChar * value)
+{
+ return(xmlSchemaValidateFacetsInternal(ctxt, base, facets, value, 1));
+}
+
/************************************************************************
* *
* Simple type validation *
@@ -5116,6 +5224,76 @@ xmlSchemaValidateFacets(xmlSchemaValidCtxtPtr ctxt,
************************************************************************/
/**
+ * xmlSchemaValidateSimpleValueUnion:
+ * @ctxt: a schema validation context
+ * @type: the type declaration
+ * @value: the value to validate
+ *
+ * Validates a value against a union.
+ *
+ * Returns 0 if the value is valid, a positive error code
+ * number otherwise and -1 in case of internal or API error.
+ */
+static int
+xmlSchemaValidateSimpleValueUnion(xmlSchemaValidCtxtPtr ctxt,
+ xmlSchemaTypePtr type, const xmlChar * value)
+{
+ int ret = 0;
+ const xmlChar *cur, *end, *prefix, *ncName;
+ xmlChar *tmp;
+ xmlSchemaTypePtr subtype;
+ xmlNsPtr ns;
+ int len;
+
+
+ /* Process referenced memberTypes. */
+ cur = type->ref;
+ do {
+ while (IS_BLANK_CH(*cur))
+ cur++;
+ end = cur;
+ while ((*end != 0) && (!(IS_BLANK_CH(*end))))
+ end++;
+ if (end == cur)
+ break;
+ tmp = xmlStrndup(cur, end - cur);
+ ncName = xmlSplitQName3(tmp, &len);
+ if (ncName != NULL) {
+ prefix = xmlStrndup(tmp, len);
+ /* prefix = xmlDictLookup(ctxt->doc->dict, tmp, len); */
+ } else {
+ prefix = NULL;
+ ncName = tmp;
+ }
+ /* We won't do additional checks here, since they have been performed during parsing. */
+ ns = xmlSearchNs(type->node->doc, type->node, prefix);
+ /* namespace = xmlDictLookup(ctxt->doc->dict, ns->href, -1); */
+ subtype = xmlSchemaGetType(ctxt->schema, ncName, ns->href);
+ if (tmp != NULL)
+ xmlFree(tmp);
+ if (prefix != NULL)
+ xmlFree((void *)prefix);
+ ret = xmlSchemaValidateSimpleValueInternal(ctxt, subtype, value, 0);
+ if ((ret == 0) || (ret == -1)) {
+ return (ret);
+ }
+ cur = end;
+ } while (*cur != 0);
+
+ if (type->subtypes != NULL) {
+ subtype = type->subtypes;
+ do {
+ ret = xmlSchemaValidateSimpleValueInternal(ctxt, subtype, value, 0);
+ if ((ret == 0) || (ret == -1)) {
+ return (ret);
+ }
+ subtype = subtype->next;
+ } while (subtype != NULL);
+ }
+ return (ret);
+}
+
+/**
* xmlSchemaValidateSimpleValue:
* @ctxt: a schema validation context
* @type: the type declaration
@@ -5130,6 +5308,25 @@ static int
xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
xmlSchemaTypePtr type, const xmlChar * value)
{
+ return (xmlSchemaValidateSimpleValueInternal(ctxt, type, value, 1));
+}
+
+/**
+ * xmlSchemaValidateSimpleValue:
+ * @ctxt: a schema validation context
+ * @type: the type declaration
+ * @value: the value to validate
+ * @fireErrors: if 0, only internal errors will be fired; otherwise all errors will be fired.
+ *
+ * Validate a value against a simple type
+ *
+ * Returns 0 if the value is valid, a positive error code
+ * number otherwise and -1 in case of internal or API error.
+ */
+static int
+xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt,
+ xmlSchemaTypePtr type, const xmlChar * value, int fireErrors)
+{
int ret = 0;
/*
@@ -5147,7 +5344,7 @@ xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
}
ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value),
ctxt->cur);
- if (ret != 0) {
+ if ((fireErrors) && (ret != 0)) {
xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_VALUE, "Failed to validate basic type %s\n", type->name, NULL);
}
} else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) {
@@ -5156,7 +5353,7 @@ xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
base = type->baseType;
if (base != NULL) {
- ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
+ ret = xmlSchemaValidateSimpleValueInternal(ctxt, base, value, fireErrors);
} else if (type->subtypes != NULL) {
TODO
}
@@ -5168,7 +5365,7 @@ xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
if (ctxt->schema != NULL) {
if (ret == 0) {
facet = type->facets;
- ret = xmlSchemaValidateFacets(ctxt, base, facet, value);
+ ret = xmlSchemaValidateFacetsInternal(ctxt, base, facet, value, fireErrors);
}
}
} else if (type->type == XML_SCHEMA_TYPE_SIMPLE) {
@@ -5176,7 +5373,7 @@ xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
base = type->subtypes;
if (base != NULL) {
- ret = xmlSchemaValidateSimpleValue(ctxt, base, value);
+ ret = xmlSchemaValidateSimpleValueInternal(ctxt, base, value, fireErrors);
} else {
TODO}
} else if (type->type == XML_SCHEMA_TYPE_LIST) {
@@ -5202,12 +5399,17 @@ xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt,
if (end == cur)
break;
tmp = xmlStrndup(cur, end - cur);
- ret2 = xmlSchemaValidateSimpleValue(ctxt, base, tmp);
+ ret2 = xmlSchemaValidateSimpleValueInternal(ctxt, base, tmp, fireErrors);
xmlFree(tmp);
if (ret2 != 0)
ret = 1;
cur = end;
} while (*cur != 0);
+ } else if (type->type == XML_SCHEMA_TYPE_UNION) {
+ ret = xmlSchemaValidateSimpleValueUnion(ctxt, type, value);
+ if ((fireErrors) && (ret != 0)) {
+ xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_VALUE, "Failed to validate type %s\n", type->name, NULL);
+ }
} else {
TODO
}
@@ -6045,10 +6247,12 @@ xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
xmlAttrPtr attr;
xmlChar *value;
xmlSchemaAttributeGroupPtr group = NULL;
+ int found;
if (attributes == NULL)
return (0);
while (attributes != NULL) {
+ found = 0;
/*
* Handle attribute groups
*/
@@ -6094,11 +6298,22 @@ xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
continue;
}
}
+ found = 1;
ctxt->cur = (xmlNodePtr) attributes;
+
if (attributes->subtypes == NULL) {
xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_INTERNAL, "Internal error: attribute %s type not resolved\n", attr->name, NULL);
continue;
}
+
+ if (attributes->occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED) {
+ xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_INVALIDATTR, "attribute %s on %s is prohibited\n", attributes->name, elem->name);
+ /* Setting the state to XML_SCHEMAS_ATTR_CHECKED seems not very logical but it
+ surpresses the "attribute is unknown" error report. Please change this if you know better */
+ ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED;
+ break;
+ }
+
value = xmlNodeListGetString(elem->doc, attr->children, 1);
ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes,
value);
@@ -6111,6 +6326,9 @@ xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem,
xmlFree(value);
}
}
+ if ((!found) && (attributes->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED)) {
+ xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_MISSING, "required attribute %s on %s is missing\n", attributes->name, elem->name);
+ }
attributes = attributes->next;
}
return (ctxt->err);