File:  [Public] / XML / schema.c
Revision 1.3: download - view: text, annotated - select for diffs
Wed Oct 25 19:26:53 2000 UTC (23 years, 7 months ago) by veillard
Branches: MAIN
CVS tags: LIBXML_2_2_8, HEAD
Message cleanup Jumbo Diff:
- in xmlerror.h : I added the export of an error context type (void *)
     an error handler type xmlGenericErrorFunc
     there is an interface
       xmlSetGenericErrorFunc  (void *ctx, xmlGenericErrorFunc handler);
     to reset the error handling routine and its argument
 (by default it's equivalent to respectively fprintf and stderr.
- in all the c files, all wild accesses to stderr or stdout within
 the library have been replaced to the handler.
- removed slashrdf.c now obsolete
Daniel

/*
 * 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 <libxml/schema.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#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) &&				\
    (xmlStrEqual(node->name, (const xmlChar *) type)) &&			\
    (xmlStrEqual(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) &&				\
    (xmlStrEqual(node->name, (const xmlChar *) type)) &&			\
    (xmlStrEqual(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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "xmlSchemaParseAnnotation()\n");
#endif


    if ((ctxt ==  NULL) || (schema == NULL) || (node == NULL))
	return(-1);

#ifdef DEBUG
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "xmlSchemaParseSimpleType()\n");
#endif


    if ((ctxt ==  NULL) || (schema == NULL) || (node == NULL))
	return(-1);

#ifdef DEBUG
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "xmlSchemaParseComplexType()\n");
#endif

    if ((ctxt ==  NULL) || (schema == NULL) || (node == NULL))
	return(-1);

#ifdef DEBUG
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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)
	xmlGenericError(xmlGenericErrorContext,
		"xmlSchemaParse() failed\n");
    else
	xmlGenericError(xmlGenericErrorContext,
		"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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "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
    xmlGenericError(xmlGenericErrorContext,
	    "xmlSchemaValidate()\n");
#endif

#ifdef DEBUG
    xmlGenericError(xmlGenericErrorContext,
	    "xmlSchemaValidate() finished : %d\n", ret);
#endif

    return(ret);
}

Webmaster