/* * schema.c : implementation of the XML Schema handling and * schema validity checking * * See Copyright for the status of this software. * * Daniel.Veillard@w3.org */ #ifdef WIN32 #include "win32config.h" #else #include "config.h" #endif #include #include #include #define DEBUG 1 /* very verobose output */ /* * The XML Schemas namespaces */ static const xmlChar *xmlSchemaNs = (const xmlChar *) "http://www.w3.org/1999/XMLSchema"; #define IS_SCHEMA(node, type) \ ((node != NULL) && (node->ns != NULL) && \ (!xmlStrcmp(node->name, (const xmlChar *) type)) && \ (!xmlStrcmp(node->ns->href, xmlSchemaNs))) /****** static const xmlChar *xmlSchemaInstanceNs = (const xmlChar *) "http://www.w3.org/1999/XMLSchema-instance"; #define IS_SCHEMA_INSTANCE(node, type) \ ((node != NULL) && (node->ns != NULL) && \ (!xmlStrcmp(node->name, (const xmlChar *) type)) && \ (!xmlStrcmp(node->ns->href, xmlSchemaInstanceNs))) ******/ /* * XML Schemas defines multiple type of types. */ typedef enum { XML_SCHEMA_TYPE_BASIC = 1, XML_SCHEMA_TYPE_SIMPLE, XML_SCHEMA_TYPE_COMPLEX, XML_SCHEMA_TYPE_UR, XML_SCHEMA_TYPE_RESTRICTION, XML_SCHEMA_TYPE_EXTENTION } xmlSchemaTypeType; /** * A facet definition typedef struct _xmlSchemaFacet xmlSchemaFacet; typedef xmlSchemaFacet *xmlSchemaFacetPtr; struct _xmlSchemaFacet { }; */ /** * A content type definition typedef struct _xmlSchemaContentType xmlSchemaContentType; typedef xmlSchemaContentType *xmlSchemaContentTypePtr; struct _xmlSchemaContentType { }; */ /** * Simple type definition. */ typedef struct _xmlSchemaType xmlSchemaType; typedef xmlSchemaType *xmlSchemaTypePtr; struct _xmlSchemaType { const xmlChar *name; /* The type name */ const xmlChar *annot; /* the annotation */ struct _xmlSchemaType *next; /* Next in the list */ xmlSchemaTypeType type; /* The kind of schema type */ }; /** * Derived type definition. */ typedef struct _xmlSchemaDerivedType xmlSchemaDerivedType; typedef xmlSchemaDerivedType *xmlSchemaDerivedTypePtr; struct _xmlSchemaDerivedType { const xmlChar *name; const xmlChar *annot; /* the annotation */ }; /** * A notation definition. */ typedef struct _xmlSchemaNotation xmlSchemaNotation; typedef xmlSchemaNotation *xmlSchemaNotationPtr; struct _xmlSchemaNotation { const xmlChar *name; const xmlChar *annot; /* the annotation */ struct _xmlSchemaNotation *next; /* Next in the list */ const xmlChar *identifier; }; /** * An attribute definition. */ typedef struct _xmlSchemaAttribute xmlSchemaAttribute; typedef xmlSchemaAttribute *xmlSchemaAttributePtr; struct _xmlSchemaAttribute { const xmlChar *name; const xmlChar *annot; /* the annotation */ struct _xmlSchemaAttribute *next; /* Next in the list */ xmlSchemaTypePtr base; int occurs; const xmlChar *defValue; }; /** * An element definition. */ typedef struct _xmlSchemaElement xmlSchemaElement; typedef xmlSchemaElement *xmlSchemaElementPtr; struct _xmlSchemaElement { const xmlChar *name; const xmlChar *annot; /* the annotation */ struct _xmlSchemaElement *next; /* Next in the list */ }; /** * A Schemas definition */ struct _xmlSchema { const xmlChar *name; /* schema name */ const xmlChar *annot; /* the annotation */ const xmlChar *targetNameSpace; /* the target namespace */ xmlSchemaTypePtr typeDefs; /* the list of types definitions */ xmlSchemaAttributePtr attrDecl; /* attributes declarations */ xmlSchemaElementPtr elemDecl; /* elements declarations */ }; /************************************************************************ * * * Allocation functions * * * ************************************************************************/ /** * xmlSchemaNewSchema: * @ctxt: a schema validation context (optional) * * Allocate a new Schema structure. * * Returns the newly allocated structure or NULL in case or error */ xmlSchemaPtr xmlSchemaNewSchema(xmlSchemaValidCtxtPtr ctxt) { xmlSchemaPtr ret; ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema)); if (ret == NULL) { if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error(ctxt->userData, "Out of memory\n"); return(NULL); } memset(ret, 0, sizeof(xmlSchema)); return(ret); } /** * xmlSchemaFreeAttribute: * @schema: a schema attribute structure * * Deallocate a Schema Attribute structure. */ void xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr) { if (attr == NULL) return; if (attr->name != NULL) xmlFree((xmlChar *) attr->name); memset(attr, -1, sizeof(xmlSchemaAttribute)); xmlFree(attr); } /** * xmlSchemaFreeAttributeList: * @cur: a schema attribute list structure * * Deallocate a Schema Attribute structure. */ void xmlSchemaFreeAttributeList(xmlSchemaAttributePtr cur) { xmlSchemaAttributePtr next; if (cur == NULL) return; while (cur != NULL) { next = cur->next; xmlSchemaFreeAttribute(cur); cur = next; } } /** * xmlSchemaFreeElement: * @schema: a schema element structure * * Deallocate a Schema Element structure. */ void xmlSchemaFreeElement(xmlSchemaElementPtr elem) { if (elem == NULL) return; if (elem->name != NULL) xmlFree((xmlChar *) elem->name); memset(elem, -1, sizeof(xmlSchemaElement)); xmlFree(elem); } /** * xmlSchemaFreeElementList: * @cur: a schema element list structure * * Deallocate a Schema Element structure. */ void xmlSchemaFreeElementList(xmlSchemaElementPtr cur) { xmlSchemaElementPtr next; if (cur == NULL) return; while (cur != NULL) { next = cur->next; xmlSchemaFreeElement(cur); cur = next; } } /** * xmlSchemaFree: * @schema: a schema structure * * Deallocate a Schema structure. */ void xmlSchemaFree(xmlSchemaPtr schema) { if (schema == NULL) return; if (schema->name != NULL) xmlFree((xmlChar *) schema->name); if (schema->attrDecl != NULL) xmlSchemaFreeAttributeList(schema->attrDecl); if (schema->elemDecl != NULL) xmlSchemaFreeElementList(schema->elemDecl); memset(schema, -1, sizeof(xmlSchema)); xmlFree(schema); } /** * xmlSchemaAddAttribute: * @ctxt: a schema validation context * @schema: the schema being built * @name: the item name * * Add an XML schema Attrribute declaration * *WARNING* this interface is highly subject to change * * Returns the new struture or NULL in case of error */ xmlSchemaAttributePtr xmlSchemaAddAttribute(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, const xmlChar *name) { xmlSchemaAttributePtr ret = NULL; #ifdef DEBUG fprintf(stderr, "xmlSchemaAddAttribute()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) return(NULL); ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute)); if (ret == NULL) { if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error(ctxt->userData, "Out of memory\n"); return(NULL); } memset(ret, 0, sizeof(xmlSchemaAttribute)); ret->name = name; ret->next = schema->attrDecl; schema->attrDecl = ret; #ifdef DEBUG fprintf(stderr, "xmlSchemaAddAttribute() finished\n"); #endif return(ret); } /** * xmlSchemaAddElement: * @ctxt: a schema validation context * @schema: the schema being built * @name: the item name * * Add an XML schema Element declaration * *WARNING* this interface is highly subject to change * * Returns the new struture or NULL in case of error */ xmlSchemaElementPtr xmlSchemaAddElement(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, const xmlChar *name) { xmlSchemaElementPtr ret = NULL; #ifdef DEBUG fprintf(stderr, "xmlSchemaAddElement()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) return(NULL); ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement)); if (ret == NULL) { if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error(ctxt->userData, "Out of memory\n"); return(NULL); } memset(ret, 0, sizeof(xmlSchemaElement)); ret->name = name; ret->next = schema->elemDecl; schema->elemDecl = ret; #ifdef DEBUG fprintf(stderr, "xmlSchemaAddElement() finished\n"); #endif return(ret); } /** * xmlSchemaAddSimpleType: * @ctxt: a schema validation context * @schema: the schema being built * @name: the item name * * Add an XML schema Simple Type definition * *WARNING* this interface is highly subject to change * * Returns the new struture or NULL in case of error */ xmlSchemaTypePtr xmlSchemaAddSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, const xmlChar *name) { xmlSchemaTypePtr ret = NULL; #ifdef DEBUG fprintf(stderr, "xmlSchemaAddSimpleType()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) return(NULL); ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); if (ret == NULL) { if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error(ctxt->userData, "Out of memory\n"); return(NULL); } memset(ret, 0, sizeof(xmlSchemaType)); ret->name = name; ret->type = XML_SCHEMA_TYPE_SIMPLE; ret->next = schema->typeDefs; schema->typeDefs = ret; #ifdef DEBUG fprintf(stderr, "xmlSchemaAddSimpleType() finished\n"); #endif return(ret); } /** * xmlSchemaAddComplexType: * @ctxt: a schema validation context * @schema: the schema being built * @name: the item name * * Add an XML schema Complex Type definition * *WARNING* this interface is highly subject to change * * Returns the new struture or NULL in case of error */ xmlSchemaTypePtr xmlSchemaAddComplexType(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, const xmlChar *name) { xmlSchemaTypePtr ret = NULL; #ifdef DEBUG fprintf(stderr, "xmlSchemaAddComplexType()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) return(NULL); ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); if (ret == NULL) { if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error(ctxt->userData, "Out of memory\n"); return(NULL); } memset(ret, 0, sizeof(xmlSchemaType)); ret->name = name; ret->type = XML_SCHEMA_TYPE_COMPLEX; ret->next = schema->typeDefs; schema->typeDefs = ret; #ifdef DEBUG fprintf(stderr, "xmlSchemaAddComplexType() finished\n"); #endif return(ret); } /************************************************************************ * * * Shema extraction from an Infoset * * * ************************************************************************/ /** * xmlSchemaParseAnnotation: * @ctxt: a schema validation context * @schema: the schema being built * @node: a subtree containing XML Schema informations * * parse a XML schema Attrribute declaration * *WARNING* this interface is highly subject to change * * Returns -1 in case of error, 0 if the declaration is inproper and * 1 in case of success. */ int xmlSchemaParseAnnotation(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node) { int ret = 0; #ifdef DEBUG fprintf(stderr, "xmlSchemaParseAnnotation()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return(-1); #ifdef DEBUG fprintf(stderr, "xmlSchemaParseAnnotation() finished\n"); #endif return(ret); } /** * xmlSchemaParseAttribute: * @ctxt: a schema validation context * @schema: the schema being built * @node: a subtree containing XML Schema informations * * parse a XML schema Attrribute declaration * *WARNING* this interface is highly subject to change * * Returns -1 in case of error, 0 if the declaration is inproper and * 1 in case of success. */ xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node) { xmlChar *name; xmlSchemaAttributePtr ret; #ifdef DEBUG fprintf(stderr, "xmlSchemaParseAttribute()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return(NULL); name = xmlGetProp(node, (const xmlChar *) "name"); if (name == NULL) { if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error(ctxt->userData, "Attribute has no name\n"); return(NULL); } ret = xmlSchemaAddAttribute(ctxt, schema, name); if (ret == NULL) { xmlFree(name); return(NULL); } #ifdef DEBUG fprintf(stderr, "xmlSchemaParseAttribute() finished\n"); #endif return(ret); } /** * xmlSchemaParseElement: * @ctxt: a schema validation context * @schema: the schema being built * @node: a subtree containing XML Schema informations * * parse a XML schema Element declaration * *WARNING* this interface is highly subject to change * * Returns -1 in case of error, 0 if the declaration is inproper and * 1 in case of success. */ xmlSchemaElementPtr xmlSchemaParseElement(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node) { xmlChar *name; xmlSchemaElementPtr ret; #ifdef DEBUG fprintf(stderr, "xmlSchemaParseElement()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return(NULL); name = xmlGetProp(node, (const xmlChar *) "name"); if (name == NULL) { if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error(ctxt->userData, "Element has no name\n"); return(NULL); } ret = xmlSchemaAddElement(ctxt, schema, name); if (ret == NULL) { xmlFree(name); return(NULL); } #ifdef DEBUG fprintf(stderr, "xmlSchemaParseElement() finished\n"); #endif return(ret); } /** * xmlSchemaParseSimpleType: * @ctxt: a schema validation context * @schema: the schema being built * @node: a subtree containing XML Schema informations * * parse a XML schema Simple Type definition * *WARNING* this interface is highly subject to change * * Returns -1 in case of error, 0 if the declaration is inproper and * 1 in case of success. */ int xmlSchemaParseSimpleType(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node) { int ret = 0; #ifdef DEBUG fprintf(stderr, "xmlSchemaParseSimpleType()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return(-1); #ifdef DEBUG fprintf(stderr, "xmlSchemaParseSimpleType() finished\n"); #endif return(ret); } /** * xmlSchemaParseComplexType: * @ctxt: a schema validation context * @schema: the schema being built * @node: a subtree containing XML Schema informations * * parse a XML schema Complex Type definition * *WARNING* this interface is highly subject to change * * Returns -1 in case of error, 0 if the declaration is inproper and * 1 in case of success. */ int xmlSchemaParseComplexType(xmlSchemaValidCtxtPtr ctxt, xmlSchemaPtr schema, xmlNodePtr node) { int ret = 0; #ifdef DEBUG fprintf(stderr, "xmlSchemaParseComplexType()\n"); #endif if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) return(-1); #ifdef DEBUG fprintf(stderr, "xmlSchemaParseComplexType() finished\n"); #endif return(ret); } /** * xmlSchemaParse: * @ctxt: a schema validation context * @node: a subtree containing XML Schema informations * * parse a XML schema definition from a node set * *WARNING* this interface is highly subject to change * * Returns the internal XML Schema structure built from the resource or * NULL in case of error */ xmlSchemaPtr xmlSchemaParse(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node) { xmlSchemaPtr schema = NULL; xmlNodePtr child; #ifdef DEBUG fprintf(stderr, "xmlSchemaParse()\n"); #endif if ((ctxt == NULL) || (node == NULL)) return(NULL); if (IS_SCHEMA(node, "schema")) { schema = xmlSchemaNewSchema(ctxt); child = node->children; while (child != NULL) { if (IS_SCHEMA(child, "element")) xmlSchemaParseElement(ctxt, schema, child); else if (IS_SCHEMA(child, "attribute")) xmlSchemaParseAttribute(ctxt, schema, child); else if (IS_SCHEMA(child, "annotation")) xmlSchemaParseAnnotation(ctxt, schema, child); else if (IS_SCHEMA(child, "complexType")) xmlSchemaParseComplexType(ctxt, schema, child); else if (IS_SCHEMA(child, "simpleType")) xmlSchemaParseSimpleType(ctxt, schema, child); child = child->next; } } #ifdef DEBUG if (schema == NULL) fprintf(stderr, "xmlSchemaParse() failed\n"); else fprintf(stderr, "xmlSchemaParse() finished\n"); #endif return(schema); } /************************************************************************ * * * Reading/Writing Schemas * * * ************************************************************************/ /** * xmlSchemaLoad: * @ctxt: a schema validation context * @URL: the location of the schema * * Load, XML parse a schema definition resource and build an internal * XML Shema struture which can be used to validate instances. * *WARNING* this interface is highly subject to change * * Returns the internal XML Schema structure built from the resource or * NULL in case of error */ xmlSchemaPtr xmlSchemaLoad(xmlSchemaValidCtxtPtr ctxt, const char *URL) { xmlSchemaPtr ret; xmlDocPtr doc; xmlNodePtr root; if ((URL == NULL) || (ctxt == NULL)) return(NULL); #ifdef DEBUG fprintf(stderr, "xmlSchemaLoad(%s)\n", URL); #endif /* * First step is to parse the input document into an DOM/Infoset * TODO: do error redirections */ doc = xmlParseFile(URL); if (doc == NULL) { if (ctxt->error != NULL) ctxt->error(ctxt->userData, "xmlSchemaLoad: %s is not WellFormed\n", URL); return(NULL); } /* * Then extract the root and Schema parse it */ root = xmlDocGetRootElement(doc); if (root == NULL) { if (ctxt->error != NULL) ctxt->error(ctxt->userData, "xmlSchemaLoad: %s is empty\n", URL); return(NULL); } ret = xmlSchemaParse(ctxt, root); /* * Cleanup */ xmlFreeDoc(doc); #ifdef DEBUG fprintf(stderr, "xmlSchemaLoad(%s) finished\n", URL); #endif return(ret); } /** * xmlSchemaValidate: * @ctxt: a schema validation context * @instance: the subtree (infoset) instance to validate. * @schema: the internal XML Schema structure * * Attempts to schema validate an instance against an XML Schema * * Returns -1 in case of general error, 0 if the instance does not validate * and 1 if it validates */ int xmlSchemaValidate(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr instance, xmlSchemaPtr schema) { int ret = 0; #ifdef DEBUG fprintf(stderr, "xmlSchemaValidate()\n"); #endif #ifdef DEBUG fprintf(stderr, "xmlSchemaValidate() finished : %d\n", ret); #endif return(ret); }