diff options
author | Mike Hommey <mh@glandium.org> | 2004-07-06 12:57:17 +0000 |
---|---|---|
committer | Mike Hommey <mh@glandium.org> | 2004-07-06 12:57:17 +0000 |
commit | c14c53a3645d81281058d4bb4cff24fa8d6faf33 (patch) | |
tree | 29bccc2e7499af078a3d1cdcfb517a1dee891be5 /xmlschemas.c | |
parent | d4e028c96af89ade493b440d4f2de6b684c03a06 (diff) | |
download | libxml2-c14c53a3645d81281058d4bb4cff24fa8d6faf33.tar.gz |
Load /tmp/tmp.DIvcnD/libxml2-2.6.11 intoupstream/2.6.11
packages/libxml2/branches/upstream/current.
Diffstat (limited to 'xmlschemas.c')
-rw-r--r-- | xmlschemas.c | 5723 |
1 files changed, 4961 insertions, 762 deletions
diff --git a/xmlschemas.c b/xmlschemas.c index e9dfadb..59cfee0 100644 --- a/xmlschemas.c +++ b/xmlschemas.c @@ -12,6 +12,9 @@ * - when types are redefined in includes, check that all * types in the redef list are equal * -> need a type equality operation. + * - if we don't intend to use the schema for schemas, we + * need to validate all schema attributes (ref, type, name) + * against their types. */ #define IN_LIBXML #include "libxml.h" @@ -42,6 +45,8 @@ /* #define DEBUG_AUTOMATA 1 */ +/* #define DEBUG_ATTR_VALIDATION 1 */ + #define UNBOUNDED (1 << 30) #define TODO \ xmlGenericError(xmlGenericErrorContext, \ @@ -100,17 +105,25 @@ struct _xmlSchemaParserCtxt { xmlDictPtr dict; /* dictionnary for interned string names */ int includes; /* the inclusion level, 0 for root or imports */ + xmlSchemaTypePtr ctxtType; /* The current context simple/complex type */ + xmlSchemaTypePtr parentItem; /* The current parent schema item */ }; #define XML_SCHEMAS_ATTR_UNKNOWN 1 #define XML_SCHEMAS_ATTR_CHECKED 2 +#define XML_SCHEMAS_ATTR_PROHIBITED 3 +#define XML_SCHEMAS_ATTR_MISSING 4 +#define XML_SCHEMAS_ATTR_INVALID_VALUE 5 +#define XML_SCHEMAS_ATTR_TYPE_NOT_RESOLVED 6 typedef struct _xmlSchemaAttrState xmlSchemaAttrState; typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr; struct _xmlSchemaAttrState { + xmlSchemaAttrStatePtr next; xmlAttrPtr attr; int state; + xmlSchemaAttributePtr decl; }; /** @@ -143,9 +156,9 @@ struct _xmlSchemaValidCtxt { xmlRegExecCtxtPtr regexp; xmlSchemaValPtr value; - int attrNr; - int attrBase; - int attrMax; + xmlSchemaAttrStatePtr attrTop; + /* xmlSchemaAttrStatePtr attrBase; */ + /* int attrMax; */ xmlSchemaAttrStatePtr attr; }; @@ -176,18 +189,32 @@ struct _xmlSchemaInclude { * Some predeclarations * * * ************************************************************************/ +#if 0 /* Not currently used. */ static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt, xmlSchemaTypePtr type, const xmlChar * value); +#endif static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node); +#if 0 static int xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt, xmlSchemaTypePtr type, const xmlChar * value, int fireErrors); +#endif /* Not currently used. */ +static void +xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl, + xmlSchemaParserCtxtPtr ctxt, const xmlChar * name); +static const char * +xmlSchemaFacetTypeToString(xmlSchemaTypeType type); +static int +xmlSchemaValidateSimpleTypeValue(xmlSchemaValidCtxtPtr ctxt, + const xmlChar *value, + int fireErrors, + int applyFacets); /************************************************************************ * * @@ -266,6 +293,50 @@ xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, xmlSchemaPErr(ctxt, node, error, msg, str1, str2); } + +/** + * xmlSchemaPErrExt: + * @ctxt: the parsing context + * @node: the context node + * @error: the error code + * @strData1: extra data + * @strData2: extra data + * @strData3: extra data + * @msg: the message + * @str1: extra parameter for the message display + * @str2: extra parameter for the message display + * @str3: extra parameter for the message display + * @str4: extra parameter for the message display + * @str5: extra parameter for the message display + * + * Handle a parser error + */ +static void +xmlSchemaPErrExt(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error, + const xmlChar * strData1, const xmlChar * strData2, + const xmlChar * strData3, const char *msg, const xmlChar * str1, + const xmlChar * str2, const xmlChar * str3, const xmlChar * str4, + const xmlChar * str5) +{ + + xmlGenericErrorFunc channel = NULL; + xmlStructuredErrorFunc schannel = NULL; + void *data = NULL; + + if (ctxt != NULL) { + ctxt->nberrors++; + channel = ctxt->error; + data = ctxt->userData; + schannel = ctxt->serror; + } + __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, + error, XML_ERR_ERROR, NULL, 0, + (const char *) strData1, (const char *) strData2, + (const char *) strData3, 0, 0, msg, str1, str2, + str3, str4, str5); +} + + /** * xmlSchemaVTypeErrMemory: * @node: a context node @@ -524,6 +595,44 @@ xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr) } /** + * xmlSchemaFreeWildcardNsSet: + * set: a schema wildcard namespace + * + * Deallocates a list of wildcard constraint structures. + */ +static void +xmlSchemaFreeWildcardNsSet(xmlSchemaWildcardNsPtr set) +{ + xmlSchemaWildcardNsPtr next; + + while (set != NULL) { + next = set->next; + xmlFree(set); + set = next; + } +} + +/** + * xmlSchemaFreeWildcard: + * @wildcard: a wildcard structure + * + * Deallocates a wildcard structure. + */ +void +xmlSchemaFreeWildcard(xmlSchemaWildcardPtr wildcard) +{ + if (wildcard == NULL) + return; + if (wildcard->annot != NULL) + xmlSchemaFreeAnnot(wildcard->annot); + if (wildcard->nsSet != NULL) + xmlSchemaFreeWildcardNsSet(wildcard->nsSet); + if (wildcard->negNsSet != NULL) + xmlFree(wildcard->negNsSet); + xmlFree(wildcard); +} + +/** * xmlSchemaFreeAttributeGroup: * @schema: a schema attribute group structure * @@ -534,10 +643,52 @@ xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr) { if (attr == NULL) return; + if (attr->annot != NULL) + xmlSchemaFreeAnnot(attr->annot); + if ((attr->flags & XML_SCHEMAS_ATTRGROUP_GLOBAL) && + (attr->attributeWildcard != NULL)) + xmlSchemaFreeWildcard(attr->attributeWildcard); + xmlFree(attr); } /** + * xmlSchemaFreeAttributeUseList: + * @attrUse: an attribute link + * + * Deallocate a list of schema attribute uses. + */ +static void +xmlSchemaFreeAttributeUseList(xmlSchemaAttributeLinkPtr attrUse) +{ + xmlSchemaAttributeLinkPtr next; + + while (attrUse != NULL) { + next = attrUse->next; + xmlFree(attrUse); + attrUse = next; + } +} + +/** + * xmlSchemaFreeTypeLinkList: + * @alink: a type link + * + * Deallocate a list of types. + */ +static void +xmlSchemaFreeTypeLinkList(xmlSchemaTypeLinkPtr link) +{ + xmlSchemaTypeLinkPtr next; + + while (link != NULL) { + next = link->next; + xmlFree(link); + link = next; + } +} + +/** * xmlSchemaFreeElement: * @schema: a schema element structure * @@ -598,6 +749,29 @@ xmlSchemaFreeType(xmlSchemaTypePtr type) facet = next; } } + if (type->type != XML_SCHEMA_TYPE_BASIC) { + if (type->attributeUses != NULL) + xmlSchemaFreeAttributeUseList(type->attributeUses); + /* TODO: There must be a way more simple than this. */ + if ((type->attributeWildcard != NULL) && + ((type->type != XML_SCHEMA_TYPE_COMPLEX) || + ((type->type == XML_SCHEMA_TYPE_COMPLEX) && + (type->flags & XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD)))) { + xmlSchemaFreeWildcard(type->attributeWildcard); + } + } + if (type->memberTypes != NULL) + xmlSchemaFreeTypeLinkList(type->memberTypes); + if (type->facetSet != NULL) { + xmlSchemaFacetLinkPtr next, link; + + link = type->facetSet; + do { + next = link->next; + xmlFree(link); + link = next; + } while (link != NULL); + } xmlFree(type); } @@ -689,16 +863,14 @@ xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output, return; fprintf(output, "Element "); - if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL) - fprintf(output, "toplevel "); + if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL) + fprintf(output, "global "); fprintf(output, ": %s ", elem->name); if (namespace != NULL) fprintf(output, "namespace '%s' ", namespace); if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE) fprintf(output, "nillable "); - if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL) - fprintf(output, "global "); if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT) fprintf(output, "default "); if (elem->flags & XML_SCHEMAS_ELEM_FIXED) @@ -830,7 +1002,7 @@ xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output) fprintf(output, "mixed "); break; case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS: - fprintf(output, "mixed_or_elems "); + /* not used. */ break; case XML_SCHEMA_CONTENT_BASIC: fprintf(output, "basic "); @@ -909,6 +1081,36 @@ xmlSchemaDump(FILE * output, xmlSchemaPtr schema) * * ************************************************************************/ +static xmlAttrPtr +xmlSchemaGetPropNode(xmlNodePtr node, const xmlChar *name) +{ + xmlAttrPtr prop; + + if ((node == NULL) || (name == NULL)) return(NULL); + prop = node->properties; + while (prop != NULL) { + if ((xmlStrEqual(prop->name, name)) && + (prop->ns == NULL)) + return(prop); + prop = prop->next; + } + return (NULL); +} + +static const xmlChar * +xmlSchemaGetNodeContent(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) +{ + xmlChar *val; + const xmlChar *ret; + + val = xmlNodeGetContent(node); + if (val == NULL) + return(NULL); + ret = xmlDictLookup(ctxt->dict, val, -1); + xmlFree(val); + return(ret); +} + /** * xmlSchemaGetProp: * @ctxt: the parser context @@ -1040,12 +1242,13 @@ xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name, if ((name == NULL) || (schema == NULL)) return (NULL); - if (namespace == NULL) { + ret = xmlHashLookup2(schema->elemDecl, name, namespace); if ((ret != NULL) && - ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) { + ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_GLOBAL))) { return (ret); - } + } else + ret = NULL; /* * This one was removed, since top level element declarations have * the target namespace specified in targetNamespace of the <schema> @@ -1062,17 +1265,19 @@ xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name, return (ret); } */ - } else { - ret = xmlHashLookup2(schema->elemDecl, name, namespace); - if ((ret != NULL) && - ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) { - return (ret); - } - } - if (level > 0) + + /* if (level > 0) */ + if (namespace == NULL) + import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_DEFAULT_NAMESPACE); + else import = xmlHashLookup(schema->schemasImports, namespace); - if (import != NULL) + if (import != NULL) { ret = xmlSchemaGetElem(import->schema, name, namespace, level + 1); + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_ELEM_GLOBAL)) { + return (ret); + } else + ret = NULL; + } #ifdef DEBUG if (ret == NULL) { if (namespace == NULL) @@ -1106,15 +1311,23 @@ xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name, return (NULL); if (schema != NULL) { ret = xmlHashLookup2(schema->typeDecl, name, namespace); - if (ret != NULL) + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_TYPE_GLOBAL)) return (ret); } ret = xmlSchemaGetPredefinedType(name, namespace); if (ret != NULL) return (ret); + if (namespace == NULL) + import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_DEFAULT_NAMESPACE); + else import = xmlHashLookup(schema->schemasImports, namespace); - if (import != NULL) + if (import != NULL) { ret = xmlSchemaGetType(import->schema, name, namespace); + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_TYPE_GLOBAL)) { + return (ret); + } else + ret = NULL; + } #ifdef DEBUG if (ret == NULL) { if (namespace == NULL) @@ -1127,6 +1340,153 @@ xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name, return (ret); } +/** + * xmlSchemaGetAttribute: + * @schema: the context of the schema + * @name: the name of the attribute + * @ns: the target namespace of the attribute + * + * Lookup a an attribute in the schema or imported schemas + * + * Returns the attribute declaration or NULL if not found. + */ +static xmlSchemaAttributePtr +xmlSchemaGetAttribute(xmlSchemaPtr schema, const xmlChar * name, + const xmlChar * namespace) +{ + xmlSchemaAttributePtr ret; + xmlSchemaImportPtr import = NULL; + + if ((name == NULL) || (schema == NULL)) + return (NULL); + + + ret = xmlHashLookup2(schema->attrDecl, name, namespace); + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_ATTR_GLOBAL)) + return (ret); + else + ret = NULL; + if (namespace == NULL) + import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_DEFAULT_NAMESPACE); + else + import = xmlHashLookup(schema->schemasImports, namespace); + if (import != NULL) { + ret = xmlSchemaGetAttribute(import->schema, name, namespace); + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_ATTR_GLOBAL)) { + return (ret); + } else + ret = NULL; + } +#ifdef DEBUG + if (ret == NULL) { + if (namespace == NULL) + fprintf(stderr, "Unable to lookup attribute %s", name); + else + fprintf(stderr, "Unable to lookup attribute %s:%s", name, + namespace); + } +#endif + return (ret); +} + +/** + * xmlSchemaGetAttributeGroup: + * @schema: the context of the schema + * @name: the name of the attribute group + * @ns: the target namespace of the attribute group + * + * Lookup a an attribute group in the schema or imported schemas + * + * Returns the attribute group definition or NULL if not found. + */ +static xmlSchemaAttributeGroupPtr +xmlSchemaGetAttributeGroup(xmlSchemaPtr schema, const xmlChar * name, + const xmlChar * namespace) +{ + xmlSchemaAttributeGroupPtr ret; + xmlSchemaImportPtr import = NULL; + + if ((name == NULL) || (schema == NULL)) + return (NULL); + + + ret = xmlHashLookup2(schema->attrgrpDecl, name, namespace); + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_ATTRGROUP_GLOBAL)) + return (ret); + else + ret = NULL; + if (namespace == NULL) + import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_DEFAULT_NAMESPACE); + else + import = xmlHashLookup(schema->schemasImports, namespace); + if (import != NULL) { + ret = xmlSchemaGetAttributeGroup(import->schema, name, namespace); + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_ATTRGROUP_GLOBAL)) + return (ret); + else + ret = NULL; + } +#ifdef DEBUG + if (ret == NULL) { + if (namespace == NULL) + fprintf(stderr, "Unable to lookup attribute group %s", name); + else + fprintf(stderr, "Unable to lookup attribute group %s:%s", name, + namespace); + } +#endif + return (ret); +} + +/** + * xmlSchemaGetGroup: + * @schema: the context of the schema + * @name: the name of the group + * @ns: the target namespace of the group + * + * Lookup a group in the schema or imported schemas + * + * Returns the group definition or NULL if not found. + */ +static xmlSchemaTypePtr +xmlSchemaGetGroup(xmlSchemaPtr schema, const xmlChar * name, + const xmlChar * namespace) +{ + xmlSchemaTypePtr ret; + xmlSchemaImportPtr import = NULL; + + if ((name == NULL) || (schema == NULL)) + return (NULL); + + + ret = xmlHashLookup2(schema->groupDecl, name, namespace); + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_TYPE_GLOBAL)) + return (ret); + else + ret = NULL; + if (namespace == NULL) + import = xmlHashLookup(schema->schemasImports, XML_SCHEMAS_DEFAULT_NAMESPACE); + else + import = xmlHashLookup(schema->schemasImports, namespace); + if (import != NULL) { + ret = xmlSchemaGetGroup(import->schema, name, namespace); + if ((ret != NULL) && (ret->flags & XML_SCHEMAS_TYPE_GLOBAL)) + return (ret); + else + ret = NULL; + } +#ifdef DEBUG + if (ret == NULL) { + if (namespace == NULL) + fprintf(stderr, "Unable to lookup group %s", name); + else + fprintf(stderr, "Unable to lookup group %s:%s", name, + namespace); + } +#endif + return (ret); +} + /************************************************************************ * * * Parsing functions * @@ -1368,12 +1728,12 @@ xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, /** * xmlSchemaAddType: - * @ctxt: a schema validation context + * @ctxt: a schema parser context * @schema: the schema being built * @name: the item name * @namespace: the namespace * - * Add an XML schema Simple Type definition + * Add an XML schema item * *WARNING* this interface is highly subject to change * * Returns the new struture or NULL in case of error @@ -1434,6 +1794,8 @@ xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, } ret->minOccurs = 1; ret->maxOccurs = 1; + ret->attributeUses = NULL; + ret->attributeWildcard = NULL; return (ret); } @@ -1487,6 +1849,60 @@ xmlSchemaAddGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, return (ret); } +/** + * xmlSchemaNewWildcardNs: + * @ctxt: a schema validation context + * + * Creates a new wildcard namespace constraint. + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaWildcardNsPtr +xmlSchemaNewWildcardNsConstraint(xmlSchemaParserCtxtPtr ctxt) +{ + xmlSchemaWildcardNsPtr ret; + + ret = (xmlSchemaWildcardNsPtr) + xmlMalloc(sizeof(xmlSchemaWildcardNs)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "creating wildcard namespace constraint", NULL); + return (NULL); + } + ret->value = NULL; + ret->next = NULL; + return (ret); +} + +/** + * xmlSchemaAddWildcard: + * @ctxt: a schema validation context + * @schema: the schema being built + * @name: the group name + * + * Add an XML schema Group definition + * + * Returns the new struture or NULL in case of error + */ +static xmlSchemaWildcardPtr +xmlSchemaAddWildcard(xmlSchemaParserCtxtPtr ctxt) +{ + xmlSchemaWildcardPtr ret = NULL; + + if (ctxt == NULL) + return (NULL); + + ret = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); + if (ret == NULL) { + xmlSchemaPErrMemory(ctxt, "adding wildcard", NULL); + return (NULL); + } + memset(ret, 0, sizeof(xmlSchemaWildcard)); + ret->minOccurs = 1; + ret->maxOccurs = 1; + + return (ret); +} + /************************************************************************ * * * Utilities for parsing * @@ -1536,7 +1952,7 @@ xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, ns = xmlSearchNs(node->doc, node, prefix); if (ns == NULL) { xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED, - "Attribute %s: the QName prefix %s is undefined\n", + "Attribute \"%s\": the QName prefix \"%s\" is undefined\n", (const xmlChar *) name, prefix); } else { *namespace = xmlDictLookup(ctxt->dict, ns->href, -1); @@ -1661,16 +2077,17 @@ xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, ************************************************************************/ static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, - xmlNodePtr node); + xmlNodePtr node, + int topLevel); static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, - xmlNodePtr node); + xmlNodePtr node, + int topLevel); static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, - xmlNodePtr node, - int simple); + xmlNodePtr node); static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node); @@ -1684,18 +2101,113 @@ static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr int topLevel); static xmlSchemaAttributeGroupPtr xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, - xmlSchemaPtr schema, xmlNodePtr node); + xmlSchemaPtr schema, xmlNodePtr node, + int topLevel); static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node); static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node); -static xmlSchemaAttributePtr +static xmlSchemaWildcardPtr xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node); /** + * xmlSchemaParseSchemaAttrValue: + * + * @ctxt: a schema parser context + * @attr: the schema attribute being validated + * @type: the built-in type to be validated against + * @value: the value to be validated + * + * Validates a value against the given built-in type. + * This one is intended to be used internally for validation + * of schema attribute values during parsing of the schema. + * + * Returns 0 if the value is valid, a positive error code + * number otherwise and -1 in case of an internal or API error. + */ +static int +xmlSchemaParseSchemaAttrValue(xmlSchemaParserCtxtPtr ctxt, + xmlAttrPtr attr, + xmlSchemaTypePtr type) +{ + const xmlChar *value; + int ret; + + if ((ctxt == NULL) || (type == NULL) || (attr == NULL)) + return (-1); + value = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr); + switch (type->builtInType) { + case XML_SCHEMAS_NCNAME: + ret = xmlValidateNCName(value, 1); + break; + case XML_SCHEMAS_QNAME: + ret = xmlValidateQName(value, 1); + if ((ret == 0) && (attr != NULL)) { + xmlChar *local = NULL; + xmlChar *prefix; + + local = xmlSplitQName2(value, &prefix); + if (prefix != NULL) { + xmlNsPtr ns; + + ns = xmlSearchNs(attr->doc, (xmlNodePtr) attr, prefix); + if (ns == NULL) { + xmlSchemaPErr(ctxt, (xmlNodePtr) attr, + XML_SCHEMAP_PREFIX_UNDEFINED, + "Attribute \"%s\": the QName prefix " + "\"%s\" is undefined.\n", + attr->name, prefix); + ret = 1; + } + } + if (local != NULL) + xmlFree(local); + if (prefix != NULL) + xmlFree(prefix); + } + break; + default: { + xmlSchemaPErr(ctxt, (xmlNodePtr) attr, + XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaParseSchemaAttrValue, validation " + "using this type in not implemented yet\"%s\".\n", + type->name, NULL); + return (-1); + } + } + if (ret > 0) { + if (type->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) { + xmlSchemaPErrExt(ctxt, (xmlNodePtr) attr, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2, + NULL, NULL, NULL, + "The schema attribute \"%s\" with the value \"%s\" is not " + "of built-in list simple type \"%s\".\n", + attr->name, value, type->name, NULL, NULL); + } else { + if (type->flags & XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE) { + xmlSchemaPErrExt(ctxt, (xmlNodePtr) attr, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, + NULL, NULL, NULL, + "The schema attribute \"%s\" with the value \"%s\" is not " + "of built-in primitive type \"%s\".\n", + attr->name, value, type->name, NULL, NULL); + } else { + xmlSchemaPErrExt(ctxt, (xmlNodePtr) attr, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, + NULL, NULL, NULL, + "The schema attribute \"%s\" with the value \"%s\" is not " + "of built-in atomic simple type \"%s\".\n", + attr->name, value, type->name, NULL, NULL); + } + } + } + return (ret); +} + +/** * xmlSchemaParseAttrDecls: * @ctxt: a schema validation context * @schema: the schema being built @@ -1720,10 +2232,13 @@ xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, attr = xmlSchemaParseAttribute(ctxt, schema, child, 0); } else if (IS_SCHEMA(child, "attributeGroup")) { attr = (xmlSchemaAttributePtr) - xmlSchemaParseAttributeGroup(ctxt, schema, child); + xmlSchemaParseAttributeGroup(ctxt, schema, child, 0); } if (attr != NULL) { if (lastattr == NULL) { + if (type->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) + ((xmlSchemaAttributeGroupPtr) type)->attributes = attr; + else type->attributes = attr; lastattr = attr; } else { @@ -1734,15 +2249,14 @@ xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, child = child->next; } if (IS_SCHEMA(child, "anyAttribute")) { - attr = xmlSchemaParseAnyAttribute(ctxt, schema, child); - if (attr != NULL) { - if (lastattr == NULL) { - type->attributes = attr; - lastattr = attr; - } else { - lastattr->next = attr; - lastattr = attr; - } + xmlSchemaWildcardPtr wildcard; + + wildcard = xmlSchemaParseAnyAttribute(ctxt, schema, child); + if (wildcard != NULL) { + if (type->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) + ((xmlSchemaAttributeGroupPtr) type)->attributeWildcard = wildcard; + else + type->attributeWildcard = wildcard; } child = child->next; } @@ -1841,6 +2355,17 @@ xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, } facet->id = xmlSchemaGetProp(ctxt, node, "id"); facet->value = value; + if ((facet->type != XML_SCHEMA_FACET_PATTERN) && + (facet->type != XML_SCHEMA_FACET_ENUMERATION)) { + const xmlChar *fixed; + + fixed = xmlSchemaGetProp(ctxt, node, "fixed"); + if (fixed != NULL) { + if (xmlStrEqual(fixed, BAD_CAST "true")) + facet->fixed = 1; + } + } + child = node->children; if (IS_SCHEMA(child, "annotation")) { @@ -1955,28 +2480,20 @@ xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, * * Returns an attribute def structure or NULL */ -static xmlSchemaAttributePtr +static xmlSchemaWildcardPtr xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node) { - const xmlChar *processContents; - xmlSchemaAttributePtr ret; + const xmlChar *processContents, *nsConstraint, *end, *cur, *dictMember; + xmlChar *member; + xmlSchemaWildcardPtr ret; + xmlSchemaWildcardNsPtr tmp, lastNs = NULL; xmlNodePtr child = NULL; - char name[100]; - if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return (NULL); - snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1); - - /* local = xmlSchemaGetNamespace(ctxt, schema, node, BAD_CAST "anyattr", &ns); */ - - /* - * TODO: namespace = ((##any | ##other) | List of (anyURI | - * (##targetNamespace | * ##local)) ) : ##any - */ - ret = xmlSchemaAddAttribute(ctxt, schema, BAD_CAST name, NULL); + ret = xmlSchemaAddWildcard(ctxt); if (ret == NULL) { return (NULL); } @@ -1985,18 +2502,88 @@ xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, processContents = xmlSchemaGetProp(ctxt, node, "processContents"); if ((processContents == NULL) || (xmlStrEqual(processContents, (const xmlChar *) "strict"))) { - ret->occurs = XML_SCHEMAS_ANYATTR_STRICT; + ret->processContents = XML_SCHEMAS_ANY_STRICT; } else if (xmlStrEqual(processContents, (const xmlChar *) "skip")) { - ret->occurs = XML_SCHEMAS_ANYATTR_SKIP; + ret->processContents = XML_SCHEMAS_ANY_SKIP; } else if (xmlStrEqual(processContents, (const xmlChar *) "lax")) { - ret->occurs = XML_SCHEMAS_ANYATTR_LAX; + ret->processContents = XML_SCHEMAS_ANY_LAX; } else { - xmlSchemaPErr2(ctxt, node, child, + xmlSchemaPErr(ctxt, node, XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD, "anyAttribute has unexpected content " "for processContents: %s\n", processContents, NULL); - ret->occurs = XML_SCHEMAS_ANYATTR_STRICT; + ret->processContents = XML_SCHEMAS_ANY_STRICT; + } + /* + * Build the namespace constraints. + */ + nsConstraint = xmlSchemaGetProp(ctxt, node, "namespace"); + if ((nsConstraint == NULL) || (xmlStrEqual(nsConstraint, BAD_CAST "##any"))) + ret->any = 1; + else if (xmlStrEqual(nsConstraint, BAD_CAST "##other")) { + ret->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (ret->negNsSet == NULL) { + xmlSchemaFreeWildcard(ret); + return (NULL); + } + ret->negNsSet->value = schema->targetNamespace; + } else { + cur = nsConstraint; + do { + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) + break; + member = xmlStrndup(cur, end - cur); + if ((xmlStrEqual(member, BAD_CAST "##other")) || + (xmlStrEqual(member, BAD_CAST "##any"))) { + xmlSchemaPErr(ctxt, ret->node, XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER, + "The namespace constraint of an anyAttribute " + "is a set and must not contain \"%s\"\n", + member, NULL); + } else { + /* + * TODO: Validate the value (anyURI). + */ + if (xmlStrEqual(member, BAD_CAST "##targetNamespace")) { + dictMember = schema->targetNamespace; + } else if (xmlStrEqual(member, BAD_CAST "##local")) { + dictMember = NULL; + } else + dictMember = xmlDictLookup(ctxt->dict, member, -1); + /* + * Avoid dublicate namespaces. + */ + tmp = ret->nsSet; + while (tmp != NULL) { + if (dictMember == tmp->value) + break; + tmp = tmp->next; + } + if (tmp == NULL) { + tmp = xmlSchemaNewWildcardNsConstraint(ctxt); + if (tmp == NULL) { + xmlFree(member); + xmlSchemaFreeWildcard(ret); + return (NULL); + } + tmp->value = dictMember; + tmp->next = NULL; + if (ret->nsSet == NULL) + ret->nsSet = tmp; + else + lastNs->next = tmp; + lastNs = tmp; + } + + } + xmlFree(member); + cur = end; + } while (*cur != 0); } child = node->children; @@ -2007,8 +2594,8 @@ xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, if (child != NULL) { xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD, - "anyAttribute %s has unexpected content\n", - (const xmlChar *) name, NULL); + "anyAttribute has unexpected content\n", + NULL, NULL); } return (ret); @@ -2093,8 +2680,8 @@ xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, if ((!topLevel) && (xmlSchemaGetProp(ctxt, node, "ref") != NULL)) { xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_ATTR_COMBINATION, - "Attribute declaration has both, \"name\" and " - "\"ref\"\n", NULL, NULL); + "Attribute declaration \"%s\" has both, \"name\" and " + "\"ref\"\n", name, NULL); } /* local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); */ @@ -2112,7 +2699,8 @@ xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, } } ret = xmlSchemaAddAttribute(ctxt, schema, name, ns); - + if (ret == NULL) + return (NULL); /* 3.2.6 Schema Component Constraint: xmlns Not Allowed */ if (xmlStrEqual(name, BAD_CAST "xmlns")) { xmlSchemaPErr(ctxt, node, @@ -2134,6 +2722,8 @@ xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, return (NULL); } ret->type = XML_SCHEMA_TYPE_ATTRIBUTE; + if (topLevel) + ret->flags |= XML_SCHEMAS_ATTR_GLOBAL; /* Handle the "use" attribute. */ attrVal = xmlSchemaGetProp(ctxt, node, "use"); @@ -2210,7 +2800,7 @@ xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, "Attribute declaration %s has both (\"ref\" or " "\"type\") and <simpleType>\n", name, NULL); } else - ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child); + ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child, 0); child = child->next; } if (child != NULL) { @@ -2235,11 +2825,11 @@ xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, */ static xmlSchemaAttributeGroupPtr xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, - xmlSchemaPtr schema, xmlNodePtr node) + xmlSchemaPtr schema, xmlNodePtr node, + int topLevel) { const xmlChar *name, *refNs = NULL, *ref = NULL; xmlSchemaAttributeGroupPtr ret; - xmlSchemaAttributePtr last = NULL, attr; xmlNodePtr child = NULL; const xmlChar *oldcontainer; char buf[100]; @@ -2249,7 +2839,6 @@ xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, oldcontainer = ctxt->container; name = xmlSchemaGetProp(ctxt, node, "name"); if (name == NULL) { - ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); if (ref == NULL) { xmlSchemaPErr2(ctxt, node, child, @@ -2272,6 +2861,8 @@ xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, ret->ref = ref; ret->refNs = refNs; ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP; + if (topLevel) + ret->flags |= XML_SCHEMAS_ATTRGROUP_GLOBAL; ret->node = node; child = node->children; ctxt->container = name; @@ -2279,6 +2870,9 @@ xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); child = child->next; } + child = xmlSchemaParseAttrDecls(ctxt, schema, child, (xmlSchemaTypePtr) ret); + /* Seems that this can be removed. */ + /* while ((IS_SCHEMA(child, "attribute")) || (IS_SCHEMA(child, "attributeGroup"))) { attr = NULL; @@ -2286,7 +2880,7 @@ xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, attr = xmlSchemaParseAttribute(ctxt, schema, child, 0); } else if (IS_SCHEMA(child, "attributeGroup")) { attr = (xmlSchemaAttributePtr) - xmlSchemaParseAttributeGroup(ctxt, schema, child); + xmlSchemaParseAttributeGroup(ctxt, schema, child, 0); } if (attr != NULL) { if (last == NULL) { @@ -2303,6 +2897,7 @@ xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, TODO child = child->next; } + */ if (child != NULL) { xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD, @@ -2326,7 +2921,7 @@ xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, */ static xmlSchemaElementPtr xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, - xmlNodePtr node, int toplevel) + xmlNodePtr node, int topLevel) { const xmlChar *name, *fixed; const xmlChar *refNs = NULL, *ref = NULL; @@ -2344,7 +2939,6 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, oldcontainer = ctxt->container; name = xmlSchemaGetProp(ctxt, node, "name"); if (name == NULL) { - ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); /* 3.3.3 : 2.1 * One of ref or name must be present, but not both @@ -2352,9 +2946,10 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, if (ref == NULL) { xmlSchemaPErr(ctxt, node, XML_SCHEMAP_ELEM_NONAME_NOREF, - "Element has no name nor ref\n", NULL, NULL); + "Element declaration has no name nor ref\n", NULL, NULL); return (NULL); } + snprintf(buf, 99, "anonelem %d", ctxt->counter++ + 1); name = (const xmlChar *) buf; ret = xmlSchemaAddElement(ctxt, schema, name, NULL); @@ -2363,7 +2958,7 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, /* Evaluate the target namespace */ if (schema->targetNamespace != NULL) { - if (toplevel) { + if (topLevel) { ns = schema->targetNamespace; } else if (xmlSchemaGetProp(ctxt, node, "form") != NULL) { if (xmlStrEqual( xmlSchemaGetProp(ctxt, node, "form"), @@ -2379,7 +2974,7 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, /* 3.3.3 : 2.1 * One of ref or name must be present, but not both */ - if ((!toplevel) && (xmlSchemaGetProp(ctxt, node, "ref") != NULL)) { + if ((!topLevel) && (xmlSchemaGetProp(ctxt, node, "ref") != NULL)) { xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_ATTR_COMBINATION, "Element declaration has both, \"name\" and " @@ -2398,7 +2993,7 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, ret->flags |= XML_SCHEMAS_ELEM_REF; /* 3.3.3 : 2.2 */ - if ((!toplevel) && (ref != NULL)) { + if ((!topLevel) && (ref != NULL)) { attr = node->properties; while (attr != NULL) { if ((attr->ns == NULL) && @@ -2416,12 +3011,14 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, } } - if (toplevel) + if (topLevel) { + ret->flags |= XML_SCHEMAS_ELEM_GLOBAL; ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL; + } if (xmlGetBooleanProp(ctxt, node, "nillable", 0)) ret->flags |= XML_SCHEMAS_ELEM_NILLABLE; if (xmlGetBooleanProp(ctxt, node, "abstract", 0)) - ret->flags |= XML_SCHEMAS_ELEM_NILLABLE; + ret->flags |= XML_SCHEMAS_ELEM_ABSTRACT; ctxt->container = name; ret->id = xmlSchemaGetProp(ctxt, node, "id"); @@ -2430,7 +3027,7 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, ret->substGroup = xmlGetQNameProp(ctxt, node, "substitutionGroup", &(ret->substGroupNs)); - if ((ret->substGroup != NULL) && (!toplevel)) { + if ((ret->substGroup != NULL) && (!topLevel)) { /* 3.3.6 : 3 */ /* * TODO: This seems to be redundant, since the schema for schemas @@ -2464,6 +3061,7 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); child = child->next; } + if (ref != NULL) { /* 3.3.3 (2.2) */ while (child != NULL) { @@ -2496,7 +3094,7 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, "and a local complex type\n", ret->name, NULL); } else - ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child); + ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child, 0); child = child->next; } else if (IS_SCHEMA(child, "simpleType")) { /* 3.3.3 : 3 @@ -2510,7 +3108,7 @@ xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, "and a local simple type\n", ret->name, NULL); } else - ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child); + ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child, 0); child = child->next; } @@ -2556,10 +3154,10 @@ xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, type = xmlSchemaAddType(ctxt, schema, name, NULL); if (type == NULL) return (NULL); - type->node = node; type->type = XML_SCHEMA_TYPE_UNION; + type->node = node; type->id = xmlSchemaGetProp(ctxt, node, "id"); - type->ref = xmlSchemaGetProp(ctxt, node, "memberTypes"); + type->base = xmlSchemaGetProp(ctxt, node, "memberTypes"); child = node->children; if (IS_SCHEMA(child, "annotation")) { @@ -2568,7 +3166,7 @@ xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, } while (IS_SCHEMA(child, "simpleType")) { subtype = (xmlSchemaTypePtr) - xmlSchemaParseSimpleType(ctxt, schema, child); + xmlSchemaParseSimpleType(ctxt, schema, child, 0); if (subtype != NULL) { if (last == NULL) { type->subtypes = subtype; @@ -2608,6 +3206,7 @@ xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, xmlSchemaTypePtr type, subtype; xmlNodePtr child = NULL; xmlChar name[30]; + xmlAttrPtr attr; if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return (NULL); @@ -2619,20 +3218,33 @@ xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, type->node = node; type->type = XML_SCHEMA_TYPE_LIST; type->id = xmlSchemaGetProp(ctxt, node, "id"); - type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs)); child = node->children; if (IS_SCHEMA(child, "annotation")) { type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); child = child->next; } - + /* + * Check type of "itemType". + */ + attr = xmlSchemaGetPropNode(node, BAD_CAST "itemType"); + if (attr != NULL) { + type->base = xmlGetQNameProp(ctxt, node, "itemType", &(type->baseNs)); + xmlSchemaParseSchemaAttrValue(ctxt, attr, + xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME)); + + } subtype = NULL; - if (IS_SCHEMA(child, "simpleType")) { - subtype = (xmlSchemaTypePtr) - xmlSchemaParseSimpleType(ctxt, schema, child); - child = child->next; - type->subtypes = subtype; + if (IS_SCHEMA(child, "simpleType")) { + subtype = (xmlSchemaTypePtr) + xmlSchemaParseSimpleType(ctxt, schema, child, 0); + type->subtypes = subtype; + /* + * This is a hack to save the information that a local + * simple type was defined. + */ + type->baseType = subtype; + child = child->next; } if (child != NULL) { xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_LIST_CHILD, @@ -2656,41 +3268,102 @@ xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, */ static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, - xmlNodePtr node) + xmlNodePtr node, int topLevel) { - xmlSchemaTypePtr type, subtype; + xmlSchemaTypePtr type, subtype, ctxtType; xmlNodePtr child = NULL; - const xmlChar *name; + const xmlChar *propVal; if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return (NULL); - - name = xmlSchemaGetProp(ctxt, node, "name"); - if (name == NULL) { + ctxtType = ctxt->ctxtType; + propVal = xmlSchemaGetProp(ctxt, node, "name"); + if (propVal == NULL) { char buf[100]; snprintf(buf, 99, "simpleType %d", ctxt->counter++ + 1); type = xmlSchemaAddType(ctxt, schema, (const xmlChar *)buf, NULL); } else { - /* local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); */ - type = xmlSchemaAddType(ctxt, schema, name, schema->targetNamespace); + if (!topLevel) { + xmlSchemaPErr(ctxt, node, + XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, + "The attribute \"name\" is not allowed on a local " + "simpleType definition\n", + propVal, NULL); + return (NULL); + } + /* + * "name" has to be of type NCName. + * TODO: Actually this should be validated by the schema for schemas. + */ + if (xmlSchemaParseSchemaAttrValue(ctxt, + xmlSchemaGetPropNode(node, BAD_CAST "name"), + xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME)) != 0) + return (NULL); + type = xmlSchemaAddType(ctxt, schema, propVal, schema->targetNamespace); } if (type == NULL) return (NULL); type->node = node; type->type = XML_SCHEMA_TYPE_SIMPLE; + if (topLevel) + type->flags |= XML_SCHEMAS_TYPE_GLOBAL; type->id = xmlSchemaGetProp(ctxt, node, "id"); - + propVal = xmlSchemaGetProp(ctxt, node, "final"); + if (propVal == NULL) { + type->flags |= XML_SCHEMAS_TYPE_FINAL_DEFAULT; + } else { + if (xmlStrEqual(propVal, BAD_CAST "#all")) { + type->flags |= XML_SCHEMAS_TYPE_FINAL_RESTRICTION; + type->flags |= XML_SCHEMAS_TYPE_FINAL_UNION; + type->flags |= XML_SCHEMAS_TYPE_FINAL_LIST; + } else { + const xmlChar *end, *cur = propVal; + xmlChar *item; + + do { + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) + break; + item = xmlStrndup(cur, end - cur); + if (xmlStrEqual(item, BAD_CAST "restriction")) { + if ((type->flags & XML_SCHEMAS_TYPE_FINAL_RESTRICTION) == 0) + type->flags |= XML_SCHEMAS_TYPE_FINAL_RESTRICTION; + } else if (xmlStrEqual(item, BAD_CAST "list")) { + if ((type->flags & XML_SCHEMAS_TYPE_FINAL_LIST) == 0) + type->flags |= XML_SCHEMAS_TYPE_FINAL_LIST; + } else if (xmlStrEqual(item, BAD_CAST "union")) { + if ((type->flags & XML_SCHEMAS_TYPE_FINAL_UNION) == 0) + type->flags |= XML_SCHEMAS_TYPE_FINAL_UNION; + } else { + xmlSchemaPErr(ctxt, node, + XML_SCHEMAS_ERR_INTERNAL, + "The attribute \"final\" of type \"%s\" " + "has an invalid value\n", + type->name, NULL); + } + if (item != NULL) + xmlFree(item); + cur = end; + } while (*cur != 0); + } + } child = node->children; if (IS_SCHEMA(child, "annotation")) { type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); child = child->next; } subtype = NULL; + ctxt->ctxtType = type; + ctxt->parentItem = type; if (IS_SCHEMA(child, "restriction")) { subtype = (xmlSchemaTypePtr) - xmlSchemaParseRestriction(ctxt, schema, child, 1); + xmlSchemaParseRestriction(ctxt, schema, child); child = child->next; } else if (IS_SCHEMA(child, "list")) { subtype = (xmlSchemaTypePtr) @@ -2702,19 +3375,23 @@ xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, child = child->next; } type->subtypes = subtype; - if (subtype == NULL) { - xmlSchemaPErr2(ctxt, node, child, - XML_SCHEMAP_MISSING_SIMPLETYPE_CHILD, - "SimpleType %s does not define a variety\n", - type->name, NULL); - } if (child != NULL) { xmlSchemaPErr2(ctxt, node, child, - XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD, - "SimpleType %s has unexpected content\n", + XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED, + "SimpleType \"%s\" has unexpected content\n", type->name, NULL); + } else { + if (subtype == NULL) { + xmlSchemaPErr2(ctxt, node, child, + XML_SCHEMAP_S4S_ELEM_MISSING, + "SimpleType \"%s\" must have one of <restriction> or " + "<list> or <union> as a child\n", + type->name, NULL); + } } + ctxt->ctxtType = ctxtType; + return (type); } @@ -2733,7 +3410,7 @@ xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, */ static xmlSchemaTypePtr xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, - xmlNodePtr node) + xmlNodePtr node, int topLevel) { xmlSchemaTypePtr type, subtype; xmlNodePtr child = NULL; @@ -2747,7 +3424,6 @@ xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, name = xmlSchemaGetProp(ctxt, node, "name"); if (name == NULL) { - ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); if (ref == NULL) { xmlSchemaPErr2(ctxt, node, child, @@ -2763,9 +3439,10 @@ xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, type = xmlSchemaAddGroup(ctxt, schema, name); if (type == NULL) return (NULL); - type->node = node; type->type = XML_SCHEMA_TYPE_GROUP; + if (topLevel) + type->flags |= XML_SCHEMAS_TYPE_GLOBAL; type->id = xmlSchemaGetProp(ctxt, node, "id"); type->ref = ref; type->refNs = refNs; @@ -2898,7 +3575,7 @@ xmlSchemaImportSchema(xmlSchemaParserCtxtPtr ctxt, newctxt = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); if (newctxt == NULL) { - xmlSchemaPErrMemory(ctxt, "allocating schama parser context", + xmlSchemaPErrMemory(ctxt, "allocating schema parser context", NULL); return (NULL); } @@ -3066,8 +3743,39 @@ xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, if (import == NULL) { return (-1); } + if (!xmlStrEqual(import->schema->targetNamespace, namespace)) { + if (namespace == NULL) { + if (import->schema->targetNamespace != NULL) { + xmlSchemaPErr(ctxt, node, XML_SCHEMAP_SRC_IMPORT_3_2, + "There is no namespace attribute on the <import> " + "element information item, so the imported document " + "must have no targetNamespace attribute.\n", + NULL, NULL); + } + } else { + if (import->schema->targetNamespace != NULL) { + xmlSchemaPErr(ctxt, node, XML_SCHEMAP_SRC_IMPORT_3_1, + "The namespace attribute \"%s\" of an <import> " + "element information item must be identical to the " + "targetNamespace attribute \"%s\" of the " + "imported document.\n", + namespace, import->schema->targetNamespace); + } else { + xmlSchemaPErr(ctxt, node, XML_SCHEMAP_SRC_IMPORT_3_1, + "The namespace attribute on the <import> " + "element information item, requires the imported " + "document to have a targetNamespace attribute " + "with the value \"%s\".\n", + namespace, NULL); + } + } + xmlSchemaFreeImport(import); + return (-1); + } + xmlHashAddEntry(schema->schemasImports, namespace, import); + } } } @@ -3205,10 +3913,10 @@ xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt, } while (child != NULL) { if (IS_SCHEMA(child, "complexType")) { - xmlSchemaParseComplexType(ctxt, schema, child); + xmlSchemaParseComplexType(ctxt, schema, child, 1); child = child->next; } else if (IS_SCHEMA(child, "simpleType")) { - xmlSchemaParseSimpleType(ctxt, schema, child); + xmlSchemaParseSimpleType(ctxt, schema, child, 1); child = child->next; } else if (IS_SCHEMA(child, "element")) { xmlSchemaParseElement(ctxt, schema, child, 1); @@ -3217,10 +3925,10 @@ xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt, xmlSchemaParseAttribute(ctxt, schema, child, 1); child = child->next; } else if (IS_SCHEMA(child, "attributeGroup")) { - xmlSchemaParseAttributeGroup(ctxt, schema, child); + xmlSchemaParseAttributeGroup(ctxt, schema, child, 1); child = child->next; } else if (IS_SCHEMA(child, "group")) { - xmlSchemaParseGroup(ctxt, schema, child); + xmlSchemaParseGroup(ctxt, schema, child, 1); child = child->next; } else if (IS_SCHEMA(child, "notation")) { xmlSchemaParseNotation(ctxt, schema, child); @@ -3241,6 +3949,8 @@ xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt, child = child->next; } } + ctxt->parentItem = NULL; + ctxt->ctxtType = NULL; } /** @@ -3355,7 +4065,7 @@ xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, if (!IS_SCHEMA(root, "schema")) { xmlSchemaPErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAP_NOT_SCHEMA, - "File %s is not a schemas", schemaLocation, NULL); + "File %s is not a schema", schemaLocation, NULL); xmlFreeDoc(doc); return (-1); } @@ -3435,7 +4145,7 @@ xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, subtype = (xmlSchemaTypePtr) xmlSchemaParseElement(ctxt, schema, child, 0); } else if (IS_SCHEMA(child, "group")) { - subtype = xmlSchemaParseGroup(ctxt, schema, child); + subtype = xmlSchemaParseGroup(ctxt, schema, child, 0); } else if (IS_SCHEMA(child, "any")) { subtype = xmlSchemaParseAny(ctxt, schema, child); } else if (IS_SCHEMA(child, "sequence")) { @@ -3513,7 +4223,7 @@ xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, subtype = (xmlSchemaTypePtr) xmlSchemaParseElement(ctxt, schema, child, 0); } else if (IS_SCHEMA(child, "group")) { - subtype = xmlSchemaParseGroup(ctxt, schema, child); + subtype = xmlSchemaParseGroup(ctxt, schema, child, 0); } else if (IS_SCHEMA(child, "any")) { subtype = xmlSchemaParseAny(ctxt, schema, child); } else if (IS_SCHEMA(child, "choice")) { @@ -3548,7 +4258,6 @@ xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, * @ctxt: a schema validation context * @schema: the schema being built * @node: a subtree containing XML Schema informations - * @simple: is that part of a simple type. * * parse a XML schema Restriction definition * *WARNING* this interface is highly subject to change @@ -3557,10 +4266,9 @@ xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, */ static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, - xmlNodePtr node, int simple) + xmlNodePtr node) { - xmlSchemaTypePtr type, subtype; - xmlSchemaFacetPtr facet, lastfacet = NULL; + xmlSchemaTypePtr type, subtype; xmlNodePtr child = NULL; xmlChar name[30]; const xmlChar *oldcontainer; @@ -3574,14 +4282,16 @@ xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, type = xmlSchemaAddType(ctxt, schema, name, NULL); if (type == NULL) return (NULL); - type->node = node; type->type = XML_SCHEMA_TYPE_RESTRICTION; + type->node = node; type->id = xmlSchemaGetProp(ctxt, node, "id"); type->base = xmlGetQNameProp(ctxt, node, "base", &(type->baseNs)); - if ((!simple) && (type->base == NULL)) { + if ((type->base == NULL) && + (ctxt->parentItem->type == XML_SCHEMA_TYPE_COMPLEX_CONTENT)) { xmlSchemaPErr2(ctxt, node, child, - XML_SCHEMAP_RESTRICTION_NONAME_NOREF, - "Restriction %s has no base\n", type->name, NULL); + XML_SCHEMAP_RESTRICTION_NONAME_NOREF, + "Restriction \"%s\" must have a \"base\" attribute.\n", + type->name, NULL); } ctxt->container = name; @@ -3592,68 +4302,107 @@ xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, } subtype = NULL; - if (IS_SCHEMA(child, "all")) { - subtype = (xmlSchemaTypePtr) - xmlSchemaParseAll(ctxt, schema, child); - child = child->next; - type->subtypes = subtype; - } else if (IS_SCHEMA(child, "choice")) { - subtype = xmlSchemaParseChoice(ctxt, schema, child); - child = child->next; - type->subtypes = subtype; - } else if (IS_SCHEMA(child, "sequence")) { - subtype = (xmlSchemaTypePtr) - xmlSchemaParseSequence(ctxt, schema, child); - child = child->next; - type->subtypes = subtype; - } else if (IS_SCHEMA(child, "group")) { - subtype = (xmlSchemaTypePtr) - xmlSchemaParseGroup(ctxt, schema, child); - child = child->next; - type->subtypes = subtype; - } else { - if (IS_SCHEMA(child, "simpleType")) { - subtype = (xmlSchemaTypePtr) - xmlSchemaParseSimpleType(ctxt, schema, child); - child = child->next; - type->baseType = subtype; - } - /* - * Facets - */ - while ((IS_SCHEMA(child, "minInclusive")) || - (IS_SCHEMA(child, "minExclusive")) || - (IS_SCHEMA(child, "maxInclusive")) || - (IS_SCHEMA(child, "maxExclusive")) || - (IS_SCHEMA(child, "totalDigits")) || - (IS_SCHEMA(child, "fractionDigits")) || - (IS_SCHEMA(child, "pattern")) || - (IS_SCHEMA(child, "enumeration")) || - (IS_SCHEMA(child, "whiteSpace")) || - (IS_SCHEMA(child, "length")) || - (IS_SCHEMA(child, "maxLength")) || - (IS_SCHEMA(child, "minLength"))) { - facet = xmlSchemaParseFacet(ctxt, schema, child); - if (facet != NULL) { - if (lastfacet == NULL) { - type->facets = facet; - lastfacet = facet; - } else { - lastfacet->next = facet; - lastfacet = facet; - } - lastfacet->next = NULL; - } - child = child->next; - } - } - child = xmlSchemaParseAttrDecls(ctxt, schema, child, type); + if (ctxt->parentItem->type == XML_SCHEMA_TYPE_COMPLEX_CONTENT) { + if (IS_SCHEMA(child, "all")) { + subtype = (xmlSchemaTypePtr) + xmlSchemaParseAll(ctxt, schema, child); + child = child->next; + type->subtypes = subtype; + } else if (IS_SCHEMA(child, "choice")) { + subtype = xmlSchemaParseChoice(ctxt, schema, child); + child = child->next; + type->subtypes = subtype; + } else if (IS_SCHEMA(child, "sequence")) { + subtype = (xmlSchemaTypePtr) + xmlSchemaParseSequence(ctxt, schema, child); + child = child->next; + type->subtypes = subtype; + } else if (IS_SCHEMA(child, "group")) { + subtype = (xmlSchemaTypePtr) + xmlSchemaParseGroup(ctxt, schema, child, 0); + child = child->next; + type->subtypes = subtype; + } + } else if ((ctxt->ctxtType->type == XML_SCHEMA_TYPE_SIMPLE) || + (ctxt->parentItem->type == XML_SCHEMA_TYPE_SIMPLE_CONTENT)) { + xmlSchemaFacetPtr facet, lastfacet = NULL; + + if (IS_SCHEMA(child, "simpleType")) { + subtype = (xmlSchemaTypePtr) + xmlSchemaParseSimpleType(ctxt, schema, child, 0); + /* + * For the simple type this serves as the base type. + */ + type->baseType = subtype; + /* + * For the complex type this serves as information for the + * definition of the content type. + * Additionally this is a hack for the simple type, to save + * the information that a local simple type was defined; thus + * allowing to check: src-restriction-base-or-simpleType. + */ + type->subtypes = subtype; + child = child->next; + } + /* + * Add the facets to the parent simpleType/complexType. + */ + while ((IS_SCHEMA(child, "minInclusive")) || + (IS_SCHEMA(child, "minExclusive")) || + (IS_SCHEMA(child, "maxInclusive")) || + (IS_SCHEMA(child, "maxExclusive")) || + (IS_SCHEMA(child, "totalDigits")) || + (IS_SCHEMA(child, "fractionDigits")) || + (IS_SCHEMA(child, "pattern")) || + (IS_SCHEMA(child, "enumeration")) || + (IS_SCHEMA(child, "whiteSpace")) || + (IS_SCHEMA(child, "length")) || + (IS_SCHEMA(child, "maxLength")) || + (IS_SCHEMA(child, "minLength"))) { + facet = xmlSchemaParseFacet(ctxt, schema, child); + if (facet != NULL) { + if (lastfacet == NULL) + ctxt->ctxtType->facets = facet; + else + lastfacet->next = facet; + lastfacet = facet; + lastfacet->next = NULL; + } + child = child->next; + } + /* + * Create links for derivation and validation. + */ + if (lastfacet != NULL) { + xmlSchemaFacetLinkPtr facetLink, lastFacetLink = NULL; + + facet = ctxt->ctxtType->facets; + do { + facetLink = (xmlSchemaFacetLinkPtr) xmlMalloc(sizeof(xmlSchemaFacetLink)); + if (facetLink == NULL) { + xmlSchemaPErrMemory(ctxt, "allocation a facet link", NULL); + xmlFree(facetLink); + return (NULL); + } + facetLink->facet = facet; + facetLink->next = NULL; + if (lastFacetLink == NULL) + ctxt->ctxtType->facetSet = facetLink; + else + lastFacetLink->next = facetLink; + lastFacetLink = facetLink; + facet = facet->next; + } while (facet != NULL); + } + } + if (ctxt->ctxtType->type == XML_SCHEMA_TYPE_COMPLEX) + child = xmlSchemaParseAttrDecls(ctxt, schema, child, type); if (child != NULL) { - xmlSchemaPErr2(ctxt, node, child, - XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD, - "Restriction %s has unexpected content\n", - type->name, NULL); - } + xmlSchemaPErr2(ctxt, node, child, + XML_SCHEMAP_UNKNOWN_RESTRICTION_CHILD, + "Restriction \"%s\" has unexpected content.\n", + type->name, NULL); + } ctxt->container = oldcontainer; return (type); } @@ -3684,11 +4433,11 @@ xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, oldcontainer = ctxt->container; snprintf((char *) name, 30, "extension %d", ctxt->counter++ + 1); - type = xmlSchemaAddType(ctxt, schema, name, NULL); + type = xmlSchemaAddType(ctxt, schema, name, NULL); if (type == NULL) return (NULL); - type->node = node; type->type = XML_SCHEMA_TYPE_EXTENSION; + type->node = node; type->id = xmlSchemaGetProp(ctxt, node, "id"); ctxt->container = name; @@ -3714,7 +4463,7 @@ xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, subtype = xmlSchemaParseSequence(ctxt, schema, child); child = child->next; } else if (IS_SCHEMA(child, "group")) { - subtype = xmlSchemaParseGroup(ctxt, schema, child); + subtype = xmlSchemaParseGroup(ctxt, schema, child, 0); child = child->next; } if (subtype != NULL) @@ -3752,13 +4501,12 @@ xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt, if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return (NULL); - snprintf((char *) name, 30, "simpleContent %d", ctxt->counter++ + 1); - type = xmlSchemaAddType(ctxt, schema, name, NULL); + type = xmlSchemaAddType(ctxt, schema, name, NULL); if (type == NULL) return (NULL); - type->node = node; type->type = XML_SCHEMA_TYPE_SIMPLE_CONTENT; + type->node = node; type->id = xmlSchemaGetProp(ctxt, node, "id"); child = node->children; @@ -3766,10 +4514,11 @@ xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt, type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); child = child->next; } - subtype = NULL; + ctxt->parentItem = type; + subtype = NULL; if (IS_SCHEMA(child, "restriction")) { subtype = (xmlSchemaTypePtr) - xmlSchemaParseRestriction(ctxt, schema, child, 0); + xmlSchemaParseRestriction(ctxt, schema, child); child = child->next; } else if (IS_SCHEMA(child, "extension")) { subtype = (xmlSchemaTypePtr) @@ -3808,13 +4557,12 @@ xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return (NULL); - snprintf((char *) name, 30, "complexContent %d", ctxt->counter++ + 1); type = xmlSchemaAddType(ctxt, schema, name, NULL); if (type == NULL) return (NULL); - type->node = node; type->type = XML_SCHEMA_TYPE_COMPLEX_CONTENT; + type->node = node; type->id = xmlSchemaGetProp(ctxt, node, "id"); child = node->children; @@ -3822,10 +4570,11 @@ xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); child = child->next; } + ctxt->parentItem = type; subtype = NULL; if (IS_SCHEMA(child, "restriction")) { subtype = (xmlSchemaTypePtr) - xmlSchemaParseRestriction(ctxt, schema, child, 0); + xmlSchemaParseRestriction(ctxt, schema, child); child = child->next; } else if (IS_SCHEMA(child, "extension")) { subtype = (xmlSchemaTypePtr) @@ -3855,9 +4604,9 @@ xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt, */ static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, - xmlNodePtr node) + xmlNodePtr node, int topLevel) { - xmlSchemaTypePtr type, subtype; + xmlSchemaTypePtr type, subtype, ctxtType; xmlNodePtr child = NULL; const xmlChar *name; const xmlChar *oldcontainer; @@ -3866,10 +4615,11 @@ xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return (NULL); + ctxtType = ctxt->ctxtType; + oldcontainer = ctxt->container; name = xmlSchemaGetProp(ctxt, node, "name"); if (name == NULL) { - snprintf(buf, 99, "complexType %d", ctxt->counter++ + 1); name = (const xmlChar *)buf; type = xmlSchemaAddType(ctxt, schema, name, NULL); @@ -3881,12 +4631,13 @@ xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, if (type == NULL) { return (NULL); } - if (xmlGetBooleanProp(ctxt, node, "mixed", 0)) type->flags |= XML_SCHEMAS_TYPE_MIXED; type->node = node; type->type = XML_SCHEMA_TYPE_COMPLEX; + if (topLevel) + type->flags |= XML_SCHEMAS_TYPE_GLOBAL; type->id = xmlSchemaGetProp(ctxt, node, "id"); ctxt->container = name; @@ -3895,6 +4646,7 @@ xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); child = child->next; } + ctxt->ctxtType = type; if (IS_SCHEMA(child, "simpleContent")) { /* 3.4.3 : 2.2 * Specifying mixed='true' when the <simpleContent> @@ -3920,7 +4672,7 @@ xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, subtype = xmlSchemaParseSequence(ctxt, schema, child); child = child->next; } else if (IS_SCHEMA(child, "group")) { - subtype = xmlSchemaParseGroup(ctxt, schema, child); + subtype = xmlSchemaParseGroup(ctxt, schema, child, 0); child = child->next; } if (subtype != NULL) @@ -3933,7 +4685,10 @@ xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, "ComplexType %s has unexpected content\n", type->name, NULL); } + if (type->attributeWildcard != NULL) + type->flags |= XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD; ctxt->container = oldcontainer; + ctxt->ctxtType = ctxtType; return (type); } @@ -3984,7 +4739,10 @@ xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) val, NULL); } } else { - schema->flags |= XML_SCHEMAS_QUALIF_ELEM; + /* Removed, since the default value for elementFormDefault + * is "unqualified". + */ + /* schema->flags |= XML_SCHEMAS_QUALIF_ELEM; */ } val = xmlSchemaGetProp(ctxt, node, "attributeFormDefault"); if (val != NULL) { @@ -3998,6 +4756,51 @@ xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) } } + val = xmlSchemaGetProp(ctxt, node, "finalDefault"); + if (val != NULL) { + if (xmlStrEqual(val, BAD_CAST "#all")) { + schema->flags |= XML_SCHEMAS_FINAL_DEFAULT_EXTENSION; + schema->flags |= XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION; + schema->flags |= XML_SCHEMAS_FINAL_DEFAULT_LIST; + schema->flags |= XML_SCHEMAS_FINAL_DEFAULT_UNION; + } else { + const xmlChar *end, *cur = val; + xmlChar *item; + + do { + while (IS_BLANK_CH(*cur)) + cur++; + end = cur; + while ((*end != 0) && (!(IS_BLANK_CH(*end)))) + end++; + if (end == cur) + break; + item = xmlStrndup(cur, end - cur); + if (xmlStrEqual(item, BAD_CAST "extension")) { + if ((schema->flags & XML_SCHEMAS_FINAL_DEFAULT_EXTENSION) == 0) + schema->flags |= XML_SCHEMAS_FINAL_DEFAULT_EXTENSION; + } else if (xmlStrEqual(item, BAD_CAST "restriction")) { + if ((schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION) == 0) + schema->flags |= XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION; + } else if (xmlStrEqual(item, BAD_CAST "list")) { + if ((schema->flags & XML_SCHEMAS_FINAL_DEFAULT_LIST) == 0) + schema->flags |= XML_SCHEMAS_FINAL_DEFAULT_LIST; + } else if (xmlStrEqual(item, BAD_CAST "union")) { + if ((schema->flags & XML_SCHEMAS_FINAL_DEFAULT_UNION) == 0) + schema->flags |= XML_SCHEMAS_FINAL_DEFAULT_UNION; + } else { + xmlSchemaPErr(ctxt, node, + XML_SCHEMAS_ERR_INTERNAL, + "Invalid value for the attribute \"finalDefault\".\n", + NULL, NULL); + } + if (item != NULL) + xmlFree(item); + cur = end; + } while (*cur != 0); + } + } + xmlSchemaParseSchemaTopLevel(ctxt, schema, node->children); } else { xmlDocPtr doc; @@ -4027,7 +4830,6 @@ xmlSchemaParseSchema(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node) xmlGenericError(xmlGenericErrorContext, "xmlSchemaParse() failed\n"); #endif - return (schema); } @@ -4182,6 +4984,7 @@ xmlSchemaBuildAContentModel(xmlSchemaTypePtr type, case XML_SCHEMA_TYPE_ANY: /* TODO : handle the namespace too */ /* TODO : make that a specific transition type */ + /* Daniel says: use xmlAutomataNewTransition2 */ TODO ctxt->state = xmlAutomataNewTransition(ctxt->am, ctxt->state, NULL, BAD_CAST "*", NULL); @@ -4464,7 +5267,11 @@ xmlSchemaBuildAContentModel(xmlSchemaTypePtr type, case XML_SCHEMA_TYPE_ALL:{ xmlAutomataStatePtr start; xmlSchemaTypePtr subtypes; - xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type; + /* + * Changed, since type in not an xmlSchemaElement here. + */ + /* xmlSchemaElementPtr elem = (xmlSchemaElementPtr) type; */ + xmlSchemaElementPtr elem; int lax; subtypes = type->subtypes; @@ -4531,7 +5338,7 @@ xmlSchemaBuildAContentModel(xmlSchemaTypePtr type, if (type->subtypes == NULL) { xmlSchemaTypePtr rgroup; if (type->ref != NULL) { - rgroup = xmlHashLookup2(ctxt->schema->groupDecl, type->ref, + rgroup = xmlSchemaGetGroup(ctxt->schema, type->ref, type->refNs); if (rgroup == NULL) { xmlSchemaPErr(ctxt, type->node, @@ -4634,22 +5441,26 @@ xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem, { if ((ctxt == NULL) || (elem == NULL)) return; + if (elem->ref != NULL) { xmlSchemaElementPtr elemDecl; if (elem->subtypes != NULL) { xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_INVALID_REF_AND_SUBTYPE, - "Schemas: element %s have both ref and subtype\n", + "Schemas: element %s has both ref and subtype\n", name, NULL); return; } elemDecl = xmlSchemaGetElem(ctxt->schema, elem->ref, elem->refNs, 0); if (elemDecl == NULL) { - xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_REF, - "Schemas: element %s ref to %s not found\n", - name, elem->ref); + xmlSchemaPErr(ctxt, elem->node, + XML_SCHEMAP_SRC_RESOLVE, + "Element \"%s\": the QName \"%s\" of the attribute " + "\"ref\" does not resolve to a schema " + "component.\n", + name, elem->ref); return; } elem->refDecl = elemDecl; @@ -4658,7 +5469,7 @@ xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem, if (elem->subtypes != NULL) { xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_TYPE_AND_SUBTYPE, - "Schemas: element %s have both type and subtype\n", + "Schemas: element %s has both type and subtype\n", name, NULL); return; } @@ -4666,9 +5477,11 @@ xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem, elem->namedTypeNs); if (typeDecl == NULL) { - xmlSchemaPErr(ctxt, elem->node, XML_SCHEMAP_UNKNOWN_TYPE, - "Schemas: element %s type %s not found\n", name, - elem->namedType); + xmlSchemaPErr(ctxt, elem->node, + XML_SCHEMAP_SRC_RESOLVE, + "Element \"%s\": the QName \"%s\" of the attribute " + "\"type\" does not resolve to a schema " + "component.\n", name, elem->namedType); return; } elem->subtypes = typeDecl; @@ -4684,29 +5497,38 @@ xmlSchemaRefFixupCallback(xmlSchemaElementPtr elem, */ static void xmlSchemaParseListRefFixup(xmlSchemaTypePtr type, xmlSchemaParserCtxtPtr ctxt) -{ - const xmlChar *itemType, *namespace; - xmlSchemaTypePtr subtype; - - /* Handle the "itemType" attribute. */ - itemType = xmlGetQNameProp(ctxt, type->node, "itemType", &namespace); - if (itemType != NULL) { - /* Do not allow more that one item type. */ - if (type->subtypes != NULL) { - xmlSchemaPErr(ctxt, type->node, - XML_SCHEMAP_SUPERNUMEROUS_LIST_ITEM_TYPE, - "List %s has more than one item type defined\n", - type->name, NULL); - } - subtype = xmlSchemaGetType(ctxt->schema, itemType, namespace); - if (subtype == NULL) { +{ + /* + * src-list-itemType-or-simpleType + * Either the itemType [attribute] or the <simpleType> [child] of + * the <list> element must be present, but not both. + */ + if (((type->base == NULL) && + (type->subtypes == NULL)) || + ((type->base != NULL) && + (type->subtypes != NULL))) { + /* + * src-restriction-base-or-simpleType + * Either the base [attribute] or the simpleType [child] of the + * <restriction> element must be present, but not both. + */ + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_SRC_LIST_ITEMTYPE_OR_SIMPLETYPE, + "List \"%s\": " + "Either the \"base\" attribute or the <simpleType> child " + "must be present, but not both.\n", + type->name, NULL); + } else if (type->base!= NULL) { + type->subtypes = xmlSchemaGetType(ctxt->schema, type->base, type->baseNs); + if (type->subtypes == NULL) { xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_UNKNOWN_TYPE, - "List %s references an unknown item type: %s\n", - type->name, xmlSchemaGetProp(ctxt, type->node, - "itemType")); - } else - type->subtypes = subtype; - } + "List \"%s\" references an unknown item type: \"%s\"\n", + type->name, type->base); + } + } + if ((type->subtypes != NULL) && + (type->subtypes->contentType == XML_SCHEMA_CONTENT_UNKNOWN)) + xmlSchemaTypeFixup(type->subtypes, ctxt, NULL); } /** @@ -4714,60 +5536,2303 @@ xmlSchemaParseListRefFixup(xmlSchemaTypePtr type, xmlSchemaParserCtxtPtr ctxt) * @typeDecl: the schema type definition * @ctxt: the schema parser context * - * Checks the memberTypes references of the union type. + * Checks and builds the memberTypes of the union type. + * Returns -1 in case of an internal error, 0 otherwise. */ -static void +static int xmlSchemaParseUnionRefCheck(xmlSchemaTypePtr type, xmlSchemaParserCtxtPtr ctxt) { const xmlChar *cur, *end, *prefix, *ncName, *namespace; xmlChar *tmp; - xmlSchemaTypePtr subtype; + xmlSchemaTypeLinkPtr link, lastLink = NULL, prevLink, subLink, newLink; + xmlSchemaTypePtr memberType, ctxtType; xmlNsPtr ns; int len; - if ((type->type != XML_SCHEMA_TYPE_UNION) || (type->ref == NULL)) - return; + /* 1 If the <union> alternative is chosen, then [Definition:] + * define the explicit members as the type definitions ·resolved· + * to by the items in the ·actual value· of the memberTypes [attribute], + * if any, followed by the type definitions corresponding to the + * <simpleType>s among the [children] of <union>, if any. + */ - 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 = xmlDictLookup(ctxt->dict, tmp, len); - } else { - prefix = NULL; - ncName = tmp; - } - ns = xmlSearchNs(type->node->doc, type->node, prefix); - if (ns == NULL) { - if (prefix != NULL) { - xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_PREFIX_UNDEFINED, - "Union %s: the namespace prefix of member type " - "%s is undefined\n", - type->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, type->node, XML_SCHEMAP_UNKNOWN_MEMBER_TYPE, - "Union %s references an unknown member type %s\n", - type->name, (const xmlChar *) tmp); - } - xmlFree(tmp); - cur = end; - } while (*cur != 0); + if (type->type != XML_SCHEMA_TYPE_UNION) + return (-1); + if (ctxt->ctxtType == NULL) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaParseUnionRefCheck, no parent type " + "available", NULL, NULL); + return (-1); + } + /* + * src-union-memberTypes-or-simpleTypes + * Either the memberTypes [attribute] of the <union> element must + * be non-empty or there must be at least one simpleType [child]. + */ + if ((type->base == NULL) && + (type->subtypes == NULL)) { + /* + * src-restriction-base-or-simpleType + * Either the base [attribute] or the simpleType [child] of the + * <restriction> element must be present, but not both. + */ + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_SRC_UNION_MEMBERTYPES_OR_SIMPLETYPES, + "Union \"%s\": " + "Either the \"memberTypes\" attribute must be non-empty " + "or there must be at least one <simpleType> child.\n", + type->name, NULL); + } + + ctxtType = ctxt->ctxtType; + if (type->base != NULL) { + cur = type->base; + 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(type->node->doc, type->node, prefix); + if (ns == NULL) { + if (prefix != NULL) { + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_PREFIX_UNDEFINED, + "Union \"%s\": the namespace prefix of member type " + "\"%s\" is undefined\n", + type->name, (const xmlChar *) tmp); + } + namespace = NULL; + } else { + namespace = xmlDictLookup(ctxt->dict, ns->href, -1); + } + memberType = xmlSchemaGetType(ctxt->schema, ncName, namespace); + if (memberType == NULL) { + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_UNKNOWN_MEMBER_TYPE, + "Union \"%s\" references an unknown member type \"%s\".\n", + type->name, (const xmlChar *) tmp); + } else { + if (memberType->contentType == XML_SCHEMA_CONTENT_UNKNOWN) + xmlSchemaTypeFixup(memberType, ctxt, NULL); + link = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); + if (link == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating a type link", NULL); + return (-1); + } + link->type = memberType; + link->next = NULL; + if (lastLink == NULL) + ctxtType->memberTypes = link; + else + lastLink->next = link; + lastLink = link; + } + xmlFree(tmp); + cur = end; + } while (*cur != 0); + } + /* + * Add local simple types, + */ + memberType = type->subtypes; + while (memberType != NULL) { + if (memberType->contentType == XML_SCHEMA_CONTENT_UNKNOWN) + xmlSchemaTypeFixup(memberType, ctxt, NULL); + link = (xmlSchemaTypeLinkPtr) xmlMalloc(sizeof(xmlSchemaTypeLink)); + if (link == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating a type link", NULL); + return (-1); + } + link->type = memberType; + link->next = NULL; + if (lastLink == NULL) + ctxtType->memberTypes = link; + else + lastLink->next = link; + lastLink = link; + memberType = memberType->next; + } + /* + * The actual value is then formed by replacing any union type + * definition in the ·explicit members· with the members of their + * {member type definitions}, in order. + */ + link = ctxtType->memberTypes; + while (link != NULL) { + if (link->type->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) { + subLink = link->type->memberTypes; + if (subLink != NULL) { + link->type = subLink->type; + if (subLink->next != NULL) { + lastLink = link->next; + subLink = subLink->next; + prevLink = link; + while (subLink != NULL) { + newLink = (xmlSchemaTypeLinkPtr) + xmlMalloc(sizeof(xmlSchemaTypeLink)); + if (newLink == NULL) { + xmlSchemaPErrMemory(ctxt, "allocating a type link", + NULL); + return (-1); + } + newLink->type = memberType; + prevLink->next = newLink; + prevLink = newLink; + newLink->next = lastLink; + + subLink = subLink->next; + } + } + } + } + link = link->next; + } + + return (0); +} + +/** + * xmlSchemaGetOnymousTypeName: + * @attr: the attribute declaration/use + * + * Returns the name of the attribute; if the attribute + * is a reference, the name of the referenced global type will be returned. + */ +static const xmlChar * +xmlSchemaGetOnymousAttrName(xmlSchemaAttributePtr attr) +{ + if (attr->ref != NULL) + return(attr->ref); + else + return(attr->name); +} + +/** + * xmlSchemaGetOnymousTargetNsURI: + * @type: the type (element or attribute) + * + * Returns the target namespace URI of the type; if the type is a reference, + * the target namespace of the referenced type will be returned. + */ +static const xmlChar * +xmlSchemaGetOnymousTargetNsURI(xmlSchemaTypePtr type) +{ + if (type->type == XML_SCHEMA_TYPE_ELEMENT) { + if (type->ref != NULL) + return(((xmlSchemaElementPtr)((xmlSchemaElementPtr) + type)->subtypes)->targetNamespace); + else + return(((xmlSchemaElementPtr) type)->targetNamespace); + } else if (type->type == XML_SCHEMA_TYPE_ATTRIBUTE) { + if (type->ref != NULL) + return(((xmlSchemaAttributePtr)((xmlSchemaAttributePtr) + type)->subtypes)->targetNamespace); + else + return(((xmlSchemaAttributePtr) type)->targetNamespace); + } else + return (NULL); +} + +/** + * xmlSchemaIsDerivedFromBuiltInType: + * @ctxt: the schema parser context + * @type: the type definition + * @valType: the value type + * + * + * Returns 1 if the type has the given value type, or + * is derived from such a type. + */ +static int +xmlSchemaIsDerivedFromBuiltInType(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type, int valType) +{ + /* TODO: Check if this works in every case. */ + if ((type->type == XML_SCHEMA_TYPE_BASIC) && + (type->contentType == XML_SCHEMA_CONTENT_BASIC)) { + if (type->builtInType == valType) + return(1); + } else if (type->type == XML_SCHEMA_TYPE_ATTRIBUTE) { + if (((xmlSchemaAttributePtr) type)->subtypes != NULL) + return(xmlSchemaIsDerivedFromBuiltInType(ctxt, + ((xmlSchemaAttributePtr) type)->subtypes, valType)); + } else if ((type->type == XML_SCHEMA_TYPE_RESTRICTION) || + (type->type == XML_SCHEMA_TYPE_EXTENSION)) { + if (type->baseType != NULL) + return(xmlSchemaIsDerivedFromBuiltInType(ctxt, type->baseType, + valType)); + } else if ((type->subtypes != NULL) && + ((type->subtypes->type == XML_SCHEMA_TYPE_COMPLEX) || + (type->subtypes->type == XML_SCHEMA_TYPE_COMPLEX_CONTENT) || + (type->subtypes->type == XML_SCHEMA_TYPE_SIMPLE) || + (type->subtypes->type == XML_SCHEMA_TYPE_SIMPLE_CONTENT))) { + return(xmlSchemaIsDerivedFromBuiltInType(ctxt, type->subtypes, + valType)); + } + + return (0); +} + +/** + * xmlSchemaIsDerivedFromBuiltInType: + * @type: the simpleType definition + * + * Returns the primitive type of the given type or + * NULL in case of error. + */ +static xmlSchemaTypePtr +xmlSchemaGetPrimitiveType(xmlSchemaTypePtr type) +{ + while (type != NULL) { + if (type->flags & XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE) + return (type); + type = type->baseType; + } + + return (NULL); +} + + +/** + * xmlSchemaBuildAttributeUsesOwned: + * @ctxt: the schema parser context + * @type: the complex type definition + * @cur: the attribute declaration list + * @lastUse: the top of the attribute use list + * + * Builds the attribute uses list on the given complex type. + * This one is supposed to be called by + * xmlSchemaBuildAttributeValidation only. + */ +static int +xmlSchemaBuildAttributeUsesOwned(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaAttributePtr cur, + xmlSchemaAttributeLinkPtr *uses, + xmlSchemaAttributeLinkPtr *lastUse) +{ + xmlSchemaAttributeLinkPtr tmp; + while (cur != NULL) { + if (cur->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) { + /* + * W3C: "2 The {attribute uses} of the attribute groups ·resolved· + * to by the ·actual value·s of the ref [attribute] of the + * <attributeGroup> [children], if any." + */ + if (xmlSchemaBuildAttributeUsesOwned(ctxt, + ((xmlSchemaAttributeGroupPtr) cur)->attributes, uses, + lastUse) == -1) { + return (-1); + } + } else { + /* W3C: "1 The set of attribute uses corresponding to the + * <attribute> [children], if any." + */ + tmp = (xmlSchemaAttributeLinkPtr) + xmlMalloc(sizeof(xmlSchemaAttributeLink)); + if (tmp == NULL) { + xmlSchemaPErrMemory(ctxt, "building attribute uses", NULL); + return (-1); + } + tmp->attr = cur; + tmp->next = NULL; + if (*uses == NULL) + *uses = tmp; + else + (*lastUse)->next = tmp; + *lastUse = tmp; + } + cur = cur->next; + } + return (0); +} + +/** + * xmlSchemaCloneWildcardNsConstraints: + * @ctxt: the schema parser context + * @dest: the destination wildcard + * @source: the source wildcard + * + * Clones the namespace constraints of source + * and assignes them to dest. + * Returns -1 on internal error, 0 otherwise. + */ +static int +xmlSchemaCloneWildcardNsConstraints(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaWildcardPtr *dest, + xmlSchemaWildcardPtr source) +{ + xmlSchemaWildcardNsPtr cur, tmp, last; + + if ((source == NULL) || (*dest == NULL)) + return(-1); + (*dest)->any = source->any; + cur = source->nsSet; + last = NULL; + while (cur != NULL) { + tmp = xmlSchemaNewWildcardNsConstraint(ctxt); + if (tmp == NULL) + return(-1); + tmp->value = cur->value; + if (last == NULL) + (*dest)->nsSet = tmp; + else + last->next = tmp; + last = tmp; + cur = cur->next; + } + if ((*dest)->negNsSet != NULL) + xmlSchemaFreeWildcardNsSet((*dest)->negNsSet); + if (source->negNsSet != NULL) { + (*dest)->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if ((*dest)->negNsSet == NULL) + return(-1); + (*dest)->negNsSet->value = source->negNsSet->value; + } else + (*dest)->negNsSet = NULL; + return(0); +} + +/** + * xmlSchemaUnionWildcards: + * @ctxt: the schema parser context + * @completeWild: the first wildcard + * @curWild: the second wildcard + * + * Unions the namespace constraints of the given wildcards. + * @completeWild will hold the resulting union. + * Returns a positive error code on failure, -1 in case of an + * internal error, 0 otherwise. + */ +static int +xmlSchemaUnionWildcards(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaWildcardPtr completeWild, + xmlSchemaWildcardPtr curWild) +{ + xmlSchemaWildcardNsPtr cur, curB, tmp; + + /* + * 1 If O1 and O2 are the same value, then that value must be the + * value. + */ + if ((completeWild->any == curWild->any) && + ((completeWild->nsSet == NULL) == (curWild->nsSet == NULL)) && + ((completeWild->negNsSet == NULL) == (curWild->negNsSet == NULL))) { + + if ((completeWild->negNsSet == NULL) || + (completeWild->negNsSet->value == curWild->negNsSet->value)) { + + if (completeWild->nsSet != NULL) { + int found = 0; + + /* + * Check equality of sets. + */ + cur = completeWild->nsSet; + while (cur != NULL) { + found = 0; + curB = curWild->nsSet; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) + break; + cur = cur->next; + } + if (found) + return(0); + } else + return(0); + } + } + /* + * 2 If either O1 or O2 is any, then any must be the value + */ + if (completeWild->any != curWild->any) { + if (completeWild->any == 0) { + completeWild->any = 1; + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + if (completeWild->negNsSet != NULL) { + xmlFree(completeWild->negNsSet); + completeWild->negNsSet = NULL; + } + } + return (0); + } + /* + * 3 If both O1 and O2 are sets of (namespace names or ·absent·), + * then the union of those sets must be the value. + */ + if ((completeWild->nsSet != NULL) && (curWild->nsSet != NULL)) { + int found; + xmlSchemaWildcardNsPtr start; + + cur = curWild->nsSet; + start = completeWild->nsSet; + while (cur != NULL) { + found = 0; + curB = start; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) { + tmp = xmlSchemaNewWildcardNsConstraint(ctxt); + if (tmp == NULL) + return (-1); + tmp->value = cur->value; + tmp->next = completeWild->nsSet; + completeWild->nsSet = tmp; + } + cur = cur->next; + } + + return(0); + } + /* + * 4 If the two are negations of different values (namespace names + * or ·absent·), then a pair of not and ·absent· must be the value. + */ + if ((completeWild->negNsSet != NULL) && + (curWild->negNsSet != NULL) && + (completeWild->negNsSet->value != curWild->negNsSet->value)) { + completeWild->negNsSet->value = NULL; + + return(0); + } + /* + * 5. + */ + if (((completeWild->negNsSet != NULL) && + (completeWild->negNsSet->value != NULL) && + (curWild->nsSet != NULL)) || + ((curWild->negNsSet != NULL) && + (curWild->negNsSet->value != NULL) && + (completeWild->nsSet != NULL))) { + + int nsFound, absentFound = 0; + + if (completeWild->nsSet != NULL) { + cur = completeWild->nsSet; + curB = curWild->negNsSet; + } else { + cur = curWild->nsSet; + curB = completeWild->negNsSet; + } + nsFound = 0; + while (cur != NULL) { + if (cur->value == NULL) + absentFound = 1; + else if (cur->value == curB->value) + nsFound = 1; + if (nsFound && absentFound) + break; + cur = cur->next; + } + + if (nsFound && absentFound) { + /* + * 5.1 If the set S includes both the negated namespace + * name and ·absent·, then any must be the value. + */ + completeWild->any = 1; + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + if (completeWild->negNsSet != NULL) { + xmlFree(completeWild->negNsSet); + completeWild->negNsSet = NULL; + } + } else if (nsFound && (!absentFound)) { + /* + * 5.2 If the set S includes the negated namespace name + * but not ·absent·, then a pair of not and ·absent· must + * be the value. + */ + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + if (completeWild->negNsSet == NULL) { + completeWild->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (completeWild->negNsSet == NULL) + return (-1); + } + completeWild->negNsSet->value = NULL; + } else if ((!nsFound) && absentFound) { + /* + * 5.3 If the set S includes ·absent· but not the negated + * namespace name, then the union is not expressible. + */ + xmlSchemaPErr(ctxt, completeWild->node, + XML_SCHEMAP_UNION_NOT_EXPRESSIBLE, + "The union of the wilcard is not expressible\n", + NULL, NULL); + return(XML_SCHEMAP_UNION_NOT_EXPRESSIBLE); + } else if ((!nsFound) && (!absentFound)) { + /* + * 5.4 If the set S does not include either the negated namespace + * name or ·absent·, then whichever of O1 or O2 is a pair of not + * and a namespace name must be the value. + */ + if (completeWild->negNsSet == NULL) { + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + completeWild->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (completeWild->negNsSet == NULL) + return (-1); + completeWild->negNsSet->value = curWild->negNsSet->value; + } + } + return (0); + } + /* + * 6. + */ + if (((completeWild->negNsSet != NULL) && + (completeWild->negNsSet->value == NULL) && + (curWild->nsSet != NULL)) || + ((curWild->negNsSet != NULL) && + (curWild->negNsSet->value == NULL) && + (completeWild->nsSet != NULL))) { + + if (completeWild->nsSet != NULL) { + cur = completeWild->nsSet; + } else { + cur = curWild->nsSet; + } + while (cur != NULL) { + if (cur->value == NULL) { + /* + * 6.1 If the set S includes ·absent·, then any must be the + * value. + */ + completeWild->any = 1; + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + if (completeWild->negNsSet != NULL) { + xmlFree(completeWild->negNsSet); + completeWild->negNsSet = NULL; + } + return (0); + } + cur = cur->next; + } + if (completeWild->negNsSet == NULL) { + /* + * 6.2 If the set S does not include ·absent·, then a pair of not + * and ·absent· must be the value. + */ + if (completeWild->nsSet != NULL) { + xmlSchemaFreeWildcardNsSet(completeWild->nsSet); + completeWild->nsSet = NULL; + } + completeWild->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt); + if (completeWild->negNsSet == NULL) + return (-1); + completeWild->negNsSet->value = NULL; + } + return (0); + } + return (0); + +} + +/** + * xmlSchemaIntersectWildcards: + * @ctxt: the schema parser context + * @completeWild: the first wildcard + * @curWild: the second wildcard + * + * Intersects the namespace constraints of the given wildcards. + * @completeWild will hold the resulting intersection. + * Returns a positive error code on failure, -1 in case of an + * internal error, 0 otherwise. + */ +static int +xmlSchemaIntersectWildcards(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaWildcardPtr completeWild, + xmlSchemaWildcardPtr curWild) +{ + xmlSchemaWildcardNsPtr cur, curB, prev, tmp; + + /* + * 1 If O1 and O2 are the same value, then that value must be the + * value. + */ + if ((completeWild->any == curWild->any) && + ((completeWild->nsSet == NULL) == (curWild->nsSet == NULL)) && + ((completeWild->negNsSet == NULL) == (curWild->negNsSet == NULL))) { + + if ((completeWild->negNsSet == NULL) || + (completeWild->negNsSet->value == curWild->negNsSet->value)) { + + if (completeWild->nsSet != NULL) { + int found = 0; + + /* + * Check equality of sets. + */ + cur = completeWild->nsSet; + while (cur != NULL) { + found = 0; + curB = curWild->nsSet; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) + break; + cur = cur->next; + } + if (found) + return(0); + } else + return(0); + } + } + /* + * 2 If either O1 or O2 is any, then the other must be the value. + */ + if ((completeWild->any != curWild->any) && (completeWild->any)) { + if (xmlSchemaCloneWildcardNsConstraints(ctxt, &completeWild, curWild) == -1) + return(-1); + return(0); + } + /* + * 3 If either O1 or O2 is a pair of not and a value (a namespace + * name or ·absent·) and the other is a set of (namespace names or + * ·absent·), then that set, minus the negated value if it was in + * the set, minus ·absent· if it was in the set, must be the value. + */ + if (((completeWild->negNsSet != NULL) && (curWild->nsSet != NULL)) || + ((curWild->negNsSet != NULL) && (completeWild->nsSet != NULL))) { + const xmlChar *neg; + + if (completeWild->nsSet == NULL) { + neg = completeWild->negNsSet->value; + if (xmlSchemaCloneWildcardNsConstraints(ctxt, &completeWild, curWild) == -1) + return(-1); + } else + neg = curWild->negNsSet->value; + /* + * Remove absent and negated. + */ + prev = NULL; + cur = completeWild->nsSet; + while (cur != NULL) { + if (cur->value == NULL) { + if (prev == NULL) + completeWild->nsSet = cur->next; + else + prev->next = cur->next; + xmlFree(cur); + break; + } + prev = cur; + cur = cur->next; + } + if (neg != NULL) { + prev = NULL; + cur = completeWild->nsSet; + while (cur != NULL) { + if (cur->value == neg) { + if (prev == NULL) + completeWild->nsSet = cur->next; + else + prev->next = cur->next; + xmlFree(cur); + break; + } + prev = cur; + cur = cur->next; + } + } + + return(0); + } + /* + * 4 If both O1 and O2 are sets of (namespace names or ·absent·), + * then the intersection of those sets must be the value. + */ + if ((completeWild->nsSet != NULL) && (curWild->nsSet != NULL)) { + int found; + + cur = completeWild->nsSet; + prev = NULL; + while (cur != NULL) { + found = 0; + curB = curWild->nsSet; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) { + if (prev == NULL) + completeWild->nsSet = cur->next; + else + prev->next = cur->next; + tmp = cur->next; + xmlFree(cur); + cur = tmp; + continue; + } + prev = cur; + cur = cur->next; + } + + return(0); + } + /* 5 If the two are negations of different namespace names, + * then the intersection is not expressible + */ + if ((completeWild->negNsSet != NULL) && + (curWild->negNsSet != NULL) && + (completeWild->negNsSet->value != curWild->negNsSet->value) && + (completeWild->negNsSet->value != NULL) && + (curWild->negNsSet->value != NULL)) { + + xmlSchemaPErr(ctxt, completeWild->node, XML_SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE, + "The intersection of the wilcard is not expressible\n", + NULL, NULL); + return(XML_SCHEMAP_INTERSECTION_NOT_EXPRESSIBLE); + } + /* + * 6 If the one is a negation of a namespace name and the other + * is a negation of ·absent·, then the one which is the negation + * of a namespace name must be the value. + */ + if ((completeWild->negNsSet != NULL) && (curWild->negNsSet != NULL) && + (completeWild->negNsSet->value != curWild->negNsSet->value) && + (completeWild->negNsSet->value == NULL)) { + completeWild->negNsSet->value = curWild->negNsSet->value; + } + return(0); +} + +/** + * xmlSchemaIsWildcardNsConstraintSubset: + * @ctxt: the schema parser context + * @wildA: the first wildcard + * @wildB: the second wildcard + * + * Returns 1 if the namespace constraint of @wildA is an intensional + * subset of @wildB, 0 otherwise. + */ +static int +xmlSchemaIsWildcardNsConstraintSubset( + xmlSchemaParserCtxtPtr ctxt ATTRIBUTE_UNUSED, + xmlSchemaWildcardPtr wildA, + xmlSchemaWildcardPtr wildB) +{ + + /* + * Schema Component Constraint: Wildcard Subset + */ + /* + * 1 super must be any. + */ + if (wildB->any) + return (1); + /* + * 2.1 sub must be a pair of not and a namespace name or ·absent·. + * 2.2 super must be a pair of not and the same value. + */ + if ((wildA->negNsSet != NULL) && + (wildB->negNsSet != NULL) && + (wildA->negNsSet->value == wildA->negNsSet->value)) + return (1); + /* + * 3.1 sub must be a set whose members are either namespace names or ·absent·. + */ + if (wildA->nsSet != NULL) { + /* + * 3.2.1 super must be the same set or a superset thereof. + */ + if (wildB->nsSet != NULL) { + xmlSchemaWildcardNsPtr cur, curB; + int found = 0; + + cur = wildA->nsSet; + while (cur != NULL) { + found = 0; + curB = wildB->nsSet; + while (curB != NULL) { + if (cur->value == curB->value) { + found = 1; + break; + } + curB = curB->next; + } + if (!found) + return (0); + cur = cur->next; + } + if (found) + return (1); + } else if (wildB->negNsSet != NULL) { + xmlSchemaWildcardNsPtr cur; + /* + * 3.2.2 super must be a pair of not and a namespace name or + * ·absent· and that value must not be in sub's set. + */ + cur = wildA->nsSet; + while (cur != NULL) { + if (cur->value == wildB->negNsSet->value) + return (0); + cur = cur->next; + } + return (1); + } + } + return (0); +} + +/** + * xmlSchemaBuildCompleteAttributeWildcard: + * @ctxt: the schema parser context + * @attrs: the attribute list + * @completeWild: the resulting complete wildcard + * + * Returns -1 in case of an internal error, 0 otherwise. + */ +static int +xmlSchemaBuildCompleteAttributeWildcard(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaAttributePtr attrs, + xmlSchemaWildcardPtr *completeWild) +{ + while (attrs != NULL) { + if (attrs->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) { + xmlSchemaAttributeGroupPtr group; + + group = (xmlSchemaAttributeGroupPtr) attrs; + if ((group->flags & XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED) == 0) { + if (group->attributes != NULL) { + if (xmlSchemaBuildCompleteAttributeWildcard(ctxt, + group->attributes, &group->attributeWildcard) == -1) + return (-1); + } + group->flags |= XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED; + } + if (group->attributeWildcard != NULL) { + if (*completeWild == NULL) { + /* + * Copy the first encountered wildcard as context, except for the annotation. + */ + *completeWild = xmlSchemaAddWildcard(ctxt); + (*completeWild)->type = XML_SCHEMA_TYPE_ANY_ATTRIBUTE; + if (xmlSchemaCloneWildcardNsConstraints(ctxt, + completeWild, group->attributeWildcard) == -1) + return (-1); + (*completeWild)->processContents = group->attributeWildcard->processContents; + /* + * Although the complete wildcard might not correspond to any + * node in the schema, we will save this context node. + */ + (*completeWild)->node = group->attributeWildcard->node; + + } else if (xmlSchemaIntersectWildcards(ctxt, *completeWild, group->attributeWildcard) == -1) { + xmlSchemaFreeWildcard(*completeWild); + return (-1); + } + } + } + attrs = attrs->next; + } + + return (0); +} + +/** + * xmlSchemaMatchesWildcardNs: + * @wild: the wildcard + * @ns: the namespace + * + * + * Returns 1 if the given namespace matches the wildcard, + * 0 otherwise. + */ +static int +xmlSchemaMatchesWildcardNs(xmlSchemaWildcardPtr wild, const xmlChar* ns) +{ + if (wild == NULL) + return(0); + + if (wild->any) + return(1); + else if (wild->nsSet != NULL) { + xmlSchemaWildcardNsPtr cur; + + cur = wild->nsSet; + while (cur != NULL) { + if (xmlStrEqual(cur->value, ns)) + return(1); + cur = cur->next; + } + } else if ((wild->negNsSet != NULL) && (ns != NULL) && + (!xmlStrEqual(wild->negNsSet->value, ns))) + return(1); + + return(0); +} + +/** + * xmlSchemaBuildAttributeValidation: + * @ctxt: the schema parser context + * @type: the complex type definition + * + * + * Builds the wildcard and the attribute uses on the given complex type. + * Returns -1 if an internal error occurs, 0 otherwise. + */ +static int +xmlSchemaBuildAttributeValidation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaTypePtr type) +{ + xmlSchemaTypePtr baseType = NULL; + xmlSchemaAttributeLinkPtr cur, base, tmp, id = NULL, prev = NULL, uses = NULL, + lastUse = NULL, lastBaseUse = NULL; + xmlSchemaAttributePtr attrs; + xmlSchemaTypePtr anyType; + int baseIsAnyType = 0; + + anyType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE); + /* + * Complex Type Definition with complex content Schema Component. + * + * Attribute uses. + */ + if (type->attributeUses != NULL) { + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaBuildAttributeValidation: " + "attribute uses already builded.\n", + NULL, NULL); + return (-1); + } + if (type->baseType == NULL) { + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaBuildAttributeValidation: " + "complex type \"%s\" has no base type.\n", + type->name, NULL); + return (-1); + } + + baseType = type->baseType; + if (baseType == NULL) { + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaBuildAttributeValidation: " + "type has no base type.\n", + NULL, NULL); + return (-1); + } + + if (baseType == anyType) + baseIsAnyType = 1; + /* + * Inherit the attribute uses of the base type. + */ + /* + * NOTE: It is allowed to "extend" the anyType complex type. + */ + if (!baseIsAnyType) { + if (baseType != NULL) { + for (cur = baseType->attributeUses; cur != NULL; cur = cur->next) { + tmp = (xmlSchemaAttributeLinkPtr) + xmlMalloc(sizeof(xmlSchemaAttributeLink)); + if (tmp == NULL) { + xmlSchemaPErrMemory(ctxt, + "building attribute uses of complexType", NULL); + return (-1); + } + tmp->attr = cur->attr; + tmp->next = NULL; + if (type->attributeUses == NULL) { + type->attributeUses = tmp; + } else + lastBaseUse->next = tmp; + lastBaseUse = tmp; + } + } + } + if ((type->subtypes != NULL) && + ((type->subtypes->type == XML_SCHEMA_TYPE_COMPLEX_CONTENT) || + (type->subtypes->type == XML_SCHEMA_TYPE_SIMPLE_CONTENT))) { + attrs = type->subtypes->subtypes->attributes; + type->attributeWildcard = type->subtypes->subtypes->attributeWildcard; + } else { + /* Short hand form of the complexType. */ + attrs = type->attributes; + } + /* + * Handle attribute wildcards. + */ + if (xmlSchemaBuildCompleteAttributeWildcard(ctxt, + attrs, &type->attributeWildcard) == -1) { + if ((type->attributeWildcard != NULL) && + /* Either we used the short hand form... */ + ((type->subtypes == NULL) || + /* Or complexType -> restriction/extension */ + (type->attributeWildcard != type->subtypes->subtypes->attributeWildcard))) + type->flags |= XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD; + return (-1); + } + /* + * TODO: This "onwed_attr_wildcard" is quite sensless: we should + * create the wildcard right from the start on the complexType, + * rather than on the <restriction>/<extension>. + */ + if ((type->attributeWildcard != NULL) && + /* Either we used the short hand form... */ + ((type->subtypes == NULL) || + /* Or complexType -> restriction/extension */ + (type->attributeWildcard != type->subtypes->subtypes->attributeWildcard))) + type->flags |= XML_SCHEMAS_TYPE_OWNED_ATTR_WILDCARD; + + if ((type->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION) && + ((baseIsAnyType) || + ((baseType != NULL) && + (baseType->type == XML_SCHEMA_TYPE_COMPLEX) && + (baseType->attributeWildcard != NULL)))) { + if (type->attributeWildcard != NULL) { + /* + * Union the complete wildcard with the base wildcard. + */ + if (xmlSchemaUnionWildcards(ctxt, type->attributeWildcard, + baseType->attributeWildcard) == -1) + return (-1); + } else { + /* + * Just inherit the wildcard. + */ + type->attributeWildcard = baseType->attributeWildcard; + } + } + + if (type->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION) { + if (type->attributeWildcard != NULL) { + /* + * Derivation Valid (Restriction, Complex) + * 4.1 The {base type definition} must also have one. + */ + if (baseType->attributeWildcard == NULL) { + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_1, + "The derived type \"%s\" has an attribute wildcard, " + "but the base type \"%s\" does not have one.\n", + type->name, baseType->name); + return (1); + } else if (xmlSchemaIsWildcardNsConstraintSubset(ctxt, + type->attributeWildcard, baseType->attributeWildcard) == 0) { + /* 4.2 */ + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_2, + "The wildcard in the derived type \"%s\" is not a valid " + "subset of the one in the base type \"%s\".\n", + type->name, baseType->name); + return (1); + } + /* 4.3 Unless the {base type definition} is the ·ur-type + * definition·, the complex type definition's {attribute + * wildcard}'s {process contents} must be identical to or + * stronger than the {base type definition}'s {attribute + * wildcard}'s {process contents}, where strict is stronger + * than lax is stronger than skip. + */ + if ((type->baseType != anyType) && + (type->attributeWildcard->processContents < + baseType->attributeWildcard->processContents)) { + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_3, + "The process contents of the wildcard in the " + "derived type \"%s\" is weaker than " + "that in the base type \"%s\".\n", + type->name, baseType->name); + return (1); + } + } + } else if (type->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION) { + /* + * Derivation Valid (Extension) + * At this point the type and the base have both, either + * no wildcard or a wildcard. + */ + if ((baseType->attributeWildcard != NULL) && + (baseType->attributeWildcard != type->attributeWildcard)) { + /* 1.3 */ + if (xmlSchemaIsWildcardNsConstraintSubset(ctxt, + baseType->attributeWildcard, type->attributeWildcard) == 0) { + xmlSchemaPErr(ctxt, type->node, XML_SCHEMAP_COS_CT_EXTENDS_1_3, + "The wildcard in the derived type \"%s\" is not a valid " + "superset of the one in the base type \"%s\".\n", + type->name, baseType->name); + return (1); + } + } + } + + /* + * Gather attribute uses defined by this type. + */ + if (attrs != NULL) { + if (xmlSchemaBuildAttributeUsesOwned(ctxt, attrs, + &uses, &lastUse) == -1) { + return (-1); + } + } + /* 3.4.6 -> Complex Type Definition Properties Correct 4. + * "Two distinct attribute declarations in the {attribute uses} must + * not have identical {name}s and {target namespace}s." + * + * For "extension" this is done further down. + */ + if ((uses != NULL) && ((type->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION) == 0)) { + cur = uses; + while (cur != NULL) { + tmp = cur->next; + while (tmp != NULL) { + if ((xmlStrEqual(xmlSchemaGetOnymousAttrName(cur->attr), + xmlSchemaGetOnymousAttrName(tmp->attr))) && + (xmlStrEqual(xmlSchemaGetOnymousTargetNsURI((xmlSchemaTypePtr) cur->attr ), + xmlSchemaGetOnymousTargetNsURI((xmlSchemaTypePtr) tmp->attr)))) { + + xmlSchemaPErr(ctxt, cur->attr->node, XML_SCHEMAP_CT_PROPS_CORRECT_4, + "ct-props-correct.4: Duplicate attribute use with the name \"%s\" specified\n", + xmlSchemaGetOnymousAttrName(cur->attr), NULL); + break; + } + tmp = tmp->next; + } + cur = cur->next; + } + } + if (type->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION) { + /* + * Derive by restriction. + */ + if (baseIsAnyType) { + type->attributeUses = uses; + } else { + int found; + + cur = uses; + while (cur != NULL) { + found = 0; + base = type->attributeUses; + while (base != NULL) { + if ((xmlStrEqual(xmlSchemaGetOnymousAttrName(cur->attr), + xmlSchemaGetOnymousAttrName(base->attr))) && + (xmlStrEqual(xmlSchemaGetOnymousTargetNsURI((xmlSchemaTypePtr) cur->attr), + xmlSchemaGetOnymousTargetNsURI((xmlSchemaTypePtr) base->attr)))) { + + found = 1; + if ((cur->attr->occurs == XML_SCHEMAS_ATTR_USE_OPTIONAL) && + (base->attr->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED)) { + /* + * derivation-ok-restriction 2.1.1 + */ + xmlSchemaPErr(ctxt, cur->attr->node, + XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_1, + "derivation-ok-restriction.2.1.1: " + "The \"optional\" attribute " + "use \"%s\" is inconsistent with a matching " + "\"required\" attribute use of the base type\n", + xmlSchemaGetOnymousAttrName(cur->attr), NULL); + } else if ((cur->attr->occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED) && + (base->attr->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED)) { + /* + * derivation-ok-restriction 3 + */ + xmlSchemaPErr(ctxt, cur->attr->node, XML_SCHEMAP_DERIVATION_OK_RESTRICTION_3, + "derivation-ok-restriction.3: " + "The \"required\" attribute use \"%s\" of the base type " + "does not have a matching attribute use in the derived type\n", + xmlSchemaGetOnymousAttrName(cur->attr), NULL); + + } else { + /* + * Override the attribute use. + */ + base->attr = cur->attr; + } + /* + * TODO: derivation-ok-restriction 2.1.2 ({type definition} must be validly derived) + * TODO: derivation-ok-restriction 2.1.3 + */ + break; + } + base = base->next; + } + + if (!found) { + if (cur->attr->occurs != XML_SCHEMAS_ATTR_USE_PROHIBITED) { + /* + * derivation-ok-restriction 2.2 + */ + if ((type->attributeWildcard != NULL) && + xmlSchemaMatchesWildcardNs(type->attributeWildcard, + cur->attr->targetNamespace)) + found = 1; + + if (!found) { + xmlSchemaPErr(ctxt, cur->attr->node, XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_2, + "derivation-ok-restriction.2.2: " + "The attribute use \"%s\" has neither a matching attribute use, " + "nor a matching wildcard in the base type\n", + xmlSchemaGetOnymousAttrName(cur->attr), NULL); + } else { + /* + * Add the attribute use. + * + * Note that this may lead to funny derivation error reports, if + * multiple equal attribute uses exist; but this is not + * allowed anyway, and it will be reported beforehand. + */ + tmp = cur; + if (prev != NULL) + prev->next = cur->next; + else + uses = cur->next; + cur = cur->next; + if (type->attributeUses == NULL) { + type->attributeUses = tmp; + } else + lastBaseUse->next = tmp; + lastBaseUse = tmp; + + continue; + } + } + } + prev = cur; + cur = cur->next; + } + if (uses != NULL) + xmlSchemaFreeAttributeUseList(uses); + } + } else if (type->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION) { + /* + * The spec allows only appending, and not other kinds of extensions. + * + * This ensures: Schema Component Constraint: Derivation Valid (Extension) : 1.2 + */ + if (uses != NULL) { + if (type->attributeUses == NULL) { + type->attributeUses = uses; + } else + lastBaseUse->next = uses; + } + } else { + /* + * Derive implicitely from the ur-type. + */ + type->attributeUses = uses; + } + /* + * 3.4.6 -> Complex Type Definition Properties Correct + */ + if (type->attributeUses != NULL) { + cur = type->attributeUses; + prev = NULL; + while (cur != NULL) { + /* + * 4. Two distinct attribute declarations in the {attribute uses} must + * not have identical {name}s and {target namespace}s. + * + * Note that this was already done for "restriction" and types derived from + * the ur-type. + */ + if (type->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION) { + tmp = cur->next; + while (tmp != NULL) { + if ((xmlStrEqual(xmlSchemaGetOnymousAttrName(cur->attr), + xmlSchemaGetOnymousAttrName(tmp->attr))) && + (xmlStrEqual(xmlSchemaGetOnymousTargetNsURI((xmlSchemaTypePtr) cur->attr ), + xmlSchemaGetOnymousTargetNsURI((xmlSchemaTypePtr) tmp->attr)))) { + + xmlSchemaPErr(ctxt, cur->attr->node, XML_SCHEMAP_CT_PROPS_CORRECT_4, + "ct-props-correct.4: Duplicate attribute use with the name \"%s\" specified\n", + xmlSchemaGetOnymousAttrName(cur->attr), NULL); + break; + } + tmp = tmp->next; + } + } + /* + * 5. Two distinct attribute declarations in the {attribute uses} must + * not have {type definition}s which are or are derived from ID. + */ + if ((cur->attr->subtypes != NULL) && + (xmlSchemaIsDerivedFromBuiltInType(ctxt, (xmlSchemaTypePtr) cur->attr, XML_SCHEMAS_ID))) { + if (id != NULL) { + xmlSchemaPErr(ctxt, cur->attr->node, XML_SCHEMAP_CT_PROPS_CORRECT_5, + "ct-props-correct.5: Two attribute declarations, " + "\"%s\" and \"%s\" have types which derived from ID\n", + xmlSchemaGetOnymousAttrName(id->attr), + xmlSchemaGetOnymousAttrName(cur->attr)); + } + id = cur; + } + /* + * Remove "prohibited" attribute uses. The reason this is done at this late + * stage is to be able to catch dublicate attribute uses. So we had to keep + * prohibited uses in the list as well. + */ + if (cur->attr->occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED) { + tmp = cur; + if (prev == NULL) + type->attributeUses = cur->next; + else + prev->next = cur->next; + cur = cur->next; + xmlFree(tmp); + } else { + prev = cur; + cur = cur->next; + } + } + } + /* + * TODO: This check should be removed if we are 100% sure of + * the base type attribute uses already being built. + */ + if ((baseType != NULL) && (!baseIsAnyType) && + (baseType->type == XML_SCHEMA_TYPE_COMPLEX) && + (baseType->contentType == XML_SCHEMA_CONTENT_UNKNOWN)) { + xmlSchemaPErr(ctxt, baseType->node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaBuildAttributeValidation: " + "attribute uses not builded on base type \"%s\".\n", + baseType->name, NULL); + } + return (0); +} + +/** + * xmlSchemaTypeFinalContains: + * @schema: the schema + * @type: the type definition + * @final: the final + * + * Evaluates if a type definition contains the given "final". + * This does take "finalDefault" into account as well. + * + * Returns 1 if the type does containt the given "final", + * 0 otherwise. + */ +static int +xmlSchemaTypeFinalContains(xmlSchemaPtr schema, xmlSchemaTypePtr type, int final) +{ + int tfinal = final, tflags = type->flags; + + if (type == NULL) + return (0); + if (type->flags & XML_SCHEMAS_TYPE_FINAL_DEFAULT) { + switch (final) { + case XML_SCHEMAS_TYPE_FINAL_RESTRICTION: + tfinal = XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION; + break; + case XML_SCHEMAS_TYPE_FINAL_EXTENSION: + tfinal = XML_SCHEMAS_FINAL_DEFAULT_EXTENSION; + break; + case XML_SCHEMAS_TYPE_FINAL_LIST: + tfinal = XML_SCHEMAS_FINAL_DEFAULT_LIST; + break; + case XML_SCHEMAS_TYPE_FINAL_UNION: + tfinal = XML_SCHEMAS_FINAL_DEFAULT_UNION; + break; + } + tflags = schema->flags; + } + if (tflags & tfinal) + return (1); + else + return (0); + +} + +/** + * xmlSchemaGetUnionSimpleTypeMemberTypes: + * @type: the Union Simple Type + * + * Returns a list of member types of @type if existing, + * returns NULL otherwise. + */ +static xmlSchemaTypeLinkPtr +xmlSchemaGetUnionSimpleTypeMemberTypes(xmlSchemaTypePtr type) +{ + while (type != NULL) { + if (type->memberTypes != NULL) + return (type->memberTypes); + else + type = type->baseType; + } + return (NULL); +} + +/** + * xmlSchemaGetListSimpleTypeItemType: + * @type: the simple type definition + * + * Returns the item type definition of the list simple type. + */ +static xmlSchemaTypePtr +xmlSchemaGetListSimpleTypeItemType(xmlSchemaTypePtr type) +{ + if ((type->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) == 0) + return (NULL); + /* + * Note: In libxml2, the built-in types do not reflect + * the datatype hierarchy (yet?) - we have to treat them + * in a special way. + */ + if (type->type == XML_SCHEMA_TYPE_BASIC) + return (xmlSchemaGetBuiltInListSimpleTypeItemType(type)); + if (type->subtypes->type == XML_SCHEMA_TYPE_LIST) + /* 1 If the <list> alternative is chosen, then the type + * definition ·resolved· to by the ·actual value· of the + * itemType [attribute] of <list>, if present, otherwise + * the type definition corresponding to the <simpleType> + * among the [children] of <list>. + */ + return (type->subtypes->subtypes); + else { + /* 2 If the <restriction> option is chosen, then the + * {item type definition} of the {base type definition}. + */ + return (xmlSchemaGetListSimpleTypeItemType(type->baseType)); + } +} + +/** + * xmlSchemaCheckCOSSTDerivedOK: + * @type: the derived simple type definition + * @baseType: the base type definition + * + * Checks wheter @type can be validly + * derived from @baseType. + * + * Returns 0 on success, an positive error code otherwise. + */ +static int +xmlSchemaCheckCOSSTDerivedOK(xmlSchemaPtr schema, + xmlSchemaTypePtr type, + xmlSchemaTypePtr baseType, + int subset) +{ + /* + * Schema Component Constraint: Type Derivation OK (Simple) + * + * + * 1 They are the same type definition. + * TODO: The identy check might have to be more complex than this. + */ + if (type == baseType) + return (0); + /* + * 2.1 restriction is not in the subset, or in the {final} + * of its own {base type definition}; + */ + if ((subset & XML_SCHEMAS_TYPE_FINAL_RESTRICTION) || + (xmlSchemaTypeFinalContains(schema, + type->baseType, XML_SCHEMAS_TYPE_FINAL_RESTRICTION))) { + return (XML_SCHEMAP_COS_ST_DERIVED_OK_2_1); + } + /* 2.2 */ + if (type->baseType == baseType) { + /* + * 2.2.1 D's ·base type definition· is B. + */ + return (0); + } + /* + * 2.2.2 D's ·base type definition· is not the ·ur-type definition· + * and is validly derived from B given the subset, as defined by this + * constraint. + */ + if ((type->baseType != xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE)) && + (xmlSchemaCheckCOSSTDerivedOK(schema, type->baseType, baseType, subset) == 0)) { + return (0); + } + /* + * 2.2.3 D's {variety} is list or union and B is the ·simple ur-type + * definition·. + */ + if (((type->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) || + (type->flags & XML_SCHEMAS_TYPE_VARIETY_UNION)) && + (baseType == xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE))) { + return (0); + } + /* + * 2.2.4 B's {variety} is union and D is validly derived from a type + * definition in B's {member type definitions} given the subset, as + * defined by this constraint. + * + * NOTE: This seems not to involve built-in types, since there is no + * built-in Union Simple Type. + */ + if (baseType->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) { + xmlSchemaTypeLinkPtr cur; + + cur = baseType->memberTypes; + while (cur != NULL) { + if (xmlSchemaCheckCOSSTDerivedOK(schema, type, + cur->type, subset) == 0) + return (0); + cur = cur->next; + } + } + + return (XML_SCHEMAP_COS_ST_DERIVED_OK_2_2); +} + + +/** + * xmlSchemaCheckSTPropsCorrect: + * @ctxt: the schema parser context + * @type: the simple type definition + * + * Checks st-props-correct. + * + * Returns 0 if the properties are correct, + * if not, a positive error code and -1 on internal + * errors. + */ +static int +xmlSchemaCheckSTPropsCorrect(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + xmlSchemaTypePtr baseType = type->baseType, anySimpleType, + anyType; + + /* + * Schema Component Constraint: Simple Type Definition Properties Correct + * + * NOTE: This is somehow redundant, since we actually built a simple type + * to have all the needed information; this acts as an self test. + */ + anySimpleType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE); + anyType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE); + /* + * TODO: 1 The values of the properties of a simple type definition must be as + * described in the property tableau in Datatype definition, modulo the + * impact of Missing Sub-components (§5.3). + */ + /* Base type: If the datatype has been ·derived· by ·restriction· + * then the Simple Type Definition component from which it is ·derived·, + * otherwise the Simple Type Definition for anySimpleType (§4.1.6). + */ + if (baseType == NULL) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_ST_PROPS_CORRECT_1, + "Simple type \"%s\" does not have a base type.\n", + type->name, NULL); + return (XML_SCHEMAP_ST_PROPS_CORRECT_1); + } + if ((baseType->type != XML_SCHEMA_TYPE_SIMPLE) && + ((baseType->type != XML_SCHEMA_TYPE_BASIC) || + (baseType == anyType))) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_ST_PROPS_CORRECT_1, + "Simple type \"%s\": its base type \"%s\" is not a simple " + "type.\n", + type->name, baseType->name); + return (XML_SCHEMAP_ST_PROPS_CORRECT_1); + } + if ((baseType != anySimpleType) && + (type->subtypes->type != XML_SCHEMA_TYPE_RESTRICTION)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_ST_PROPS_CORRECT_1, + "Simple type \"%s\" (not derived by restriction) must have" + "the simple ur-type definition as base type, not \"%s\".\n", + type->name, NULL); + return (XML_SCHEMAP_ST_PROPS_CORRECT_1); + } + /* + * Variety: One of {atomic, list, union}. + */ + if (((type->flags & XML_SCHEMAS_TYPE_VARIETY_ATOMIC) == 0) && + ((type->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) == 0) && + ((type->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) == 0)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_ST_PROPS_CORRECT_1, + "Simple type \"%s\" has an absent variety.\n", + type->name, NULL); + return (XML_SCHEMAP_ST_PROPS_CORRECT_1); + } + /* TODO: Finish this. */ + + /* + * 2 All simple type definitions must be derived ultimately from the ·simple + * ur-type definition (so· circular definitions are disallowed). That is, it + * must be possible to reach a built-in primitive datatype or the ·simple + * ur-type definition· by repeatedly following the {base type definition}. + */ + baseType = type->baseType; + while ((baseType != NULL) && (baseType->type != XML_SCHEMA_TYPE_BASIC)) { + if (baseType->contentType == XML_SCHEMA_CONTENT_UNKNOWN) + xmlSchemaTypeFixup(baseType, ctxt, NULL); + if (baseType == anySimpleType) + break; + else if (baseType == type) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_ST_PROPS_CORRECT_2, + "Simple type \"%s\" is not derived from the simple " + "ur-type definition (circular definitions are disallowed).\n", + type->name, NULL); + return (XML_SCHEMAP_ST_PROPS_CORRECT_2); + } + baseType = baseType->baseType; + } + /* + * 3 The {final} of the {base type definition} must not contain restriction. + */ + if (xmlSchemaTypeFinalContains(ctxt->schema, baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_ST_PROPS_CORRECT_3, + "Simple type \"%s\": the \"final\" of its base type " + "\"%s\" must not contain \"restriction\".\n", + type->name, baseType->name); + return (XML_SCHEMAP_ST_PROPS_CORRECT_3); + } + return (0); +} + +/** + * xmlSchemaCheckDerivationValidSimpleRestriction: + * @ctxt: the schema parser context + * @type: the simple type definition + * + * Checks if the given @type (simpleType) is derived + * validly by restriction. + * + * Returns -1 on internal errors, 0 if the type is validly derived, + * a positive error code otherwise. + */ +static int +xmlSchemaCheckCOSSTRestricts(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + + if (type->type != XML_SCHEMA_TYPE_SIMPLE) { + xmlSchemaPErr(ctxt, type->node, + XML_ERR_INTERNAL_ERROR, + "xmlSchemaCheckDerivationValidSimpleRestriction: the given " + "type \"%s\" is not a user-derived simpleType.\n", + type->name, NULL); + return (-1); + } + + if (type->flags & XML_SCHEMAS_TYPE_VARIETY_ATOMIC) { + xmlSchemaTypePtr primitive; + /* + * 1.1 The {base type definition} must be an atomic simple + * type definition or a built-in primitive datatype. + */ + if ((type->baseType->flags & XML_SCHEMAS_TYPE_VARIETY_ATOMIC) == 0) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_1_1, + "Atomic simple type \"%s\": " + "its base type \"%s\" is not an atomic simple type.\n", + type->name, NULL); + return (XML_SCHEMAP_COS_ST_RESTRICTS_1_1); + } + /* 1.2 The {final} of the {base type definition} must not contain + * restriction. + */ + /* OPTIMIZE: This is already done in xmlSchemaCheckStPropsCorrect */ + if (xmlSchemaTypeFinalContains(ctxt->schema, type->baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_1_2, + "Atomic simple type \"%s\": the \"final\" of its base type " + "\"%s\" must not contain \"restriction\".\n", + type->name, type->baseType->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_1_2); + } + + /* + * 1.3.1 DF must be an allowed constraining facet for the {primitive + * type definition}, as specified in the appropriate subsection of 3.2 + * Primitive datatypes. + */ + if (type->facets != NULL) { + xmlSchemaFacetPtr facet; + int ok = 1; + + primitive = xmlSchemaGetPrimitiveType(type); + if (primitive == NULL) { + xmlSchemaPErr(ctxt, type->node, + XML_ERR_INTERNAL_ERROR, + "xmlSchemaCheckDerivationValidSimpleRestriction: failed " + "to get primitive type of type \"%s\".\n", + type->name, NULL); + return (-1); + } + facet = type->facets; + do { + if (xmlSchemaIsBuiltInTypeFacet(primitive, facet->type) == 0) { + xmlSchemaPErrExt(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1, + NULL, NULL, NULL, + "Atomic simple type \"%s\": the facet \"%s\" " + "is not allowed on primitive type \"%s\".\n", + type->name, + (const xmlChar *) + xmlSchemaFacetTypeToString(facet->type), + BAD_CAST primitive->name, NULL, NULL); + + ok = 0; + } + facet = facet->next; + } while (facet != NULL); + if (ok == 0) + return (XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1); + + } + /* + * TODO: 1.3.2 (facet derivation) + */ + } else if (type->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) { + xmlSchemaTypePtr itemType = NULL; + + itemType = xmlSchemaGetListSimpleTypeItemType(type); + if (itemType == NULL) { + xmlSchemaPErr(ctxt, type->node, + XML_ERR_INTERNAL_ERROR, + "Internal error: xmlSchemaCheckDerivationValidSimpleRestriction: " + "failed to evaluate the item type of type \"%s\".\n", + type->name, NULL); + return (-1); + } + /* + * 2.1 The {item type definition} must have a {variety} of atomic or + * union (in which case all the {member type definitions} + * must be atomic). + */ + if (((itemType->flags & XML_SCHEMAS_TYPE_VARIETY_ATOMIC) == 0) && + ((itemType->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) == 0)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_2_1, + "List simple type \"%s\": its item type \"%s\" " + "is not an atomic or union simple type.\n", + type->name, itemType->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_1); + } else if (itemType->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) { + xmlSchemaTypeLinkPtr member; + + member = itemType->memberTypes; + while (member != NULL) { + if ((member->type->flags & + XML_SCHEMAS_TYPE_VARIETY_ATOMIC) == 0) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_2_1, + "List simple type \"%s\": its item type " + "is a union simple type, but the member type " + "\"%s\" of this item type is not an \"atomic\" " + "simple type.\n", + type->name, member->type->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_1); + } + member = member->next; + } + } + + if (type->baseType == xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE)) { + xmlSchemaFacetPtr facet; + /* + * This is the case if we have: <simpleType><list .. + */ + /* + * 2.3.1 + * 2.3.1.1 The {final} of the {item type definition} must not + * contain list. + */ + if (xmlSchemaTypeFinalContains(ctxt->schema, + itemType, XML_SCHEMAS_TYPE_FINAL_LIST)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_1, + "List simple type \"%s\": the \"final\" of its item type " + "\"%s\" must not contain \"list\".\n", + type->name, itemType->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_1); + } + /* + * 2.3.1.2 The {facets} must only contain the whiteSpace + * facet component. + */ + if (type->facets != NULL) { + facet = type->facets; + do { + if (facet->type != XML_SCHEMA_FACET_WHITESPACE) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2, + "List simple type \"%s\": the facet \"%s\" " + "is not allowed.\n", + type->name, + BAD_CAST xmlSchemaFacetTypeToString(facet->type)); + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2); + } + facet = facet->next; + } while (facet != NULL); + } + /* + * TODO: Datatypes states: + * A ·list· datatype can be ·derived· from an ·atomic· datatype + * whose ·lexical space· allows space (such as string or anyURI)or + * a ·union· datatype any of whose {member type definitions}'s + * ·lexical space· allows space. + */ + } else { + /* + * This is the case if we have: <simpleType><restriction ... + */ + /* + * 2.3.2 + * 2.3.2.1 The {base type definition} must have a {variety} of list. + */ + if ((type->baseType->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) == 0) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1, + "List simple type \"%s\": its base type \"%s\" must " + "have a variety of list.\n", + type->name, type->baseType->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1); + } + /* + * 2.3.2.2 The {final} of the {base type definition} must not + * contain restriction. + */ + if (xmlSchemaTypeFinalContains(ctxt->schema, type->baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2, + "List simple type \"%s\": its base type \"%s\" must not " + "have a \"final\" containing \"restriction\".\n", + type->name, type->baseType->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2); + } + /* + * 2.3.2.3 The {item type definition} must be validly derived + * from the {base type definition}'s {item type definition} given + * the empty set, as defined in Type Derivation OK (Simple) (§3.14.6). + */ + { + xmlSchemaTypePtr baseItemType; + + baseItemType = xmlSchemaGetListSimpleTypeItemType(type->baseType); + if (baseItemType == NULL) { + xmlSchemaPErr(ctxt, type->node, + XML_ERR_INTERNAL_ERROR, + "xmlSchemaCheckDerivationValidSimpleRestriction: " + "List simple type \"%s\": failed to " + "evaluate the item type of its base type \"%s\".\n", + type->name, type->baseType->name); + return (-1); + } + if ((itemType != baseItemType) && + (xmlSchemaCheckCOSSTDerivedOK(ctxt->schema, itemType, + baseItemType, 0) != 0)) { + xmlSchemaPErrExt(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3, NULL, NULL, NULL, + "List simple type \"%s\": its item type \"%s\" is not " + "validly derived from the item type \"%s\" of the " + "base type \"%s\" as defined in Type Derivation OK " + "(Simple).\n", + type->name, itemType->name, baseItemType->name, + type->baseType->name, NULL); + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3); + } + } + + if (type->facets != NULL) { + xmlSchemaFacetPtr facet; + int ok = 1; + /* + * 2.3.2.4 Only length, minLength, maxLength, whiteSpace, pattern + * and enumeration facet components are allowed among the {facets}. + */ + facet = type->facets; + do { + switch (facet->type) { + case XML_SCHEMA_FACET_LENGTH: + case XML_SCHEMA_FACET_MINLENGTH: + case XML_SCHEMA_FACET_MAXLENGTH: + case XML_SCHEMA_FACET_WHITESPACE: + /* + * TODO: 2.5.1.2 List datatypes + * The value of ·whiteSpace· is fixed to the value collapse. + */ + case XML_SCHEMA_FACET_PATTERN: + case XML_SCHEMA_FACET_ENUMERATION: + break; + default: { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4, + "List simple type \"%s\": the facet \"%s\" " + "is not allowed.\n", + type->name, + BAD_CAST xmlSchemaFacetTypeToString(facet->type)); + /* + * We could return, but it's nicer to report all + * invalid facets. + */ + ok = 0; + } + } + facet = facet->next; + } while (facet != NULL); + if (ok == 0) + return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4); + /* + * TODO: 2.3.2.5 For each facet in the {facets} (call this DF), if there + * is a facet of the same kind in the {facets} of the {base type + * definition} (call this BF),then the DF's {value} must be a valid + * restriction of BF's {value} as defined in [XML Schemas: Datatypes]. + */ + } + + + } + } else if (type->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) { + /* + * 3.1 The {member type definitions} must all have {variety} of + * atomic or list. + */ + xmlSchemaTypeLinkPtr member; + + member = type->memberTypes; + while (member != NULL) { + if (((member->type->flags & + XML_SCHEMAS_TYPE_VARIETY_ATOMIC) == 0) && + ((member->type->flags & + XML_SCHEMAS_TYPE_VARIETY_LIST) == 0)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_3_1, + "Union simple type \"%s\": the member type " + "\"%s\" is not an \"atomic\" simple type.\n", + type->name, member->type->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_1); + } + member = member->next; + } + /* + * 3.3.1 If the {base type definition} is the ·simple ur-type + * definition· + */ + if (type->baseType == xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE)) { + /* + * 3.3.1.1 All of the {member type definitions} must have a + * {final} which does not contain union. + */ + member = type->memberTypes; + while (member != NULL) { + if (xmlSchemaTypeFinalContains(ctxt->schema, member->type, + XML_SCHEMAS_TYPE_FINAL_UNION)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1, + "Union simple type \"%s\": the \"final\" of member type " + "\"%s\" contains \"union\".\n", + type->name, member->type->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1); + } + member = member->next; + } + /* + * 3.3.1.2 The {facets} must be empty. + */ + if (type->facetSet != NULL) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2, + "Union simple type \"%s\": the facets must be empty.\n", + type->name, NULL); + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2); + } + } else { + /* + * 3.3.2.1 The {base type definition} must have a {variety} of union. + */ + if ((type->baseType->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) == 0) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1, + "Union simple type \"%s\": its base type \"%s\" has not a " + "variety of union.\n", + type->name, type->baseType->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1); + } + /* + * 3.3.2.2 The {final} of the {base type definition} must not contain restriction. + */ + if (xmlSchemaTypeFinalContains(ctxt->schema, type->baseType, + XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2, + "Union simple type \"%s\": the \"final\" of its base " + "type \"%s\" must not contain \"restriction\".\n", + type->name, type->baseType->name); + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2); + } + /* + * 3.3.2.3 The {member type definitions}, in order, must be validly + * derived from the corresponding type definitions in the {base + * type definition}'s {member type definitions} given the empty set, + * as defined in Type Derivation OK (Simple) (§3.14.6). + */ + { + xmlSchemaTypeLinkPtr baseMember; + + /* + * OPTIMIZE: if the type is restricting, it has no local defined + * member types and inherits the member types of the base type; + * thus a check for equality can be skipped. + */ + /* + * TODO: Even worse: I cannot see a scenario where a restricting + * union simple type can have other member types as the member + * types of it's base type. This check seems not necessary with + * respect to the derivation process in libxml2. + */ + if (type->memberTypes != NULL) { + member = type->memberTypes; + baseMember = xmlSchemaGetUnionSimpleTypeMemberTypes(type->baseType); + if ((member == NULL) && (baseMember != NULL)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAS_ERR_INTERNAL, + "Internal error: " + "xmlSchemaCheckDerivationValidSimpleRestriction " + "(3.3.2.3), union simple type \"%s\", unequal number " + "of member types in the base type\n", + type->name, NULL); + } + while (member != NULL) { + if (baseMember == NULL) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAS_ERR_INTERNAL, + "Internal error: " + "xmlSchemaCheckDerivationValidSimpleRestriction " + "(3.3.2.3), union simple type \"%s\", unequal number " + "of member types in the base type\n", + type->name, NULL); + } + if ((member->type != baseMember->type) && + (xmlSchemaCheckCOSSTDerivedOK(ctxt->schema, + member->type, baseMember->type, 0) != 0)) { + xmlSchemaPErrExt(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3, NULL, + NULL, NULL, + "Union simple type \"%s\": its member type " + "\"%s\" is not validly derived from its " + "corresponding member type \"%s\" of the base " + "type \"%s\" as defined in Type Derivation OK " + "(Simple).\n", + type->name, member->type->name, + baseMember->type->name, + type->baseType->name, NULL); + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3); + } + member = member->next; + baseMember = baseMember->next; + } + } + } + /* + * 3.3.2.4 Only pattern and enumeration facet components are + * allowed among the {facets}. + */ + if (type->facets != NULL) { + xmlSchemaFacetPtr facet; + int ok = 1; + + facet = type->facets; + do { + if ((facet->type != XML_SCHEMA_FACET_PATTERN) && + (facet->type != XML_SCHEMA_FACET_ENUMERATION)) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4, + "Union simple type \"%s\": the facet \"%s\" " + "is not allowed.\n", + type->name, + BAD_CAST xmlSchemaFacetTypeToString(facet->type)); + ok = 0; + } + facet = facet->next; + } while (facet != NULL); + if (ok == 0) + return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4); + + } + /* + * TODO: 3.3.2.5 (facet derivation) + */ + } + } + + return (0); +} + +/** + * xmlSchemaCheckSRCSimpleType: + * @ctxt: the schema parser context + * @type: the simple type definition + * + * Checks crc-simple-type constraints. + * + * Returns 0 if the constraints are satisfied, + * if not a positive error code and -1 on internal + * errors. + */ +static int +xmlSchemaCheckSRCSimpleType(xmlSchemaParserCtxtPtr ctxt, + xmlSchemaTypePtr type) +{ + /* + * NOTE: src-simple-type 2-4 are redundant, since the checks + * were are done for the corresponding <restriction>, <list> and <union> + * elements, but W3C wants a <simpleType> error as well, so it gets one. + * Maby this can be skipped in the future, if we get sure it's not needed. + */ + if (type->subtypes == NULL) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaCheckSRCSimpleType, " + "no subtype on simple type \"%s\".\n", + type->name, NULL); + return (-1); + } + /* + * src-simple-type.1 The corresponding simple type definition, if any, + * must satisfy the conditions set out in Constraints on Simple Type + * Definition Schema Components (§3.14.6). + */ + if ((xmlSchemaCheckSTPropsCorrect(ctxt, type) != 0) || + (xmlSchemaCheckCOSSTRestricts(ctxt, type) != 0)) { + /* + * TODO: Removed this, since it got annoying to get an + * extra error report, if anything failed until now. + * Enable this if needed. + */ + /* + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_SRC_SIMPLE_TYPE_1, + "Simple type \"%s\" does not satisfy the constraints " + "on simple type definitions.\n", + type->name, NULL); + */ + return (XML_SCHEMAP_SRC_SIMPLE_TYPE_1); + } + + if (type->subtypes->type == XML_SCHEMA_TYPE_RESTRICTION) { + /* + * src-simple-type.2 If the <restriction> alternative is chosen, + * either it must have a base [attribute] or a <simpleType> among its + * [children], but not both. + */ + if (((type->subtypes->base == NULL) && + ((type->subtypes->subtypes == NULL) || + (type->subtypes->subtypes->type != XML_SCHEMA_TYPE_SIMPLE))) || + ((type->subtypes->base != NULL) && + (type->subtypes->subtypes != NULL) && + (type->subtypes->subtypes->type == XML_SCHEMA_TYPE_SIMPLE))) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_SRC_SIMPLE_TYPE_2, + "Simple type \"%s\": " + "The <restriction> alternative is chosen, thus either the " + "\"base\" attribute or the <simpleType> child " + "must be present, but not both.\n", + type->name, NULL); + return (XML_SCHEMAP_SRC_SIMPLE_TYPE_2); + } + } else if (type->subtypes->type == XML_SCHEMA_TYPE_LIST) { + /* src-simple-type.3 If the <list> alternative is chosen, either it must have + * an itemType [attribute] or a <simpleType> among its [children], + * but not both. + * NOTE: baseType is set to the local simple type definiton, + * if existent, at parse time. This is a hack and not nice. + */ + if (((type->subtypes->base == NULL) && + (type->baseType == NULL)) || + ((type->subtypes->base != NULL) && + (type->subtypes->baseType != NULL))) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_SRC_SIMPLE_TYPE_3, + "Simple type \"%s\": " + "The <list> alternative is chosen, thus either the " + "\"itemType\" attribute or the <simpleType> child " + "must be present, but not both.\n", + type->name, NULL); + return (XML_SCHEMAP_SRC_SIMPLE_TYPE_3); + } + + + } else if (type->subtypes->type == XML_SCHEMA_TYPE_UNION) { + xmlSchemaTypeLinkPtr member; + xmlSchemaTypePtr ancestor, anySimpleType; + + anySimpleType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE); + + /* src-simple-type.4 Circular union type definition is disallowed. That is, if + * the <union> alternative is chosen, there must not be any entries + * in the memberTypes [attribute] at any depth which resolve to the + * component corresponding to the <simpleType>. + */ + member = type->memberTypes; + while (member != NULL) { + ancestor = member->type; + while ((ancestor != NULL) && (ancestor->type != XML_SCHEMA_TYPE_BASIC)) { + if (ancestor->contentType == XML_SCHEMA_CONTENT_UNKNOWN) + xmlSchemaTypeFixup(ancestor, ctxt, NULL); + if (ancestor == anySimpleType) + break; + else if (ancestor == type) { + xmlSchemaPErr(ctxt, type->node, + XML_SCHEMAP_SRC_SIMPLE_TYPE_4, + "Simple type \"%s\" is not derived from the simple " + "ur-type definition (circular definitions are disallowed).\n", + type->name, NULL); + return (XML_SCHEMAP_SRC_SIMPLE_TYPE_4); + } else if (ancestor->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) { + /* + * TODO: Although a list simple type must not have a union ST + * type as item type, which in turn has a list ST as member + * type, we will assume this here as well, since this check + * was not yet performed. + */ + + } + ancestor = ancestor->baseType; + } + member = member->next; + } + + } + + return (0); } /** @@ -4781,162 +7846,269 @@ static void xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl, xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) { + xmlSchemaTypePtr ctxtType; + if (typeDecl == NULL) return; + /* + * Do not allow the following types to be typefixed, prior to + * the corresponding simple/complex types. + */ + if (ctxt->ctxtType == NULL) { + switch (typeDecl->type) { + case XML_SCHEMA_TYPE_SIMPLE_CONTENT: + case XML_SCHEMA_TYPE_COMPLEX_CONTENT: + case XML_SCHEMA_TYPE_UNION: + case XML_SCHEMA_TYPE_RESTRICTION: + case XML_SCHEMA_TYPE_EXTENSION: + return; + default: + break; + } + } if (name == NULL) name = typeDecl->name; if (typeDecl->contentType == XML_SCHEMA_CONTENT_UNKNOWN) { switch (typeDecl->type) { - case XML_SCHEMA_TYPE_SIMPLE_CONTENT:{ - xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); - if (typeDecl->subtypes != NULL) + case XML_SCHEMA_TYPE_SIMPLE_CONTENT:{ + if (typeDecl->subtypes != NULL) { + if (typeDecl->subtypes->contentType == + XML_SCHEMA_CONTENT_UNKNOWN) { + xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, + NULL); + } typeDecl->contentType = typeDecl->subtypes->contentType; + } break; } case XML_SCHEMA_TYPE_RESTRICTION:{ + xmlSchemaTypePtr base = NULL; + + ctxt->ctxtType->flags |= + XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION; if (typeDecl->subtypes != NULL) xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); if (typeDecl->base != NULL) { - xmlSchemaTypePtr baseType; - - baseType = + base = xmlSchemaGetType(ctxt->schema, typeDecl->base, typeDecl->baseNs); - if (baseType == NULL) { + if (base == NULL) { xmlSchemaPErr(ctxt, typeDecl->node, - XML_SCHEMAP_UNKNOWN_BASE_TYPE, - "Schemas: type %s base type %s not found\n", - name, typeDecl->base); - } - typeDecl->baseType = baseType; - } - if (typeDecl->subtypes == NULL) - if (typeDecl->baseType != NULL) { - /* The base type might be not "type fixed" yet, + XML_SCHEMAP_SRC_RESOLVE, + "Restriction \"%s\": the QName \"%s\" of the " + "attribute \"base\" does not resolve to a schema " + "component.\n", + name, typeDecl->base); + } else if (base->contentType == + XML_SCHEMA_CONTENT_UNKNOWN) { + /* + * The base type might be not "type fixed" yet, * so do it now. */ - if (typeDecl->baseType->contentType == - XML_SCHEMA_CONTENT_UNKNOWN) - xmlSchemaTypeFixup(typeDecl->baseType, ctxt, NULL); + /* + * TODO: Is a check for circular derivation already + * done? + */ + xmlSchemaTypeFixup(base, ctxt, NULL); + } + } + if (ctxt->ctxtType->type == XML_SCHEMA_TYPE_COMPLEX) { + /* + * ComplexType restriction. + */ + /* + * Base type: The type definition ·resolved· to by the ·actual + * value· of the base [attribute] + */ + ctxt->ctxtType->baseType = base; + /* + * Content type. + */ + if (typeDecl->subtypes == NULL) + /* 1.1.1 */ + typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; + else if ((typeDecl->subtypes->subtypes == NULL) && + ((typeDecl->subtypes->type == + XML_SCHEMA_TYPE_ALL) + || (typeDecl->subtypes->type == + XML_SCHEMA_TYPE_SEQUENCE))) + /* 1.1.2 */ + typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; + else if ((typeDecl->subtypes->type == + XML_SCHEMA_TYPE_CHOICE) + && (typeDecl->subtypes->subtypes == NULL)) + /* 1.1.3 */ + typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; + else { + /* 1.2 and 2.X are applied at the other layer */ typeDecl->contentType = - typeDecl->baseType->contentType; + XML_SCHEMA_CONTENT_ELEMENTS; + } + } else { + /* + * SimpleType restriction. + */ + /* Base type: + * The Simple Type Definition component resolved to by + * the actual value of the base [attribute] or the + * <simpleType> [children], whichever is present. + */ + if ((base == NULL) && (typeDecl->subtypes != NULL)) { + base = typeDecl->subtypes; + ctxt->ctxtType->baseType = base; + if (base->contentType == XML_SCHEMA_CONTENT_UNKNOWN) + xmlSchemaTypeFixup(base, ctxt, NULL); } else - /* 1.1.1 */ - typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; - else if ((typeDecl->subtypes->subtypes == NULL) && - ((typeDecl->subtypes->type == - XML_SCHEMA_TYPE_ALL) - || (typeDecl->subtypes->type == - XML_SCHEMA_TYPE_SEQUENCE))) - /* 1.1.2 */ - typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; - else if ((typeDecl->subtypes->type == - XML_SCHEMA_TYPE_CHOICE) - && (typeDecl->subtypes->subtypes == NULL)) - /* 1.1.3 */ - typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; - else { - /* 1.2 and 2.X are applied at the other layer */ - typeDecl->contentType = - XML_SCHEMA_CONTENT_ELEMENTS; - } + ctxt->ctxtType->baseType = base; + + if (((typeDecl->base == NULL) && + ((typeDecl->subtypes == NULL) || + (typeDecl->subtypes->type != XML_SCHEMA_TYPE_SIMPLE))) || + ((typeDecl->base != NULL) && + (typeDecl->subtypes != NULL) && + (typeDecl->subtypes->type == XML_SCHEMA_TYPE_SIMPLE))) { + /* + * src-restriction-base-or-simpleType + * Either the base [attribute] or the simpleType [child] of the + * <restriction> element must be present, but not both. + */ + xmlSchemaPErr(ctxt, typeDecl->node, + XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE, + "Restriction \"%s\": " + "Either the \"base\" attribute or the <simpleType> child " + "must be present, but not both.\n", + typeDecl->name, NULL); + } + } break; } case XML_SCHEMA_TYPE_EXTENSION:{ - xmlSchemaContentType explicitContentType; - xmlSchemaTypePtr base; - - if (typeDecl->base != NULL) { - xmlSchemaTypePtr baseType; - - baseType = - xmlSchemaGetType(ctxt->schema, typeDecl->base, - typeDecl->baseNs); - if (baseType == NULL) { - xmlSchemaPErr(ctxt, typeDecl->node, - XML_SCHEMAP_UNKNOWN_BASE_TYPE, - "Schemas: type %s base type %s not found\n", - name, typeDecl->base); - } - typeDecl->baseType = baseType; - } - if (typeDecl->subtypes != NULL) - xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); - - explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS; - if (typeDecl->subtypes == NULL) - /* 1.1.1 */ - explicitContentType = XML_SCHEMA_CONTENT_EMPTY; - else if ((typeDecl->subtypes->subtypes == NULL) && - ((typeDecl->subtypes->type == - XML_SCHEMA_TYPE_ALL) - || (typeDecl->subtypes->type == - XML_SCHEMA_TYPE_SEQUENCE))) - /* 1.1.2 */ - explicitContentType = XML_SCHEMA_CONTENT_EMPTY; - else if ((typeDecl->subtypes->type == - XML_SCHEMA_TYPE_CHOICE) - && (typeDecl->subtypes->subtypes == NULL)) - /* 1.1.3 */ - explicitContentType = XML_SCHEMA_CONTENT_EMPTY; - - base = xmlSchemaGetType(ctxt->schema, typeDecl->base, - typeDecl->baseNs); - if (base == NULL) { - xmlSchemaPErr(ctxt, typeDecl->node, - XML_SCHEMAP_UNKNOWN_BASE_TYPE, - "Schemas: base type %s of type %s not found\n", - typeDecl->base, name); - return; - } - if (typeDecl->recurse) { + xmlSchemaTypePtr base = NULL; + xmlSchemaContentType explicitContentType; + + /* + * An extension does exist on a complexType only. + */ + ctxt->ctxtType->flags |= + XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION; + if (typeDecl->recurse) { + /* TODO: The word "recursive" should be changed to "circular" here. */ 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; - } else if (base->contentType == - XML_SCHEMA_CONTENT_EMPTY) { - /* 2.2 imbitable ! */ - typeDecl->contentType = - XML_SCHEMA_CONTENT_ELEMENTS; - } else { - /* 2.3 imbitable pareil ! */ - typeDecl->contentType = - XML_SCHEMA_CONTENT_ELEMENTS; + if (typeDecl->base != NULL) { + base = + xmlSchemaGetType(ctxt->schema, typeDecl->base, + typeDecl->baseNs); + if (base == NULL) { + xmlSchemaPErr(ctxt, typeDecl->node, + XML_SCHEMAP_SRC_RESOLVE, + "Extension \"%s\": the QName \"%s\" of the " + "attribute \"base\" does not resolve to a schema " + "component.\n", + name, typeDecl->base); + } else if (base->contentType == + XML_SCHEMA_CONTENT_UNKNOWN) { + typeDecl->recurse = 1; + xmlSchemaTypeFixup(base, ctxt, NULL); + typeDecl->recurse = 0; + } + /* + * The type definition ·resolved· to by the ·actual + * value· of the base [attribute] + */ + ctxt->ctxtType->baseType = base; + /* + * TODO: This one is still needed for computation of + * the content model by xmlSchemaBuildAContentModel. + * Try to get rid of it. + */ + typeDecl->baseType = base; } + if ((typeDecl->subtypes != NULL) && + (typeDecl->subtypes->contentType == XML_SCHEMA_CONTENT_UNKNOWN)) + xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); + + explicitContentType = XML_SCHEMA_CONTENT_ELEMENTS; + if (typeDecl->subtypes == NULL) + /* 1.1.1 */ + explicitContentType = XML_SCHEMA_CONTENT_EMPTY; + else if ((typeDecl->subtypes->subtypes == NULL) && + ((typeDecl->subtypes->type == + XML_SCHEMA_TYPE_ALL) + || (typeDecl->subtypes->type == + XML_SCHEMA_TYPE_SEQUENCE))) + /* 1.1.2 */ + explicitContentType = XML_SCHEMA_CONTENT_EMPTY; + else if ((typeDecl->subtypes->type == + XML_SCHEMA_TYPE_CHOICE) + && (typeDecl->subtypes->subtypes == NULL)) + /* 1.1.3 */ + explicitContentType = XML_SCHEMA_CONTENT_EMPTY; + if (base != NULL) { + /* It will be reported later, if the base is missing. */ + if (explicitContentType == XML_SCHEMA_CONTENT_EMPTY) { + /* 2.1 */ + typeDecl->contentType = base->contentType; + } else if (base->contentType == + XML_SCHEMA_CONTENT_EMPTY) { + /* 2.2 imbitable ! */ + typeDecl->contentType = + XML_SCHEMA_CONTENT_ELEMENTS; + } else { + /* 2.3 imbitable pareil ! */ + typeDecl->contentType = + XML_SCHEMA_CONTENT_ELEMENTS; + } + } break; } case XML_SCHEMA_TYPE_COMPLEX:{ + ctxtType = ctxt->ctxtType; + ctxt->ctxtType = typeDecl; + if ((typeDecl->subtypes == NULL) || + ((typeDecl->subtypes->type != + XML_SCHEMA_TYPE_SIMPLE_CONTENT) && + (typeDecl->subtypes->type != + XML_SCHEMA_TYPE_COMPLEX_CONTENT))) { + /* + * This case is understood as shorthand for complex + * content restricting the ur-type definition, and + * the details of the mappings should be modified as + * necessary. + */ + typeDecl->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE); + typeDecl->flags |= + XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION; + } if (typeDecl->subtypes == NULL) { - typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; - + typeDecl->contentType = XML_SCHEMA_CONTENT_EMPTY; if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) typeDecl->contentType = - XML_SCHEMA_CONTENT_MIXED; + XML_SCHEMA_CONTENT_MIXED; } else { - if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) + if ((typeDecl->subtypes != NULL) && + (typeDecl->subtypes->contentType == + XML_SCHEMA_CONTENT_UNKNOWN)) { + xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, + NULL); + } + if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) { typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED; - else { - xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, - NULL); - if (typeDecl->subtypes != NULL) + } else { + if (typeDecl->subtypes != NULL) { typeDecl->contentType = typeDecl->subtypes->contentType; - } - if (typeDecl->attributes == NULL) - typeDecl->attributes = - typeDecl->subtypes->attributes; + } + } } + xmlSchemaBuildAttributeValidation(ctxt, typeDecl); + ctxt->ctxtType = ctxtType; break; } case XML_SCHEMA_TYPE_COMPLEX_CONTENT:{ @@ -4946,42 +8118,174 @@ xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl, typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED; } else { - if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) + if (typeDecl->flags & XML_SCHEMAS_TYPE_MIXED) { typeDecl->contentType = XML_SCHEMA_CONTENT_MIXED; - else { + } else { xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); if (typeDecl->subtypes != NULL) typeDecl->contentType = typeDecl->subtypes->contentType; } + /* + * Removed due to implementation of the build of attribute uses. + */ + /* if (typeDecl->attributes == NULL) typeDecl->attributes = typeDecl->subtypes->attributes; + */ } break; } + case XML_SCHEMA_TYPE_SIMPLE: + /* + * Simple Type Definition Schema Component + * + */ + ctxtType = ctxt->ctxtType; + typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE; + if (typeDecl->subtypes->contentType == + XML_SCHEMA_CONTENT_UNKNOWN) { + ctxt->ctxtType = typeDecl; + xmlSchemaTypeFixup(typeDecl->subtypes, ctxt, NULL); + } + /* Fixup base type */ + if ((typeDecl->baseType != NULL) && + (typeDecl->baseType->contentType == + XML_SCHEMA_CONTENT_UNKNOWN)) { + /* OPTIMIZE: Actually this one will never by hit, since + * the base type is already type-fixed in <restriction>. + */ + ctxt->ctxtType = typeDecl; + xmlSchemaTypeFixup(typeDecl->baseType, ctxt, NULL); + } + /* Base type: + * 2 If the <list> or <union> alternative is chosen, + * then the ·simple ur-type definition·. + */ + if (typeDecl->subtypes->type == + XML_SCHEMA_TYPE_LIST) { + typeDecl->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE); + typeDecl->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST; + } else if (typeDecl->subtypes->type == + XML_SCHEMA_TYPE_UNION) { + typeDecl->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE); + typeDecl->flags |= XML_SCHEMAS_TYPE_VARIETY_UNION; + } else if (typeDecl->subtypes->type == + XML_SCHEMA_TYPE_RESTRICTION) { + xmlSchemaFacetLinkPtr facet, cur, last = NULL; + + /* + * Variety + * If the <restriction> alternative is chosen, then the + * {variety} of the {base type definition}. + */ + if (typeDecl->baseType != NULL) { + if (typeDecl->baseType->flags & + XML_SCHEMAS_TYPE_VARIETY_ATOMIC) + typeDecl->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC; + else if (typeDecl->baseType->flags & + XML_SCHEMAS_TYPE_VARIETY_LIST) + typeDecl->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST; + else if (typeDecl->baseType->flags & + XML_SCHEMAS_TYPE_VARIETY_UNION) + typeDecl->flags |= XML_SCHEMAS_TYPE_VARIETY_UNION; + /* + * Schema Component Constraint: Simple Type Restriction + * (Facets) + * NOTE: Satisfaction of 1 and 2 arise from the fixup + * applied beforehand. + * + * 3 The {facets} of R are the union of S and the {facets} + * of B, eliminating duplicates. To eliminate duplicates, + * when a facet of the same kind occurs in both S and the + * {facets} of B, the one in the {facets} of B is not + * included, with the exception of enumeration and pattern + * facets, for which multiple occurrences with distinct values + * are allowed. + */ + if (typeDecl->baseType->facetSet != NULL) { + last = typeDecl->facetSet; + if (last != NULL) + while (last->next != NULL) + last = last->next; + cur = typeDecl->baseType->facetSet; + for (; cur != NULL; cur = cur->next) { + /* + * Base patterns won't be add here: + * they are ORed in a type and + * ANDed in derived types. This will + * happed at validation level by + * walking the base axis of the type. + */ + if (cur->facet->type == + XML_SCHEMA_FACET_PATTERN) + continue; + facet = NULL; + if ((typeDecl->facetSet != NULL) && + (cur->facet->type != + XML_SCHEMA_FACET_PATTERN) && + (cur->facet->type != + XML_SCHEMA_FACET_ENUMERATION)) { + facet = typeDecl->facetSet; + do { + if (cur->facet->type == + facet->facet->type) + break; + facet = facet->next; + } while (facet != NULL); + } + if (facet == NULL) { + facet = (xmlSchemaFacetLinkPtr) + xmlMalloc(sizeof(xmlSchemaFacetLink)); + if (facet == NULL) { + xmlSchemaPErrMemory(ctxt, + "fixing simpleType", NULL); + return; + } + facet->facet = cur->facet; + facet->next = NULL; + if (last == NULL) + typeDecl->facetSet = facet; + else + last->next = facet; + last = facet; + } + } + } + } + } + /* + * Check constraints. + */ + xmlSchemaCheckSRCSimpleType(ctxt, typeDecl); + ctxt->ctxtType = ctxtType; + break; case XML_SCHEMA_TYPE_SEQUENCE: case XML_SCHEMA_TYPE_GROUP: case XML_SCHEMA_TYPE_ALL: case XML_SCHEMA_TYPE_CHOICE: typeDecl->contentType = XML_SCHEMA_CONTENT_ELEMENTS; break; + case XML_SCHEMA_TYPE_LIST: + xmlSchemaParseListRefFixup(typeDecl, ctxt); + typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE; + break; + case XML_SCHEMA_TYPE_UNION: + xmlSchemaParseUnionRefCheck(typeDecl, ctxt); + typeDecl->contentType = XML_SCHEMA_CONTENT_SIMPLE; + break; case XML_SCHEMA_TYPE_BASIC: case XML_SCHEMA_TYPE_ANY: case XML_SCHEMA_TYPE_FACET: - case XML_SCHEMA_TYPE_SIMPLE: case XML_SCHEMA_TYPE_UR: case XML_SCHEMA_TYPE_ELEMENT: case XML_SCHEMA_TYPE_ATTRIBUTE: case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: case XML_SCHEMA_TYPE_NOTATION: - case XML_SCHEMA_TYPE_LIST: - xmlSchemaParseListRefFixup(typeDecl, ctxt); - case XML_SCHEMA_TYPE_UNION: - xmlSchemaParseUnionRefCheck(typeDecl, ctxt); case XML_SCHEMA_FACET_MININCLUSIVE: case XML_SCHEMA_FACET_MINEXCLUSIVE: case XML_SCHEMA_FACET_MAXINCLUSIVE: @@ -5025,9 +8329,12 @@ xmlSchemaTypeFixup(xmlSchemaTypePtr typeDecl, case XML_SCHEMA_CONTENT_MIXED: xmlGenericError(xmlGenericErrorContext, "mixed\n"); break; + /* Removed, since not used. */ + /* case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS: xmlGenericError(xmlGenericErrorContext, "mixed or elems\n"); break; + */ case XML_SCHEMA_CONTENT_BASIC: xmlGenericError(xmlGenericErrorContext, "basic\n"); break; @@ -5060,72 +8367,150 @@ xmlSchemaCheckFacet(xmlSchemaFacetPtr facet, if (nonNegativeIntegerType == NULL) { nonNegativeIntegerType = - xmlSchemaGetPredefinedType(BAD_CAST "nonNegativeInteger", - xmlSchemaNs); + xmlSchemaGetBuiltInType(XML_SCHEMAS_NNINTEGER); } switch (facet->type) { case XML_SCHEMA_FACET_MININCLUSIVE: case XML_SCHEMA_FACET_MINEXCLUSIVE: case XML_SCHEMA_FACET_MAXINCLUSIVE: - case XML_SCHEMA_FACET_MAXEXCLUSIVE:{ + case XML_SCHEMA_FACET_MAXEXCLUSIVE: + case XML_SCHEMA_FACET_ENUMERATION: { /* * Okay we need to validate the value * at that point. */ xmlSchemaValidCtxtPtr vctxt; - + xmlSchemaTypePtr base; + + /* 4.3.5.5 Constraints on enumeration Schema Components + * Schema Component Constraint: enumeration valid restriction + * It is an ·error· if any member of {value} is not in the + * ·value space· of {base type definition}. + * + * minInclusive, maxInclusive, minExclusive, maxExclusive: + * The value ·must· be in the + * ·value space· of the ·base type·. + */ + /* + * This function is intended to deliver a compiled value + * on the facet. In XML Schemas the type holding a facet, + * cannot be a built-in type. Thus to ensure that other API + * calls (relaxng) do work, if the given type is a built-in + * type, we will assume that the given built-in type *is + * already* the base type. + */ + if (typeDecl->type != XML_SCHEMA_TYPE_BASIC) { + base = typeDecl->baseType; + if (base == NULL) { + xmlSchemaPErr(ctxt, typeDecl->node, + XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaCheckFacet, " + "the type \"%s\" has no base type.\n", + typeDecl->name, NULL); + return (-1); + } + } else + base = typeDecl; + /* + * TODO: Try to avoid creating a new context. + */ vctxt = xmlSchemaNewValidCtxt(NULL); - if (vctxt == NULL) - break; - xmlSchemaValidateSimpleValue(vctxt, typeDecl, - facet->value); - facet->val = vctxt->value; - vctxt->value = NULL; - if (facet->val == NULL) { + if (vctxt == NULL) { + xmlSchemaPErr(ctxt, typeDecl->node, + XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaCheckFacet, " + "creating a new validation context.\n", + typeDecl->name, NULL); + return (-1); + } + vctxt->type = base; + ret = xmlSchemaValidateSimpleTypeValue(vctxt, facet->value, 0, 1); + facet->val = vctxt->value; + vctxt->value = NULL; + if (ret > 0) { /* error code */ if (ctxt != NULL) { - xmlSchemaPErr(ctxt, facet->node, - XML_SCHEMAP_INVALID_FACET, - "Schemas: type %s facet value %s invalid\n", - name, facet->value); + xmlSchemaPErrExt(ctxt, facet->node, + XML_SCHEMAP_INVALID_FACET, + NULL, NULL, NULL, + "Type \"%s\": the value \"%s\" of the " + "facet \"%s\" is invalid.\n", + name, facet->value, + BAD_CAST xmlSchemaFacetTypeToString(facet->type), + NULL, NULL); } ret = -1; - } - xmlSchemaFreeValidCtxt(vctxt); + } else if (ret < 0) { + xmlSchemaPErrExt(ctxt, facet->node, + XML_SCHEMAS_ERR_INTERNAL, + NULL, NULL, NULL, + "Internal error: xmlSchemaCheckFacet, " + "failed to validate the value \"%s\" name of the " + "facet \"%s\" against the base type \"%s\".\n", + facet->value, + BAD_CAST xmlSchemaFacetTypeToString(facet->type), + base->name, NULL, NULL); + ret = -1; + } + xmlSchemaFreeValidCtxt(vctxt); break; } + /* + * Removed, since added to the case above. + * case XML_SCHEMA_FACET_ENUMERATION:{ - /* + * * Okay we need to validate the value * at that point. - */ + * xmlSchemaValidCtxtPtr vctxt; int tmp; + xmlSchemaTypePtr base; + * 4.3.5.5 Constraints on enumeration Schema Components + * Schema Component Constraint: enumeration valid restriction + * It is an ·error· if any member of {value} is not in the + * ·value space· of {base type definition}. + * vctxt = xmlSchemaNewValidCtxt(NULL); if (vctxt == NULL) break; - tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl, + base = typeDecl->baseType; + if (base == NULL) { + xmlSchemaPErr(ctxt, typeDecl->node, + XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaCheckFacet, " + "the type \"%s\" has no base type.\n", + typeDecl->name, NULL); + return (-1); + } + vctxt->type = base; + tmp = xmlSchemaValidateSimpleTypeValue(vctxt, facet->value, 0, 1); + * tmp = xmlSchemaValidateSimpleValue(vctxt, typeDecl, facet->value); + * if (tmp != 0) { if (ctxt != NULL) { xmlSchemaPErr(ctxt, facet->node, - XML_SCHEMAP_INVALID_ENUM, - "Schemas: type %s enumeration value %s invalid\n", - name, facet->value); + XML_SCHEMAP_INVALID_ENUM, + "Type \"%s\": the value \"%s\" of the " + "facet \"enumeration\" is invalid.\n", + name, facet->value); } ret = -1; } xmlSchemaFreeValidCtxt(vctxt); break; } + */ case XML_SCHEMA_FACET_PATTERN: facet->regexp = xmlRegexpCompile(facet->value); if (facet->regexp == NULL) { xmlSchemaPErr(ctxt, typeDecl->node, - XML_SCHEMAP_REGEXP_INVALID, - "Schemas: type %s facet regexp %s invalid\n", - name, facet->value); + XML_SCHEMAP_REGEXP_INVALID, + "Type \"%s\": the value \"%s\" of the " + "facet \"pattern\" is invalid.\n", + name, facet->value); ret = -1; } break; @@ -5143,10 +8528,14 @@ xmlSchemaCheckFacet(xmlSchemaFacetPtr facet, if (tmp != 0) { /* error code */ if (ctxt != NULL) { - xmlSchemaPErr(ctxt, facet->node, - XML_SCHEMAP_INVALID_FACET_VALUE, - "Schemas: type %s facet value %s invalid\n", - name, facet->value); + xmlSchemaPErrExt(ctxt, facet->node, + XML_SCHEMAP_INVALID_FACET_VALUE, + NULL, NULL, NULL, + "Type \"%s\": the value \"%s\" of the " + "facet \"%s\" is invalid.\n", + name, facet->value, + BAD_CAST xmlSchemaFacetTypeToString(facet->type), + NULL, NULL); } ret = -1; } @@ -5162,9 +8551,10 @@ xmlSchemaCheckFacet(xmlSchemaFacetPtr facet, } else { if (ctxt != NULL) { xmlSchemaPErr(ctxt, facet->node, - XML_SCHEMAP_INVALID_WHITE_SPACE, - "Schemas: type %s whiteSpace value %s invalid\n", - name, facet->value); + XML_SCHEMAP_INVALID_WHITE_SPACE, + "Type \"%s\": the value \"%s\" of the " + "facet \"whiteSpace\" is invalid.\n", + name, facet->value); } ret = -1; } @@ -5187,17 +8577,19 @@ xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl, xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) { if (name == NULL) - name = typeDecl->name; - if (typeDecl->type == XML_SCHEMA_TYPE_RESTRICTION) { - if (typeDecl->facets != NULL) { - xmlSchemaFacetPtr facet = typeDecl->facets; - - while (facet != NULL) { - xmlSchemaCheckFacet(facet, typeDecl, ctxt, name); - facet = facet->next; - } - } - } + name = typeDecl->name; + /* + * NOTE: It is intended to use the facets list, instead + * of facetSet. + */ + if (typeDecl->facets != NULL) { + xmlSchemaFacetPtr facet = typeDecl->facets; + + while (facet != NULL) { + xmlSchemaCheckFacet(facet, typeDecl, ctxt, name); + facet = facet->next; + } + } } /** @@ -5209,32 +8601,41 @@ xmlSchemaCheckDefaults(xmlSchemaTypePtr typeDecl, * Fixes finish doing the computations on the attributes definitions */ static void -xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrpDecl, +xmlSchemaAttrGrpFixup(xmlSchemaAttributeGroupPtr attrgrp, xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) { if (name == NULL) - name = attrgrpDecl->name; - if (attrgrpDecl->attributes != NULL) + name = attrgrp->name; + if (attrgrp->attributes != NULL) return; - if (attrgrpDecl->ref != NULL) { + if (attrgrp->ref != NULL) { xmlSchemaAttributeGroupPtr ref; - ref = xmlHashLookup2(ctxt->schema->attrgrpDecl, attrgrpDecl->ref, - attrgrpDecl->refNs); + ref = xmlSchemaGetAttributeGroup(ctxt->schema, attrgrp->ref, attrgrp->refNs); if (ref == NULL) { - xmlSchemaPErr(ctxt, attrgrpDecl->node, - XML_SCHEMAP_UNKNOWN_ATTRIBUTE_GROUP, - "Schemas: attribute group %s reference %s not found\n", - name, attrgrpDecl->ref); + xmlSchemaPErr(ctxt, attrgrp->node, + XML_SCHEMAP_SRC_RESOLVE, + "Attribute group \"%s\": the QName \"%s\" of the attribute " + "\"ref\" does not resolve to a schema " + "component.\n", + name, attrgrp->ref); return; } xmlSchemaAttrGrpFixup(ref, ctxt, NULL); - attrgrpDecl->attributes = ref->attributes; - } else { - xmlSchemaPErr(ctxt, attrgrpDecl->node, XML_SCHEMAP_NOATTR_NOREF, - "Schemas: attribute %s has no attributes nor reference\n", + attrgrp->attributes = ref->attributes; + attrgrp->attributeWildcard = ref->attributeWildcard; + } + /* + * Removed, since a global attribute group does not need to hold any + * attributes or wildcard + */ + /* + else { + xmlSchemaPErr(ctxt, attrgrp->node, XML_SCHEMAP_NOATTR_NOREF, + "Schemas: attribute group %s has no attributes nor reference\n", name, NULL); } + */ } /** @@ -5249,6 +8650,12 @@ static void xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl, xmlSchemaParserCtxtPtr ctxt, const xmlChar * name) { + /* + * The simple type definition corresponding to the <simpleType> element + * information item in the [children], if present, otherwise the simple + * type definition ·resolved· to by the ·actual value· of the type + * [attribute], if present, otherwise the ·simple ur-type definition·. + */ if (name == NULL) name = attrDecl->name; if (attrDecl->subtypes != NULL) @@ -5256,31 +8663,34 @@ xmlSchemaAttrFixup(xmlSchemaAttributePtr attrDecl, if (attrDecl->typeName != NULL) { xmlSchemaTypePtr type; - type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName, - attrDecl->typeNs); - if (type == NULL) { - xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_TYPE, - "Schemas: attribute %s type %s not found\n", - name, attrDecl->typeName); - } + type = xmlSchemaGetType(ctxt->schema, attrDecl->typeName, + attrDecl->typeNs); + if (type == NULL) { + xmlSchemaPErr(ctxt, attrDecl->node, + XML_SCHEMAP_SRC_RESOLVE, + "Attribute \"%s\": the QName \"%s\" of the attribute " + "\"type\" does not resolve to a schema " + "component.\n", + name, attrDecl->typeName); + } attrDecl->subtypes = type; } else if (attrDecl->ref != NULL) { xmlSchemaAttributePtr ref; - ref = xmlHashLookup2(ctxt->schema->attrDecl, attrDecl->ref, - attrDecl->refNs); + ref = xmlSchemaGetAttribute(ctxt->schema, attrDecl->ref, attrDecl->refNs); if (ref == NULL) { - xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_UNKNOWN_REF, - "Schemas: attribute %s reference %s not found\n", - name, attrDecl->ref); + xmlSchemaPErr(ctxt, attrDecl->node, + XML_SCHEMAP_SRC_RESOLVE, + "Attribute \"%s\": the QName \"%s\" of the attribute " + "\"ref\" does not resolve to a schema " + "component.\n", + name, attrDecl->ref); return; } xmlSchemaAttrFixup(ref, ctxt, NULL); attrDecl->subtypes = ref->subtypes; - } else if (attrDecl->type != XML_SCHEMA_TYPE_ANY_ATTRIBUTE) { - xmlSchemaPErr(ctxt, attrDecl->node, XML_SCHEMAP_NOTYPE_NOREF, - "Schemas: attribute %s has no type nor reference\n", - name, NULL); + } else { + attrDecl->subtypes = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE); } } @@ -5403,6 +8813,8 @@ xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt) /* * Then fixup all types properties */ + ctxt->ctxtType = NULL; + ctxt->parentItem = NULL; xmlHashScan(ret->typeDecl, (xmlHashScanner) xmlSchemaTypeFixup, ctxt); /* @@ -5506,72 +8918,54 @@ xmlSchemaFacetTypeToString(xmlSchemaTypeType type) static int xmlSchemaValidateFacetsInternal(xmlSchemaValidCtxtPtr ctxt, xmlSchemaTypePtr base, - xmlSchemaFacetPtr facets, + xmlSchemaFacetLinkPtr facets, const xmlChar * value, int fireErrors) { int ret = 0; int tmp = 0; xmlSchemaTypeType type; - xmlSchemaFacetPtr facet = facets; + xmlSchemaFacetLinkPtr facetLink = facets; - while (facet != NULL) { - type = facet->type; + while (facetLink != NULL) { + type = facetLink->facet->type; if (type == XML_SCHEMA_FACET_ENUMERATION) { tmp = 1; - while (facet != NULL) { + while (facetLink != NULL) { tmp = - xmlSchemaValidateFacet(base, facet, value, + xmlSchemaValidateFacet(base, facetLink->facet, value, ctxt->value); if (tmp == 0) { return 0; } - facet = facet->next; + facetLink = facetLink->next; } } else - tmp = xmlSchemaValidateFacet(base, facet, value, ctxt->value); + tmp = xmlSchemaValidateFacet(base, facetLink->facet, value, + ctxt->value); if (tmp != 0) { ret = tmp; - if (fireErrors) - 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, tmp, + "The value failed to validate against the facet \"%s\".\n", + (const xmlChar *) xmlSchemaFacetTypeToString(type), + NULL); + + } } - if (facet != NULL) - facet = facet->next; + if (facetLink != NULL) + facetLink = facetLink->next; } 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 * * * ************************************************************************/ - +#if 0 /* Not currently used. */ /** * xmlSchemaValidateSimpleValueUnion: * @ctxt: a schema validation context @@ -5703,7 +9097,6 @@ xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt, } } else if (type->type == XML_SCHEMA_TYPE_RESTRICTION) { xmlSchemaTypePtr base; - xmlSchemaFacetPtr facet; base = type->baseType; if (base != NULL) { @@ -5718,9 +9111,11 @@ xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt, * building the Schemas */ if (ctxt->schema != NULL) { - if (ret == 0) { - facet = type->facets; - ret = xmlSchemaValidateFacetsInternal(ctxt, base, facet, + xmlSchemaFacetLinkPtr facetLink; + + if ((ret == 0) && (type->facetSet != NULL)) { + facetLink = type->facetSet; + ret = xmlSchemaValidateFacetsInternal(ctxt, base, facetLink, value, fireErrors); } } @@ -5774,6 +9169,7 @@ xmlSchemaValidateSimpleValueInternal(xmlSchemaValidCtxtPtr ctxt, } return (ret); } +#endif /************************************************************************ * * @@ -5785,12 +9181,31 @@ static int xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node); static int xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, - xmlSchemaAttributePtr attributes); + xmlSchemaTypePtr type); static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, xmlSchemaElementPtr elemDecl, xmlSchemaTypePtr type); + +/** + * xmlSchemaFreeAttrStates: + * @state: a list of attribute states + * + * Free the given list of attribute states + * + */ +static void +xmlSchemaFreeAttributeStates(xmlSchemaAttrStatePtr state) +{ + xmlSchemaAttrStatePtr tmp; + while (state != NULL) { + tmp = state; + state = state->next; + xmlFree(tmp); + } +} + /** * xmlSchemaRegisterAttributes: * @ctxt: a schema validation context @@ -5803,29 +9218,30 @@ static int xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, static int xmlSchemaRegisterAttributes(xmlSchemaValidCtxtPtr ctxt, xmlAttrPtr attrs) { + xmlSchemaAttrStatePtr tmp; + + ctxt->attr = NULL; + ctxt->attrTop = NULL; while (attrs != NULL) { if ((attrs->ns != NULL) && (xmlStrEqual(attrs->ns->href, xmlSchemaInstanceNs))) { attrs = attrs->next; continue; } - if (ctxt->attrNr >= ctxt->attrMax) { - xmlSchemaAttrStatePtr tmp; - - ctxt->attrMax *= 2; tmp = (xmlSchemaAttrStatePtr) - xmlRealloc(ctxt->attr, ctxt->attrMax * - sizeof(xmlSchemaAttrState)); + xmlMalloc(sizeof(xmlSchemaAttrState)); if (tmp == NULL) { xmlSchemaVErrMemory(ctxt, "registering attributes", NULL); - ctxt->attrMax /= 2; return (-1); } + tmp->attr = attrs; + tmp->state = XML_SCHEMAS_ATTR_UNKNOWN; + tmp->next = NULL; + if (ctxt->attr == NULL) ctxt->attr = tmp; - } - ctxt->attr[ctxt->attrNr].attr = attrs; - ctxt->attr[ctxt->attrNr].state = XML_SCHEMAS_ATTR_UNKNOWN; - ctxt->attrNr++; + else + ctxt->attrTop->next = tmp; + ctxt->attrTop = tmp; attrs = attrs->next; } return (0); @@ -5845,18 +9261,41 @@ static int xmlSchemaCheckAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) { int ret = 0; - int i; + xmlSchemaAttrStatePtr cur; - for (i = ctxt->attrBase; i < ctxt->attrNr; i++) { - if (ctxt->attr[i].attr == NULL) - break; - if (ctxt->attr[i].state == XML_SCHEMAS_ATTR_UNKNOWN) { + cur = ctxt->attr; + while ((cur != NULL) && (cur != ctxt->attrTop->next)) { + if (cur->state != XML_SCHEMAS_ATTR_CHECKED) { ret = 1; + if (cur->state == XML_SCHEMAS_ATTR_UNKNOWN) xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ATTRUNKNOWN, - "Attribute %s on %s is unknown\n", - ctxt->attr[i].attr->name, node->name); + "Attribute \"%s\" is not allowed.\n", + cur->attr->name, NULL); + else if (cur->state == XML_SCHEMAS_ATTR_PROHIBITED) + /* + * TODO: This won't ever be touched so remove it. + */ + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ATTRUNKNOWN, + "Attribute \"%s\" is prohibited.\n", + cur->attr->name, NULL); + else if (cur->state == XML_SCHEMAS_ATTR_INVALID_VALUE) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_ATTRINVALID, + "Attribute \"%s\": the value is not valid.\n", + cur->attr->name, node->name); + } else if (cur->state == XML_SCHEMAS_ATTR_MISSING) { + if (cur->decl->ref != NULL) + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_MISSING, + "Attribute \"%s\" is required but missing.\n", + cur->decl->ref, NULL); + else + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_MISSING, + "Attribute \"%s\" is required but missing.\n", + cur->decl->name, NULL); } } + cur = cur->next; + } + return (ret); } @@ -5903,10 +9342,16 @@ xmlSchemaValidateSimpleContent(xmlSchemaValidCtxtPtr ctxt, ret = xmlSchemaValidateFacets(ctxt, base, facet, value); } - if ((ret == 0) && (type->attributes != NULL)) { + /* + * This should attempt to validate the attributes even + * when validation of the value failed. + */ + /* + if (type->attributes != NULL) { ret = xmlSchemaValidateAttributes(ctxt, node, type->attributes); } + */ break; } case XML_SCHEMA_TYPE_EXTENSION:{ @@ -5951,38 +9396,6 @@ xmlSchemaValidateCheckNodeList(xmlNodePtr nodelist) } /** - * xmlSchemaSkipIgnored: - * @ctxt: a schema validation context - * @type: the current type context - * @node: the top node. - * - * Skip ignorable nodes in that context - * - * Returns the new sibling - * number otherwise and -1 in case of internal or API error. - */ -static xmlNodePtr -xmlSchemaSkipIgnored(xmlSchemaValidCtxtPtr ctxt ATTRIBUTE_UNUSED, - xmlSchemaTypePtr type, xmlNodePtr node) -{ - int mixed = 0; - - /* - * TODO complete and handle entities - */ - mixed = ((type->contentType == XML_SCHEMA_CONTENT_MIXED) || - (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS)); - while ((node != NULL) && - ((node->type == XML_COMMENT_NODE) || - ((mixed == 1) && (node->type == XML_TEXT_NODE)) || - (((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) && - (node->type == XML_TEXT_NODE) && (IS_BLANK_NODE(node)))))) { - node = node->next; - } - return (node); -} - -/** * xmlSchemaValidateCallback: * @ctxt: a schema validation context * @name: the name of the element detected (might be NULL) @@ -6047,7 +9460,7 @@ xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt, ret = xmlSchemaValidateCheckNodeList(child); if (ret < 0) { xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, - "Internal error: xmlSchemaValidateSimpleType %s content\n", + "Internal error: xmlSchemaValidateSimpleRestrictionType %s content\n", node->name, NULL); return (-1); } else if (ret == 0) { @@ -6063,6 +9476,7 @@ xmlSchemaValidateSimpleRestrictionType(xmlSchemaValidCtxtPtr ctxt, } #endif +#if 0 /* Not used any more */ /** * xmlSchemaValidateSimpleType: * @ctxt: a schema validation context @@ -6147,22 +9561,18 @@ xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) value = xmlNodeGetContent(child); switch (variety->type) { case XML_SCHEMA_TYPE_RESTRICTION:{ - xmlSchemaFacetPtr facet; - base = variety->baseType; if (base != NULL) { ret = xmlSchemaValidateSimpleValue(ctxt, base, value); } else { - TODO} - if (ret == 0) { - facet = variety->facets; - ret = - xmlSchemaValidateFacets(ctxt, base, facet, value); - } + TODO} + + /* Removed due to changes of attribute validation: if ((ret == 0) && (variety->attributes != NULL)) { ret = xmlSchemaValidateAttributes(ctxt, node, variety->attributes); } + */ break; } case XML_SCHEMA_TYPE_LIST: @@ -6178,6 +9588,9 @@ xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) ret = ctxt->err; } } + if ((ret == 0) && (variety->facetSet != NULL)) { + ret = xmlSchemaValidateFacets(ctxt, base, variety->facetSet, value); + } if (value != NULL) xmlFree(value); @@ -6188,6 +9601,496 @@ xmlSchemaValidateSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) ctxt->type = type; return (ret); } +#endif + +/** + * xmlSchemaValidateSimpleTypeValue: + * @ctxt: a schema validation context + * @value: the value to be validated + * @fireErrors: shall errors be reported? + * @applyFacets: shall facets be applied? + * + * Validates a value by the given type (user derived or built-in). + * + * Returns 0 if the value is valid, a positive error code + * number otherwise and -1 in case of an internal or API error. + * Note on reported errors: Although it might be nice to report + * the name of the simple/complex type, used to validate the content + * of a node, it is quite unnecessary: for global defined types + * the local name of the element is equal to the NCName of the type, + * for local defined types it makes no sense to output the internal + * computed name of the type. TODO: Instead, one should attach the + * struct of the type involved to the error handler - this allows + * the report of any additional information by the user. + * TODO: Correct character normalization of union simple types. + */ +static int +xmlSchemaValidateSimpleTypeValue(xmlSchemaValidCtxtPtr ctxt, + const xmlChar *value, + int fireErrors, + int applyFacets) +{ + xmlSchemaTypePtr type; + int ret = 0; + type = ctxt->type; + + if (type->type == XML_SCHEMA_TYPE_BASIC) { + xmlNodePtr child; + + if (ctxt->value != NULL) { + xmlSchemaFreeValue(ctxt->value); + ctxt->value = NULL; + } + child = ctxt->node; + while (child != NULL) { + switch (child->type) { + case XML_TEXT_NODE: + case XML_CDATA_SECTION_NODE: + case XML_PI_NODE: + case XML_COMMENT_NODE: + case XML_XINCLUDE_START: + case XML_XINCLUDE_END: + break; + case XML_ENTITY_REF_NODE: + case XML_ENTITY_NODE: + TODO break; + case XML_ELEMENT_NODE: + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INVALIDELEM, + "Element \"%s\": child \"%s\" should not be present.\n", + ctxt->cur->name, child->name); + return (ctxt->err); + case XML_ATTRIBUTE_NODE: + case XML_DOCUMENT_NODE: + case XML_DOCUMENT_TYPE_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_NOTATION_NODE: + case XML_HTML_DOCUMENT_NODE: + case XML_DTD_NODE: + case XML_ELEMENT_DECL: + case XML_ATTRIBUTE_DECL: + case XML_ENTITY_DECL: + case XML_NAMESPACE_DECL: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INVALIDELEM, + "Element \"%s\": node type of node unexpected here.\n", + ctxt->cur->name, NULL); + return (ctxt->err); + } + child = child->next; + } + ret = xmlSchemaValPredefTypeNode(type, value, &(ctxt->value), + ctxt->cur); + if (ret > 0) { + if (type->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2; + else + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1; + if (fireErrors) { + if (ctxt->cur->type == XML_ATTRIBUTE_NODE) + xmlSchemaVErr(ctxt, ctxt->cur, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, + "The value of attribute \"%s\" is not valid.\n", + ctxt->cur->name, NULL); + else + xmlSchemaVErr(ctxt, ctxt->cur, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, + "The value is not valid.\n", + NULL, NULL); + } + } else if (ret < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "validating built-in type \"%s\"\n", + type->name, NULL); + } + } else if (type->flags & XML_SCHEMAS_TYPE_VARIETY_ATOMIC) { + /* 1.2.1 if {variety} is ·atomic· then the string must ·match· + * a literal in the ·lexical space· of {base type definition} + */ + ctxt->type = type->baseType; + ret = xmlSchemaValidateSimpleTypeValue(ctxt, value, 0, 0); + if (ret < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "validating atomic simple type \"%s\"\n", + type->name, NULL); + } else if (ret > 0) { + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1; + if (fireErrors) { + xmlSchemaVErr(ctxt, ctxt->cur, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, + "The value is not valid.\n", + NULL, NULL); + } + + } else if ((applyFacets) && + (type->facetSet != NULL)) { + xmlSchemaTypePtr builtIn; + + /* + * Check facets. Be sure to pass the built-in type to + * xmlSchemaValidateFacetsInternal. + */ + builtIn = type->baseType; + while (builtIn->type != XML_SCHEMA_TYPE_BASIC) + builtIn = builtIn->baseType; + ret = xmlSchemaValidateFacetsInternal(ctxt, builtIn, + type->facetSet, value, fireErrors); + if (ret < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "validating facets of atomic simple type \"%s\"\n", + type->name, NULL); + } else if (ret > 0) { + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1; + if (fireErrors) { + xmlSchemaVErr(ctxt, ctxt->cur, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, + "The value is not valid.\n", + NULL, NULL); + } + } + } + } else if (type->flags & XML_SCHEMAS_TYPE_VARIETY_LIST) { + + xmlSchemaTypePtr tmpType; + const xmlChar *cur, *end; + xmlChar *tmp; + int len = 0; + + /* 1.2.2 if {variety} is ·list· then the string must be a sequence + * of white space separated tokens, each of which ·match·es a literal + * in the ·lexical space· of {item type definition} + */ + + tmpType = xmlSchemaGetListSimpleTypeItemType(type); + cur = value; + 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); + len++; + ctxt->type = tmpType; + ret = xmlSchemaValidateSimpleTypeValue(ctxt, tmp, 0, 1); + xmlFree(tmp); + if (ret > 0) { + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2; + if (fireErrors) { + xmlSchemaVErr(ctxt, ctxt->cur, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2, + "The value is not valid.\n", + NULL, NULL); + } + break; + } else if (ret < 0) + break; + cur = end; + } while (*cur != 0); + /* + * Check facets. + */ + if (ret < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "validating list simple type \"%s\"\n", + type->name, NULL); + } else if ((ret == 0) && (applyFacets) && + (type->facetSet != NULL)) { + int okFacet = 0, hasFacet = 0; + unsigned long expLen; + xmlSchemaFacetPtr facet; + xmlSchemaFacetLinkPtr facetLink; + xmlChar *collapsedValue = NULL; + + /* + * The value of ·whiteSpace· is fixed to the value collapse. + */ + collapsedValue = xmlSchemaCollapseString((const xmlChar *) value); + if (collapsedValue != NULL) + value = (const xmlChar *) collapsedValue; + facetLink = type->facetSet; + do { + facet = facetLink->facet; + /* + * List types need a special facet treatment. + * Skip whiteSpace, since it is fixed to "collapse". + */ + if ((facet->type != XML_SCHEMA_FACET_WHITESPACE) && + (facet->type != XML_SCHEMA_FACET_PATTERN)) { + ret = xmlSchemaValidateListSimpleTypeFacet(facet, value, + len, &expLen); + if (facet->type == XML_SCHEMA_FACET_ENUMERATION) { + hasFacet = 1; + if (ret == 0) + okFacet = 1; + } else if ((ret > 0) && (fireErrors)) { + char l[25], fl[25]; + /* FIXME: What is the max expected string length of the + * length value? + */ + snprintf(l, 24, "%d", len); + snprintf(fl, 24, "%lu", expLen); + if (ret == XML_SCHEMAV_CVC_LENGTH_VALID) { + xmlSchemaVErr(ctxt, ctxt->cur, ret, + "The value with length \"%s\" is not " + "facet-valid with respect to length = \"%s\".\n", + (const xmlChar *)l, (const xmlChar *)fl); + } else if (ret == XML_SCHEMAV_CVC_MINLENGTH_VALID) { + xmlSchemaVErr(ctxt, ctxt->cur, ret, + "The value with length \"%s\" is not " + "facet-valid with respect to minLength = \"%s\".\n", + (const xmlChar *)l, (const xmlChar *)fl); + } else if (ret == XML_SCHEMAV_CVC_MAXLENGTH_VALID) { + xmlSchemaVErr(ctxt, ctxt->cur, ret, + "The value with length \"%s\" is not " + "facet-valid with respect to maxLength = \"%s\".\n", + (const xmlChar *)l, (const xmlChar *)fl); + } else { + xmlSchemaVErr(ctxt, ctxt->cur, ret, + "The value is not valid with respect " + "to the facet \"%s\".\n", + (const xmlChar *) + xmlSchemaFacetTypeToString(facet->type), + NULL); + } + } else if (ret < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "validating facets of list simple type \"%s\"\n", + type->name, NULL); + break; + } + } + facetLink = facetLink->next; + } while (facetLink != NULL); + if (ret >= 0) { + if ((hasFacet) && (okFacet == 0)) { + ret = XML_SCHEMAV_CVC_ENUMERATION_VALID; + if (fireErrors) { + /* + * TODO: Try to create a report that outputs all the enumeration + * values in use. + */ + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAV_CVC_ENUMERATION_VALID, + "The value is not valid with respect " + "to the \"enumeration\" facet(s).\n", + NULL, NULL); + } + + } + /* + * Pattern facets are ORed at type level and ANDed + * if derived. Walk the base axis. + */ + hasFacet = 0; + tmpType = type; + do { + okFacet = 0; + for (facetLink = tmpType->facetSet; facetLink != NULL; + facetLink = facetLink->next) { + if (facetLink->facet->type != XML_SCHEMA_FACET_PATTERN) + continue; + okFacet = xmlSchemaValidateListSimpleTypeFacet( + facetLink->facet, value, len, &expLen); + if (okFacet <= 0) + break; + } + if (okFacet != 0) + break; + tmpType = tmpType->baseType; + } while ((tmpType != NULL) && (tmpType->type != XML_SCHEMA_TYPE_BASIC)); + if (okFacet < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "validating \"pattern\" facets of type \"%s\"\n", + type->name, NULL); + } else if (okFacet > 0) { + ret = XML_SCHEMAV_CVC_PATTERN_VALID; + if (fireErrors) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAV_CVC_ENUMERATION_VALID, + "The value is not valid with respect " + "to the \"pattern\" facet(s) of type " + "\"%s\".\n", + tmpType->name, NULL); + } + } + } + + if (collapsedValue != NULL) + xmlFree(collapsedValue); + } + } else if (type->flags & XML_SCHEMAS_TYPE_VARIETY_UNION) { + xmlSchemaTypeLinkPtr memberLink; + + /* + * TODO: For all datatypes ·derived· by ·union· whiteSpace does + * not apply directly; however, the normalization behavior of ·union· + * types is controlled by the value of whiteSpace on that one of the + * ·memberTypes· against which the ·union· is successfully validated. + * + * This means that the value is normalized by the first validating + * member type, then the facets of the union type are applied. This + * needs changing of the value! + */ + + /* + * 1.2.3 if {variety} is ·union· then the string must ·match· a + * literal in the ·lexical space· of at least one member of + * {member type definitions} + */ + memberLink = xmlSchemaGetUnionSimpleTypeMemberTypes(type); + if (memberLink == NULL) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "union simple type \"%s\" has no member types\n", + type->name, NULL); + ret = -1; + } + if (ret == 0) { + while (memberLink != NULL) { + ctxt->type = memberLink->type; + ret = xmlSchemaValidateSimpleTypeValue(ctxt, value, 0, 1); + if ((ret <= 0) || (ret == 0)) + break; + memberLink = memberLink->next; + } + if (ret > 0) { + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3; + if (fireErrors) { + xmlSchemaVErr(ctxt, ctxt->cur, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3, + "The value is not valid.\n", + NULL, NULL); + } + } else if (ret < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "validating members of union simple type \"%s\"\n", + type->name, NULL); + } + } + /* + * Apply facets (pattern, enumeration). + */ + if ((ret == 0) && (applyFacets) && + (type->facetSet != NULL)) { + xmlSchemaTypePtr anySimpleType; + /* + * Check facets. Be sure to pass the built-in type (the + * simple ur-type in this case) to xmlSchemaValidateFacetsInternal. + */ + anySimpleType = type->baseType; + while (anySimpleType->type != XML_SCHEMA_TYPE_BASIC) + anySimpleType = anySimpleType->baseType; + ret = xmlSchemaValidateFacetsInternal(ctxt, anySimpleType, + type->facetSet, value, fireErrors); + if (ret < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeValue, " + "validating facets of union simple type \"%s\"\n", + type->name, NULL); + } else if (ret > 0) { + ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3; + if (fireErrors) { + xmlSchemaVErr(ctxt, ctxt->cur, + XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, + "The value is not valid.\n", + NULL, NULL); + } + } + } + } + ctxt->type = type; + return (ret); +} + +/** + * xmlSchemaValidateSimpleTypeElement: + * @ctxt: a schema validation context + * @node: the element node to be validated. + * + * Validate the element against a simple type. + * + * Returns 0 if the element is valid, a positive error code + * number otherwise and -1 in case of an internal or API error. + */ +static int +xmlSchemaValidateSimpleTypeElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) +{ + xmlNodePtr child; + xmlSchemaTypePtr type; + xmlAttrPtr attr; + int ret; + xmlChar *value; + + + child = ctxt->node; + type = ctxt->type; + + if ((ctxt == NULL) || (type == NULL)) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeElement %s\n", + node->name, NULL); + return (-1); + } + + /* + * Only text and text based entities references shall be found there + */ + ret = xmlSchemaValidateCheckNodeList(child); + if (ret < 0) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateSimpleTypeElement %s content\n", + node->name, NULL); + return (-1); + } else if (ret == 0) { + /* 3.1.2 The element information item must have no element + * information item [children]. + */ + xmlSchemaVErr(ctxt, node, XML_SCHEMAV_CVC_TYPE_3_1_2, + "Element \"%s\" must have no element children.\n", + node->name, NULL); + return (-1); + } + /* + * Validation Rule: Element Locally Valid (Type): 3.1.1 + */ + attr = node->properties; + while (attr != NULL) { + if ((attr->ns == NULL) || + (!xmlStrEqual(attr->ns->href, xmlSchemaInstanceNs)) || + ((!xmlStrEqual(attr->name, BAD_CAST "type")) && + (!xmlStrEqual(attr->name, BAD_CAST "nil")) && + (!xmlStrEqual(attr->name, BAD_CAST "schemaLocation")) && + (!xmlStrEqual + (attr->name, BAD_CAST "noNamespaceSchemaLocation")))) { + xmlSchemaVErr(ctxt, node, + XML_SCHEMAV_CVC_TYPE_3_1_1, + "The attributes of element \"%s\" must be empty, excepting " + "those whose namespace name is identical to " + "http://www.w3.org/2001/XMLSchema-instance and whose local " + "name is one of type, nil, schemaLocation or " + "noNamespaceSchemaLocation.\n", + node->name, attr->name); + return (ctxt->err); + } + attr = attr->next; + } + value = xmlNodeGetContent(child); + ret = xmlSchemaValidateSimpleTypeValue(ctxt, value, 1, 1); + if (value != NULL) + xmlFree(value); + + ctxt->type = type; + return (ret); +} /** * xmlSchemaValidateElementType: @@ -6207,7 +10110,18 @@ xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) xmlSchemaTypePtr type; xmlRegExecCtxtPtr oldregexp; /* cont model of the parent */ xmlSchemaElementPtr decl; - int ret, attrBase; + int ret; + xmlSchemaAttrStatePtr attrs = NULL, attrTop = NULL; + + /* This one is called by xmlSchemaValidateContent only. */ + /* + * TODO: Look into "xmlSchemaValidateElement" for missing parts, which should + * go in here as well. + */ + + /* TODO: Is this one called always with an element declaration as the + * context's type? + */ oldregexp = ctxt->regexp; @@ -6241,10 +10155,12 @@ xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) /* * Verify the attributes */ - attrBase = ctxt->attrBase; - ctxt->attrBase = ctxt->attrNr; - xmlSchemaRegisterAttributes(ctxt, child->properties); - xmlSchemaValidateAttributes(ctxt, child, type->attributes); + + attrs = ctxt->attr; + attrTop = ctxt->attrTop; + + xmlSchemaRegisterAttributes(ctxt, child->properties); + /* * Verify the element content recursively */ @@ -6289,16 +10205,17 @@ xmlSchemaValidateElementType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) * Verify that all attributes were Schemas-validated */ xmlSchemaCheckAttributes(ctxt, node); - ctxt->attrNr = ctxt->attrBase; - ctxt->attrBase = attrBase; - + if (ctxt->attr != NULL) + xmlSchemaFreeAttributeStates(ctxt->attr); + ctxt->attr = attrs; + ctxt->attrTop = attrTop; ctxt->regexp = oldregexp; - ctxt->node = child; ctxt->type = type; return (ctxt->err); } +#if 0 /* Not currently used. */ /** * xmlSchemaValidateBasicType: * @ctxt: a schema validation context @@ -6326,6 +10243,13 @@ xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) node->name, NULL); return (-1); } + if (type->type != XML_SCHEMA_TYPE_BASIC) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateBasicType, " + "the given type is not a built-in type.\n", + node->name, NULL); + return (-1); + } /* * First check the content model of the node. */ @@ -6377,9 +10301,11 @@ xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) xmlSchemaFreeValue(ctxt->value); ctxt->value = NULL; } + ret = xmlSchemaValidatePredefinedType(type, value, &(ctxt->value)); + if (value != NULL) - xmlFree(value); + xmlFree(value); if (ret != 0) { xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_VALUE, "Element %s: failed to validate basic type %s\n", @@ -6387,6 +10313,7 @@ xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) } return (ret); } +#endif /** * xmlSchemaValidateComplexType: @@ -6398,101 +10325,221 @@ xmlSchemaValidateBasicType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) * Validation Rule: Element Locally Valid (Complex Type) * * Returns 0 if the element is schemas valid, a positive error code - * number otherwise and -1 in case of internal or API error. + * number otherwise and -1 in case of internal or API error. + * Note on reported errors: Although it might be nice to report + * the name of the simple/complex type, used to validate the content + * of a node, it is quite unnecessary: for global defined types + * the local name of the element is equal to the NCName of the type, + * for local defined types it makes no sense to output the internal + * computed name of the type. TODO: Instead, one should attach the + * struct of the type involved to the error handler - this allows + * the report of any additional information by the user. */ static int xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) { xmlNodePtr child; - xmlSchemaTypePtr type, subtype; - int ret; + xmlSchemaTypePtr type; + int ret = 0; child = ctxt->node; type = ctxt->type; ctxt->cur = node; switch (type->contentType) { - case XML_SCHEMA_CONTENT_EMPTY: - if (type->baseType != NULL) { - } else if (child != NULL) { - xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_NOTEMPTY, - "Element %s is supposed to be empty\n", - node->name, NULL); - } - if (type->attributes != NULL) { - xmlSchemaValidateAttributes(ctxt, node, type->attributes); - } - subtype = type->subtypes; - while (subtype != NULL) { - ctxt->type = subtype; - xmlSchemaValidateComplexType(ctxt, node); - subtype = subtype->next; - } + case XML_SCHEMA_CONTENT_EMPTY: { + /* + * 1 If the {content type} is empty, then the element information + * item has no character or element information item [children]. + */ + /* TODO: Hmm, Xerces reports nodes like Comment to be invalid + * content, but XSV does not. + */ + /* + * TODO: Is the entity stuff correct? + */ + while (child != NULL) { + if ((child->type == XML_ELEMENT_NODE) || + /* + * TODO: Ask Daniel if this are all character nodes. + */ + (child->type == XML_TEXT_NODE) || + (child->type == XML_CDATA_SECTION_NODE) || + (child->type == XML_ENTITY_REF_NODE) || + (child->type == XML_ENTITY_NODE)) { + break; + } + child = child->next; + } + if (child != NULL) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1, + "Character or element children are not allowed, " + "because the content type is empty.\n", + NULL, NULL); + } break; + } case XML_SCHEMA_CONTENT_ELEMENTS: - case XML_SCHEMA_CONTENT_MIXED: - case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS: - /* - * Skip ignorable nodes in that context - */ - child = xmlSchemaSkipIgnored(ctxt, type, child); - while (child != NULL) { - if (child->type == XML_ELEMENT_NODE) { - ret = xmlRegExecPushString(ctxt->regexp, - child->name, child); + case XML_SCHEMA_CONTENT_MIXED: + while (child != NULL) { + if (child->type == XML_ELEMENT_NODE) { + ret = xmlRegExecPushString(ctxt->regexp, + child->name, child); #ifdef DEBUG_AUTOMATA - if (ret < 0) - xmlGenericError(xmlGenericErrorContext, - " --> %s Error\n", child->name); - else - xmlGenericError(xmlGenericErrorContext, - " --> %s\n", child->name); + if (ret < 0) + xmlGenericError(xmlGenericErrorContext, + " --> %s Error\n", child->name); + else + xmlGenericError(xmlGenericErrorContext, + " --> %s\n", child->name); #endif - } - child = child->next; - /* - * Skip ignorable nodes in that context - */ - child = xmlSchemaSkipIgnored(ctxt, type, child); - } - if (((type->contentType == XML_SCHEMA_CONTENT_MIXED) || - (type->contentType == XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS)) && - (type->subtypes != NULL)) { - TODO - } - - - if (type->attributes != NULL) { - xmlSchemaValidateAttributes(ctxt, node, type->attributes); - } + } else if ((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) && + /* + * TODO: Ask Daniel if this are all character nodes. + */ + (((child->type == XML_TEXT_NODE) && (!IS_BLANK_NODE(child))) || + (child->type == XML_ENTITY_NODE) || + (child->type == XML_ENTITY_REF_NODE) || + (child->type == XML_CDATA_SECTION_NODE))) { + /* + * 2.3 If the {content type} is element-only, then the + * element information item has no character information + * item [children] other than those whose [character + * code] is defined as a white space in [XML 1.0 (Second + * Edition)]. + */ + xmlSchemaVErr(ctxt, node, XML_SCHEMAV_CVC_COMPLEX_TYPE_2_3, + "Character children are not allowed, " + "because the content type is element-only.\n", + NULL, NULL); + break; + } + child = child->next; + } break; + case XML_SCHEMA_CONTENT_SIMPLE: case XML_SCHEMA_CONTENT_BASIC:{ - if (type->subtypes != NULL) { - ctxt->type = type->subtypes; - xmlSchemaValidateComplexType(ctxt, node); - } - if (type->baseType != NULL) { - ctxt->type = type->baseType; - if (type->baseType->type == XML_SCHEMA_TYPE_BASIC) - xmlSchemaValidateBasicType(ctxt, node); - else if (type->baseType->type == XML_SCHEMA_TYPE_COMPLEX) - xmlSchemaValidateComplexType(ctxt, node); - else if (type->baseType->type == XML_SCHEMA_TYPE_SIMPLE) - xmlSchemaValidateSimpleType(ctxt, node); - else - xmlGenericError(xmlGenericErrorContext, - "unexpected content type of base: %d\n", - type->contentType); - - } - if (type->attributes != NULL) { - xmlSchemaValidateAttributes(ctxt, node, - type->attributes); - } - ctxt->type = type; - break; - } - case XML_SCHEMA_CONTENT_SIMPLE:{ + xmlSchemaTypePtr base, anyType; + xmlChar *value = NULL; + /* + * We hit a complexType with a simpleContent resolving + * to a user derived or built-in simple type. + */ + anyType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE); + /* + * Internal check for integrity of the base type. + */ + base = type->baseType; + while ((base != NULL) && + (base->type != XML_SCHEMA_TYPE_SIMPLE) && + (base->type != XML_SCHEMA_TYPE_BASIC) && + (base != anyType)) { + base = base->baseType; + } + if ((base == NULL) || + (((type->contentType == XML_SCHEMA_CONTENT_SIMPLE) && + (base->type != XML_SCHEMA_TYPE_SIMPLE)) || + ((type->contentType == XML_SCHEMA_CONTENT_BASIC) && + (base->type != XML_SCHEMA_TYPE_BASIC)))) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateComplexType, " + "Element \"%s\": the base type of the corresponding " + "complex type \"%s\" is not a user derived or a " + "built-in simple type.\n", + node->name, type->name); + return (-1); + } + /* + * 2.2 If the {content type} is a simple type definition, + * then the element information item has no element + * information item [children], and the ·normalized value· + * of the element information item is ·valid· with respect + * to that simple type definition as defined by String + * Valid (§3.14.4). + */ + child = node->children; + while (child != NULL) { + if (child->type == XML_ELEMENT_NODE) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2, + "Element children are not allowed, because " + "the content type is a simple type.\n", + NULL, NULL); + ret = XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2; + break; + } + child = child->next; + } + if (ret == 0) { + /* + * Validate the character content against a simple type. + */ + if (ctxt->node == NULL) + value = NULL; + else + value = xmlNodeGetContent(node); + ctxt->type = base; + ret = xmlSchemaValidateSimpleTypeValue(ctxt, value, 1, 1); + ctxt->type = type; + if (ret > 0) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2, + "The character value " + "is not valid with respect to the simple type.\n", + NULL, NULL); + ret = XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2; + } else if (ret < 0) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateComplexType, " + "Element \"%s\": error while validating character " + "content against complex type \"%s\".\n", + node->name, type->name); + return (-1); + } + } + if (ret == 0) { + /* + * Apply facets of the complexType. Be sure to pass the + * built-in type to xmlSchemaValidateFacetsInternal. + */ + /* TODO: I don't know yet if the facets of the simple type + * are used, or if the facets, defined by this complex type, + * are to be used only. This here applies both facet sets. + */ + while (base->type != XML_SCHEMA_TYPE_BASIC) + base = base->baseType; + if (base == NULL) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateComplexType, " + "Element \"%s\": error while validating character " + "content against complex type \"%s\"; failed to " + "compute the built-in simple type for facet " + "validation.\n", + node->name, type->name); + return (-1); + } + ret = xmlSchemaValidateFacetsInternal(ctxt, base, + type->facetSet, value, 1); + if (ret > 0) { + xmlSchemaVErr(ctxt, node, XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2, + "The character value " + "is not valid with respect to the simple type.\n", + NULL, NULL); + ret = XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2; + } else if (ret < 0) { + xmlSchemaVErr(ctxt, ctxt->cur, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateComplexType, " + "Element \"%s\": error while validating character " + "content against complex type \"%s\"; failed to " + "apply facets.\n", + type->name, NULL); + } + } + if (value != NULL) + xmlFree(value); + /* TODO: facets */ + break; + } + /* + case XML_SCHEMA_CONTENT_SIMPLE:{ if (type->subtypes != NULL) { ctxt->type = type->subtypes; xmlSchemaValidateComplexType(ctxt, node); @@ -6501,18 +10548,25 @@ xmlSchemaValidateComplexType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) ctxt->type = type->baseType; xmlSchemaValidateComplexType(ctxt, node); } + * Removed due to changes of attribute validation: if (type->attributes != NULL) { xmlSchemaValidateAttributes(ctxt, node, type->attributes); } + * ctxt->type = type; break; } + */ default: TODO xmlGenericError(xmlGenericErrorContext, "unimplemented content type %d\n", type->contentType); } + if (type->type == XML_SCHEMA_TYPE_COMPLEX) { + xmlSchemaValidateAttributes(ctxt, node, type); + } + ctxt->cur = node; return (ctxt->err); } @@ -6537,7 +10591,6 @@ xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) type = ctxt->type; ctxt->cur = node; - xmlSchemaValidateAttributes(ctxt, node, type->attributes); ctxt->cur = node; switch (type->type) { @@ -6570,13 +10623,11 @@ xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) break; } case XML_SCHEMA_TYPE_BASIC: - xmlSchemaValidateBasicType(ctxt, node); + case XML_SCHEMA_TYPE_SIMPLE: + xmlSchemaValidateSimpleTypeElement(ctxt, node); break; case XML_SCHEMA_TYPE_FACET: - TODO break; - case XML_SCHEMA_TYPE_SIMPLE: - xmlSchemaValidateSimpleType(ctxt, node); - break; + TODO break; case XML_SCHEMA_TYPE_SEQUENCE: TODO break; case XML_SCHEMA_TYPE_CHOICE: @@ -6633,7 +10684,6 @@ xmlSchemaValidateContent(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) case XML_SCHEMA_TYPE_ANY_ATTRIBUTE: TODO break; } - xmlSchemaValidateAttributes(ctxt, node, type->attributes); if (ctxt->node == NULL) return (ctxt->err); @@ -6662,6 +10712,10 @@ xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, if ((elem == NULL) || (type == NULL) || (elemDecl == NULL)) return (0); + /* This one is called by "xmlSchemaValidateElementType" and + * "xmlSchemaValidateElement". + */ + /* * 3.3.4 : 2 */ @@ -6710,9 +10764,7 @@ xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, ctxt->type = elemDecl->subtypes; ctxt->node = elem->children; - xmlSchemaValidateContent(ctxt, elem); - xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes); - + xmlSchemaValidateContent(ctxt, elem); return (ctxt->err); } @@ -6721,7 +10773,7 @@ xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, * xmlSchemaValidateAttributes: * @ctxt: a schema validation context * @elem: an element - * @attributes: the list of attribute declarations + * @type: the complexType holding the attribute uses * * Validate the attributes of an element. * @@ -6729,44 +10781,69 @@ xmlSchemaValidateType(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, * number otherwise and -1 in case of internal or API error. */ static int -xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, - xmlSchemaAttributePtr attributes) +xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, xmlSchemaTypePtr type) { - int i, ret; - xmlAttrPtr attr; + int ret; + xmlAttrPtr attr; /* An attribute on the element. */ xmlChar *value; - xmlSchemaAttributeGroupPtr group = NULL; + const xmlChar *nsURI; + xmlSchemaAttributeLinkPtr attrUse; + xmlSchemaAttributePtr attrDecl; int found; + xmlSchemaAttrStatePtr curState, reqAttrStates = NULL, reqAttrStatesTop = NULL; +#ifdef DEBUG_ATTR_VALIDATION + int redundant = 0; +#endif + if (type->type != XML_SCHEMA_TYPE_COMPLEX) { + xmlSchemaVErr(ctxt, elem, XML_SCHEMAS_ERR_INTERNAL, + "Internal error: xmlSchemaValidateAttributes: " + "given type \"%s\"is not a complexType\n", + type->name, NULL); + return(-1); + } - if (attributes == NULL) + if ((type->attributeUses == NULL) && (type->attributeWildcard == NULL)) return (0); - while (attributes != NULL) { + + attrUse = type->attributeUses; + + while (attrUse != NULL) { found = 0; - /* - * Handle attribute groups - */ - if (attributes->type == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) { - group = (xmlSchemaAttributeGroupPtr) attributes; - xmlSchemaValidateAttributes(ctxt, elem, group->attributes); - attributes = group->next; - continue; + attrDecl = attrUse->attr; +#ifdef DEBUG_ATTR_VALIDATION + printf("attr use - name: %s\n", xmlSchemaGetOnymousAttrName(attrDecl)); + printf("attr use - use: %d\n", attrDecl->occurs); +#endif + for (curState = ctxt->attr; curState != NULL; curState = curState->next) { + + if (curState->decl == attrUse->attr) { +#ifdef DEBUG_ATTR_VALIDATION + redundant = 1; +#endif } - for (i = ctxt->attrBase; i < ctxt->attrNr; i++) { - attr = ctxt->attr[i].attr; + attr = curState->attr; +#ifdef DEBUG_ATTR_VALIDATION + printf("attr - name: %s\n", attr->name); + if (attr->ns != NULL) + printf("attr - ns: %s\n", attr->ns->href); + else + printf("attr - ns: none\n"); +#endif + /* TODO: Can this ever happen? */ if (attr == NULL) continue; - if (attributes->ref != NULL) { - if (!xmlStrEqual(attr->name, attributes->ref)) + if (attrDecl->ref != NULL) { + if (!xmlStrEqual(attr->name, attrDecl->ref)) continue; if (attr->ns != NULL) { - if ((attributes->refNs == NULL) || - (!xmlStrEqual(attr->ns->href, attributes->refNs))) + if ((attrDecl->refNs == NULL) || + (!xmlStrEqual(attr->ns->href, attrDecl->refNs))) continue; - } else if (attributes->refNs != NULL) { + } else if (attrDecl->refNs != NULL) { continue; } } else { - if (!xmlStrEqual(attr->name, attributes->name)) + if (!xmlStrEqual(attr->name, attrDecl->name)) continue; /* * handle the namespaces checks here @@ -6776,7 +10853,7 @@ xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, * accept an unqualified attribute only if the target * namespace of the declaration is absent. */ - if (attributes->targetNamespace != NULL) + if (attrDecl->targetNamespace != NULL) /* * This check was removed, since the target namespace * was evaluated during parsing and already took @@ -6785,57 +10862,176 @@ xmlSchemaValidateAttributes(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem, /* ((attributes->flags & XML_SCHEMAS_ATTR_NSDEFAULT) == 0)) */ continue; } else { - if (attributes->targetNamespace == NULL) + if (attrDecl->targetNamespace == NULL) continue; - if (!xmlStrEqual(attributes->targetNamespace, + if (!xmlStrEqual(attrDecl->targetNamespace, attr->ns->href)) continue; } } +#ifdef DEBUG_ATTR_VALIDATION + printf("found\n"); +#endif found = 1; - ctxt->cur = (xmlNodePtr) attributes; - - if (attributes->subtypes == NULL) { + ctxt->cur = (xmlNodePtr) attr; + ctxt->node = attr->children; + + if (attrDecl->subtypes == NULL) { + curState->state = XML_SCHEMAS_ATTR_TYPE_NOT_RESOLVED; + curState->decl = attrDecl; + /* + * This could be put into "xmlSchemaCheckAttributes" as well, but + * since it reports an internal error, it better stays here to ease + * debugging. + */ xmlSchemaVErr(ctxt, (xmlNodePtr) attr, XML_SCHEMAS_ERR_INTERNAL, "Internal error: attribute %s type not resolved\n", attr->name, NULL); continue; } + value = xmlNodeListGetString(elem->doc, attr->children, 1); + ctxt->type = attrDecl->subtypes; + ret = xmlSchemaValidateSimpleTypeValue(ctxt, value, 0, 1); + ctxt->type = type; + if (ret != 0) + curState->state = XML_SCHEMAS_ATTR_INVALID_VALUE; + else + curState->state = XML_SCHEMAS_ATTR_CHECKED; + curState->decl = attrDecl; + if (value != NULL) { + xmlFree(value); + } + } + if ((!found) && (attrDecl->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED)) { + xmlSchemaAttrStatePtr tmp; - 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 suppresses the - * "attribute is unknown" error report. Please change - * this if you know better */ - ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED; - break; +#ifdef DEBUG_ATTR_VALIDATION + printf("required attr not found\n"); +#endif + /* + * Add a new dummy attribute state. + */ + tmp = (xmlSchemaAttrStatePtr) xmlMalloc(sizeof(xmlSchemaAttrState)); + if (tmp == NULL) { + xmlSchemaVErrMemory(ctxt, "registering required attributes", NULL); + return (-1); } + tmp->attr = NULL; + tmp->state = XML_SCHEMAS_ATTR_MISSING; + tmp->decl = attrDecl; + tmp->next = NULL; - value = xmlNodeListGetString(elem->doc, attr->children, 1); - ret = xmlSchemaValidateSimpleValue(ctxt, attributes->subtypes, - value); - if (ret != 0) { - xmlSchemaVErr(ctxt, (xmlNodePtr) attr, - XML_SCHEMAS_ERR_ATTRINVALID, - "attribute %s on %s does not match type\n", - attr->name, elem->name); + if (reqAttrStates == NULL) { + reqAttrStates = tmp; + reqAttrStatesTop = tmp; } else { - ctxt->attr[i].state = XML_SCHEMAS_ATTR_CHECKED; + reqAttrStatesTop->next = tmp; + reqAttrStatesTop = tmp; } - if (value != NULL) { - xmlFree(value); + + } + attrUse = attrUse->next; + } + /* + * Add required attributes to the attribute states of the context. + */ + if (reqAttrStates != NULL) { + if (ctxt->attr == NULL) { + ctxt->attr = reqAttrStates; + } else { + ctxt->attrTop->next = reqAttrStates; + } + ctxt->attrTop = reqAttrStatesTop; } + /* + * Process wildcards. + */ + if (type->attributeWildcard != NULL) { +#ifdef DEBUG_ATTR_VALIDATION + xmlSchemaWildcardNsPtr ns; + printf("matching wildcard: [%d] of complexType: %s\n", type->attributeWildcard, type->name); + if (type->attributeWildcard->processContents == + XML_SCHEMAS_ANY_LAX) + printf("processContents: lax\n"); + else if (type->attributeWildcard->processContents == + XML_SCHEMAS_ANY_STRICT) + printf("processContents: strict\n"); + else + printf("processContents: skip\n"); + if (type->attributeWildcard->any) + printf("type: any\n"); + else if (type->attributeWildcard->negNsSet != NULL) { + printf("type: negated\n"); + if (type->attributeWildcard->negNsSet->value == NULL) + printf("ns: (absent)\n"); + else + printf("ns: %s\n", type->attributeWildcard->negNsSet->value); + } else if (type->attributeWildcard->nsSet != NULL) { + printf("type: set\n"); + ns = type->attributeWildcard->nsSet; + while (ns != NULL) { + if (ns->value == NULL) + printf("ns: (absent)\n"); + else + printf("ns: %s\n", ns->value); + ns = ns->next; + } + } else + printf("empty\n"); + + +#endif + curState = ctxt->attr; + while (curState != NULL) { + if (curState->state == XML_SCHEMAS_ATTR_UNKNOWN) { + if (curState->attr->ns != NULL) + nsURI = curState->attr->ns->href; + else + nsURI = NULL; + if (xmlSchemaMatchesWildcardNs(type->attributeWildcard, + nsURI)) { + /* + * Handle processContents. + */ + if ((type->attributeWildcard->processContents == + XML_SCHEMAS_ANY_LAX) || + (type->attributeWildcard->processContents == + XML_SCHEMAS_ANY_STRICT)) { + + attr = curState->attr; + attrDecl = xmlSchemaGetAttribute(ctxt->schema, + attr->name, nsURI); + if (attrDecl != NULL) { + value = xmlNodeListGetString(elem->doc, attr->children, 1); + ctxt->type = attrDecl->subtypes; + ret = xmlSchemaValidateSimpleTypeValue(ctxt, value, 1, 1); + ctxt->type = type; + if (ret != 0) + curState->state = XML_SCHEMAS_ATTR_INVALID_VALUE; + else + curState->state = XML_SCHEMAS_ATTR_CHECKED; + curState->decl = attrDecl; + if (value != NULL) { + xmlFree(value); + } + + } else if (type->attributeWildcard->processContents == + XML_SCHEMAS_ANY_LAX) { + curState->state = XML_SCHEMAS_ATTR_CHECKED; + } + } else + curState->state = XML_SCHEMAS_ATTR_CHECKED; + } + } + curState = curState->next; } - 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; } +#ifdef DEBUG_ATTR_VALIDATION + if (redundant) + xmlGenericError(xmlGenericErrorContext, + "xmlSchemaValidateAttributes: redundant call by type: %s\n", + type->name); +#endif return (ctxt->err); } @@ -6853,7 +11049,8 @@ static int xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) { xmlSchemaElementPtr elemDecl; - int ret, attrBase; + int ret; + xmlSchemaAttrStatePtr attrs, attrTop; if (elem->ns != NULL) { elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, @@ -6862,22 +11059,7 @@ xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, elem->name, NULL, NULL); } - /* - * special case whe elementFormDefault is unqualified for top-level elem. - */ - /* - * This was removed, since elementFormDefault does not apply to top-level - * element declarations. - */ - /* - if ((elemDecl == NULL) && (elem->ns != NULL) && - (elem->parent != NULL) && (elem->parent->type != XML_ELEMENT_NODE) && - (xmlStrEqual(ctxt->schema->targetNamespace, elem->ns->href)) && - ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) { - elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, - elem->name, NULL, NULL); - } - */ + /* This one is called by xmlSchemaValidateDocument only. */ /* * 3.3.4 : 1 @@ -6895,10 +11077,9 @@ xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) /* * Verify the attributes */ - attrBase = ctxt->attrBase; - ctxt->attrBase = ctxt->attrNr; + attrs = ctxt->attr; + attrTop = ctxt->attrTop; xmlSchemaRegisterAttributes(ctxt, elem->properties); - xmlSchemaValidateAttributes(ctxt, elem, elemDecl->attributes); /* * Verify the element content recursively */ @@ -6939,8 +11120,10 @@ xmlSchemaValidateElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem) * Verify that all attributes were Schemas-validated */ xmlSchemaCheckAttributes(ctxt, elem); - ctxt->attrNr = ctxt->attrBase; - ctxt->attrBase = attrBase; + if (ctxt->attr != NULL) + xmlSchemaFreeAttributeStates(ctxt->attr); + ctxt->attr = attrs; + ctxt->attrTop = attrTop; return (ctxt->err); } @@ -6960,7 +11143,7 @@ xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) { xmlNodePtr root; xmlSchemaElementPtr elemDecl; - + root = xmlDocGetRootElement(doc); if (root == NULL) { xmlSchemaVErr(ctxt, (xmlNodePtr) doc, XML_SCHEMAS_ERR_NOROOT, @@ -6974,22 +11157,27 @@ xmlSchemaValidateDocument(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc) else elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, root->name, NULL, NULL); + /* * special case whe elementFormDefault is unqualified for top-level elem. */ + /* Removed, since elementFormDefault does not apply to top level + * elements */ + /* if ((elemDecl == NULL) && (root->ns != NULL) && (xmlStrEqual(ctxt->schema->targetNamespace, root->ns->href)) && ((ctxt->schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0)) { elemDecl = xmlHashLookup3(ctxt->schema->elemDecl, root->name, NULL, NULL); } + */ if (elemDecl == NULL) { xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_UNDECLAREDELEM, "Element %s not declared\n", root->name, NULL); - } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_TOPLEVEL) == 0) { + } else if ((elemDecl->flags & XML_SCHEMAS_ELEM_GLOBAL) == 0) { xmlSchemaVErr(ctxt, root, XML_SCHEMAS_ERR_NOTTOPLEVEL, - "Root element %s not toplevel\n", root->name, NULL); + "Root element %s not global\n", root->name, NULL); } /* * Okay, start the recursive validation @@ -7031,8 +11219,17 @@ xmlSchemaNewValidCtxt(xmlSchemaPtr schema) } memset(ret, 0, sizeof(xmlSchemaValidCtxt)); ret->schema = schema; - ret->attrNr = 0; - ret->attrMax = 10; + /* + * Removed due to changes of the attribute state list. + */ + /* ret->attrNr = 0; */ + /* ret->attrMax = 10; */ + /* ret->attrBase = NULL; */ + ret->attrTop = NULL; + ret->attr = NULL; + /* + * Removed due to changes of the attribute state list. + * ret->attr = (xmlSchemaAttrStatePtr) xmlMalloc(ret->attrMax * sizeof (xmlSchemaAttrState)); @@ -7042,6 +11239,8 @@ xmlSchemaNewValidCtxt(xmlSchemaPtr schema) return (NULL); } memset(ret->attr, 0, ret->attrMax * sizeof(xmlSchemaAttrState)); + */ + return (ret); } @@ -7057,7 +11256,7 @@ xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt) if (ctxt == NULL) return; if (ctxt->attr != NULL) - xmlFree(ctxt->attr); + xmlSchemaFreeAttributeStates(ctxt->attr); if (ctxt->value != NULL) xmlSchemaFreeValue(ctxt->value); xmlFree(ctxt); |