diff options
Diffstat (limited to 'xmlschemas.c')
-rw-r--r-- | xmlschemas.c | 242 |
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); |