text: /*
   * schemas.c : implementation of the XML Schema handling and
   *             schema validity checking
   *
   * See Copyright for the status of this software.
   *
   * Daniel Veillard <veillard@redhat.com>
   */
  
  /*
   * TODO:
   *   - 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.
   *   - Eliminate item creation for: ??
   *
   * URGENT TODO:
   *   - For xsi-driven schema acquisition, augment the IDCs after every
   *     acquisition episode (xmlSchemaAugmentIDC).
   *
   * NOTES:
   *   - Eliminated item creation for: <restriction>, <extension>,
   *     <simpleContent>, <complexContent>, <list>, <union>
   *
   * PROBLEMS:
   *   - http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005JulSep/0337.html
   *     IDC XPath expression and chameleon includes: the targetNamespace is changed, so
   *     XPath will have trouble to resolve to this namespace, since not known.
   *
   *
   * CONSTRAINTS:
   *
   * Schema Component Constraint:
   *   All Group Limited (cos-all-limited)
   *   Status: complete
   *   (1.2)
   *     In xmlSchemaGroupDefReferenceTermFixup() and
   *   (2)
   *     In xmlSchemaParseModelGroup()
   *     TODO: Actually this should go to component-level checks,
   *     but is done here due to performance. Move it to an other layer
   *     is schema construction via an API is implemented.
   */
  
  /* To avoid EBCDIC trouble when parsing on zOS */
  #if defined(__MVS__)
  #pragma convert("ISO8859-1")
  #endif
  
  #define IN_LIBXML
  #include "libxml.h"
  
  #ifdef LIBXML_SCHEMAS_ENABLED
  
  #include <string.h>
  #include <libxml/xmlmemory.h>
  #include <libxml/parser.h>
  #include <libxml/parserInternals.h>
  #include <libxml/hash.h>
  #include <libxml/uri.h>
  #include <libxml/xmlschemas.h>
  #include <libxml/schemasInternals.h>
  #include <libxml/xmlschemastypes.h>
  #include <libxml/xmlautomata.h>
  #include <libxml/xmlregexp.h>
  #include <libxml/dict.h>
  #include <libxml/encoding.h>
  #include <libxml/xmlIO.h>
  #ifdef LIBXML_PATTERN_ENABLED
  #include <libxml/pattern.h>
  #endif
  #ifdef LIBXML_READER_ENABLED
  #include <libxml/xmlreader.h>
  #endif
  
  /* #define DEBUG 1 */
  
  /* #define DEBUG_CONTENT 1 */
  
  /* #define DEBUG_TYPE 1 */
  
  /* #define DEBUG_CONTENT_REGEXP 1 */
  
  /* #define DEBUG_AUTOMATA 1 */
  
  /* #define DEBUG_IDC */
  
  /* #define DEBUG_IDC_NODE_TABLE */
  
  /* #define WXS_ELEM_DECL_CONS_ENABLED */
  
  #ifdef DEBUG_IDC
   #ifndef DEBUG_IDC_NODE_TABLE
    #define DEBUG_IDC_NODE_TABLE
   #endif
  #endif
  
  /* #define ENABLE_PARTICLE_RESTRICTION 1 */
  
  #define ENABLE_REDEFINE
  
  /* #define ENABLE_NAMED_LOCALS */
  
  /* #define ENABLE_IDC_NODE_TABLES_TEST */
  
  #define DUMP_CONTENT_MODEL
  
  #ifdef LIBXML_READER_ENABLED
  /* #define XML_SCHEMA_READER_ENABLED */
  #endif
  
  #define UNBOUNDED (1 << 30)
  #define TODO								\
      xmlGenericError(xmlGenericErrorContext,				\
  	    "Unimplemented block at %s:%d\n",				\
              __FILE__, __LINE__);
  
  #define XML_SCHEMAS_NO_NAMESPACE (const xmlChar *) "##"
  
  /*
   * The XML Schemas namespaces
   */
  static const xmlChar *xmlSchemaNs = (const xmlChar *)
      "http://www.w3.org/2001/XMLSchema";
  
  static const xmlChar *xmlSchemaInstanceNs = (const xmlChar *)
      "http://www.w3.org/2001/XMLSchema-instance";
  
  static const xmlChar *xmlNamespaceNs = (const xmlChar *)
      "http://www.w3.org/2000/xmlns/";
  
  /*
  * Come casting macros.
  */
  #define ACTXT_CAST (xmlSchemaAbstractCtxtPtr)
  #define PCTXT_CAST (xmlSchemaParserCtxtPtr)
  #define VCTXT_CAST (xmlSchemaValidCtxtPtr)
  #define WXS_BASIC_CAST (xmlSchemaBasicItemPtr)
  #define WXS_TREE_CAST (xmlSchemaTreeItemPtr)
  #define WXS_PTC_CAST (xmlSchemaParticlePtr)
  #define WXS_TYPE_CAST (xmlSchemaTypePtr)
  #define WXS_ELEM_CAST (xmlSchemaElementPtr)
  #define WXS_ATTR_GROUP_CAST (xmlSchemaAttributeGroupPtr)
  #define WXS_ATTR_CAST (xmlSchemaAttributePtr)
  #define WXS_ATTR_USE_CAST (xmlSchemaAttributeUsePtr)
  #define WXS_ATTR_PROHIB_CAST (xmlSchemaAttributeUseProhibPtr)
  #define WXS_MODEL_GROUPDEF_CAST (xmlSchemaModelGroupDefPtr)
  #define WXS_MODEL_GROUP_CAST (xmlSchemaModelGroupPtr)
  #define WXS_IDC_CAST (xmlSchemaIDCPtr)
  #define WXS_QNAME_CAST (xmlSchemaQNameRefPtr)
  #define WXS_LIST_CAST (xmlSchemaItemListPtr)
  
  /*
  * Macros to query common properties of components.
  */
  #define WXS_ITEM_NODE(i) xmlSchemaGetComponentNode(WXS_BASIC_CAST (i))
  
  #define WXS_ITEM_TYPE_NAME(i) xmlSchemaGetComponentTypeStr(WXS_BASIC_CAST (i))
  /*
  * Macros for element declarations.
  */
  #define WXS_ELEM_TYPEDEF(e) (e)->subtypes
  
  #define WXS_SUBST_HEAD(item) (item)->refDecl
  /*
  * Macros for attribute declarations.
  */
  #define WXS_ATTR_TYPEDEF(a) (a)->subtypes
  /*
  * Macros for attribute uses.
  */
  #define WXS_ATTRUSE_DECL(au) (WXS_ATTR_USE_CAST (au))->attrDecl
  
  #define WXS_ATTRUSE_TYPEDEF(au) WXS_ATTR_TYPEDEF(WXS_ATTRUSE_DECL( WXS_ATTR_USE_CAST au))
  
  #define WXS_ATTRUSE_DECL_NAME(au) (WXS_ATTRUSE_DECL(au))->name
  
  #define WXS_ATTRUSE_DECL_TNS(au) (WXS_ATTRUSE_DECL(au))->targetNamespace
  /*
  * Macros for attribute groups.
  */
  #define WXS_ATTR_GROUP_HAS_REFS(ag) ((WXS_ATTR_GROUP_CAST (ag))->flags & XML_SCHEMAS_ATTRGROUP_HAS_REFS)
  #define WXS_ATTR_GROUP_EXPANDED(ag) ((WXS_ATTR_GROUP_CAST (ag))->flags & XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED)
  /*
  * Macros for particles.
  */
  #define WXS_PARTICLE(p) WXS_PTC_CAST (p)
  
  #define WXS_PARTICLE_TERM(p) (WXS_PARTICLE(p))->children
  
  #define WXS_PARTICLE_TERM_AS_ELEM(p) (WXS_ELEM_CAST WXS_PARTICLE_TERM(p))
  
  #define WXS_PARTICLE_MODEL(p) WXS_MODEL_GROUP_CAST WXS_PARTICLE(p)->children
  /*
  * Macros for model groups definitions.
  */
  #define WXS_MODELGROUPDEF_MODEL(mgd) (WXS_MODEL_GROUP_CAST (mgd))->children
  /*
  * Macros for model groups.
  */
  #define WXS_IS_MODEL_GROUP(i) \
      (((i)->type == XML_SCHEMA_TYPE_SEQUENCE) || \
       ((i)->type == XML_SCHEMA_TYPE_CHOICE) || \
       ((i)->type == XML_SCHEMA_TYPE_ALL))
  
  #define WXS_MODELGROUP_PARTICLE(mg) WXS_PTC_CAST (mg)->children
  /*
  * Macros for schema buckets.
  */
  #define WXS_IS_BUCKET_INCREDEF(t) (((t) == XML_SCHEMA_SCHEMA_INCLUDE) || \
      ((t) == XML_SCHEMA_SCHEMA_REDEFINE))
  
  #define WXS_IS_BUCKET_IMPMAIN(t) (((t) == XML_SCHEMA_SCHEMA_MAIN) || \
      ((t) == XML_SCHEMA_SCHEMA_IMPORT))
  
  #define WXS_IMPBUCKET(b) ((xmlSchemaImportPtr) (b))
  
  #define WXS_INCBUCKET(b) ((xmlSchemaIncludePtr) (b))
  /*
  * Macros for complex/simple types.
  */
  #define WXS_IS_ANYTYPE(i) \
       (( (i)->type == XML_SCHEMA_TYPE_BASIC) && \
        ( (WXS_TYPE_CAST (i))->builtInType == XML_SCHEMAS_ANYTYPE))
  
  #define WXS_IS_COMPLEX(i) \
      (((i)->type == XML_SCHEMA_TYPE_COMPLEX) || \
       ((i)->builtInType == XML_SCHEMAS_ANYTYPE))
  
  #define WXS_IS_SIMPLE(item) \
      ((item->type == XML_SCHEMA_TYPE_SIMPLE) || \
       ((item->type == XML_SCHEMA_TYPE_BASIC) && \
        (item->builtInType != XML_SCHEMAS_ANYTYPE)))
  
  #define WXS_IS_ANY_SIMPLE_TYPE(i) \
      (((i)->type == XML_SCHEMA_TYPE_BASIC) && \
        ((i)->builtInType == XML_SCHEMAS_ANYSIMPLETYPE))
  
  #define WXS_IS_RESTRICTION(t) \
      ((t)->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION)
  
  #define WXS_IS_EXTENSION(t) \
      ((t)->flags & XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION)
  
  #define WXS_IS_TYPE_NOT_FIXED(i) \
      (((i)->type != XML_SCHEMA_TYPE_BASIC) && \
       (((i)->flags & XML_SCHEMAS_TYPE_INTERNAL_RESOLVED) == 0))
  
  #define WXS_IS_TYPE_NOT_FIXED_1(item) \
      (((item)->type != XML_SCHEMA_TYPE_BASIC) && \
       (((item)->flags & XML_SCHEMAS_TYPE_FIXUP_1) == 0))
  
  #define WXS_TYPE_IS_GLOBAL(t) ((t)->flags & XML_SCHEMAS_TYPE_GLOBAL)
  
  #define WXS_TYPE_IS_LOCAL(t) (((t)->flags & XML_SCHEMAS_TYPE_GLOBAL) == 0)
  /*
  * Macros for exclusively for complex types.
  */
  #define WXS_HAS_COMPLEX_CONTENT(item) \
      ((item->contentType == XML_SCHEMA_CONTENT_MIXED) || \
       (item->contentType == XML_SCHEMA_CONTENT_EMPTY) || \
       (item->contentType == XML_SCHEMA_CONTENT_ELEMENTS))
  
  #define WXS_HAS_SIMPLE_CONTENT(item) \
      ((item->contentType == XML_SCHEMA_CONTENT_SIMPLE) || \
       (item->contentType == XML_SCHEMA_CONTENT_BASIC))
  
  #define WXS_HAS_MIXED_CONTENT(item) \
      (item->contentType == XML_SCHEMA_CONTENT_MIXED)
  
  #define WXS_EMPTIABLE(t) \
      (xmlSchemaIsParticleEmptiable(WXS_PTC_CAST (t)->subtypes))
  
  #define WXS_TYPE_CONTENTTYPE(t) (t)->subtypes
  
  #define WXS_TYPE_PARTICLE(t) WXS_PTC_CAST (t)->subtypes
  
  #define WXS_TYPE_PARTICLE_TERM(t) WXS_PARTICLE_TERM(WXS_TYPE_PARTICLE(t))
  /*
  * Macros for exclusively for simple types.
  */
  #define WXS_LIST_ITEMTYPE(t) (t)->subtypes
  
  #define WXS_IS_ATOMIC(t) (t->flags & XML_SCHEMAS_TYPE_VARIETY_ATOMIC)
  
  #define WXS_IS_LIST(t) (t->flags & XML_SCHEMAS_TYPE_VARIETY_LIST)
  
  #define WXS_IS_UNION(t) (t->flags & XML_SCHEMAS_TYPE_VARIETY_UNION)
  /*
  * Misc parser context macros.
  */
  #define WXS_CONSTRUCTOR(ctx) (ctx)->constructor
  
  #define WXS_HAS_BUCKETS(ctx) \
  ( (WXS_CONSTRUCTOR((ctx))->buckets != NULL) && \
  (WXS_CONSTRUCTOR((ctx))->buckets->nbItems > 0) )
  
  #define WXS_SUBST_GROUPS(ctx) WXS_CONSTRUCTOR((ctx))->substGroups
  
  #define WXS_BUCKET(ctx) WXS_CONSTRUCTOR((ctx))->bucket
  
  #define WXS_SCHEMA(ctx) (ctx)->schema
  
  #define WXS_ADD_LOCAL(ctx, item) \
      xmlSchemaAddItemSize(&(WXS_BUCKET(ctx)->locals), 10, item)
  
  #define WXS_ADD_GLOBAL(ctx, item) \
      xmlSchemaAddItemSize(&(WXS_BUCKET(ctx)->globals), 5, item)
  
  #define WXS_ADD_PENDING(ctx, item) \
      xmlSchemaAddItemSize(&((ctx)->constructor->pending), 10, item)
  /*
  * xmlSchemaItemList macros.
  */
  #define WXS_ILIST_IS_EMPTY(l) ((l == NULL) || ((l)->nbItems == 0))
  /*
  * Misc macros.
  */
  #define IS_SCHEMA(node, type) \
     ((node != NULL) && (node->ns != NULL) && \
      (xmlStrEqual(node->name, (const xmlChar *) type)) && \
      (xmlStrEqual(node->ns->href, xmlSchemaNs)))
  
  #define FREE_AND_NULL(str) if ((str) != NULL) { xmlFree((xmlChar *) (str)); str = NULL; }
  
  /*
  * Since we put the default/fixed values into the dict, we can
  * use pointer comparison for those values.
  * REMOVED: (xmlStrEqual((v1), (v2)))
  */
  #define WXS_ARE_DEFAULT_STR_EQUAL(v1, v2) ((v1) == (v2))
  
  #define INODE_NILLED(item) (item->flags & XML_SCHEMA_ELEM_INFO_NILLED)
  
  #define CAN_PARSE_SCHEMA(b) (((b)->doc != NULL) && ((b)->parsed == 0))
  
  #define HFAILURE if (res == -1) goto exit_failure;
  
  #define HERROR if (res != 0) goto exit_error;
  
  #define HSTOP(ctx) if ((ctx)->stop) goto exit;
  /*
  * Some flags used for various schema constraints.
  */
  #define SUBSET_RESTRICTION  1<<0
  #define SUBSET_EXTENSION    1<<1
  #define SUBSET_SUBSTITUTION 1<<2
  #define SUBSET_LIST         1<<3
  #define SUBSET_UNION        1<<4
  
  typedef struct _xmlSchemaNodeInfo xmlSchemaNodeInfo;
  typedef xmlSchemaNodeInfo *xmlSchemaNodeInfoPtr;
  
  typedef struct _xmlSchemaItemList xmlSchemaItemList;
  typedef xmlSchemaItemList *xmlSchemaItemListPtr;
  struct _xmlSchemaItemList {
      void **items;  /* used for dynamic addition of schemata */
      int nbItems; /* used for dynamic addition of schemata */
      int sizeItems; /* used for dynamic addition of schemata */
  };
  
  #define XML_SCHEMA_CTXT_PARSER 1
  #define XML_SCHEMA_CTXT_VALIDATOR 2
  
  typedef struct _xmlSchemaAbstractCtxt xmlSchemaAbstractCtxt;
  typedef xmlSchemaAbstractCtxt *xmlSchemaAbstractCtxtPtr;
  struct _xmlSchemaAbstractCtxt {
      int type; /* E.g. XML_SCHEMA_CTXT_VALIDATOR */
      void *dummy; /* Fix alignment issues */
  };
  
  typedef struct _xmlSchemaBucket xmlSchemaBucket;
  typedef xmlSchemaBucket *xmlSchemaBucketPtr;
  
  #define XML_SCHEMA_SCHEMA_MAIN 0
  #define XML_SCHEMA_SCHEMA_IMPORT 1
  #define XML_SCHEMA_SCHEMA_INCLUDE 2
  #define XML_SCHEMA_SCHEMA_REDEFINE 3
  
  /**
   * xmlSchemaSchemaRelation:
   *
   * Used to create a graph of schema relationships.
   */
  typedef struct _xmlSchemaSchemaRelation xmlSchemaSchemaRelation;
  typedef xmlSchemaSchemaRelation *xmlSchemaSchemaRelationPtr;
  struct _xmlSchemaSchemaRelation {
      xmlSchemaSchemaRelationPtr next;
      int type; /* E.g. XML_SCHEMA_SCHEMA_IMPORT */
      const xmlChar *importNamespace;
      xmlSchemaBucketPtr bucket;
  };
  
  #define XML_SCHEMA_BUCKET_MARKED 1<<0
  #define XML_SCHEMA_BUCKET_COMPS_ADDED 1<<1
  
  struct _xmlSchemaBucket {
      int type;
      int flags;
      const xmlChar *schemaLocation;
      const xmlChar *origTargetNamespace;
      const xmlChar *targetNamespace;
      xmlDocPtr doc;
      xmlSchemaSchemaRelationPtr relations;
      int located;
      int parsed;
      int imported;
      int preserveDoc;
      xmlSchemaItemListPtr globals; /* Global components. */
      xmlSchemaItemListPtr locals; /* Local components. */
  };
  
  /**
   * xmlSchemaImport:
   * (extends xmlSchemaBucket)
   *
   * Reflects a schema. Holds some information
   * about the schema and its toplevel components. Duplicate
   * toplevel components are not checked at this level.
   */
  typedef struct _xmlSchemaImport xmlSchemaImport;
  typedef xmlSchemaImport *xmlSchemaImportPtr;
  struct _xmlSchemaImport {
      int type; /* Main OR import OR include. */
      int flags;
      const xmlChar *schemaLocation; /* The URI of the schema document. */
      /* For chameleon includes, @origTargetNamespace will be NULL */
      const xmlChar *origTargetNamespace;
      /*
      * For chameleon includes, @targetNamespace will be the
      * targetNamespace of the including schema.
      */
      const xmlChar *targetNamespace;
      xmlDocPtr doc; /* The schema node-tree. */
      /* @relations will hold any included/imported/redefined schemas. */
      xmlSchemaSchemaRelationPtr relations;
      int located;
      int parsed;
      int imported;
      int preserveDoc;
      xmlSchemaItemListPtr globals;
      xmlSchemaItemListPtr locals;
      /* The imported schema. */
      xmlSchemaPtr schema;
  };
  
  /*
  * (extends xmlSchemaBucket)
  */
  typedef struct _xmlSchemaInclude xmlSchemaInclude;
  typedef xmlSchemaInclude *xmlSchemaIncludePtr;
  struct _xmlSchemaInclude {
      int type;
      int flags;
      const xmlChar *schemaLocation;
      const xmlChar *origTargetNamespace;
      const xmlChar *targetNamespace;
      xmlDocPtr doc;
      xmlSchemaSchemaRelationPtr relations;
      int located;
      int parsed;
      int imported;
      int preserveDoc;
      xmlSchemaItemListPtr globals; /* Global components. */
      xmlSchemaItemListPtr locals; /* Local components. */
  
      /* The owning main or import schema bucket. */
      xmlSchemaImportPtr ownerImport;
  };
  
  /**
   * xmlSchemaBasicItem:
   *
   * The abstract base type for schema components.
   */
  typedef struct _xmlSchemaBasicItem xmlSchemaBasicItem;
  typedef xmlSchemaBasicItem *xmlSchemaBasicItemPtr;
  struct _xmlSchemaBasicItem {
      xmlSchemaTypeType type;
      void *dummy; /* Fix alignment issues */
  };
  
  /**
   * xmlSchemaAnnotItem:
   *
   * The abstract base type for annotated schema components.
   * (Extends xmlSchemaBasicItem)
   */
  typedef struct _xmlSchemaAnnotItem xmlSchemaAnnotItem;
  typedef xmlSchemaAnnotItem *xmlSchemaAnnotItemPtr;
  struct _xmlSchemaAnnotItem {
      xmlSchemaTypeType type;
      xmlSchemaAnnotPtr annot;
  };
  
  /**
   * xmlSchemaTreeItem:
   *
   * The abstract base type for tree-like structured schema components.
   * (Extends xmlSchemaAnnotItem)
   */
  typedef struct _xmlSchemaTreeItem xmlSchemaTreeItem;
  typedef xmlSchemaTreeItem *xmlSchemaTreeItemPtr;
  struct _xmlSchemaTreeItem {
      xmlSchemaTypeType type;
      xmlSchemaAnnotPtr annot;
      xmlSchemaTreeItemPtr next;
      xmlSchemaTreeItemPtr children;
  };
  
  
  #define XML_SCHEMA_ATTR_USE_FIXED 1<<0
  /**
   * xmlSchemaAttributeUsePtr:
   *
   * The abstract base type for tree-like structured schema components.
   * (Extends xmlSchemaTreeItem)
   */
  typedef struct _xmlSchemaAttributeUse xmlSchemaAttributeUse;
  typedef xmlSchemaAttributeUse *xmlSchemaAttributeUsePtr;
  struct _xmlSchemaAttributeUse {
      xmlSchemaTypeType type;
      xmlSchemaAnnotPtr annot;
      xmlSchemaAttributeUsePtr next; /* The next attr. use. */
      /*
      * The attr. decl. OR a QName-ref. to an attr. decl. OR
      * a QName-ref. to an attribute group definition.
      */
      xmlSchemaAttributePtr attrDecl;
  
      int flags;
      xmlNodePtr node;
      int occurs; /* required, optional */
      const xmlChar * defValue;
      xmlSchemaValPtr defVal;
  };
  
  /**
   * xmlSchemaAttributeUseProhibPtr:
   *
   * A helper component to reflect attribute prohibitions.
   * (Extends xmlSchemaBasicItem)
   */
  typedef struct _xmlSchemaAttributeUseProhib xmlSchemaAttributeUseProhib;
  typedef xmlSchemaAttributeUseProhib *xmlSchemaAttributeUseProhibPtr;
  struct _xmlSchemaAttributeUseProhib {
      xmlSchemaTypeType type; /* == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB */
      xmlNodePtr node;
      const xmlChar *name;
      const xmlChar *targetNamespace;
      int isRef;
  };
  
  /**
   * xmlSchemaRedef:
   */
  typedef struct _xmlSchemaRedef xmlSchemaRedef;
  typedef xmlSchemaRedef *xmlSchemaRedefPtr;
  struct _xmlSchemaRedef {
      xmlSchemaRedefPtr next;
      xmlSchemaBasicItemPtr item; /* The redefining component. */
      xmlSchemaBasicItemPtr reference; /* The referencing component. */
      xmlSchemaBasicItemPtr target; /* The to-be-redefined component. */
      const xmlChar *refName; /* The name of the to-be-redefined component. */
      const xmlChar *refTargetNs; /* The target namespace of the
                                     to-be-redefined comp. */
      xmlSchemaBucketPtr targetBucket; /* The redefined schema. */
  };
  
  /**
   * xmlSchemaConstructionCtxt:
   */
  typedef struct _xmlSchemaConstructionCtxt xmlSchemaConstructionCtxt;
  typedef xmlSchemaConstructionCtxt *xmlSchemaConstructionCtxtPtr;
  struct _xmlSchemaConstructionCtxt {
      xmlSchemaPtr mainSchema; /* The main schema. */
      xmlSchemaBucketPtr mainBucket; /* The main schema bucket */
      xmlDictPtr dict;
      xmlSchemaItemListPtr buckets; /* List of schema buckets. */
      /* xmlSchemaItemListPtr relations; */ /* List of schema relations. */
      xmlSchemaBucketPtr bucket; /* The current schema bucket */
      xmlSchemaItemListPtr pending; /* All Components of all schemas that
                                       need to be fixed. */
      xmlHashTablePtr substGroups;
      xmlSchemaRedefPtr redefs;
      xmlSchemaRedefPtr lastRedef;
  };
  
  #define XML_SCHEMAS_PARSE_ERROR		1
  #define SCHEMAS_PARSE_OPTIONS XML_PARSE_NOENT
  
  struct _xmlSchemaParserCtxt {
      int type;
      void *errCtxt;             /* user specific error context */
      xmlSchemaValidityErrorFunc error;   /* the callback in case of errors */
      xmlSchemaValidityWarningFunc warning;       /* the callback in case of warning */
      int err;
      int nberrors;
      xmlStructuredErrorFunc serror;
  
      xmlSchemaConstructionCtxtPtr constructor;
      int ownsConstructor; /* TODO: Move this to parser *flags*. */
  
      /* xmlSchemaPtr topschema;	*/
      /* xmlHashTablePtr namespaces;  */
  
      xmlSchemaPtr schema;        /* The main schema in use */
      int counter;
  
      const xmlChar *URL;
      xmlDocPtr doc;
      int preserve;		/* Whether the doc should be freed  */
  
      const char *buffer;
      int size;
  
      /*
       * Used to build complex element content models
       */
      xmlAutomataPtr am;
      xmlAutomataStatePtr start;
      xmlAutomataStatePtr end;
      xmlAutomataStatePtr state;
  
      xmlDictPtr dict;		/* dictionary for interned string names */
      xmlSchemaTypePtr ctxtType; /* The current context simple/complex type */
      int options;
      xmlSchemaValidCtxtPtr vctxt;
      int isS4S;
      int isRedefine;
      int xsiAssemble;
      int stop; /* If the parser should stop; i.e. a critical error. */
      const xmlChar *targetNamespace;
      xmlSchemaBucketPtr redefined; /* The schema to be redefined. */
  
      xmlSchemaRedefPtr redef; /* Used for redefinitions. */
      int redefCounter; /* Used for redefinitions. */
      xmlSchemaItemListPtr attrProhibs;
  };
  
  /**
   * xmlSchemaQNameRef:
   *
   * A component reference item (not a schema component)
   * (Extends xmlSchemaBasicItem)
   */
  typedef struct _xmlSchemaQNameRef xmlSchemaQNameRef;
  typedef xmlSchemaQNameRef *xmlSchemaQNameRefPtr;
  struct _xmlSchemaQNameRef {
      xmlSchemaTypeType type;
      xmlSchemaBasicItemPtr item; /* The resolved referenced item. */
      xmlSchemaTypeType itemType;
      const xmlChar *name;
      const xmlChar *targetNamespace;
      xmlNodePtr node;
  };
  
  /**
   * xmlSchemaParticle:
   *
   * A particle component.
   * (Extends xmlSchemaTreeItem)
   */
  typedef struct _xmlSchemaParticle xmlSchemaParticle;
  typedef xmlSchemaParticle *xmlSchemaParticlePtr;
  struct _xmlSchemaParticle {
      xmlSchemaTypeType type;
      xmlSchemaAnnotPtr annot;
      xmlSchemaTreeItemPtr next; /* next particle */
      xmlSchemaTreeItemPtr children; /* the "term" (e.g. a model group,
  	a group definition, a XML_SCHEMA_EXTRA_QNAMEREF (if a reference),
          etc.) */
      int minOccurs;
      int maxOccurs;
      xmlNodePtr node;
  };
  
  /**
   * xmlSchemaModelGroup:
   *
   * A model group component.
   * (Extends xmlSchemaTreeItem)
   */
  typedef struct _xmlSchemaModelGroup xmlSchemaModelGroup;
  typedef xmlSchemaModelGroup *xmlSchemaModelGroupPtr;
  struct _xmlSchemaModelGroup {
      xmlSchemaTypeType type; /* XML_SCHEMA_TYPE_SEQUENCE, XML_SCHEMA_TYPE_CHOICE, XML_SCHEMA_TYPE_ALL */
      xmlSchemaAnnotPtr annot;
      xmlSchemaTreeItemPtr next; /* not used */
      xmlSchemaTreeItemPtr children; /* first particle (OR "element decl" OR "wildcard") */
      xmlNodePtr node;
  };
  
  #define XML_SCHEMA_MODEL_GROUP_DEF_MARKED 1<<0
  #define XML_SCHEMA_MODEL_GROUP_DEF_REDEFINED 1<<1
  /**
   * xmlSchemaModelGroupDef:
   *
   * A model group definition component.
   * (Extends xmlSchemaTreeItem)
   */
  typedef struct _xmlSchemaModelGroupDef xmlSchemaModelGroupDef;
  typedef xmlSchemaModelGroupDef *xmlSchemaModelGroupDefPtr;
  struct _xmlSchemaModelGroupDef {
      xmlSchemaTypeType type; /* XML_SCHEMA_TYPE_GROUP */
      xmlSchemaAnnotPtr annot;
      xmlSchemaTreeItemPtr next; /* not used */
      xmlSchemaTreeItemPtr children; /* the "model group" */
      const xmlChar *name;
      const xmlChar *targetNamespace;
      xmlNodePtr node;
      int flags;
  };
  
  typedef struct _xmlSchemaIDC xmlSchemaIDC;
  typedef xmlSchemaIDC *xmlSchemaIDCPtr;
  
  /**
   * xmlSchemaIDCSelect:
   *
   * The identity-constraint "field" and "selector" item, holding the
   * XPath expression.
   */
  typedef struct _xmlSchemaIDCSelect xmlSchemaIDCSelect;
  typedef xmlSchemaIDCSelect *xmlSchemaIDCSelectPtr;
  struct _xmlSchemaIDCSelect {
      xmlSchemaIDCSelectPtr next;
      xmlSchemaIDCPtr idc;
      int index; /* an index position if significant for IDC key-sequences */
      const xmlChar *xpath; /* the XPath expression */
      void *xpathComp; /* the compiled XPath expression */
  };
  
  /**
   * xmlSchemaIDC:
   *
   * The identity-constraint definition component.
   * (Extends xmlSchemaAnnotItem)
   */
  
  struct _xmlSchemaIDC {
      xmlSchemaTypeType type;
      xmlSchemaAnnotPtr annot;
      xmlSchemaIDCPtr next;
      xmlNodePtr node;
      const xmlChar *name;
      const xmlChar *targetNamespace;
      xmlSchemaIDCSelectPtr selector;
      xmlSchemaIDCSelectPtr fields;
      int nbFields;
      xmlSchemaQNameRefPtr ref;
  };
  
  /**
   * xmlSchemaIDCAug:
   *
   * The augmented IDC information used for validation.
   */
  typedef struct _xmlSchemaIDCAug xmlSchemaIDCAug;
  typedef xmlSchemaIDCAug *xmlSchemaIDCAugPtr;
  struct _xmlSchemaIDCAug {
      xmlSchemaIDCAugPtr next; /* next in a list */
      xmlSchemaIDCPtr def; /* the IDC definition */
      int keyrefDepth; /* the lowest tree level to which IDC
                          tables need to be bubbled upwards */
  };
  
  /**
   * xmlSchemaPSVIIDCKeySequence:
   *
   * The key sequence of a node table item.
   */
  typedef struct _xmlSchemaPSVIIDCKey xmlSchemaPSVIIDCKey;
  typedef xmlSchemaPSVIIDCKey *xmlSchemaPSVIIDCKeyPtr;
  struct _xmlSchemaPSVIIDCKey {
      xmlSchemaTypePtr type;
      xmlSchemaValPtr val;
  };
  
  /**
   * xmlSchemaPSVIIDCNode:
   *
   * The node table item of a node table.
   */
  typedef struct _xmlSchemaPSVIIDCNode xmlSchemaPSVIIDCNode;
  typedef xmlSchemaPSVIIDCNode *xmlSchemaPSVIIDCNodePtr;
  struct _xmlSchemaPSVIIDCNode {
      xmlNodePtr node;
      xmlSchemaPSVIIDCKeyPtr *keys;
      int nodeLine;
      int nodeQNameID;
  
  };
  
  /**
   * xmlSchemaPSVIIDCBinding:
   *
   * The identity-constraint binding item of the [identity-constraint table].
   */
  typedef struct _xmlSchemaPSVIIDCBinding xmlSchemaPSVIIDCBinding;
  typedef xmlSchemaPSVIIDCBinding *xmlSchemaPSVIIDCBindingPtr;
  struct _xmlSchemaPSVIIDCBinding {
      xmlSchemaPSVIIDCBindingPtr next; /* next binding of a specific node */
      xmlSchemaIDCPtr definition; /* the IDC definition */
      xmlSchemaPSVIIDCNodePtr *nodeTable; /* array of key-sequences */
      int nbNodes; /* number of entries in the node table */
      int sizeNodes; /* size of the node table */
      xmlSchemaItemListPtr dupls;
  };
  
  
  #define XPATH_STATE_OBJ_TYPE_IDC_SELECTOR 1
  #define XPATH_STATE_OBJ_TYPE_IDC_FIELD 2
  
  #define XPATH_STATE_OBJ_MATCHES -2
  #define XPATH_STATE_OBJ_BLOCKED -3
  
  typedef struct _xmlSchemaIDCMatcher xmlSchemaIDCMatcher;
  typedef xmlSchemaIDCMatcher *xmlSchemaIDCMatcherPtr;
  
  /**
   * xmlSchemaIDCStateObj:
   *
   * The state object used to evaluate XPath expressions.
   */
  typedef struct _xmlSchemaIDCStateObj xmlSchemaIDCStateObj;
  typedef xmlSchemaIDCStateObj *xmlSchemaIDCStateObjPtr;
  struct _xmlSchemaIDCStateObj {
      int type;
      xmlSchemaIDCStateObjPtr next; /* next if in a list */
      int depth; /* depth of creation */
      int *history; /* list of (depth, state-id) tuples */
      int nbHistory;
      int sizeHistory;
      xmlSchemaIDCMatcherPtr matcher; /* the correspondent field/selector
                                         matcher */
      xmlSchemaIDCSelectPtr sel;
      void *xpathCtxt;
  };
  
  #define IDC_MATCHER 0
  
  /**
   * xmlSchemaIDCMatcher:
   *
   * Used to evaluate IDC selectors (and fields).
   */
  struct _xmlSchemaIDCMatcher {
      int type;
      int depth; /* the tree depth at creation time */
      xmlSchemaIDCMatcherPtr next; /* next in the list */
      xmlSchemaIDCMatcherPtr nextCached; /* next in the cache list */
      xmlSchemaIDCAugPtr aidc; /* the augmented IDC item */
      int idcType;
      xmlSchemaPSVIIDCKeyPtr **keySeqs; /* the key-sequences of the target
                                           elements */
      int sizeKeySeqs;
      xmlSchemaItemListPtr targets; /* list of target-node
                                       (xmlSchemaPSVIIDCNodePtr) entries */
  };
  
  /*
  * Element info flags.
  */
  #define XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES  1<<0
  #define XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES 1<<1
  #define XML_SCHEMA_ELEM_INFO_NILLED	       1<<2
  #define XML_SCHEMA_ELEM_INFO_LOCAL_TYPE	       1<<3
  
  #define XML_SCHEMA_NODE_INFO_VALUE_NEEDED      1<<4
  #define XML_SCHEMA_ELEM_INFO_EMPTY             1<<5
  #define XML_SCHEMA_ELEM_INFO_HAS_CONTENT       1<<6
  
  #define XML_SCHEMA_ELEM_INFO_HAS_ELEM_CONTENT  1<<7
  #define XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT  1<<8
  #define XML_SCHEMA_NODE_INFO_ERR_NOT_EXPECTED  1<<9
  #define XML_SCHEMA_NODE_INFO_ERR_BAD_TYPE  1<<10
  
  /**
   * xmlSchemaNodeInfo:
   *
   * Holds information of an element node.
   */
  struct _xmlSchemaNodeInfo {
      int nodeType;
      xmlNodePtr node;
      int nodeLine;
      const xmlChar *localName;
      const xmlChar *nsName;
      const xmlChar *value;
      xmlSchemaValPtr val; /* the pre-computed value if any */
      xmlSchemaTypePtr typeDef; /* the complex/simple type definition if any */
  
      int flags; /* combination of node info flags */
  
      int valNeeded;
      int normVal;
  
      xmlSchemaElementPtr decl; /* the element/attribute declaration */
      int depth;
      xmlSchemaPSVIIDCBindingPtr idcTable; /* the table of PSVI IDC bindings
                                              for the scope element*/
      xmlSchemaIDCMatcherPtr idcMatchers; /* the IDC matchers for the scope
                                             element */
      xmlRegExecCtxtPtr regexCtxt;
  
      const xmlChar **nsBindings; /* Namespace bindings on this element */
      int nbNsBindings;
      int sizeNsBindings;
  
      int hasKeyrefs;
      int appliedXPath; /* Indicates that an XPath has been applied. */
  };
  
  #define XML_SCHEMAS_ATTR_UNKNOWN 1
  #define XML_SCHEMAS_ATTR_ASSESSED 2
  #define XML_SCHEMAS_ATTR_PROHIBITED 3
  #define XML_SCHEMAS_ATTR_ERR_MISSING 4
  #define XML_SCHEMAS_ATTR_INVALID_VALUE 5
  #define XML_SCHEMAS_ATTR_ERR_NO_TYPE 6
  #define XML_SCHEMAS_ATTR_ERR_FIXED_VALUE 7
  #define XML_SCHEMAS_ATTR_DEFAULT 8
  #define XML_SCHEMAS_ATTR_VALIDATE_VALUE 9
  #define XML_SCHEMAS_ATTR_ERR_WILD_STRICT_NO_DECL 10
  #define XML_SCHEMAS_ATTR_HAS_ATTR_USE 11
  #define XML_SCHEMAS_ATTR_HAS_ATTR_DECL 12
  #define XML_SCHEMAS_ATTR_WILD_SKIP 13
  #define XML_SCHEMAS_ATTR_WILD_LAX_NO_DECL 14
  #define XML_SCHEMAS_ATTR_ERR_WILD_DUPLICATE_ID 15
  #define XML_SCHEMAS_ATTR_ERR_WILD_AND_USE_ID 16
  #define XML_SCHEMAS_ATTR_META 17
  /*
  * @metaType values of xmlSchemaAttrInfo.
  */
  #define XML_SCHEMA_ATTR_INFO_META_XSI_TYPE 1
  #define XML_SCHEMA_ATTR_INFO_META_XSI_NIL 2
  #define XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC 3
  #define XML_SCHEMA_ATTR_INFO_META_XSI_NO_NS_SCHEMA_LOC 4
  #define XML_SCHEMA_ATTR_INFO_META_XMLNS 5
  
  typedef struct _xmlSchemaAttrInfo xmlSchemaAttrInfo;
  typedef xmlSchemaAttrInfo *xmlSchemaAttrInfoPtr;
  struct _xmlSchemaAttrInfo {
      int nodeType;
      xmlNodePtr node;
      int nodeLine;
      const xmlChar *localName;
      const xmlChar *nsName;
      const xmlChar *value;
      xmlSchemaValPtr val; /* the pre-computed value if any */
      xmlSchemaTypePtr typeDef; /* the complex/simple type definition if any */
      int flags; /* combination of node info flags */
  
      xmlSchemaAttributePtr decl; /* the attribute declaration */
      xmlSchemaAttributeUsePtr use;  /* the attribute use */
      int state;
      int metaType;
      const xmlChar *vcValue; /* the value constraint value */
      xmlSchemaNodeInfoPtr parent;
  };
  
  
  #define XML_SCHEMA_VALID_CTXT_FLAG_STREAM 1
  /**
   * xmlSchemaValidCtxt:
   *
   * A Schemas validation context
   */
  struct _xmlSchemaValidCtxt {
      int type;
      void *errCtxt;             /* user specific data block */
      xmlSchemaValidityErrorFunc error;   /* the callback in case of errors */
      xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */
      xmlStructuredErrorFunc serror;
  
      xmlSchemaPtr schema;        /* The schema in use */
      xmlDocPtr doc;
      xmlParserInputBufferPtr input;
      xmlCharEncoding enc;
      xmlSAXHandlerPtr sax;
      xmlParserCtxtPtr parserCtxt;
      void *user_data; /* TODO: What is this for? */
      char *filename;
  
      int err;
      int nberrors;
  
      xmlNodePtr node;
      xmlNodePtr cur;
      /* xmlSchemaTypePtr type; */
  
      xmlRegExecCtxtPtr regexp;
      xmlSchemaValPtr value;
  
      int valueWS;
      int options;
      xmlNodePtr validationRoot;
      xmlSchemaParserCtxtPtr pctxt;
      int xsiAssemble;
  
      int depth;
      xmlSchemaNodeInfoPtr *elemInfos; /* array of element informations */
      int sizeElemInfos;
      xmlSchemaNodeInfoPtr inode; /* the current element information */
  
      xmlSchemaIDCAugPtr aidcs; /* a list of augmented IDC informations */
  
      xmlSchemaIDCStateObjPtr xpathStates; /* first active state object. */
      xmlSchemaIDCStateObjPtr xpathStatePool; /* first stored state object. */
      xmlSchemaIDCMatcherPtr idcMatcherCache; /* Cache for IDC matcher objects. */
  
      xmlSchemaPSVIIDCNodePtr *idcNodes; /* list of all IDC node-table entries*/
      int nbIdcNodes;
      int sizeIdcNodes;
  
      xmlSchemaPSVIIDCKeyPtr *idcKeys; /* list of all IDC node-table entries */
      int nbIdcKeys;
      int sizeIdcKeys;
  
      int flags;
  
      xmlDictPtr dict;
  
  #ifdef LIBXML_READER_ENABLED
      xmlTextReaderPtr reader;
  #endif
  
      xmlSchemaAttrInfoPtr *attrInfos;
      int nbAttrInfos;
      int sizeAttrInfos;
  
      int skipDepth;
      xmlSchemaItemListPtr nodeQNames;
      int hasKeyrefs;
      int createIDCNodeTables;
      int psviExposeIDCNodeTables;
  
      /* Locator for error reporting in streaming mode */
      xmlSchemaValidityLocatorFunc locFunc;
      void *locCtxt;
  };
  
  /**
   * xmlSchemaSubstGroup:
   *
   *
   */
  typedef struct _xmlSchemaSubstGroup xmlSchemaSubstGroup;
  typedef xmlSchemaSubstGroup *xmlSchemaSubstGroupPtr;
  struct _xmlSchemaSubstGroup {
      xmlSchemaElementPtr head;
      xmlSchemaItemListPtr members;
  };
  
  /************************************************************************
   *									*
   *			Some predeclarations				*
   *									*
   ************************************************************************/
  
  static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt,
                                   xmlSchemaPtr schema,
                                   xmlNodePtr node);
  static int xmlSchemaParseRedefine(xmlSchemaParserCtxtPtr ctxt,
                                   xmlSchemaPtr schema,
                                   xmlNodePtr node);
  static int
  xmlSchemaTypeFixup(xmlSchemaTypePtr type,
                     xmlSchemaAbstractCtxtPtr ctxt);
  static const xmlChar *
  xmlSchemaFacetTypeToString(xmlSchemaTypeType type);
  static int
  xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                       xmlNodePtr node);
  static int
  xmlSchemaCheckFacetValues(xmlSchemaTypePtr typeDecl,
                         xmlSchemaParserCtxtPtr ctxt);
  static void
  xmlSchemaClearValidCtxt(xmlSchemaValidCtxtPtr vctxt);
  static xmlSchemaWhitespaceValueType
  xmlSchemaGetWhiteSpaceFacetValue(xmlSchemaTypePtr type);
  static xmlSchemaTreeItemPtr
  xmlSchemaParseModelGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
  			 xmlNodePtr node, xmlSchemaTypeType type,
  			 int withParticle);
  static const xmlChar *
  xmlSchemaGetComponentTypeStr(xmlSchemaBasicItemPtr item);
  static xmlSchemaTypeLinkPtr
  xmlSchemaGetUnionSimpleTypeMemberTypes(xmlSchemaTypePtr type);
  static void
  xmlSchemaInternalErr(xmlSchemaAbstractCtxtPtr actxt,
  		     const char *funcName,
  		     const char *message) LIBXML_ATTR_FORMAT(3,0);
  static int
  xmlSchemaCheckCOSSTDerivedOK(xmlSchemaAbstractCtxtPtr ctxt,
  			     xmlSchemaTypePtr type,
  			     xmlSchemaTypePtr baseType,
  			     int subset);
  static void
  xmlSchemaCheckElementDeclComponent(xmlSchemaElementPtr elemDecl,
  				   xmlSchemaParserCtxtPtr ctxt);
  static void
  xmlSchemaComponentListFree(xmlSchemaItemListPtr list);
  static xmlSchemaQNameRefPtr
  xmlSchemaParseAttributeGroupRef(xmlSchemaParserCtxtPtr pctxt,
  				xmlSchemaPtr schema,
  				xmlNodePtr node);
  
  /************************************************************************
   *									*
   *			Helper functions			        *
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaItemTypeToStr:
   * @type: the type of the schema item
   *
   * Returns the component name of a schema item.
   */
  static const xmlChar *
  xmlSchemaItemTypeToStr(xmlSchemaTypeType type)
  {
      switch (type) {
  	case XML_SCHEMA_TYPE_BASIC:
  	    return(BAD_CAST "simple type definition");
  	case XML_SCHEMA_TYPE_SIMPLE:
  	    return(BAD_CAST "simple type definition");
  	case XML_SCHEMA_TYPE_COMPLEX:
  	    return(BAD_CAST "complex type definition");
  	case XML_SCHEMA_TYPE_ELEMENT:
  	    return(BAD_CAST "element declaration");
  	case XML_SCHEMA_TYPE_ATTRIBUTE_USE:
  	    return(BAD_CAST "attribute use");
  	case XML_SCHEMA_TYPE_ATTRIBUTE:
  	    return(BAD_CAST "attribute declaration");
  	case XML_SCHEMA_TYPE_GROUP:
  	    return(BAD_CAST "model group definition");
  	case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  	    return(BAD_CAST "attribute group definition");
  	case XML_SCHEMA_TYPE_NOTATION:
  	    return(BAD_CAST "notation declaration");
  	case XML_SCHEMA_TYPE_SEQUENCE:
  	    return(BAD_CAST "model group (sequence)");
  	case XML_SCHEMA_TYPE_CHOICE:
  	    return(BAD_CAST "model group (choice)");
  	case XML_SCHEMA_TYPE_ALL:
  	    return(BAD_CAST "model group (all)");
  	case XML_SCHEMA_TYPE_PARTICLE:
  	    return(BAD_CAST "particle");
  	case XML_SCHEMA_TYPE_IDC_UNIQUE:
  	    return(BAD_CAST "unique identity-constraint");
  	    /* return(BAD_CAST "IDC (unique)"); */
  	case XML_SCHEMA_TYPE_IDC_KEY:
  	    return(BAD_CAST "key identity-constraint");
  	    /* return(BAD_CAST "IDC (key)"); */
  	case XML_SCHEMA_TYPE_IDC_KEYREF:
  	    return(BAD_CAST "keyref identity-constraint");
  	    /* return(BAD_CAST "IDC (keyref)"); */
  	case XML_SCHEMA_TYPE_ANY:
  	    return(BAD_CAST "wildcard (any)");
  	case XML_SCHEMA_EXTRA_QNAMEREF:
  	    return(BAD_CAST "[helper component] QName reference");
  	case XML_SCHEMA_EXTRA_ATTR_USE_PROHIB:
  	    return(BAD_CAST "[helper component] attribute use prohibition");
  	default:
  	    return(BAD_CAST "Not a schema component");
      }
  }
  
  /**
   * xmlSchemaGetComponentTypeStr:
   * @type: the type of the schema item
   *
   * Returns the component name of a schema item.
   */
  static const xmlChar *
  xmlSchemaGetComponentTypeStr(xmlSchemaBasicItemPtr item)
  {
      switch (item->type) {
  	case XML_SCHEMA_TYPE_BASIC:
  	    if (WXS_IS_COMPLEX(WXS_TYPE_CAST item))
  		return(BAD_CAST "complex type definition");
  	    else
  		return(BAD_CAST "simple type definition");
  	default:
  	    return(xmlSchemaItemTypeToStr(item->type));
      }
  }
  
  /**
   * xmlSchemaGetComponentNode:
   * @item: a schema component
   *
   * Returns node associated with the schema component.
   * NOTE that such a node need not be available; plus, a component's
   * node need not to reflect the component directly, since there is no
   * one-to-one relationship between the XML Schema representation and
   * the component representation.
   */
  static xmlNodePtr
  xmlSchemaGetComponentNode(xmlSchemaBasicItemPtr item)
  {
      switch (item->type) {
  	case XML_SCHEMA_TYPE_ELEMENT:
  	    return (((xmlSchemaElementPtr) item)->node);
  	case XML_SCHEMA_TYPE_ATTRIBUTE:
  	    return (((xmlSchemaAttributePtr) item)->node);
  	case XML_SCHEMA_TYPE_COMPLEX:
  	case XML_SCHEMA_TYPE_SIMPLE:
  	    return (((xmlSchemaTypePtr) item)->node);
  	case XML_SCHEMA_TYPE_ANY:
  	case XML_SCHEMA_TYPE_ANY_ATTRIBUTE:
  	    return (((xmlSchemaWildcardPtr) item)->node);
  	case XML_SCHEMA_TYPE_PARTICLE:
  	    return (((xmlSchemaParticlePtr) item)->node);
  	case XML_SCHEMA_TYPE_SEQUENCE:
  	case XML_SCHEMA_TYPE_CHOICE:
  	case XML_SCHEMA_TYPE_ALL:
  	    return (((xmlSchemaModelGroupPtr) item)->node);
  	case XML_SCHEMA_TYPE_GROUP:
  	    return (((xmlSchemaModelGroupDefPtr) item)->node);
  	case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  	    return (((xmlSchemaAttributeGroupPtr) item)->node);
  	case XML_SCHEMA_TYPE_IDC_UNIQUE:
  	case XML_SCHEMA_TYPE_IDC_KEY:
  	case XML_SCHEMA_TYPE_IDC_KEYREF:
  	    return (((xmlSchemaIDCPtr) item)->node);
  	case XML_SCHEMA_EXTRA_QNAMEREF:
  	    return(((xmlSchemaQNameRefPtr) item)->node);
  	/* TODO: What to do with NOTATIONs?
  	case XML_SCHEMA_TYPE_NOTATION:
  	    return (((xmlSchemaNotationPtr) item)->node);
  	*/
  	case XML_SCHEMA_TYPE_ATTRIBUTE_USE:
  	    return (((xmlSchemaAttributeUsePtr) item)->node);
  	default:
  	    return (NULL);
      }
  }
  
  #if 0
  /**
   * xmlSchemaGetNextComponent:
   * @item: a schema component
   *
   * Returns the next sibling of the schema component.
   */
  static xmlSchemaBasicItemPtr
  xmlSchemaGetNextComponent(xmlSchemaBasicItemPtr item)
  {
      switch (item->type) {
  	case XML_SCHEMA_TYPE_ELEMENT:
  	    return ((xmlSchemaBasicItemPtr) ((xmlSchemaElementPtr) item)->next);
  	case XML_SCHEMA_TYPE_ATTRIBUTE:
  	    return ((xmlSchemaBasicItemPtr) ((xmlSchemaAttributePtr) item)->next);
  	case XML_SCHEMA_TYPE_COMPLEX:
  	case XML_SCHEMA_TYPE_SIMPLE:
  	    return ((xmlSchemaBasicItemPtr) ((xmlSchemaTypePtr) item)->next);
  	case XML_SCHEMA_TYPE_ANY:
  	case XML_SCHEMA_TYPE_ANY_ATTRIBUTE:
  	    return (NULL);
  	case XML_SCHEMA_TYPE_PARTICLE:
  	    return ((xmlSchemaBasicItemPtr) ((xmlSchemaParticlePtr) item)->next);
  	case XML_SCHEMA_TYPE_SEQUENCE:
  	case XML_SCHEMA_TYPE_CHOICE:
  	case XML_SCHEMA_TYPE_ALL:
  	    return (NULL);
  	case XML_SCHEMA_TYPE_GROUP:
  	    return (NULL);
  	case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  	    return ((xmlSchemaBasicItemPtr) ((xmlSchemaAttributeGroupPtr) item)->next);
  	case XML_SCHEMA_TYPE_IDC_UNIQUE:
  	case XML_SCHEMA_TYPE_IDC_KEY:
  	case XML_SCHEMA_TYPE_IDC_KEYREF:
  	    return ((xmlSchemaBasicItemPtr) ((xmlSchemaIDCPtr) item)->next);
  	default:
  	    return (NULL);
      }
  }
  #endif
  
  
  /**
   * xmlSchemaFormatQName:
   * @buf: the string buffer
   * @namespaceName:  the namespace name
   * @localName: the local name
   *
   * Returns the given QName in the format "{namespaceName}localName" or
   * just "localName" if @namespaceName is NULL.
   *
   * Returns the localName if @namespaceName is NULL, a formatted
   * string otherwise.
   */
  static const xmlChar*
  xmlSchemaFormatQName(xmlChar **buf,
  		     const xmlChar *namespaceName,
  		     const xmlChar *localName)
  {
      FREE_AND_NULL(*buf)
      if (namespaceName != NULL) {
  	*buf = xmlStrdup(BAD_CAST "{");
  	*buf = xmlStrcat(*buf, namespaceName);
  	*buf = xmlStrcat(*buf, BAD_CAST "}");
      }
      if (localName != NULL) {
  	if (namespaceName == NULL)
  	    return(localName);
  	*buf = xmlStrcat(*buf, localName);
      } else {
  	*buf = xmlStrcat(*buf, BAD_CAST "(NULL)");
      }
      return ((const xmlChar *) *buf);
  }
  
  static const xmlChar*
  xmlSchemaFormatQNameNs(xmlChar **buf, xmlNsPtr ns, const xmlChar *localName)
  {
      if (ns != NULL)
  	return (xmlSchemaFormatQName(buf, ns->href, localName));
      else
  	return (xmlSchemaFormatQName(buf, NULL, localName));
  }
  
  static const xmlChar *
  xmlSchemaGetComponentName(xmlSchemaBasicItemPtr item)
  {
      switch (item->type) {
  	case XML_SCHEMA_TYPE_ELEMENT:
  	    return (((xmlSchemaElementPtr) item)->name);
  	case XML_SCHEMA_TYPE_ATTRIBUTE:
  	    return (((xmlSchemaAttributePtr) item)->name);
  	case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  	    return (((xmlSchemaAttributeGroupPtr) item)->name);
  	case XML_SCHEMA_TYPE_BASIC:
  	case XML_SCHEMA_TYPE_SIMPLE:
  	case XML_SCHEMA_TYPE_COMPLEX:
  	    return (((xmlSchemaTypePtr) item)->name);
  	case XML_SCHEMA_TYPE_GROUP:
  	    return (((xmlSchemaModelGroupDefPtr) item)->name);
  	case XML_SCHEMA_TYPE_IDC_KEY:
  	case XML_SCHEMA_TYPE_IDC_UNIQUE:
  	case XML_SCHEMA_TYPE_IDC_KEYREF:
  	    return (((xmlSchemaIDCPtr) item)->name);
  	case XML_SCHEMA_TYPE_ATTRIBUTE_USE:
  	    if (WXS_ATTRUSE_DECL(item) != NULL) {
  		return(xmlSchemaGetComponentName(
  		    WXS_BASIC_CAST WXS_ATTRUSE_DECL(item)));
  	    } else
  		return(NULL);
  	case XML_SCHEMA_EXTRA_QNAMEREF:
  	    return (((xmlSchemaQNameRefPtr) item)->name);
  	case XML_SCHEMA_TYPE_NOTATION:
  	    return (((xmlSchemaNotationPtr) item)->name);
  	default:
  	    /*
  	    * Other components cannot have names.
  	    */
  	    break;
      }
      return (NULL);
  }
  
  #define xmlSchemaGetQNameRefName(r) (WXS_QNAME_CAST (r))->name
  #define xmlSchemaGetQNameRefTargetNs(r) (WXS_QNAME_CAST (r))->targetNamespace
  /*
  static const xmlChar *
  xmlSchemaGetQNameRefName(void *ref)
  {
      return(((xmlSchemaQNameRefPtr) ref)->name);
  }
  
  static const xmlChar *
  xmlSchemaGetQNameRefTargetNs(void *ref)
  {
      return(((xmlSchemaQNameRefPtr) ref)->targetNamespace);
  }
  */
  
  static const xmlChar *
  xmlSchemaGetComponentTargetNs(xmlSchemaBasicItemPtr item)
  {
      switch (item->type) {
  	case XML_SCHEMA_TYPE_ELEMENT:
  	    return (((xmlSchemaElementPtr) item)->targetNamespace);
  	case XML_SCHEMA_TYPE_ATTRIBUTE:
  	    return (((xmlSchemaAttributePtr) item)->targetNamespace);
  	case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  	    return (((xmlSchemaAttributeGroupPtr) item)->targetNamespace);
  	case XML_SCHEMA_TYPE_BASIC:
  	    return (BAD_CAST "http://www.w3.org/2001/XMLSchema");
  	case XML_SCHEMA_TYPE_SIMPLE:
  	case XML_SCHEMA_TYPE_COMPLEX:
  	    return (((xmlSchemaTypePtr) item)->targetNamespace);
  	case XML_SCHEMA_TYPE_GROUP:
  	    return (((xmlSchemaModelGroupDefPtr) item)->targetNamespace);
  	case XML_SCHEMA_TYPE_IDC_KEY:
  	case XML_SCHEMA_TYPE_IDC_UNIQUE:
  	case XML_SCHEMA_TYPE_IDC_KEYREF:
  	    return (((xmlSchemaIDCPtr) item)->targetNamespace);
  	case XML_SCHEMA_TYPE_ATTRIBUTE_USE:
  	    if (WXS_ATTRUSE_DECL(item) != NULL) {
  		return(xmlSchemaGetComponentTargetNs(
  		    WXS_BASIC_CAST WXS_ATTRUSE_DECL(item)));
  	    }
  	    /* TODO: Will returning NULL break something? */
  	    break;
  	case XML_SCHEMA_EXTRA_QNAMEREF:
  	    return (((xmlSchemaQNameRefPtr) item)->targetNamespace);
  	case XML_SCHEMA_TYPE_NOTATION:
  	    return (((xmlSchemaNotationPtr) item)->targetNamespace);
  	default:
  	    /*
  	    * Other components cannot have names.
  	    */
  	    break;
      }
      return (NULL);
  }
  
  static const xmlChar*
  xmlSchemaGetComponentQName(xmlChar **buf,
  			   void *item)
  {
      return (xmlSchemaFormatQName(buf,
  	xmlSchemaGetComponentTargetNs((xmlSchemaBasicItemPtr) item),
  	xmlSchemaGetComponentName((xmlSchemaBasicItemPtr) item)));
  }
  
  static const xmlChar*
  xmlSchemaGetComponentDesignation(xmlChar **buf, void *item)
  {
      xmlChar *str = NULL;
  
      *buf = xmlStrcat(*buf, WXS_ITEM_TYPE_NAME(item));
      *buf = xmlStrcat(*buf, BAD_CAST " '");
      *buf = xmlStrcat(*buf, xmlSchemaGetComponentQName(&str,
  	(xmlSchemaBasicItemPtr) item));
      *buf = xmlStrcat(*buf, BAD_CAST "'");
      FREE_AND_NULL(str);
      return(*buf);
  }
  
  static const xmlChar*
  xmlSchemaGetIDCDesignation(xmlChar **buf, xmlSchemaIDCPtr idc)
  {
      return(xmlSchemaGetComponentDesignation(buf, idc));
  }
  
  /**
   * xmlSchemaWildcardPCToString:
   * @pc: the type of processContents
   *
   * Returns a string representation of the type of
   * processContents.
   */
  static const xmlChar *
  xmlSchemaWildcardPCToString(int pc)
  {
      switch (pc) {
  	case XML_SCHEMAS_ANY_SKIP:
  	    return (BAD_CAST "skip");
  	case XML_SCHEMAS_ANY_LAX:
  	    return (BAD_CAST "lax");
  	case XML_SCHEMAS_ANY_STRICT:
  	    return (BAD_CAST "strict");
  	default:
  	    return (BAD_CAST "invalid process contents");
      }
  }
  
  /**
   * xmlSchemaGetCanonValueWhtspExt:
   * @val: the precomputed value
   * @retValue: the returned value
   * @ws: the whitespace type of the value
   *
   * Get a the canonical representation of the value.
   * The caller has to free the returned retValue.
   *
   * Returns 0 if the value could be built and -1 in case of
   *         API errors or if the value type is not supported yet.
   */
  static int
  xmlSchemaGetCanonValueWhtspExt(xmlSchemaValPtr val,
  			       xmlSchemaWhitespaceValueType ws,
  			       xmlChar **retValue)
  {
      int list;
      xmlSchemaValType valType;
      const xmlChar *value, *value2 = NULL;
  
  
      if ((retValue == NULL) || (val == NULL))
  	return (-1);
      list = xmlSchemaValueGetNext(val) ? 1 : 0;
      *retValue = NULL;
      do {
  	value = NULL;
  	valType = xmlSchemaGetValType(val);
  	switch (valType) {
  	    case XML_SCHEMAS_STRING:
  	    case XML_SCHEMAS_NORMSTRING:
  	    case XML_SCHEMAS_ANYSIMPLETYPE:
  		value = xmlSchemaValueGetAsString(val);
  		if (value != NULL) {
  		    if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE)
  			value2 = xmlSchemaCollapseString(value);
  		    else if (ws == XML_SCHEMA_WHITESPACE_REPLACE)
  			value2 = xmlSchemaWhiteSpaceReplace(value);
  		    if (value2 != NULL)
  			value = value2;
  		}
  		break;
  	    default:
  		if (xmlSchemaGetCanonValue(val, &value2) == -1) {
  		    if (value2 != NULL)
  			xmlFree((xmlChar *) value2);
  		    goto internal_error;
  		}
  		value = value2;
  	}
  	if (*retValue == NULL)
  	    if (value == NULL) {
  		if (! list)
  		    *retValue = xmlStrdup(BAD_CAST "");
  	    } else
  		*retValue = xmlStrdup(value);
  	else if (value != NULL) {
  	    /* List. */
  	    *retValue = xmlStrcat((xmlChar *) *retValue, BAD_CAST " ");
  	    *retValue = xmlStrcat((xmlChar *) *retValue, value);
  	}
  	FREE_AND_NULL(value2)
  	val = xmlSchemaValueGetNext(val);
      } while (val != NULL);
  
      return (0);
  internal_error:
      if (*retValue != NULL)
  	xmlFree((xmlChar *) (*retValue));
      if (value2 != NULL)
  	xmlFree((xmlChar *) value2);
      return (-1);
  }
  
  /**
   * xmlSchemaFormatItemForReport:
   * @buf: the string buffer
   * @itemDes: the designation of the item
   * @itemName: the name of the item
   * @item: the item as an object
   * @itemNode: the node of the item
   * @local: the local name
   * @parsing: if the function is used during the parse
   *
   * Returns a representation of the given item used
   * for error reports.
   *
   * The following order is used to build the resulting
   * designation if the arguments are not NULL:
   * 1a. If itemDes not NULL -> itemDes
   * 1b. If (itemDes not NULL) and (itemName not NULL)
   *     -> itemDes + itemName
   * 2. If the preceding was NULL and (item not NULL) -> item
   * 3. If the preceding was NULL and (itemNode not NULL) -> itemNode
   *
   * If the itemNode is an attribute node, the name of the attribute
   * will be appended to the result.
   *
   * Returns the formatted string and sets @buf to the resulting value.
   */
  static xmlChar*
  xmlSchemaFormatItemForReport(xmlChar **buf,
  		     const xmlChar *itemDes,
  		     xmlSchemaBasicItemPtr item,
  		     xmlNodePtr itemNode)
  {
      xmlChar *str = NULL;
      int named = 1;
  
      if (*buf != NULL) {
  	xmlFree(*buf);
  	*buf = NULL;
      }
  
      if (itemDes != NULL) {
  	*buf = xmlStrdup(itemDes);
      } else if (item != NULL) {
  	switch (item->type) {
  	case XML_SCHEMA_TYPE_BASIC: {
  	    xmlSchemaTypePtr type = WXS_TYPE_CAST item;
  
  	    if (WXS_IS_ATOMIC(type))
  		*buf = xmlStrdup(BAD_CAST "atomic type 'xs:");
  	    else if (WXS_IS_LIST(type))
  		*buf = xmlStrdup(BAD_CAST "list type 'xs:");
  	    else if (WXS_IS_UNION(type))
  		*buf = xmlStrdup(BAD_CAST "union type 'xs:");
  	    else
  		*buf = xmlStrdup(BAD_CAST "simple type 'xs:");
  	    *buf = xmlStrcat(*buf, type->name);
  	    *buf = xmlStrcat(*buf, BAD_CAST "'");
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_SIMPLE: {
  	    xmlSchemaTypePtr type = WXS_TYPE_CAST item;
  
  	    if (type->flags & XML_SCHEMAS_TYPE_GLOBAL) {
  		*buf = xmlStrdup(BAD_CAST"");
  	    } else {
  		*buf = xmlStrdup(BAD_CAST "local ");
  	    }
  	    if (WXS_IS_ATOMIC(type))
  		*buf = xmlStrcat(*buf, BAD_CAST "atomic type");
  	    else if (WXS_IS_LIST(type))
  		*buf = xmlStrcat(*buf, BAD_CAST "list type");
  	    else if (WXS_IS_UNION(type))
  		*buf = xmlStrcat(*buf, BAD_CAST "union type");
  	    else
  		*buf = xmlStrcat(*buf, BAD_CAST "simple type");
  	    if (type->flags & XML_SCHEMAS_TYPE_GLOBAL) {
  		*buf = xmlStrcat(*buf, BAD_CAST " '");
  		*buf = xmlStrcat(*buf, type->name);
  		*buf = xmlStrcat(*buf, BAD_CAST "'");
  	    }
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_COMPLEX: {
  	    xmlSchemaTypePtr type = WXS_TYPE_CAST item;
  
  	    if (type->flags & XML_SCHEMAS_TYPE_GLOBAL)
  		*buf = xmlStrdup(BAD_CAST "");
  	    else
  		*buf = xmlStrdup(BAD_CAST "local ");
  	    *buf = xmlStrcat(*buf, BAD_CAST "complex type");
  	    if (type->flags & XML_SCHEMAS_TYPE_GLOBAL) {
  		*buf = xmlStrcat(*buf, BAD_CAST " '");
  		*buf = xmlStrcat(*buf, type->name);
  		*buf = xmlStrcat(*buf, BAD_CAST "'");
  	    }
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_ATTRIBUTE_USE: {
  		xmlSchemaAttributeUsePtr ause;
  
  		ause = WXS_ATTR_USE_CAST item;
  		*buf = xmlStrdup(BAD_CAST "attribute use ");
  		if (WXS_ATTRUSE_DECL(ause) != NULL) {
  		    *buf = xmlStrcat(*buf, BAD_CAST "'");
  		    *buf = xmlStrcat(*buf,
  			xmlSchemaGetComponentQName(&str, WXS_ATTRUSE_DECL(ause)));
  		    FREE_AND_NULL(str)
  			*buf = xmlStrcat(*buf, BAD_CAST "'");
  		} else {
  		    *buf = xmlStrcat(*buf, BAD_CAST "(unknown)");
  		}
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_ATTRIBUTE: {
  		xmlSchemaAttributePtr attr;
  
  		attr = (xmlSchemaAttributePtr) item;
  		*buf = xmlStrdup(BAD_CAST "attribute decl.");
  		*buf = xmlStrcat(*buf, BAD_CAST " '");
  		*buf = xmlStrcat(*buf, xmlSchemaFormatQName(&str,
  		    attr->targetNamespace, attr->name));
  		FREE_AND_NULL(str)
  		    *buf = xmlStrcat(*buf, BAD_CAST "'");
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  	    xmlSchemaGetComponentDesignation(buf, item);
  	    break;
  	case XML_SCHEMA_TYPE_ELEMENT: {
  		xmlSchemaElementPtr elem;
  
  		elem = (xmlSchemaElementPtr) item;
  		*buf = xmlStrdup(BAD_CAST "element decl.");
  		*buf = xmlStrcat(*buf, BAD_CAST " '");
  		*buf = xmlStrcat(*buf, xmlSchemaFormatQName(&str,
  		    elem->targetNamespace, elem->name));
  		*buf = xmlStrcat(*buf, BAD_CAST "'");
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_IDC_UNIQUE:
  	case XML_SCHEMA_TYPE_IDC_KEY:
  	case XML_SCHEMA_TYPE_IDC_KEYREF:
  	    if (item->type == XML_SCHEMA_TYPE_IDC_UNIQUE)
  		*buf = xmlStrdup(BAD_CAST "unique '");
  	    else if (item->type == XML_SCHEMA_TYPE_IDC_KEY)
  		*buf = xmlStrdup(BAD_CAST "key '");
  	    else
  		*buf = xmlStrdup(BAD_CAST "keyRef '");
  	    *buf = xmlStrcat(*buf, ((xmlSchemaIDCPtr) item)->name);
  	    *buf = xmlStrcat(*buf, BAD_CAST "'");
  	    break;
  	case XML_SCHEMA_TYPE_ANY:
  	case XML_SCHEMA_TYPE_ANY_ATTRIBUTE:
  	    *buf = xmlStrdup(xmlSchemaWildcardPCToString(
  		    ((xmlSchemaWildcardPtr) item)->processContents));
  	    *buf = xmlStrcat(*buf, BAD_CAST " wildcard");
  	    break;
  	case XML_SCHEMA_FACET_MININCLUSIVE:
  	case XML_SCHEMA_FACET_MINEXCLUSIVE:
  	case XML_SCHEMA_FACET_MAXINCLUSIVE:
  	case XML_SCHEMA_FACET_MAXEXCLUSIVE:
  	case XML_SCHEMA_FACET_TOTALDIGITS:
  	case XML_SCHEMA_FACET_FRACTIONDIGITS:
  	case XML_SCHEMA_FACET_PATTERN:
  	case XML_SCHEMA_FACET_ENUMERATION:
  	case XML_SCHEMA_FACET_WHITESPACE:
  	case XML_SCHEMA_FACET_LENGTH:
  	case XML_SCHEMA_FACET_MAXLENGTH:
  	case XML_SCHEMA_FACET_MINLENGTH:
  	    *buf = xmlStrdup(BAD_CAST "facet '");
  	    *buf = xmlStrcat(*buf, xmlSchemaFacetTypeToString(item->type));
  	    *buf = xmlStrcat(*buf, BAD_CAST "'");
  	    break;
  	case XML_SCHEMA_TYPE_GROUP: {
  		*buf = xmlStrdup(BAD_CAST "model group def.");
  		*buf = xmlStrcat(*buf, BAD_CAST " '");
  		*buf = xmlStrcat(*buf, xmlSchemaGetComponentQName(&str, item));
  		*buf = xmlStrcat(*buf, BAD_CAST "'");
  		FREE_AND_NULL(str)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_SEQUENCE:
  	case XML_SCHEMA_TYPE_CHOICE:
  	case XML_SCHEMA_TYPE_ALL:
  	case XML_SCHEMA_TYPE_PARTICLE:
  	    *buf = xmlStrdup(WXS_ITEM_TYPE_NAME(item));
  	    break;
  	case XML_SCHEMA_TYPE_NOTATION: {
  		*buf = xmlStrdup(WXS_ITEM_TYPE_NAME(item));
  		*buf = xmlStrcat(*buf, BAD_CAST " '");
  		*buf = xmlStrcat(*buf, xmlSchemaGetComponentQName(&str, item));
  		*buf = xmlStrcat(*buf, BAD_CAST "'");
  		FREE_AND_NULL(str);
  	    }
              /* Falls through. */
  	default:
  	    named = 0;
  	}
      } else
  	named = 0;
  
      if ((named == 0) && (itemNode != NULL)) {
  	xmlNodePtr elem;
  
  	if (itemNode->type == XML_ATTRIBUTE_NODE)
  	    elem = itemNode->parent;
  	else
  	    elem = itemNode;
  	*buf = xmlStrdup(BAD_CAST "Element '");
  	if (elem->ns != NULL) {
  	    *buf = xmlStrcat(*buf,
  		xmlSchemaFormatQName(&str, elem->ns->href, elem->name));
  	    FREE_AND_NULL(str)
  	} else
  	    *buf = xmlStrcat(*buf, elem->name);
  	*buf = xmlStrcat(*buf, BAD_CAST "'");
  
      }
      if ((itemNode != NULL) && (itemNode->type == XML_ATTRIBUTE_NODE)) {
  	*buf = xmlStrcat(*buf, BAD_CAST ", attribute '");
  	if (itemNode->ns != NULL) {
  	    *buf = xmlStrcat(*buf, xmlSchemaFormatQName(&str,
  		itemNode->ns->href, itemNode->name));
  	    FREE_AND_NULL(str)
  	} else
  	    *buf = xmlStrcat(*buf, itemNode->name);
  	*buf = xmlStrcat(*buf, BAD_CAST "'");
      }
      FREE_AND_NULL(str)
  
      return (xmlEscapeFormatString(buf));
  }
  
  /**
   * xmlSchemaFormatFacetEnumSet:
   * @buf: the string buffer
   * @type: the type holding the enumeration facets
   *
   * Builds a string consisting of all enumeration elements.
   *
   * Returns a string of all enumeration elements.
   */
  static const xmlChar *
  xmlSchemaFormatFacetEnumSet(xmlSchemaAbstractCtxtPtr actxt,
  			    xmlChar **buf, xmlSchemaTypePtr type)
  {
      xmlSchemaFacetPtr facet;
      xmlSchemaWhitespaceValueType ws;
      xmlChar *value = NULL;
      int res, found = 0;
  
      if (*buf != NULL)
  	xmlFree(*buf);
      *buf = NULL;
  
      do {
  	/*
  	* Use the whitespace type of the base type.
  	*/
  	ws = xmlSchemaGetWhiteSpaceFacetValue(type->baseType);
  	for (facet = type->facets; facet != NULL; facet = facet->next) {
  	    if (facet->type != XML_SCHEMA_FACET_ENUMERATION)
  		continue;
  	    found = 1;
  	    res = xmlSchemaGetCanonValueWhtspExt(facet->val,
  		ws, &value);
  	    if (res == -1) {
  		xmlSchemaInternalErr(actxt,
  		    "xmlSchemaFormatFacetEnumSet",
  		    "compute the canonical lexical representation");
  		if (*buf != NULL)
  		    xmlFree(*buf);
  		*buf = NULL;
  		return (NULL);
  	    }
  	    if (*buf == NULL)
  		*buf = xmlStrdup(BAD_CAST "'");
  	    else
  		*buf = xmlStrcat(*buf, BAD_CAST ", '");
  	    *buf = xmlStrcat(*buf, BAD_CAST value);
  	    *buf = xmlStrcat(*buf, BAD_CAST "'");
  	    if (value != NULL) {
  		xmlFree((xmlChar *)value);
  		value = NULL;
  	    }
  	}
  	/*
  	* The enumeration facet of a type restricts the enumeration
  	* facet of the ancestor type; i.e., such restricted enumerations
  	* do not belong to the set of the given type. Thus we break
  	* on the first found enumeration.
  	*/
  	if (found)
  	    break;
  	type = type->baseType;
      } while ((type != NULL) && (type->type != XML_SCHEMA_TYPE_BASIC));
  
      return ((const xmlChar *) *buf);
  }
  
  /************************************************************************
   *									*
   *			Error functions				        *
   *									*
   ************************************************************************/
  
  #if 0
  static void
  xmlSchemaErrMemory(const char *msg)
  {
      __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, NULL, NULL,
                       msg);
  }
  #endif
  
  static void
  xmlSchemaPSimpleErr(const char *msg)
  {
      __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, NULL, NULL,
                       msg);
  }
  
  /**
   * xmlSchemaPErrMemory:
   * @node: a context node
   * @extra:  extra informations
   *
   * Handle an out of memory condition
   */
  static void
  xmlSchemaPErrMemory(xmlSchemaParserCtxtPtr ctxt,
                      const char *extra, xmlNodePtr node)
  {
      if (ctxt != NULL)
          ctxt->nberrors++;
      __xmlSimpleError(XML_FROM_SCHEMASP, XML_ERR_NO_MEMORY, node, NULL,
                       extra);
  }
  
  /**
   * xmlSchemaPErr:
   * @ctxt: the parsing context
   * @node: the context node
   * @error: the error code
   * @msg: the error message
   * @str1: extra data
   * @str2: extra data
   *
   * Handle a parser error
   */
  static void LIBXML_ATTR_FORMAT(4,0)
  xmlSchemaPErr(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int error,
                const char *msg, const xmlChar * str1, const xmlChar * str2)
  {
      xmlGenericErrorFunc channel = NULL;
      xmlStructuredErrorFunc schannel = NULL;
      void *data = NULL;
  
      if (ctxt != NULL) {
          ctxt->nberrors++;
  	ctxt->err = error;
          channel = ctxt->error;
          data = ctxt->errCtxt;
  	schannel = ctxt->serror;
      }
      __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP,
                      error, XML_ERR_ERROR, NULL, 0,
                      (const char *) str1, (const char *) str2, NULL, 0, 0,
                      msg, str1, str2);
  }
  
  /**
   * xmlSchemaPErr2:
   * @ctxt: the parsing context
   * @node: the context node
   * @node: the current child
   * @error: the error code
   * @msg: the error message
   * @str1: extra data
   * @str2: extra data
   *
   * Handle a parser error
   */
  static void LIBXML_ATTR_FORMAT(5,0)
  xmlSchemaPErr2(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
                 xmlNodePtr child, int error,
                 const char *msg, const xmlChar * str1, const xmlChar * str2)
  {
      if (child != NULL)
          xmlSchemaPErr(ctxt, child, error, msg, str1, str2);
      else
          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 LIBXML_ATTR_FORMAT(7,0)
  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++;
  	ctxt->err = error;
          channel = ctxt->error;
          data = ctxt->errCtxt;
  	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);
  }
  
  /************************************************************************
   *									*
   *			Allround error functions			*
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaVTypeErrMemory:
   * @node: a context node
   * @extra:  extra informations
   *
   * Handle an out of memory condition
   */
  static void
  xmlSchemaVErrMemory(xmlSchemaValidCtxtPtr ctxt,
                      const char *extra, xmlNodePtr node)
  {
      if (ctxt != NULL) {
          ctxt->nberrors++;
          ctxt->err = XML_SCHEMAV_INTERNAL;
      }
      __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL,
                       extra);
  }
  
  static void LIBXML_ATTR_FORMAT(2,0)
  xmlSchemaPSimpleInternalErr(xmlNodePtr node,
  			    const char *msg, const xmlChar *str)
  {
       __xmlSimpleError(XML_FROM_SCHEMASP, XML_SCHEMAP_INTERNAL, node,
  	 msg, (const char *) str);
  }
  
  #define WXS_ERROR_TYPE_ERROR 1
  #define WXS_ERROR_TYPE_WARNING 2
  /**
   * xmlSchemaErr4Line:
   * @ctxt: the validation context
   * @errorLevel: the error level
   * @error: the error code
   * @node: the context node
   * @line: the line number
   * @msg: the error message
   * @str1: extra data
   * @str2: extra data
   * @str3: extra data
   * @str4: extra data
   *
   * Handle a validation error
   */
  static void LIBXML_ATTR_FORMAT(6,0)
  xmlSchemaErr4Line(xmlSchemaAbstractCtxtPtr ctxt,
  		  xmlErrorLevel errorLevel,
  		  int error, xmlNodePtr node, int line, const char *msg,
  		  const xmlChar *str1, const xmlChar *str2,
  		  const xmlChar *str3, const xmlChar *str4)
  {
      xmlStructuredErrorFunc schannel = NULL;
      xmlGenericErrorFunc channel = NULL;
      void *data = NULL;
  
      if (ctxt != NULL) {
  	if (ctxt->type == XML_SCHEMA_CTXT_VALIDATOR) {
  	    xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctxt;
  	    const char *file = NULL;
  	    int col = 0;
  	    if (errorLevel != XML_ERR_WARNING) {
  		vctxt->nberrors++;
  		vctxt->err = error;
  		channel = vctxt->error;
  	    } else {
  		channel = vctxt->warning;
  	    }
  	    schannel = vctxt->serror;
  	    data = vctxt->errCtxt;
  
  	    /*
  	    * Error node. If we specify a line number, then
  	    * do not channel any node to the error function.
  	    */
  	    if (line == 0) {
  		if ((node == NULL) &&
  		    (vctxt->depth >= 0) &&
  		    (vctxt->inode != NULL)) {
  		    node = vctxt->inode->node;
  		}
  		/*
  		* Get filename and line if no node-tree.
  		*/
  		if ((node == NULL) &&
  		    (vctxt->parserCtxt != NULL) &&
  		    (vctxt->parserCtxt->input != NULL)) {
  		    file = vctxt->parserCtxt->input->filename;
  		    line = vctxt->parserCtxt->input->line;
  		    col = vctxt->parserCtxt->input->col;
  		}
  	    } else {
  		/*
  		* Override the given node's (if any) position
  		* and channel only the given line number.
  		*/
  		node = NULL;
  		/*
  		* Get filename.
  		*/
  		if (vctxt->doc != NULL)
  		    file = (const char *) vctxt->doc->URL;
  		else if ((vctxt->parserCtxt != NULL) &&
  		    (vctxt->parserCtxt->input != NULL))
  		    file = vctxt->parserCtxt->input->filename;
  	    }
  	    if (vctxt->locFunc != NULL) {
  	        if ((file == NULL) || (line == 0)) {
  		    unsigned long l;
  		    const char *f;
  		    vctxt->locFunc(vctxt->locCtxt, &f, &l);
  		    if (file == NULL)
  		        file = f;
  		    if (line == 0)
  		        line = (int) l;
  		}
  	    }
  	    if ((file == NULL) && (vctxt->filename != NULL))
  	        file = vctxt->filename;
  
  	    __xmlRaiseError(schannel, channel, data, ctxt,
  		node, XML_FROM_SCHEMASV,
  		error, errorLevel, file, line,
  		(const char *) str1, (const char *) str2,
  		(const char *) str3, 0, col, msg, str1, str2, str3, str4);
  
  	} else if (ctxt->type == XML_SCHEMA_CTXT_PARSER) {
  	    xmlSchemaParserCtxtPtr pctxt = (xmlSchemaParserCtxtPtr) ctxt;
  	    if (errorLevel != XML_ERR_WARNING) {
  		pctxt->nberrors++;
  		pctxt->err = error;
  		channel = pctxt->error;
  	    } else {
  		channel = pctxt->warning;
  	    }
  	    schannel = pctxt->serror;
  	    data = pctxt->errCtxt;
  	    __xmlRaiseError(schannel, channel, data, ctxt,
  		node, XML_FROM_SCHEMASP, error,
  		errorLevel, NULL, 0,
  		(const char *) str1, (const char *) str2,
  		(const char *) str3, 0, 0, msg, str1, str2, str3, str4);
  	} else {
  	    TODO
  	}
      }
  }
  
  /**
   * xmlSchemaErr3:
   * @ctxt: the validation context
   * @node: the context node
   * @error: the error code
   * @msg: the error message
   * @str1: extra data
   * @str2: extra data
   * @str3: extra data
   *
   * Handle a validation error
   */
  static void LIBXML_ATTR_FORMAT(4,0)
  xmlSchemaErr3(xmlSchemaAbstractCtxtPtr actxt,
  	      int error, xmlNodePtr node, const char *msg,
  	      const xmlChar *str1, const xmlChar *str2, const xmlChar *str3)
  {
      xmlSchemaErr4Line(actxt, XML_ERR_ERROR, error, node, 0,
  	msg, str1, str2, str3, NULL);
  }
  
  static void LIBXML_ATTR_FORMAT(4,0)
  xmlSchemaErr4(xmlSchemaAbstractCtxtPtr actxt,
  	      int error, xmlNodePtr node, const char *msg,
  	      const xmlChar *str1, const xmlChar *str2,
  	      const xmlChar *str3, const xmlChar *str4)
  {
      xmlSchemaErr4Line(actxt, XML_ERR_ERROR, error, node, 0,
  	msg, str1, str2, str3, str4);
  }
  
  static void LIBXML_ATTR_FORMAT(4,0)
  xmlSchemaErr(xmlSchemaAbstractCtxtPtr actxt,
  	     int error, xmlNodePtr node, const char *msg,
  	     const xmlChar *str1, const xmlChar *str2)
  {
      xmlSchemaErr4(actxt, error, node, msg, str1, str2, NULL, NULL);
  }
  
  static xmlChar *
  xmlSchemaFormatNodeForError(xmlChar ** msg,
  			    xmlSchemaAbstractCtxtPtr actxt,
  			    xmlNodePtr node)
  {
      xmlChar *str = NULL;
  
      *msg = NULL;
      if ((node != NULL) &&
  	(node->type != XML_ELEMENT_NODE) &&
  	(node->type != XML_ATTRIBUTE_NODE))
      {
  	/*
  	* Don't try to format other nodes than element and
  	* attribute nodes.
  	* Play safe and return an empty string.
  	*/
  	*msg = xmlStrdup(BAD_CAST "");
  	return(*msg);
      }
      if (node != NULL) {
  	/*
  	* Work on tree nodes.
  	*/
  	if (node->type == XML_ATTRIBUTE_NODE) {
  	    xmlNodePtr elem = node->parent;
  
  	    *msg = xmlStrdup(BAD_CAST "Element '");
  	    if (elem->ns != NULL)
  		*msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str,
  		    elem->ns->href, elem->name));
  	    else
  		*msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str,
  		    NULL, elem->name));
  	    FREE_AND_NULL(str);
  	    *msg = xmlStrcat(*msg, BAD_CAST "', ");
  	    *msg = xmlStrcat(*msg, BAD_CAST "attribute '");
  	} else {
  	    *msg = xmlStrdup(BAD_CAST "Element '");
  	}
  	if (node->ns != NULL)
  	    *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str,
  	    node->ns->href, node->name));
  	else
  	    *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str,
  	    NULL, node->name));
  	FREE_AND_NULL(str);
  	*msg = xmlStrcat(*msg, BAD_CAST "': ");
      } else if (actxt->type == XML_SCHEMA_CTXT_VALIDATOR) {
  	xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) actxt;
  	/*
  	* Work on node infos.
  	*/
  	if (vctxt->inode->nodeType == XML_ATTRIBUTE_NODE) {
  	    xmlSchemaNodeInfoPtr ielem =
  		vctxt->elemInfos[vctxt->depth];
  
  	    *msg = xmlStrdup(BAD_CAST "Element '");
  	    *msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str,
  		ielem->nsName, ielem->localName));
  	    FREE_AND_NULL(str);
  	    *msg = xmlStrcat(*msg, BAD_CAST "', ");
  	    *msg = xmlStrcat(*msg, BAD_CAST "attribute '");
  	} else {
  	    *msg = xmlStrdup(BAD_CAST "Element '");
  	}
  	*msg = xmlStrcat(*msg, xmlSchemaFormatQName(&str,
  	    vctxt->inode->nsName, vctxt->inode->localName));
  	FREE_AND_NULL(str);
  	*msg = xmlStrcat(*msg, BAD_CAST "': ");
      } else if (actxt->type == XML_SCHEMA_CTXT_PARSER) {
  	/*
  	* Hmm, no node while parsing?
  	* Return an empty string, in case NULL will break something.
  	*/
  	*msg = xmlStrdup(BAD_CAST "");
      } else {
  	TODO
  	return (NULL);
      }
  
      /*
       * xmlSchemaFormatItemForReport() also returns an escaped format
       * string, so do this before calling it below (in the future).
       */
      xmlEscapeFormatString(msg);
  
      /*
      * VAL TODO: The output of the given schema component is currently
      * disabled.
      */
  #if 0
      if ((type != NULL) && (xmlSchemaIsGlobalItem(type))) {
  	*msg = xmlStrcat(*msg, BAD_CAST " [");
  	*msg = xmlStrcat(*msg, xmlSchemaFormatItemForReport(&str,
  	    NULL, type, NULL, 0));
  	FREE_AND_NULL(str)
  	*msg = xmlStrcat(*msg, BAD_CAST "]");
      }
  #endif
      return (*msg);
  }
  
  static void LIBXML_ATTR_FORMAT(3,0)
  xmlSchemaInternalErr2(xmlSchemaAbstractCtxtPtr actxt,
  		     const char *funcName,
  		     const char *message,
  		     const xmlChar *str1,
  		     const xmlChar *str2)
  {
      xmlChar *msg = NULL;
  
      if (actxt == NULL)
          return;
      msg = xmlStrdup(BAD_CAST "Internal error: %s, ");
      msg = xmlStrcat(msg, BAD_CAST message);
      msg = xmlStrcat(msg, BAD_CAST ".\n");
  
      if (actxt->type == XML_SCHEMA_CTXT_VALIDATOR)
  	xmlSchemaErr3(actxt, XML_SCHEMAV_INTERNAL, NULL,
  	    (const char *) msg, (const xmlChar *) funcName, str1, str2);
      else if (actxt->type == XML_SCHEMA_CTXT_PARSER)
  	xmlSchemaErr3(actxt, XML_SCHEMAP_INTERNAL, NULL,
  	    (const char *) msg, (const xmlChar *) funcName, str1, str2);
  
      FREE_AND_NULL(msg)
  }
  
  static void LIBXML_ATTR_FORMAT(3,0)
  xmlSchemaInternalErr(xmlSchemaAbstractCtxtPtr actxt,
  		     const char *funcName,
  		     const char *message)
  {
      xmlSchemaInternalErr2(actxt, funcName, message, NULL, NULL);
  }
  
  #if 0
  static void LIBXML_ATTR_FORMAT(3,0)
  xmlSchemaPInternalErr(xmlSchemaParserCtxtPtr pctxt,
  		     const char *funcName,
  		     const char *message,
  		     const xmlChar *str1,
  		     const xmlChar *str2)
  {
      xmlSchemaInternalErr2(ACTXT_CAST pctxt, funcName, message,
  	str1, str2);
  }
  #endif
  
  static void LIBXML_ATTR_FORMAT(5,0)
  xmlSchemaCustomErr4(xmlSchemaAbstractCtxtPtr actxt,
  		   xmlParserErrors error,
  		   xmlNodePtr node,
  		   xmlSchemaBasicItemPtr item,
  		   const char *message,
  		   const xmlChar *str1, const xmlChar *str2,
  		   const xmlChar *str3, const xmlChar *str4)
  {
      xmlChar *msg = NULL;
  
      if ((node == NULL) && (item != NULL) &&
  	(actxt->type == XML_SCHEMA_CTXT_PARSER)) {
  	node = WXS_ITEM_NODE(item);
  	xmlSchemaFormatItemForReport(&msg, NULL, item, NULL);
  	msg = xmlStrcat(msg, BAD_CAST ": ");
      } else
  	xmlSchemaFormatNodeForError(&msg, actxt, node);
      msg = xmlStrcat(msg, (const xmlChar *) message);
      msg = xmlStrcat(msg, BAD_CAST ".\n");
      xmlSchemaErr4(actxt, error, node,
  	(const char *) msg, str1, str2, str3, str4);
      FREE_AND_NULL(msg)
  }
  
  static void LIBXML_ATTR_FORMAT(5,0)
  xmlSchemaCustomErr(xmlSchemaAbstractCtxtPtr actxt,
  		   xmlParserErrors error,
  		   xmlNodePtr node,
  		   xmlSchemaBasicItemPtr item,
  		   const char *message,
  		   const xmlChar *str1,
  		   const xmlChar *str2)
  {
      xmlSchemaCustomErr4(actxt, error, node, item,
  	message, str1, str2, NULL, NULL);
  }
  
  
  
  static void LIBXML_ATTR_FORMAT(5,0)
  xmlSchemaCustomWarning(xmlSchemaAbstractCtxtPtr actxt,
  		   xmlParserErrors error,
  		   xmlNodePtr node,
  		   xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
  		   const char *message,
  		   const xmlChar *str1,
  		   const xmlChar *str2,
  		   const xmlChar *str3)
  {
      xmlChar *msg = NULL;
  
      xmlSchemaFormatNodeForError(&msg, actxt, node);
      msg = xmlStrcat(msg, (const xmlChar *) message);
      msg = xmlStrcat(msg, BAD_CAST ".\n");
  
      /* URGENT TODO: Set the error code to something sane. */
      xmlSchemaErr4Line(actxt, XML_ERR_WARNING, error, node, 0,
  	(const char *) msg, str1, str2, str3, NULL);
  
      FREE_AND_NULL(msg)
  }
  
  
  
  static void LIBXML_ATTR_FORMAT(5,0)
  xmlSchemaKeyrefErr(xmlSchemaValidCtxtPtr vctxt,
  		   xmlParserErrors error,
  		   xmlSchemaPSVIIDCNodePtr idcNode,
  		   xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
  		   const char *message,
  		   const xmlChar *str1,
  		   const xmlChar *str2)
  {
      xmlChar *msg = NULL, *qname = NULL;
  
      msg = xmlStrdup(BAD_CAST "Element '%s': ");
      msg = xmlStrcat(msg, (const xmlChar *) message);
      msg = xmlStrcat(msg, BAD_CAST ".\n");
      xmlSchemaErr4Line(ACTXT_CAST vctxt, XML_ERR_ERROR,
  	error, NULL, idcNode->nodeLine, (const char *) msg,
  	xmlSchemaFormatQName(&qname,
  	    vctxt->nodeQNames->items[idcNode->nodeQNameID +1],
  	    vctxt->nodeQNames->items[idcNode->nodeQNameID]),
  	str1, str2, NULL);
      FREE_AND_NULL(qname);
      FREE_AND_NULL(msg);
  }
  
  static int
  xmlSchemaEvalErrorNodeType(xmlSchemaAbstractCtxtPtr actxt,
  			   xmlNodePtr node)
  {
      if (node != NULL)
  	return (node->type);
      if ((actxt->type == XML_SCHEMA_CTXT_VALIDATOR) &&
  	(((xmlSchemaValidCtxtPtr) actxt)->inode != NULL))
  	return ( ((xmlSchemaValidCtxtPtr) actxt)->inode->nodeType);
      return (-1);
  }
  
  static int
  xmlSchemaIsGlobalItem(xmlSchemaTypePtr item)
  {
      switch (item->type) {
  	case XML_SCHEMA_TYPE_COMPLEX:
  	case XML_SCHEMA_TYPE_SIMPLE:
  	    if (item->flags & XML_SCHEMAS_TYPE_GLOBAL)
  		return(1);
  	    break;
  	case XML_SCHEMA_TYPE_GROUP:
  	    return (1);
  	case XML_SCHEMA_TYPE_ELEMENT:
  	    if ( ((xmlSchemaElementPtr) item)->flags &
  		XML_SCHEMAS_ELEM_GLOBAL)
  		return(1);
  	    break;
  	case XML_SCHEMA_TYPE_ATTRIBUTE:
  	    if ( ((xmlSchemaAttributePtr) item)->flags &
  		XML_SCHEMAS_ATTR_GLOBAL)
  		return(1);
  	    break;
  	/* Note that attribute groups are always global. */
  	default:
  	    return(1);
      }
      return (0);
  }
  
  static void
  xmlSchemaSimpleTypeErr(xmlSchemaAbstractCtxtPtr actxt,
  		       xmlParserErrors error,
  		       xmlNodePtr node,
  		       const xmlChar *value,
  		       xmlSchemaTypePtr type,
  		       int displayValue)
  {
      xmlChar *msg = NULL;
  
      xmlSchemaFormatNodeForError(&msg, actxt, node);
  
      if (displayValue || (xmlSchemaEvalErrorNodeType(actxt, node) ==
  	    XML_ATTRIBUTE_NODE))
  	msg = xmlStrcat(msg, BAD_CAST "'%s' is not a valid value of ");
      else
  	msg = xmlStrcat(msg, BAD_CAST "The character content is not a valid "
  	    "value of ");
  
      if (! xmlSchemaIsGlobalItem(type))
  	msg = xmlStrcat(msg, BAD_CAST "the local ");
      else
  	msg = xmlStrcat(msg, BAD_CAST "the ");
  
      if (WXS_IS_ATOMIC(type))
  	msg = xmlStrcat(msg, BAD_CAST "atomic type");
      else if (WXS_IS_LIST(type))
  	msg = xmlStrcat(msg, BAD_CAST "list type");
      else if (WXS_IS_UNION(type))
  	msg = xmlStrcat(msg, BAD_CAST "union type");
  
      if (xmlSchemaIsGlobalItem(type)) {
  	xmlChar *str = NULL;
  	msg = xmlStrcat(msg, BAD_CAST " '");
  	if (type->builtInType != 0) {
  	    msg = xmlStrcat(msg, BAD_CAST "xs:");
  	    str = xmlStrdup(type->name);
  	} else {
  	    const xmlChar *qName = xmlSchemaFormatQName(&str, type->targetNamespace, type->name);
  	    if (!str)
  		str = xmlStrdup(qName);
  	}
  	msg = xmlStrcat(msg, xmlEscapeFormatString(&str));
  	msg = xmlStrcat(msg, BAD_CAST "'");
  	FREE_AND_NULL(str);
      }
      msg = xmlStrcat(msg, BAD_CAST ".\n");
      if (displayValue || (xmlSchemaEvalErrorNodeType(actxt, node) ==
  	    XML_ATTRIBUTE_NODE))
  	xmlSchemaErr(actxt, error, node, (const char *) msg, value, NULL);
      else
  	xmlSchemaErr(actxt, error, node, (const char *) msg, NULL, NULL);
      FREE_AND_NULL(msg)
  }
  
  static const xmlChar *
  xmlSchemaFormatErrorNodeQName(xmlChar ** str,
  			      xmlSchemaNodeInfoPtr ni,
  			      xmlNodePtr node)
  {
      if (node != NULL) {
  	if (node->ns != NULL)
  	    return (xmlSchemaFormatQName(str, node->ns->href, node->name));
  	else
  	    return (xmlSchemaFormatQName(str, NULL, node->name));
      } else if (ni != NULL)
  	return (xmlSchemaFormatQName(str, ni->nsName, ni->localName));
      return (NULL);
  }
  
  static void
  xmlSchemaIllegalAttrErr(xmlSchemaAbstractCtxtPtr actxt,
  			xmlParserErrors error,
  			xmlSchemaAttrInfoPtr ni,
  			xmlNodePtr node)
  {
      xmlChar *msg = NULL, *str = NULL;
  
      xmlSchemaFormatNodeForError(&msg, actxt, node);
      msg = xmlStrcat(msg, BAD_CAST "The attribute '%s' is not allowed.\n");
      xmlSchemaErr(actxt, error, node, (const char *) msg,
  	xmlSchemaFormatErrorNodeQName(&str, (xmlSchemaNodeInfoPtr) ni, node),
  	NULL);
      FREE_AND_NULL(str)
      FREE_AND_NULL(msg)
  }
  
  static void LIBXML_ATTR_FORMAT(5,0)
  xmlSchemaComplexTypeErr(xmlSchemaAbstractCtxtPtr actxt,
  		        xmlParserErrors error,
  		        xmlNodePtr node,
  			xmlSchemaTypePtr type ATTRIBUTE_UNUSED,
  			const char *message,
  			int nbval,
  			int nbneg,
  			xmlChar **values)
  {
      xmlChar *str = NULL, *msg = NULL;
      xmlChar *localName, *nsName;
      const xmlChar *cur, *end;
      int i;
  
      xmlSchemaFormatNodeForError(&msg, actxt, node);
      msg = xmlStrcat(msg, (const xmlChar *) message);
      msg = xmlStrcat(msg, BAD_CAST ".");
      /*
      * Note that is does not make sense to report that we have a
      * wildcard here, since the wildcard might be unfolded into
      * multiple transitions.
      */
      if (nbval + nbneg > 0) {
  	if (nbval + nbneg > 1) {
  	    str = xmlStrdup(BAD_CAST " Expected is one of ( ");
  	} else
  	    str = xmlStrdup(BAD_CAST " Expected is ( ");
  	nsName = NULL;
  
  	for (i = 0; i < nbval + nbneg; i++) {
  	    cur = values[i];
  	    if (cur == NULL)
  	        continue;
  	    if ((cur[0] == 'n') && (cur[1] == 'o') && (cur[2] == 't') &&
  	        (cur[3] == ' ')) {
  		cur += 4;
  		str = xmlStrcat(str, BAD_CAST "##other");
  	    }
  	    /*
  	    * Get the local name.
  	    */
  	    localName = NULL;
  
  	    end = cur;
  	    if (*end == '*') {
  		localName = xmlStrdup(BAD_CAST "*");
  		end++;
  	    } else {
  		while ((*end != 0) && (*end != '|'))
  		    end++;
  		localName = xmlStrncat(localName, BAD_CAST cur, end - cur);
  	    }
  	    if (*end != 0) {
  		end++;
  		/*
  		* Skip "*|*" if they come with negated expressions, since
  		* they represent the same negated wildcard.
  		*/
  		if ((nbneg == 0) || (*end != '*') || (*localName != '*')) {
  		    /*
  		    * Get the namespace name.
  		    */
  		    cur = end;
  		    if (*end == '*') {
  			nsName = xmlStrdup(BAD_CAST "{*}");
  		    } else {
  			while (*end != 0)
  			    end++;
  
  			if (i >= nbval)
  			    nsName = xmlStrdup(BAD_CAST "{##other:");
  			else
  			    nsName = xmlStrdup(BAD_CAST "{");
  
  			nsName = xmlStrncat(nsName, BAD_CAST cur, end - cur);
  			nsName = xmlStrcat(nsName, BAD_CAST "}");
  		    }
  		    str = xmlStrcat(str, BAD_CAST nsName);
  		    FREE_AND_NULL(nsName)
  		} else {
  		    FREE_AND_NULL(localName);
  		    continue;
  		}
  	    }
  	    str = xmlStrcat(str, BAD_CAST localName);
  	    FREE_AND_NULL(localName);
  
  	    if (i < nbval + nbneg -1)
  		str = xmlStrcat(str, BAD_CAST ", ");
  	}
  	str = xmlStrcat(str, BAD_CAST " ).\n");
  	msg = xmlStrcat(msg, xmlEscapeFormatString(&str));
  	FREE_AND_NULL(str)
      } else
        msg = xmlStrcat(msg, BAD_CAST "\n");
      xmlSchemaErr(actxt, error, node, (const char *) msg, NULL, NULL);
      xmlFree(msg);
  }
  
  static void LIBXML_ATTR_FORMAT(8,0)
  xmlSchemaFacetErr(xmlSchemaAbstractCtxtPtr actxt,
  		  xmlParserErrors error,
  		  xmlNodePtr node,
  		  const xmlChar *value,
  		  unsigned long length,
  		  xmlSchemaTypePtr type,
  		  xmlSchemaFacetPtr facet,
  		  const char *message,
  		  const xmlChar *str1,
  		  const xmlChar *str2)
  {
      xmlChar *str = NULL, *msg = NULL;
      xmlSchemaTypeType facetType;
      int nodeType = xmlSchemaEvalErrorNodeType(actxt, node);
  
      xmlSchemaFormatNodeForError(&msg, actxt, node);
      if (error == XML_SCHEMAV_CVC_ENUMERATION_VALID) {
  	facetType = XML_SCHEMA_FACET_ENUMERATION;
  	/*
  	* If enumerations are validated, one must not expect the
  	* facet to be given.
  	*/
      } else
  	facetType = facet->type;
      msg = xmlStrcat(msg, BAD_CAST "[");
      msg = xmlStrcat(msg, BAD_CAST "facet '");
      msg = xmlStrcat(msg, xmlSchemaFacetTypeToString(facetType));
      msg = xmlStrcat(msg, BAD_CAST "'] ");
      if (message == NULL) {
  	/*
  	* Use a default message.
  	*/
  	if ((facetType == XML_SCHEMA_FACET_LENGTH) ||
  	    (facetType == XML_SCHEMA_FACET_MINLENGTH) ||
  	    (facetType == XML_SCHEMA_FACET_MAXLENGTH)) {
  
  	    char len[25], actLen[25];
  
  	    /* FIXME, TODO: What is the max expected string length of the
  	    * this value?
  	    */
  	    if (nodeType == XML_ATTRIBUTE_NODE)
  		msg = xmlStrcat(msg, BAD_CAST "The value '%s' has a length of '%s'; ");
  	    else
  		msg = xmlStrcat(msg, BAD_CAST "The value has a length of '%s'; ");
  
  	    snprintf(len, 24, "%lu", xmlSchemaGetFacetValueAsULong(facet));
  	    snprintf(actLen, 24, "%lu", length);
  
  	    if (facetType == XML_SCHEMA_FACET_LENGTH)
  		msg = xmlStrcat(msg,
  		BAD_CAST "this differs from the allowed length of '%s'.\n");
  	    else if (facetType == XML_SCHEMA_FACET_MAXLENGTH)
  		msg = xmlStrcat(msg,
  		BAD_CAST "this exceeds the allowed maximum length of '%s'.\n");
  	    else if (facetType == XML_SCHEMA_FACET_MINLENGTH)
  		msg = xmlStrcat(msg,
  		BAD_CAST "this underruns the allowed minimum length of '%s'.\n");
  
  	    if (nodeType == XML_ATTRIBUTE_NODE)
  		xmlSchemaErr3(actxt, error, node, (const char *) msg,
  		    value, (const xmlChar *) actLen, (const xmlChar *) len);
  	    else
  		xmlSchemaErr(actxt, error, node, (const char *) msg,
  		    (const xmlChar *) actLen, (const xmlChar *) len);
  
  	} else if (facetType == XML_SCHEMA_FACET_ENUMERATION) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' is not an element "
  		"of the set {%s}.\n");
  	    xmlSchemaErr(actxt, error, node, (const char *) msg, value,
  		xmlSchemaFormatFacetEnumSet(actxt, &str, type));
  	} else if (facetType == XML_SCHEMA_FACET_PATTERN) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' is not accepted "
  		"by the pattern '%s'.\n");
  	    xmlSchemaErr(actxt, error, node, (const char *) msg, value,
  		facet->value);
  	} else if (facetType == XML_SCHEMA_FACET_MININCLUSIVE) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' is less than the "
  		"minimum value allowed ('%s').\n");
  	    xmlSchemaErr(actxt, error, node, (const char *) msg, value,
  		facet->value);
  	} else if (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' is greater than the "
  		"maximum value allowed ('%s').\n");
  	    xmlSchemaErr(actxt, error, node, (const char *) msg, value,
  		facet->value);
  	} else if (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' must be greater than "
  		"'%s'.\n");
  	    xmlSchemaErr(actxt, error, node, (const char *) msg, value,
  		facet->value);
  	} else if (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' must be less than "
  		"'%s'.\n");
  	    xmlSchemaErr(actxt, error, node, (const char *) msg, value,
  		facet->value);
  	} else if (facetType == XML_SCHEMA_FACET_TOTALDIGITS) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' has more "
  		"digits than are allowed ('%s').\n");
  	    xmlSchemaErr(actxt, error, node, (const char*) msg, value,
  		facet->value);
  	} else if (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' has more fractional "
  		"digits than are allowed ('%s').\n");
  	    xmlSchemaErr(actxt, error, node, (const char*) msg, value,
  		facet->value);
  	} else if (nodeType == XML_ATTRIBUTE_NODE) {
  	    msg = xmlStrcat(msg, BAD_CAST "The value '%s' is not facet-valid.\n");
  	    xmlSchemaErr(actxt, error, node, (const char *) msg, value, NULL);
  	} else {
  	    msg = xmlStrcat(msg, BAD_CAST "The value is not facet-valid.\n");
  	    xmlSchemaErr(actxt, error, node, (const char *) msg, NULL, NULL);
  	}
      } else {
  	msg = xmlStrcat(msg, (const xmlChar *) message);
  	msg = xmlStrcat(msg, BAD_CAST ".\n");
  	xmlSchemaErr(actxt, error, node, (const char *) msg, str1, str2);
      }
      FREE_AND_NULL(str)
      xmlFree(msg);
  }
  
  #define VERROR(err, type, msg) \
      xmlSchemaCustomErr(ACTXT_CAST vctxt, err, NULL, type, msg, NULL, NULL);
  
  #define VERROR_INT(func, msg) xmlSchemaInternalErr(ACTXT_CAST vctxt, func, msg);
  
  #define PERROR_INT(func, msg) xmlSchemaInternalErr(ACTXT_CAST pctxt, func, msg);
  #define PERROR_INT2(func, msg) xmlSchemaInternalErr(ACTXT_CAST ctxt, func, msg);
  
  #define AERROR_INT(func, msg) xmlSchemaInternalErr(actxt, func, msg);
  
  
  /**
   * xmlSchemaPMissingAttrErr:
   * @ctxt: the schema validation context
   * @ownerItem: the owner as a schema object
   * @ownerElem: the owner as an element node
   * @node: the parent element node of the missing attribute node
   * @type: the corresponding type of the attribute node
   *
   * Reports an illegal attribute.
   */
  static void
  xmlSchemaPMissingAttrErr(xmlSchemaParserCtxtPtr ctxt,
  			 xmlParserErrors error,
  			 xmlSchemaBasicItemPtr ownerItem,
  			 xmlNodePtr ownerElem,
  			 const char *name,
  			 const char *message)
  {
      xmlChar *des = NULL;
  
      xmlSchemaFormatItemForReport(&des, NULL, ownerItem, ownerElem);
  
      if (message != NULL)
  	xmlSchemaPErr(ctxt, ownerElem, error, "%s: %s.\n", BAD_CAST des, BAD_CAST message);
      else
  	xmlSchemaPErr(ctxt, ownerElem, error,
  	    "%s: The attribute '%s' is required but missing.\n",
  	    BAD_CAST des, BAD_CAST name);
      FREE_AND_NULL(des);
  }
  
  
  /**
   * xmlSchemaPResCompAttrErr:
   * @ctxt: the schema validation context
   * @error: the error code
   * @ownerItem: the owner as a schema object
   * @ownerElem: the owner as an element node
   * @name: the name of the attribute holding the QName
   * @refName: the referenced local name
   * @refURI: the referenced namespace URI
   * @message: optional message
   *
   * Used to report QName attribute values that failed to resolve
   * to schema components.
   */
  static void
  xmlSchemaPResCompAttrErr(xmlSchemaParserCtxtPtr ctxt,
  			 xmlParserErrors error,
  			 xmlSchemaBasicItemPtr ownerItem,
  			 xmlNodePtr ownerElem,
  			 const char *name,
  			 const xmlChar *refName,
  			 const xmlChar *refURI,
  			 xmlSchemaTypeType refType,
  			 const char *refTypeStr)
  {
      xmlChar *des = NULL, *strA = NULL;
  
      xmlSchemaFormatItemForReport(&des, NULL, ownerItem, ownerElem);
      if (refTypeStr == NULL)
  	refTypeStr = (const char *) xmlSchemaItemTypeToStr(refType);
      xmlSchemaPErrExt(ctxt, ownerElem, error,
  	    NULL, NULL, NULL,
  	    "%s, attribute '%s': The QName value '%s' does not resolve to a(n) "
  	    "%s.\n", BAD_CAST des, BAD_CAST name,
  	    xmlSchemaFormatQName(&strA, refURI, refName),
  	    BAD_CAST refTypeStr, NULL);
      FREE_AND_NULL(des)
      FREE_AND_NULL(strA)
  }
  
  /**
   * xmlSchemaPCustomAttrErr:
   * @ctxt: the schema parser context
   * @error: the error code
   * @ownerDes: the designation of the owner
   * @ownerItem: the owner as a schema object
   * @attr: the illegal attribute node
   *
   * Reports an illegal attribute during the parse.
   */
  static void
  xmlSchemaPCustomAttrErr(xmlSchemaParserCtxtPtr ctxt,
  			xmlParserErrors error,
  			xmlChar **ownerDes,
  			xmlSchemaBasicItemPtr ownerItem,
  			xmlAttrPtr attr,
  			const char *msg)
  {
      xmlChar *des = NULL;
  
      if (ownerDes == NULL)
  	xmlSchemaFormatItemForReport(&des, NULL, ownerItem, attr->parent);
      else if (*ownerDes == NULL) {
  	xmlSchemaFormatItemForReport(ownerDes, NULL, ownerItem, attr->parent);
  	des = *ownerDes;
      } else
  	des = *ownerDes;
      if (attr == NULL) {
  	xmlSchemaPErrExt(ctxt, NULL, error, NULL, NULL, NULL,
  	    "%s, attribute '%s': %s.\n",
  	    BAD_CAST des, (const xmlChar *) "Unknown",
  	    (const xmlChar *) msg, NULL, NULL);
      } else {
  	xmlSchemaPErrExt(ctxt, (xmlNodePtr) attr, error, NULL, NULL, NULL,
  	    "%s, attribute '%s': %s.\n",
  	    BAD_CAST des, attr->name, (const xmlChar *) msg, NULL, NULL);
      }
      if (ownerDes == NULL)
  	FREE_AND_NULL(des);
  }
  
  /**
   * xmlSchemaPIllegalAttrErr:
   * @ctxt: the schema parser context
   * @error: the error code
   * @ownerItem: the attribute's owner item
   * @attr: the illegal attribute node
   *
   * Reports an illegal attribute during the parse.
   */
  static void
  xmlSchemaPIllegalAttrErr(xmlSchemaParserCtxtPtr ctxt,
  			 xmlParserErrors error,
  			 xmlSchemaBasicItemPtr ownerComp ATTRIBUTE_UNUSED,
  			 xmlAttrPtr attr)
  {
      xmlChar *strA = NULL, *strB = NULL;
  
      xmlSchemaFormatNodeForError(&strA, ACTXT_CAST ctxt, attr->parent);
      xmlSchemaErr4(ACTXT_CAST ctxt, error, (xmlNodePtr) attr,
  	"%sThe attribute '%s' is not allowed.\n", BAD_CAST strA,
  	xmlSchemaFormatQNameNs(&strB, attr->ns, attr->name),
  	NULL, NULL);
      FREE_AND_NULL(strA);
      FREE_AND_NULL(strB);
  }
  
  /**
   * xmlSchemaPCustomErr:
   * @ctxt: the schema parser context
   * @error: the error code
   * @itemDes: the designation of the schema item
   * @item: the schema item
   * @itemElem: the node of the schema item
   * @message: the error message
   * @str1: an optional param for the error message
   * @str2: an optional param for the error message
   * @str3: an optional param for the error message
   *
   * Reports an error during parsing.
   */
  static void LIBXML_ATTR_FORMAT(5,0)
  xmlSchemaPCustomErrExt(xmlSchemaParserCtxtPtr ctxt,
  		    xmlParserErrors error,
  		    xmlSchemaBasicItemPtr item,
  		    xmlNodePtr itemElem,
  		    const char *message,
  		    const xmlChar *str1,
  		    const xmlChar *str2,
  		    const xmlChar *str3)
  {
      xmlChar *des = NULL, *msg = NULL;
  
      xmlSchemaFormatItemForReport(&des, NULL, item, itemElem);
      msg = xmlStrdup(BAD_CAST "%s: ");
      msg = xmlStrcat(msg, (const xmlChar *) message);
      msg = xmlStrcat(msg, BAD_CAST ".\n");
      if ((itemElem == NULL) && (item != NULL))
  	itemElem = WXS_ITEM_NODE(item);
      xmlSchemaPErrExt(ctxt, itemElem, error, NULL, NULL, NULL,
  	(const char *) msg, BAD_CAST des, str1, str2, str3, NULL);
      FREE_AND_NULL(des);
      FREE_AND_NULL(msg);
  }
  
  /**
   * xmlSchemaPCustomErr:
   * @ctxt: the schema parser context
   * @error: the error code
   * @itemDes: the designation of the schema item
   * @item: the schema item
   * @itemElem: the node of the schema item
   * @message: the error message
   * @str1: the optional param for the error message
   *
   * Reports an error during parsing.
   */
  static void LIBXML_ATTR_FORMAT(5,0)
  xmlSchemaPCustomErr(xmlSchemaParserCtxtPtr ctxt,
  		    xmlParserErrors error,
  		    xmlSchemaBasicItemPtr item,
  		    xmlNodePtr itemElem,
  		    const char *message,
  		    const xmlChar *str1)
  {
      xmlSchemaPCustomErrExt(ctxt, error, item, itemElem, message,
  	str1, NULL, NULL);
  }
  
  /**
   * xmlSchemaPAttrUseErr:
   * @ctxt: the schema parser context
   * @error: the error code
   * @itemDes: the designation of the schema type
   * @item: the schema type
   * @itemElem: the node of the schema type
   * @attr: the invalid schema attribute
   * @message: the error message
   * @str1: the optional param for the error message
   *
   * Reports an attribute use error during parsing.
   */
  static void LIBXML_ATTR_FORMAT(6,0)
  xmlSchemaPAttrUseErr4(xmlSchemaParserCtxtPtr ctxt,
  		    xmlParserErrors error,
  		    xmlNodePtr node,
  		    xmlSchemaBasicItemPtr ownerItem,
  		    const xmlSchemaAttributeUsePtr attruse,
  		    const char *message,
  		    const xmlChar *str1, const xmlChar *str2,
  		    const xmlChar *str3,const xmlChar *str4)
  {
      xmlChar *str = NULL, *msg = NULL;
  
      xmlSchemaFormatItemForReport(&msg, NULL, ownerItem, NULL);
      msg = xmlStrcat(msg, BAD_CAST ", ");
      msg = xmlStrcat(msg,
  	BAD_CAST xmlSchemaFormatItemForReport(&str, NULL,
  	WXS_BASIC_CAST attruse, NULL));
      FREE_AND_NULL(str);
      msg = xmlStrcat(msg, BAD_CAST ": ");
      msg = xmlStrcat(msg, (const xmlChar *) message);
      msg = xmlStrcat(msg, BAD_CAST ".\n");
      xmlSchemaErr4(ACTXT_CAST ctxt, error, node,
  	(const char *) msg, str1, str2, str3, str4);
      xmlFree(msg);
  }
  
  /**
   * xmlSchemaPIllegalFacetAtomicErr:
   * @ctxt: the schema parser context
   * @error: the error code
   * @type: the schema type
   * @baseType: the base type of type
   * @facet: the illegal facet
   *
   * Reports an illegal facet for atomic simple types.
   */
  static void
  xmlSchemaPIllegalFacetAtomicErr(xmlSchemaParserCtxtPtr ctxt,
  			  xmlParserErrors error,
  			  xmlSchemaTypePtr type,
  			  xmlSchemaTypePtr baseType,
  			  xmlSchemaFacetPtr facet)
  {
      xmlChar *des = NULL, *strT = NULL;
  
      xmlSchemaFormatItemForReport(&des, NULL, WXS_BASIC_CAST type, type->node);
      xmlSchemaPErrExt(ctxt, type->node, error, NULL, NULL, NULL,
  	"%s: The facet '%s' is not allowed on types derived from the "
  	"type %s.\n",
  	BAD_CAST des, xmlSchemaFacetTypeToString(facet->type),
  	xmlSchemaFormatItemForReport(&strT, NULL, WXS_BASIC_CAST baseType, NULL),
  	NULL, NULL);
      FREE_AND_NULL(des);
      FREE_AND_NULL(strT);
  }
  
  /**
   * xmlSchemaPIllegalFacetListUnionErr:
   * @ctxt: the schema parser context
   * @error: the error code
   * @itemDes: the designation of the schema item involved
   * @item: the schema item involved
   * @facet: the illegal facet
   *
   * Reports an illegal facet for <list> and <union>.
   */
  static void
  xmlSchemaPIllegalFacetListUnionErr(xmlSchemaParserCtxtPtr ctxt,
  			  xmlParserErrors error,
  			  xmlSchemaTypePtr type,
  			  xmlSchemaFacetPtr facet)
  {
      xmlChar *des = NULL;
  
      xmlSchemaFormatItemForReport(&des, NULL, WXS_BASIC_CAST type,
  	type->node);
      xmlSchemaPErr(ctxt, type->node, error,
  	"%s: The facet '%s' is not allowed.\n",
  	BAD_CAST des, xmlSchemaFacetTypeToString(facet->type));
      FREE_AND_NULL(des);
  }
  
  /**
   * xmlSchemaPMutualExclAttrErr:
   * @ctxt: the schema validation context
   * @error: the error code
   * @elemDes: the designation of the parent element node
   * @attr: the bad attribute node
   * @type: the corresponding type of the attribute node
   *
   * Reports an illegal attribute.
   */
  static void
  xmlSchemaPMutualExclAttrErr(xmlSchemaParserCtxtPtr ctxt,
  			 xmlParserErrors error,
  			 xmlSchemaBasicItemPtr ownerItem,
  			 xmlAttrPtr attr,
  			 const char *name1,
  			 const char *name2)
  {
      xmlChar *des = NULL;
  
      xmlSchemaFormatItemForReport(&des, NULL, WXS_BASIC_CAST ownerItem, attr->parent);
      xmlSchemaPErrExt(ctxt, (xmlNodePtr) attr, error, NULL, NULL, NULL,
  	"%s: The attributes '%s' and '%s' are mutually exclusive.\n",
  	BAD_CAST des, BAD_CAST name1, BAD_CAST name2, NULL, NULL);
      FREE_AND_NULL(des);
  }
  
  /**
   * xmlSchemaPSimpleTypeErr:
   * @ctxt:  the schema validation context
   * @error: the error code
   * @type: the type specifier
   * @ownerItem: the schema object if existent
   * @node: the validated node
   * @value: the validated value
   *
   * Reports a simple type validation error.
   * TODO: Should this report the value of an element as well?
   */
  static void LIBXML_ATTR_FORMAT(8,0)
  xmlSchemaPSimpleTypeErr(xmlSchemaParserCtxtPtr ctxt,
  			xmlParserErrors error,
  			xmlSchemaBasicItemPtr ownerItem ATTRIBUTE_UNUSED,
  			xmlNodePtr node,
  			xmlSchemaTypePtr type,
  			const char *expected,
  			const xmlChar *value,
  			const char *message,
  			const xmlChar *str1,
  			const xmlChar *str2)
  {
      xmlChar *msg = NULL;
  
      xmlSchemaFormatNodeForError(&msg, ACTXT_CAST ctxt, node);
      if (message == NULL) {
  	/*
  	* Use default messages.
  	*/
  	if (type != NULL) {
  	    if (node->type == XML_ATTRIBUTE_NODE)
  		msg = xmlStrcat(msg, BAD_CAST "'%s' is not a valid value of ");
  	    else
  		msg = xmlStrcat(msg, BAD_CAST "The character content is not a "
  		"valid value of ");
  	    if (! xmlSchemaIsGlobalItem(type))
  		msg = xmlStrcat(msg, BAD_CAST "the local ");
  	    else
  		msg = xmlStrcat(msg, BAD_CAST "the ");
  
  	    if (WXS_IS_ATOMIC(type))
  		msg = xmlStrcat(msg, BAD_CAST "atomic type");
  	    else if (WXS_IS_LIST(type))
  		msg = xmlStrcat(msg, BAD_CAST "list type");
  	    else if (WXS_IS_UNION(type))
  		msg = xmlStrcat(msg, BAD_CAST "union type");
  
  	    if (xmlSchemaIsGlobalItem(type)) {
  		xmlChar *str = NULL;
  		msg = xmlStrcat(msg, BAD_CAST " '");
  		if (type->builtInType != 0) {
  		    msg = xmlStrcat(msg, BAD_CAST "xs:");
  		    str = xmlStrdup(type->name);
  		} else {
  		    const xmlChar *qName = xmlSchemaFormatQName(&str, type->targetNamespace, type->name);
  		    if (!str)
  			str = xmlStrdup(qName);
  		}
  		msg = xmlStrcat(msg, xmlEscapeFormatString(&str));
  		msg = xmlStrcat(msg, BAD_CAST "'.");
  		FREE_AND_NULL(str);
  	    }
  	} else {
  	    if (node->type == XML_ATTRIBUTE_NODE)
  		msg = xmlStrcat(msg, BAD_CAST "The value '%s' is not valid.");
  	    else
  		msg = xmlStrcat(msg, BAD_CAST "The character content is not "
  		"valid.");
  	}
  	if (expected) {
  	    xmlChar *expectedEscaped = xmlCharStrdup(expected);
  	    msg = xmlStrcat(msg, BAD_CAST " Expected is '");
  	    msg = xmlStrcat(msg, xmlEscapeFormatString(&expectedEscaped));
  	    FREE_AND_NULL(expectedEscaped);
  	    msg = xmlStrcat(msg, BAD_CAST "'.\n");
  	} else
  	    msg = xmlStrcat(msg, BAD_CAST "\n");
  	if (node->type == XML_ATTRIBUTE_NODE)
  	    xmlSchemaPErr(ctxt, node, error, (const char *) msg, value, NULL);
  	else
  	    xmlSchemaPErr(ctxt, node, error, (const char *) msg, NULL, NULL);
      } else {
  	msg = xmlStrcat(msg, BAD_CAST message);
  	msg = xmlStrcat(msg, BAD_CAST ".\n");
  	xmlSchemaPErrExt(ctxt, node, error, NULL, NULL, NULL,
  	     (const char*) msg, str1, str2, NULL, NULL, NULL);
      }
      /* Cleanup. */
      FREE_AND_NULL(msg)
  }
  
  /**
   * xmlSchemaPContentErr:
   * @ctxt: the schema parser context
   * @error: the error code
   * @ownerItem: the owner item of the holder of the content
   * @ownerElem: the node of the holder of the content
   * @child: the invalid child node
   * @message: the optional error message
   * @content: the optional string describing the correct content
   *
   * Reports an error concerning the content of a schema element.
   */
  static void
  xmlSchemaPContentErr(xmlSchemaParserCtxtPtr ctxt,
  		     xmlParserErrors error,
  		     xmlSchemaBasicItemPtr ownerItem,
  		     xmlNodePtr ownerElem,
  		     xmlNodePtr child,
  		     const char *message,
  		     const char *content)
  {
      xmlChar *des = NULL;
  
      xmlSchemaFormatItemForReport(&des, NULL, ownerItem, ownerElem);
      if (message != NULL)
  	xmlSchemaPErr2(ctxt, ownerElem, child, error,
  	    "%s: %s.\n",
  	    BAD_CAST des, BAD_CAST message);
      else {
  	if (content != NULL) {
  	    xmlSchemaPErr2(ctxt, ownerElem, child, error,
  		"%s: The content is not valid. Expected is %s.\n",
  		BAD_CAST des, BAD_CAST content);
  	} else {
  	    xmlSchemaPErr2(ctxt, ownerElem, child, error,
  		"%s: The content is not valid.\n",
  		BAD_CAST des, NULL);
  	}
      }
      FREE_AND_NULL(des)
  }
  
  /************************************************************************
   *									*
   *			Streamable error functions                      *
   *									*
   ************************************************************************/
  
  
  
  
  /************************************************************************
   *									*
   *			Validation helper functions			*
   *									*
   ************************************************************************/
  
  
  /************************************************************************
   *									*
   *			Allocation functions				*
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaNewSchemaForParserCtxt:
   * @ctxt:  a schema validation context
   *
   * Allocate a new Schema structure.
   *
   * Returns the newly allocated structure or NULL in case or error
   */
  static xmlSchemaPtr
  xmlSchemaNewSchema(xmlSchemaParserCtxtPtr ctxt)
  {
      xmlSchemaPtr ret;
  
      ret = (xmlSchemaPtr) xmlMalloc(sizeof(xmlSchema));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt, "allocating schema", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchema));
      ret->dict = ctxt->dict;
      xmlDictReference(ret->dict);
  
      return (ret);
  }
  
  /**
   * xmlSchemaNewFacet:
   *
   * Allocate a new Facet structure.
   *
   * Returns the newly allocated structure or NULL in case or error
   */
  xmlSchemaFacetPtr
  xmlSchemaNewFacet(void)
  {
      xmlSchemaFacetPtr ret;
  
      ret = (xmlSchemaFacetPtr) xmlMalloc(sizeof(xmlSchemaFacet));
      if (ret == NULL) {
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaFacet));
  
      return (ret);
  }
  
  /**
   * xmlSchemaNewAnnot:
   * @ctxt:  a schema validation context
   * @node:  a node
   *
   * Allocate a new annotation structure.
   *
   * Returns the newly allocated structure or NULL in case or error
   */
  static xmlSchemaAnnotPtr
  xmlSchemaNewAnnot(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node)
  {
      xmlSchemaAnnotPtr ret;
  
      ret = (xmlSchemaAnnotPtr) xmlMalloc(sizeof(xmlSchemaAnnot));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt, "allocating annotation", node);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaAnnot));
      ret->content = node;
      return (ret);
  }
  
  static xmlSchemaItemListPtr
  xmlSchemaItemListCreate(void)
  {
      xmlSchemaItemListPtr ret;
  
      ret = xmlMalloc(sizeof(xmlSchemaItemList));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(NULL,
  	    "allocating an item list structure", NULL);
  	return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaItemList));
      return (ret);
  }
  
  static void
  xmlSchemaItemListClear(xmlSchemaItemListPtr list)
  {
      if (list->items != NULL) {
  	xmlFree(list->items);
  	list->items = NULL;
      }
      list->nbItems = 0;
      list->sizeItems = 0;
  }
  
  static int
  xmlSchemaItemListAdd(xmlSchemaItemListPtr list, void *item)
  {
      if (list->items == NULL) {
  	list->items = (void **) xmlMalloc(
  	    20 * sizeof(void *));
  	if (list->items == NULL) {
  	    xmlSchemaPErrMemory(NULL, "allocating new item list", NULL);
  	    return(-1);
  	}
  	list->sizeItems = 20;
      } else if (list->sizeItems <= list->nbItems) {
  	list->sizeItems *= 2;
  	list->items = (void **) xmlRealloc(list->items,
  	    list->sizeItems * sizeof(void *));
  	if (list->items == NULL) {
  	    xmlSchemaPErrMemory(NULL, "growing item list", NULL);
  	    list->sizeItems = 0;
  	    return(-1);
  	}
      }
      list->items[list->nbItems++] = item;
      return(0);
  }
  
  static int
  xmlSchemaItemListAddSize(xmlSchemaItemListPtr list,
  			 int initialSize,
  			 void *item)
  {
      if (list->items == NULL) {
  	if (initialSize <= 0)
  	    initialSize = 1;
  	list->items = (void **) xmlMalloc(
  	    initialSize * sizeof(void *));
  	if (list->items == NULL) {
  	    xmlSchemaPErrMemory(NULL, "allocating new item list", NULL);
  	    return(-1);
  	}
  	list->sizeItems = initialSize;
      } else if (list->sizeItems <= list->nbItems) {
  	list->sizeItems *= 2;
  	list->items = (void **) xmlRealloc(list->items,
  	    list->sizeItems * sizeof(void *));
  	if (list->items == NULL) {
  	    xmlSchemaPErrMemory(NULL, "growing item list", NULL);
  	    list->sizeItems = 0;
  	    return(-1);
  	}
      }
      list->items[list->nbItems++] = item;
      return(0);
  }
  
  static int
  xmlSchemaItemListInsert(xmlSchemaItemListPtr list, void *item, int idx)
  {
      if (list->items == NULL) {
  	list->items = (void **) xmlMalloc(
  	    20 * sizeof(void *));
  	if (list->items == NULL) {
  	    xmlSchemaPErrMemory(NULL, "allocating new item list", NULL);
  	    return(-1);
  	}
  	list->sizeItems = 20;
      } else if (list->sizeItems <= list->nbItems) {
  	list->sizeItems *= 2;
  	list->items = (void **) xmlRealloc(list->items,
  	    list->sizeItems * sizeof(void *));
  	if (list->items == NULL) {
  	    xmlSchemaPErrMemory(NULL, "growing item list", NULL);
  	    list->sizeItems = 0;
  	    return(-1);
  	}
      }
      /*
      * Just append if the index is greater/equal than the item count.
      */
      if (idx >= list->nbItems) {
  	list->items[list->nbItems++] = item;
      } else {
  	int i;
  	for (i = list->nbItems; i > idx; i--)
  	    list->items[i] = list->items[i-1];
  	list->items[idx] = item;
  	list->nbItems++;
      }
      return(0);
  }
  
  #if 0 /* enable if ever needed */
  static int
  xmlSchemaItemListInsertSize(xmlSchemaItemListPtr list,
  			    int initialSize,
  			    void *item,
  			    int idx)
  {
      if (list->items == NULL) {
  	if (initialSize <= 0)
  	    initialSize = 1;
  	list->items = (void **) xmlMalloc(
  	    initialSize * sizeof(void *));
  	if (list->items == NULL) {
  	    xmlSchemaPErrMemory(NULL, "allocating new item list", NULL);
  	    return(-1);
  	}
  	list->sizeItems = initialSize;
      } else if (list->sizeItems <= list->nbItems) {
  	list->sizeItems *= 2;
  	list->items = (void **) xmlRealloc(list->items,
  	    list->sizeItems * sizeof(void *));
  	if (list->items == NULL) {
  	    xmlSchemaPErrMemory(NULL, "growing item list", NULL);
  	    list->sizeItems = 0;
  	    return(-1);
  	}
      }
      /*
      * Just append if the index is greater/equal than the item count.
      */
      if (idx >= list->nbItems) {
  	list->items[list->nbItems++] = item;
      } else {
  	int i;
  	for (i = list->nbItems; i > idx; i--)
  	    list->items[i] = list->items[i-1];
  	list->items[idx] = item;
  	list->nbItems++;
      }
      return(0);
  }
  #endif
  
  static int
  xmlSchemaItemListRemove(xmlSchemaItemListPtr list, int idx)
  {
      int i;
      if ((list->items == NULL) || (idx >= list->nbItems)) {
  	xmlSchemaPSimpleErr("Internal error: xmlSchemaItemListRemove, "
  	    "index error.\n");
  	return(-1);
      }
  
      if (list->nbItems == 1) {
  	/* TODO: Really free the list? */
  	xmlFree(list->items);
  	list->items = NULL;
  	list->nbItems = 0;
  	list->sizeItems = 0;
      } else if (list->nbItems -1 == idx) {
  	list->nbItems--;
      } else {
  	for (i = idx; i < list->nbItems -1; i++)
  	    list->items[i] = list->items[i+1];
  	list->nbItems--;
      }
      return(0);
  }
  
  /**
   * xmlSchemaItemListFree:
   * @annot:  a schema type structure
   *
   * Deallocate a annotation structure
   */
  static void
  xmlSchemaItemListFree(xmlSchemaItemListPtr list)
  {
      if (list == NULL)
  	return;
      if (list->items != NULL)
  	xmlFree(list->items);
      xmlFree(list);
  }
  
  static void
  xmlSchemaBucketFree(xmlSchemaBucketPtr bucket)
  {
      if (bucket == NULL)
  	return;
      if (bucket->globals != NULL) {
  	xmlSchemaComponentListFree(bucket->globals);
  	xmlSchemaItemListFree(bucket->globals);
      }
      if (bucket->locals != NULL) {
  	xmlSchemaComponentListFree(bucket->locals);
  	xmlSchemaItemListFree(bucket->locals);
      }
      if (bucket->relations != NULL) {
  	xmlSchemaSchemaRelationPtr prev, cur = bucket->relations;
  	do {
  	    prev = cur;
  	    cur = cur->next;
  	    xmlFree(prev);
  	} while (cur != NULL);
      }
      if ((! bucket->preserveDoc) && (bucket->doc != NULL)) {
  	xmlFreeDoc(bucket->doc);
      }
      if (bucket->type == XML_SCHEMA_SCHEMA_IMPORT) {
  	if (WXS_IMPBUCKET(bucket)->schema != NULL)
  	    xmlSchemaFree(WXS_IMPBUCKET(bucket)->schema);
      }
      xmlFree(bucket);
  }
  
  static void
  xmlSchemaBucketFreeEntry(void *bucket, const xmlChar *name ATTRIBUTE_UNUSED)
  {
      xmlSchemaBucketFree((xmlSchemaBucketPtr) bucket);
  }
  
  static xmlSchemaBucketPtr
  xmlSchemaBucketCreate(xmlSchemaParserCtxtPtr pctxt,
  			 int type, const xmlChar *targetNamespace)
  {
      xmlSchemaBucketPtr ret;
      int size;
      xmlSchemaPtr mainSchema;
  
      if (WXS_CONSTRUCTOR(pctxt)->mainSchema == NULL) {
  	PERROR_INT("xmlSchemaBucketCreate",
  	    "no main schema on constructor");
  	return(NULL);
      }
      mainSchema = WXS_CONSTRUCTOR(pctxt)->mainSchema;
      /* Create the schema bucket. */
      if (WXS_IS_BUCKET_INCREDEF(type))
  	size = sizeof(xmlSchemaInclude);
      else
  	size = sizeof(xmlSchemaImport);
      ret = (xmlSchemaBucketPtr) xmlMalloc(size);
      if (ret == NULL) {
  	xmlSchemaPErrMemory(NULL, "allocating schema bucket", NULL);
  	return(NULL);
      }
      memset(ret, 0, size);
      ret->targetNamespace = targetNamespace;
      ret->type = type;
      ret->globals = xmlSchemaItemListCreate();
      if (ret->globals == NULL) {
  	xmlFree(ret);
  	return(NULL);
      }
      ret->locals = xmlSchemaItemListCreate();
      if (ret->locals == NULL) {
  	xmlFree(ret);
  	return(NULL);
      }
      /*
      * The following will assure that only the first bucket is marked as
      * XML_SCHEMA_SCHEMA_MAIN and it points to the *main* schema.
      * For each following import buckets an xmlSchema will be created.
      * An xmlSchema will be created for every distinct targetNamespace.
      * We assign the targetNamespace to the schemata here.
      */
      if (! WXS_HAS_BUCKETS(pctxt)) {
  	if (WXS_IS_BUCKET_INCREDEF(type)) {
  	    PERROR_INT("xmlSchemaBucketCreate",
  		"first bucket but it's an include or redefine");
  	    xmlSchemaBucketFree(ret);
  	    return(NULL);
  	}
  	/* Force the type to be XML_SCHEMA_SCHEMA_MAIN. */
  	ret->type = XML_SCHEMA_SCHEMA_MAIN;
  	/* Point to the *main* schema. */
  	WXS_CONSTRUCTOR(pctxt)->mainBucket = ret;
  	WXS_IMPBUCKET(ret)->schema = mainSchema;
  	/*
  	* Ensure that the main schema gets a targetNamespace.
  	*/
  	mainSchema->targetNamespace = targetNamespace;
      } else {
  	if (type == XML_SCHEMA_SCHEMA_MAIN) {
  	    PERROR_INT("xmlSchemaBucketCreate",
  		"main bucket but it's not the first one");
  	    xmlSchemaBucketFree(ret);
  	    return(NULL);
  	} else if (type == XML_SCHEMA_SCHEMA_IMPORT) {
  	    /*
  	    * Create a schema for imports and assign the
  	    * targetNamespace.
  	    */
  	    WXS_IMPBUCKET(ret)->schema = xmlSchemaNewSchema(pctxt);
  	    if (WXS_IMPBUCKET(ret)->schema == NULL) {
  		xmlSchemaBucketFree(ret);
  		return(NULL);
  	    }
  	    WXS_IMPBUCKET(ret)->schema->targetNamespace = targetNamespace;
  	}
      }
      if (WXS_IS_BUCKET_IMPMAIN(type)) {
  	int res;
  	/*
  	* Imports go into the "schemasImports" slot of the main *schema*.
  	* Note that we create an import entry for the main schema as well; i.e.,
  	* even if there's only one schema, we'll get an import.
  	*/
  	if (mainSchema->schemasImports == NULL) {
  	    mainSchema->schemasImports = xmlHashCreateDict(5,
  		WXS_CONSTRUCTOR(pctxt)->dict);
  	    if (mainSchema->schemasImports == NULL) {
  		xmlSchemaBucketFree(ret);
  		return(NULL);
  	    }
  	}
  	if (targetNamespace == NULL)
  	    res = xmlHashAddEntry(mainSchema->schemasImports,
  		XML_SCHEMAS_NO_NAMESPACE, ret);
  	else
  	    res = xmlHashAddEntry(mainSchema->schemasImports,
  		targetNamespace, ret);
  	if (res != 0) {
  	    PERROR_INT("xmlSchemaBucketCreate",
  		"failed to add the schema bucket to the hash");
  	    xmlSchemaBucketFree(ret);
  	    return(NULL);
  	}
      } else {
  	/* Set the @ownerImport of an include bucket. */
  	if (WXS_IS_BUCKET_IMPMAIN(WXS_CONSTRUCTOR(pctxt)->bucket->type))
  	    WXS_INCBUCKET(ret)->ownerImport =
  		WXS_IMPBUCKET(WXS_CONSTRUCTOR(pctxt)->bucket);
  	else
  	    WXS_INCBUCKET(ret)->ownerImport =
  		WXS_INCBUCKET(WXS_CONSTRUCTOR(pctxt)->bucket)->ownerImport;
  
  	/* Includes got into the "includes" slot of the *main* schema. */
  	if (mainSchema->includes == NULL) {
  	    mainSchema->includes = xmlSchemaItemListCreate();
  	    if (mainSchema->includes == NULL) {
  		xmlSchemaBucketFree(ret);
  		return(NULL);
  	    }
  	}
  	xmlSchemaItemListAdd(mainSchema->includes, ret);
      }
      /*
      * Add to list of all buckets; this is used for lookup
      * during schema construction time only.
      */
      if (xmlSchemaItemListAdd(WXS_CONSTRUCTOR(pctxt)->buckets, ret) == -1)
  	return(NULL);
      return(ret);
  }
  
  static int
  xmlSchemaAddItemSize(xmlSchemaItemListPtr *list, int initialSize, void *item)
  {
      if (*list == NULL) {
  	*list = xmlSchemaItemListCreate();
  	if (*list == NULL)
  	    return(-1);
      }
      xmlSchemaItemListAddSize(*list, initialSize, item);
      return(0);
  }
  
  /**
   * xmlSchemaFreeAnnot:
   * @annot:  a schema type structure
   *
   * Deallocate a annotation structure
   */
  static void
  xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot)
  {
      if (annot == NULL)
          return;
      if (annot->next == NULL) {
  	xmlFree(annot);
      } else {
  	xmlSchemaAnnotPtr prev;
  
  	do {
  	    prev = annot;
  	    annot = annot->next;
  	    xmlFree(prev);
  	} while (annot != NULL);
      }
  }
  
  /**
   * xmlSchemaFreeNotation:
   * @schema:  a schema notation structure
   *
   * Deallocate a Schema Notation structure.
   */
  static void
  xmlSchemaFreeNotation(xmlSchemaNotationPtr nota)
  {
      if (nota == NULL)
          return;
      xmlFree(nota);
  }
  
  /**
   * xmlSchemaFreeAttribute:
   * @attr:  an attribute declaration
   *
   * Deallocates an attribute declaration structure.
   */
  static void
  xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr)
  {
      if (attr == NULL)
          return;
      if (attr->annot != NULL)
  	xmlSchemaFreeAnnot(attr->annot);
      if (attr->defVal != NULL)
  	xmlSchemaFreeValue(attr->defVal);
      xmlFree(attr);
  }
  
  /**
   * xmlSchemaFreeAttributeUse:
   * @use:  an attribute use
   *
   * Deallocates an attribute use structure.
   */
  static void
  xmlSchemaFreeAttributeUse(xmlSchemaAttributeUsePtr use)
  {
      if (use == NULL)
          return;
      if (use->annot != NULL)
  	xmlSchemaFreeAnnot(use->annot);
      if (use->defVal != NULL)
  	xmlSchemaFreeValue(use->defVal);
      xmlFree(use);
  }
  
  /**
   * xmlSchemaFreeAttributeUseProhib:
   * @prohib:  an attribute use prohibition
   *
   * Deallocates an attribute use structure.
   */
  static void
  xmlSchemaFreeAttributeUseProhib(xmlSchemaAttributeUseProhibPtr prohib)
  {
      if (prohib == NULL)
          return;
      xmlFree(prohib);
  }
  
  /**
   * 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
   *
   * Deallocate a Schema Attribute Group structure.
   */
  static void
  xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attrGr)
  {
      if (attrGr == NULL)
          return;
      if (attrGr->annot != NULL)
          xmlSchemaFreeAnnot(attrGr->annot);
      if (attrGr->attrUses != NULL)
  	xmlSchemaItemListFree(WXS_LIST_CAST attrGr->attrUses);
      xmlFree(attrGr);
  }
  
  /**
   * xmlSchemaFreeQNameRef:
   * @item: a QName reference structure
   *
   * Deallocatea a QName reference structure.
   */
  static void
  xmlSchemaFreeQNameRef(xmlSchemaQNameRefPtr item)
  {
      xmlFree(item);
  }
  
  /**
   * 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;
      }
  }
  
  static void
  xmlSchemaFreeIDCStateObjList(xmlSchemaIDCStateObjPtr sto)
  {
      xmlSchemaIDCStateObjPtr next;
      while (sto != NULL) {
  	next = sto->next;
  	if (sto->history != NULL)
  	    xmlFree(sto->history);
  	if (sto->xpathCtxt != NULL)
  	    xmlFreeStreamCtxt((xmlStreamCtxtPtr) sto->xpathCtxt);
  	xmlFree(sto);
  	sto = next;
      }
  }
  
  /**
   * xmlSchemaFreeIDC:
   * @idc: a identity-constraint definition
   *
   * Deallocates an identity-constraint definition.
   */
  static void
  xmlSchemaFreeIDC(xmlSchemaIDCPtr idcDef)
  {
      xmlSchemaIDCSelectPtr cur, prev;
  
      if (idcDef == NULL)
  	return;
      if (idcDef->annot != NULL)
          xmlSchemaFreeAnnot(idcDef->annot);
      /* Selector */
      if (idcDef->selector != NULL) {
  	if (idcDef->selector->xpathComp != NULL)
  	    xmlFreePattern((xmlPatternPtr) idcDef->selector->xpathComp);
  	xmlFree(idcDef->selector);
      }
      /* Fields */
      if (idcDef->fields != NULL) {
  	cur = idcDef->fields;
  	do {
  	    prev = cur;
  	    cur = cur->next;
  	    if (prev->xpathComp != NULL)
  		xmlFreePattern((xmlPatternPtr) prev->xpathComp);
  	    xmlFree(prev);
  	} while (cur != NULL);
      }
      xmlFree(idcDef);
  }
  
  /**
   * xmlSchemaFreeElement:
   * @schema:  a schema element structure
   *
   * Deallocate a Schema Element structure.
   */
  static void
  xmlSchemaFreeElement(xmlSchemaElementPtr elem)
  {
      if (elem == NULL)
          return;
      if (elem->annot != NULL)
          xmlSchemaFreeAnnot(elem->annot);
      if (elem->contModel != NULL)
          xmlRegFreeRegexp(elem->contModel);
      if (elem->defVal != NULL)
  	xmlSchemaFreeValue(elem->defVal);
      xmlFree(elem);
  }
  
  /**
   * xmlSchemaFreeFacet:
   * @facet:  a schema facet structure
   *
   * Deallocate a Schema Facet structure.
   */
  void
  xmlSchemaFreeFacet(xmlSchemaFacetPtr facet)
  {
      if (facet == NULL)
          return;
      if (facet->val != NULL)
          xmlSchemaFreeValue(facet->val);
      if (facet->regexp != NULL)
          xmlRegFreeRegexp(facet->regexp);
      if (facet->annot != NULL)
          xmlSchemaFreeAnnot(facet->annot);
      xmlFree(facet);
  }
  
  /**
   * xmlSchemaFreeType:
   * @type:  a schema type structure
   *
   * Deallocate a Schema Type structure.
   */
  void
  xmlSchemaFreeType(xmlSchemaTypePtr type)
  {
      if (type == NULL)
          return;
      if (type->annot != NULL)
          xmlSchemaFreeAnnot(type->annot);
      if (type->facets != NULL) {
          xmlSchemaFacetPtr facet, next;
  
          facet = type->facets;
          while (facet != NULL) {
              next = facet->next;
              xmlSchemaFreeFacet(facet);
              facet = next;
          }
      }
      if (type->attrUses != NULL)
  	xmlSchemaItemListFree((xmlSchemaItemListPtr) type->attrUses);
      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);
      }
      if (type->contModel != NULL)
          xmlRegFreeRegexp(type->contModel);
      xmlFree(type);
  }
  
  /**
   * xmlSchemaFreeModelGroupDef:
   * @item:  a schema model group definition
   *
   * Deallocates a schema model group definition.
   */
  static void
  xmlSchemaFreeModelGroupDef(xmlSchemaModelGroupDefPtr item)
  {
      if (item->annot != NULL)
  	xmlSchemaFreeAnnot(item->annot);
      xmlFree(item);
  }
  
  /**
   * xmlSchemaFreeModelGroup:
   * @item:  a schema model group
   *
   * Deallocates a schema model group structure.
   */
  static void
  xmlSchemaFreeModelGroup(xmlSchemaModelGroupPtr item)
  {
      if (item->annot != NULL)
  	xmlSchemaFreeAnnot(item->annot);
      xmlFree(item);
  }
  
  static void
  xmlSchemaComponentListFree(xmlSchemaItemListPtr list)
  {
      if ((list == NULL) || (list->nbItems == 0))
  	return;
      {
  	xmlSchemaTreeItemPtr item;
  	xmlSchemaTreeItemPtr *items = (xmlSchemaTreeItemPtr *) list->items;
  	int i;
  
  	for (i = 0; i < list->nbItems; i++) {
  	    item = items[i];
  	    if (item == NULL)
  		continue;
  	    switch (item->type) {
  		case XML_SCHEMA_TYPE_SIMPLE:
  		case XML_SCHEMA_TYPE_COMPLEX:
  		    xmlSchemaFreeType((xmlSchemaTypePtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_ATTRIBUTE:
  		    xmlSchemaFreeAttribute((xmlSchemaAttributePtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_ATTRIBUTE_USE:
  		    xmlSchemaFreeAttributeUse((xmlSchemaAttributeUsePtr) item);
  		    break;
  		case XML_SCHEMA_EXTRA_ATTR_USE_PROHIB:
  		    xmlSchemaFreeAttributeUseProhib(
  			(xmlSchemaAttributeUseProhibPtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_ELEMENT:
  		    xmlSchemaFreeElement((xmlSchemaElementPtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_PARTICLE:
  		    if (item->annot != NULL)
  			xmlSchemaFreeAnnot(item->annot);
  		    xmlFree(item);
  		    break;
  		case XML_SCHEMA_TYPE_SEQUENCE:
  		case XML_SCHEMA_TYPE_CHOICE:
  		case XML_SCHEMA_TYPE_ALL:
  		    xmlSchemaFreeModelGroup((xmlSchemaModelGroupPtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  		    xmlSchemaFreeAttributeGroup(
  			(xmlSchemaAttributeGroupPtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_GROUP:
  		    xmlSchemaFreeModelGroupDef(
  			(xmlSchemaModelGroupDefPtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_ANY:
  		case XML_SCHEMA_TYPE_ANY_ATTRIBUTE:
  		    xmlSchemaFreeWildcard((xmlSchemaWildcardPtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_IDC_KEY:
  		case XML_SCHEMA_TYPE_IDC_UNIQUE:
  		case XML_SCHEMA_TYPE_IDC_KEYREF:
  		    xmlSchemaFreeIDC((xmlSchemaIDCPtr) item);
  		    break;
  		case XML_SCHEMA_TYPE_NOTATION:
  		    xmlSchemaFreeNotation((xmlSchemaNotationPtr) item);
  		    break;
  		case XML_SCHEMA_EXTRA_QNAMEREF:
  		    xmlSchemaFreeQNameRef((xmlSchemaQNameRefPtr) item);
  		    break;
  		default: {
  		    /* TODO: This should never be hit. */
  		    xmlSchemaPSimpleInternalErr(NULL,
  			"Internal error: xmlSchemaComponentListFree, "
  			"unexpected component type '%s'\n",
  			(const xmlChar *) WXS_ITEM_TYPE_NAME(item));
  			 }
  		    break;
  	    }
  	}
  	list->nbItems = 0;
      }
  }
  
  /**
   * xmlSchemaFree:
   * @schema:  a schema structure
   *
   * Deallocate a Schema structure.
   */
  void
  xmlSchemaFree(xmlSchemaPtr schema)
  {
      if (schema == NULL)
          return;
      /* @volatiles is not used anymore :-/ */
      if (schema->volatiles != NULL)
  	TODO
      /*
      * Note that those slots are not responsible for freeing
      * schema components anymore; this will now be done by
      * the schema buckets.
      */
      if (schema->notaDecl != NULL)
          xmlHashFree(schema->notaDecl, NULL);
      if (schema->attrDecl != NULL)
          xmlHashFree(schema->attrDecl, NULL);
      if (schema->attrgrpDecl != NULL)
          xmlHashFree(schema->attrgrpDecl, NULL);
      if (schema->elemDecl != NULL)
          xmlHashFree(schema->elemDecl, NULL);
      if (schema->typeDecl != NULL)
          xmlHashFree(schema->typeDecl, NULL);
      if (schema->groupDecl != NULL)
          xmlHashFree(schema->groupDecl, NULL);
      if (schema->idcDef != NULL)
          xmlHashFree(schema->idcDef, NULL);
  
      if (schema->schemasImports != NULL)
  	xmlHashFree(schema->schemasImports, xmlSchemaBucketFreeEntry);
      if (schema->includes != NULL) {
  	xmlSchemaItemListPtr list = (xmlSchemaItemListPtr) schema->includes;
  	int i;
  	for (i = 0; i < list->nbItems; i++) {
  	    xmlSchemaBucketFree((xmlSchemaBucketPtr) list->items[i]);
  	}
  	xmlSchemaItemListFree(list);
      }
      if (schema->annot != NULL)
          xmlSchemaFreeAnnot(schema->annot);
      /* Never free the doc here, since this will be done by the buckets. */
  
      xmlDictFree(schema->dict);
      xmlFree(schema);
  }
  
  /************************************************************************
   *									*
   *			Debug functions					*
   *									*
   ************************************************************************/
  
  #ifdef LIBXML_OUTPUT_ENABLED
  
  static void
  xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output); /* forward */
  
  /**
   * xmlSchemaElementDump:
   * @elem:  an element
   * @output:  the file output
   *
   * Dump the element
   */
  static void
  xmlSchemaElementDump(void *payload, void *data,
                       const xmlChar * name ATTRIBUTE_UNUSED,
  		     const xmlChar * namespace ATTRIBUTE_UNUSED,
                       const xmlChar * context ATTRIBUTE_UNUSED)
  {
      xmlSchemaElementPtr elem = (xmlSchemaElementPtr) payload;
      FILE *output = (FILE *) data;
      if (elem == NULL)
          return;
  
  
      fprintf(output, "Element");
      if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL)
  	fprintf(output, " (global)");
      fprintf(output, ": '%s' ", elem->name);
      if (namespace != NULL)
  	fprintf(output, "ns '%s'", namespace);
      fprintf(output, "\n");
  #if 0
      if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) {
  	fprintf(output, "  min %d ", elem->minOccurs);
          if (elem->maxOccurs >= UNBOUNDED)
              fprintf(output, "max: unbounded\n");
          else if (elem->maxOccurs != 1)
              fprintf(output, "max: %d\n", elem->maxOccurs);
          else
              fprintf(output, "\n");
      }
  #endif
      /*
      * Misc other properties.
      */
      if ((elem->flags & XML_SCHEMAS_ELEM_NILLABLE) ||
  	(elem->flags & XML_SCHEMAS_ELEM_ABSTRACT) ||
  	(elem->flags & XML_SCHEMAS_ELEM_FIXED) ||
  	(elem->flags & XML_SCHEMAS_ELEM_DEFAULT)) {
  	fprintf(output, "  props: ");
  	if (elem->flags & XML_SCHEMAS_ELEM_FIXED)
  	    fprintf(output, "[fixed] ");
  	if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT)
  	    fprintf(output, "[default] ");
  	if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT)
  	    fprintf(output, "[abstract] ");
  	if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE)
  	    fprintf(output, "[nillable] ");
  	fprintf(output, "\n");
      }
      /*
      * Default/fixed value.
      */
      if (elem->value != NULL)
  	fprintf(output, "  value: '%s'\n", elem->value);
      /*
      * Type.
      */
      if (elem->namedType != NULL) {
  	fprintf(output, "  type: '%s' ", elem->namedType);
  	if (elem->namedTypeNs != NULL)
  	    fprintf(output, "ns '%s'\n", elem->namedTypeNs);
  	else
  	    fprintf(output, "\n");
      } else if (elem->subtypes != NULL) {
  	/*
  	* Dump local types.
  	*/
  	xmlSchemaTypeDump(elem->subtypes, output);
      }
      /*
      * Substitution group.
      */
      if (elem->substGroup != NULL) {
  	fprintf(output, "  substitutionGroup: '%s' ", elem->substGroup);
  	if (elem->substGroupNs != NULL)
  	    fprintf(output, "ns '%s'\n", elem->substGroupNs);
  	else
  	    fprintf(output, "\n");
      }
  }
  
  /**
   * xmlSchemaAnnotDump:
   * @output:  the file output
   * @annot:  a annotation
   *
   * Dump the annotation
   */
  static void
  xmlSchemaAnnotDump(FILE * output, xmlSchemaAnnotPtr annot)
  {
      xmlChar *content;
  
      if (annot == NULL)
          return;
  
      content = xmlNodeGetContent(annot->content);
      if (content != NULL) {
          fprintf(output, "  Annot: %s\n", content);
          xmlFree(content);
      } else
          fprintf(output, "  Annot: empty\n");
  }
  
  /**
   * xmlSchemaContentModelDump:
   * @particle: the schema particle
   * @output: the file output
   * @depth: the depth used for indentation
   *
   * Dump a SchemaType structure
   */
  static void
  xmlSchemaContentModelDump(xmlSchemaParticlePtr particle, FILE * output, int depth)
  {
      xmlChar *str = NULL;
      xmlSchemaTreeItemPtr term;
      char shift[100];
      int i;
  
      if (particle == NULL)
  	return;
      for (i = 0;((i < depth) && (i < 25));i++)
          shift[2 * i] = shift[2 * i + 1] = ' ';
      shift[2 * i] = shift[2 * i + 1] = 0;
      fprintf(output, "%s", shift);
      if (particle->children == NULL) {
  	fprintf(output, "MISSING particle term\n");
  	return;
      }
      term = particle->children;
      if (term == NULL) {
  	fprintf(output, "(NULL)");
      } else {
  	switch (term->type) {
  	    case XML_SCHEMA_TYPE_ELEMENT:
  		fprintf(output, "ELEM '%s'", xmlSchemaFormatQName(&str,
  		    ((xmlSchemaElementPtr)term)->targetNamespace,
  		    ((xmlSchemaElementPtr)term)->name));
  		FREE_AND_NULL(str);
  		break;
  	    case XML_SCHEMA_TYPE_SEQUENCE:
  		fprintf(output, "SEQUENCE");
  		break;
  	    case XML_SCHEMA_TYPE_CHOICE:
  		fprintf(output, "CHOICE");
  		break;
  	    case XML_SCHEMA_TYPE_ALL:
  		fprintf(output, "ALL");
  		break;
  	    case XML_SCHEMA_TYPE_ANY:
  		fprintf(output, "ANY");
  		break;
  	    default:
  		fprintf(output, "UNKNOWN\n");
  		return;
  	}
      }
      if (particle->minOccurs != 1)
  	fprintf(output, " min: %d", particle->minOccurs);
      if (particle->maxOccurs >= UNBOUNDED)
  	fprintf(output, " max: unbounded");
      else if (particle->maxOccurs != 1)
  	fprintf(output, " max: %d", particle->maxOccurs);
      fprintf(output, "\n");
      if (term &&
  	((term->type == XML_SCHEMA_TYPE_SEQUENCE) ||
  	 (term->type == XML_SCHEMA_TYPE_CHOICE) ||
  	 (term->type == XML_SCHEMA_TYPE_ALL)) &&
  	 (term->children != NULL)) {
  	xmlSchemaContentModelDump((xmlSchemaParticlePtr) term->children,
  	    output, depth +1);
      }
      if (particle->next != NULL)
  	xmlSchemaContentModelDump((xmlSchemaParticlePtr) particle->next,
  		output, depth);
  }
  
  /**
   * xmlSchemaAttrUsesDump:
   * @uses:  attribute uses list
   * @output:  the file output
   *
   * Dumps a list of attribute use components.
   */
  static void
  xmlSchemaAttrUsesDump(xmlSchemaItemListPtr uses, FILE * output)
  {
      xmlSchemaAttributeUsePtr use;
      xmlSchemaAttributeUseProhibPtr prohib;
      xmlSchemaQNameRefPtr ref;
      const xmlChar *name, *tns;
      xmlChar *str = NULL;
      int i;
  
      if ((uses == NULL) || (uses->nbItems == 0))
          return;
  
      fprintf(output, "  attributes:\n");
      for (i = 0; i < uses->nbItems; i++) {
  	use = uses->items[i];
  	if (use->type == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB) {
  	    fprintf(output, "  [prohibition] ");
  	    prohib = (xmlSchemaAttributeUseProhibPtr) use;
  	    name = prohib->name;
  	    tns = prohib->targetNamespace;
  	} else if (use->type == XML_SCHEMA_EXTRA_QNAMEREF) {
  	    fprintf(output, "  [reference] ");
  	    ref = (xmlSchemaQNameRefPtr) use;
  	    name = ref->name;
  	    tns = ref->targetNamespace;
  	} else {
  	    fprintf(output, "  [use] ");
  	    name = WXS_ATTRUSE_DECL_NAME(use);
  	    tns = WXS_ATTRUSE_DECL_TNS(use);
  	}
  	fprintf(output, "'%s'\n",
  	    (const char *) xmlSchemaFormatQName(&str, tns, name));
  	FREE_AND_NULL(str);
      }
  }
  
  /**
   * xmlSchemaTypeDump:
   * @output:  the file output
   * @type:  a type structure
   *
   * Dump a SchemaType structure
   */
  static void
  xmlSchemaTypeDump(xmlSchemaTypePtr type, FILE * output)
  {
      if (type == NULL) {
          fprintf(output, "Type: NULL\n");
          return;
      }
      fprintf(output, "Type: ");
      if (type->name != NULL)
          fprintf(output, "'%s' ", type->name);
      else
          fprintf(output, "(no name) ");
      if (type->targetNamespace != NULL)
  	fprintf(output, "ns '%s' ", type->targetNamespace);
      switch (type->type) {
          case XML_SCHEMA_TYPE_BASIC:
              fprintf(output, "[basic] ");
              break;
          case XML_SCHEMA_TYPE_SIMPLE:
              fprintf(output, "[simple] ");
              break;
          case XML_SCHEMA_TYPE_COMPLEX:
              fprintf(output, "[complex] ");
              break;
          case XML_SCHEMA_TYPE_SEQUENCE:
              fprintf(output, "[sequence] ");
              break;
          case XML_SCHEMA_TYPE_CHOICE:
              fprintf(output, "[choice] ");
              break;
          case XML_SCHEMA_TYPE_ALL:
              fprintf(output, "[all] ");
              break;
          case XML_SCHEMA_TYPE_UR:
              fprintf(output, "[ur] ");
              break;
          case XML_SCHEMA_TYPE_RESTRICTION:
              fprintf(output, "[restriction] ");
              break;
          case XML_SCHEMA_TYPE_EXTENSION:
              fprintf(output, "[extension] ");
              break;
          default:
              fprintf(output, "[unknown type %d] ", type->type);
              break;
      }
      fprintf(output, "content: ");
      switch (type->contentType) {
          case XML_SCHEMA_CONTENT_UNKNOWN:
              fprintf(output, "[unknown] ");
              break;
          case XML_SCHEMA_CONTENT_EMPTY:
              fprintf(output, "[empty] ");
              break;
          case XML_SCHEMA_CONTENT_ELEMENTS:
              fprintf(output, "[element] ");
              break;
          case XML_SCHEMA_CONTENT_MIXED:
              fprintf(output, "[mixed] ");
              break;
          case XML_SCHEMA_CONTENT_MIXED_OR_ELEMENTS:
  	/* not used. */
              break;
          case XML_SCHEMA_CONTENT_BASIC:
              fprintf(output, "[basic] ");
              break;
          case XML_SCHEMA_CONTENT_SIMPLE:
              fprintf(output, "[simple] ");
              break;
          case XML_SCHEMA_CONTENT_ANY:
              fprintf(output, "[any] ");
              break;
      }
      fprintf(output, "\n");
      if (type->base != NULL) {
          fprintf(output, "  base type: '%s'", type->base);
  	if (type->baseNs != NULL)
  	    fprintf(output, " ns '%s'\n", type->baseNs);
  	else
  	    fprintf(output, "\n");
      }
      if (type->attrUses != NULL)
  	xmlSchemaAttrUsesDump(type->attrUses, output);
      if (type->annot != NULL)
          xmlSchemaAnnotDump(output, type->annot);
  #ifdef DUMP_CONTENT_MODEL
      if ((type->type == XML_SCHEMA_TYPE_COMPLEX) &&
  	(type->subtypes != NULL)) {
  	xmlSchemaContentModelDump((xmlSchemaParticlePtr) type->subtypes,
  	    output, 1);
      }
  #endif
  }
  
  static void
  xmlSchemaTypeDumpEntry(void *type, void *output,
                         const xmlChar *name ATTRIBUTE_UNUSED)
  {
      xmlSchemaTypeDump((xmlSchemaTypePtr) type, (FILE *) output);
  }
  
  /**
   * xmlSchemaDump:
   * @output:  the file output
   * @schema:  a schema structure
   *
   * Dump a Schema structure.
   */
  void
  xmlSchemaDump(FILE * output, xmlSchemaPtr schema)
  {
      if (output == NULL)
          return;
      if (schema == NULL) {
          fprintf(output, "Schemas: NULL\n");
          return;
      }
      fprintf(output, "Schemas: ");
      if (schema->name != NULL)
          fprintf(output, "%s, ", schema->name);
      else
          fprintf(output, "no name, ");
      if (schema->targetNamespace != NULL)
          fprintf(output, "%s", (const char *) schema->targetNamespace);
      else
          fprintf(output, "no target namespace");
      fprintf(output, "\n");
      if (schema->annot != NULL)
          xmlSchemaAnnotDump(output, schema->annot);
      xmlHashScan(schema->typeDecl, xmlSchemaTypeDumpEntry, output);
      xmlHashScanFull(schema->elemDecl, xmlSchemaElementDump, output);
  }
  
  #ifdef DEBUG_IDC_NODE_TABLE
  /**
   * xmlSchemaDebugDumpIDCTable:
   * @vctxt: the WXS validation context
   *
   * Displays the current IDC table for debug purposes.
   */
  static void
  xmlSchemaDebugDumpIDCTable(FILE * output,
  			   const xmlChar *namespaceName,
  			   const xmlChar *localName,
  			   xmlSchemaPSVIIDCBindingPtr bind)
  {
      xmlChar *str = NULL;
      const xmlChar *value;
      xmlSchemaPSVIIDCNodePtr tab;
      xmlSchemaPSVIIDCKeyPtr key;
      int i, j, res;
  
      fprintf(output, "IDC: TABLES on '%s'\n",
  	xmlSchemaFormatQName(&str, namespaceName, localName));
      FREE_AND_NULL(str)
  
      if (bind == NULL)
  	return;
      do {
  	fprintf(output, "IDC:   BINDING '%s' (%d)\n",
  	    xmlSchemaGetComponentQName(&str,
  		bind->definition), bind->nbNodes);
  	FREE_AND_NULL(str)
  	for (i = 0; i < bind->nbNodes; i++) {
  	    tab = bind->nodeTable[i];
  	    fprintf(output, "         ( ");
  	    for (j = 0; j < bind->definition->nbFields; j++) {
  		key = tab->keys[j];
  		if ((key != NULL) && (key->val != NULL)) {
  		    res = xmlSchemaGetCanonValue(key->val, &value);
  		    if (res >= 0)
  			fprintf(output, "'%s' ", value);
  		    else
  			fprintf(output, "CANON-VALUE-FAILED ");
  		    if (res == 0)
  			FREE_AND_NULL(value)
  		} else if (key != NULL)
  		    fprintf(output, "(no val), ");
  		else
  		    fprintf(output, "(key missing), ");
  	    }
  	    fprintf(output, ")\n");
  	}
  	if (bind->dupls && bind->dupls->nbItems) {
  	    fprintf(output, "IDC:     dupls (%d):\n", bind->dupls->nbItems);
  	    for (i = 0; i < bind->dupls->nbItems; i++) {
  		tab = bind->dupls->items[i];
  		fprintf(output, "         ( ");
  		for (j = 0; j < bind->definition->nbFields; j++) {
  		    key = tab->keys[j];
  		    if ((key != NULL) && (key->val != NULL)) {
  			res = xmlSchemaGetCanonValue(key->val, &value);
  			if (res >= 0)
  			    fprintf(output, "'%s' ", value);
  			else
  			    fprintf(output, "CANON-VALUE-FAILED ");
  			if (res == 0)
  			    FREE_AND_NULL(value)
  		    } else if (key != NULL)
  		    fprintf(output, "(no val), ");
  			else
  			    fprintf(output, "(key missing), ");
  		}
  		fprintf(output, ")\n");
  	    }
  	}
  	bind = bind->next;
      } while (bind != NULL);
  }
  #endif /* DEBUG_IDC */
  #endif /* LIBXML_OUTPUT_ENABLED */
  
  /************************************************************************
   *									*
   *			Utilities					*
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaGetPropNode:
   * @node: the element node
   * @name: the name of the attribute
   *
   * Seeks an attribute with a name of @name in
   * no namespace.
   *
   * Returns the attribute or NULL if not present.
   */
  static xmlAttrPtr
  xmlSchemaGetPropNode(xmlNodePtr node, const char *name)
  {
      xmlAttrPtr prop;
  
      if ((node == NULL) || (name == NULL))
  	return(NULL);
      prop = node->properties;
      while (prop != NULL) {
          if ((prop->ns == NULL) && xmlStrEqual(prop->name, BAD_CAST name))
  	    return(prop);
  	prop = prop->next;
      }
      return (NULL);
  }
  
  /**
   * xmlSchemaGetPropNodeNs:
   * @node: the element node
   * @uri: the uri
   * @name: the name of the attribute
   *
   * Seeks an attribute with a local name of @name and
   * a namespace URI of @uri.
   *
   * Returns the attribute or NULL if not present.
   */
  static xmlAttrPtr
  xmlSchemaGetPropNodeNs(xmlNodePtr node, const char *uri, const char *name)
  {
      xmlAttrPtr prop;
  
      if ((node == NULL) || (name == NULL))
  	return(NULL);
      prop = node->properties;
      while (prop != NULL) {
  	if ((prop->ns != NULL) &&
  	    xmlStrEqual(prop->name, BAD_CAST name) &&
  	    xmlStrEqual(prop->ns->href, BAD_CAST uri))
  	    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)
  	val = xmlStrdup((xmlChar *)"");
      ret = xmlDictLookup(ctxt->dict, val, -1);
      xmlFree(val);
      return(ret);
  }
  
  static const xmlChar *
  xmlSchemaGetNodeContentNoDict(xmlNodePtr node)
  {
      return((const xmlChar*) xmlNodeGetContent(node));
  }
  
  /**
   * xmlSchemaGetProp:
   * @ctxt: the parser context
   * @node: the node
   * @name: the property name
   *
   * Read a attribute value and internalize the string
   *
   * Returns the string or NULL if not present.
   */
  static const xmlChar *
  xmlSchemaGetProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
                   const char *name)
  {
      xmlChar *val;
      const xmlChar *ret;
  
      val = xmlGetNoNsProp(node, BAD_CAST name);
      if (val == NULL)
          return(NULL);
      ret = xmlDictLookup(ctxt->dict, val, -1);
      xmlFree(val);
      return(ret);
  }
  
  /************************************************************************
   *									*
   *			Parsing functions				*
   *									*
   ************************************************************************/
  
  #define WXS_FIND_GLOBAL_ITEM(slot)			\
      if (xmlStrEqual(nsName, schema->targetNamespace)) { \
  	ret = xmlHashLookup(schema->slot, name); \
  	if (ret != NULL) goto exit; \
      } \
      if (xmlHashSize(schema->schemasImports) > 1) { \
  	xmlSchemaImportPtr import; \
  	if (nsName == NULL) \
  	    import = xmlHashLookup(schema->schemasImports, \
  		XML_SCHEMAS_NO_NAMESPACE); \
  	else \
  	    import = xmlHashLookup(schema->schemasImports, nsName); \
  	if (import == NULL) \
  	    goto exit; \
  	ret = xmlHashLookup(import->schema->slot, name); \
      }
  
  /**
   * xmlSchemaGetElem:
   * @schema:  the schema context
   * @name:  the element name
   * @ns:  the element namespace
   *
   * Lookup a global element declaration in the schema.
   *
   * Returns the element declaration or NULL if not found.
   */
  static xmlSchemaElementPtr
  xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name,
                   const xmlChar * nsName)
  {
      xmlSchemaElementPtr ret = NULL;
  
      if ((name == NULL) || (schema == NULL))
          return(NULL);
      if (schema != NULL) {
  	WXS_FIND_GLOBAL_ITEM(elemDecl)
      }
  exit:
  #ifdef DEBUG
      if (ret == NULL) {
          if (nsName == NULL)
              fprintf(stderr, "Unable to lookup element decl. %s", name);
          else
              fprintf(stderr, "Unable to lookup element decl. %s:%s", name,
                      nsName);
      }
  #endif
      return (ret);
  }
  
  /**
   * xmlSchemaGetType:
   * @schema:  the main schema
   * @name:  the type's name
   * nsName:  the type's namespace
   *
   * Lookup a type in the schemas or the predefined types
   *
   * Returns the group definition or NULL if not found.
   */
  static xmlSchemaTypePtr
  xmlSchemaGetType(xmlSchemaPtr schema, const xmlChar * name,
                   const xmlChar * nsName)
  {
      xmlSchemaTypePtr ret = NULL;
  
      if (name == NULL)
          return (NULL);
      /* First try the built-in types. */
      if ((nsName != NULL) && xmlStrEqual(nsName, xmlSchemaNs)) {
  	ret = xmlSchemaGetPredefinedType(name, nsName);
  	if (ret != NULL)
  	    goto exit;
  	/*
  	* Note that we try the parsed schemas as well here
  	* since one might have parsed the S4S, which contain more
  	* than the built-in types.
  	* TODO: Can we optimize this?
  	*/
      }
      if (schema != NULL) {
  	WXS_FIND_GLOBAL_ITEM(typeDecl)
      }
  exit:
  
  #ifdef DEBUG
      if (ret == NULL) {
          if (nsName == NULL)
              fprintf(stderr, "Unable to lookup type %s", name);
          else
              fprintf(stderr, "Unable to lookup type %s:%s", name,
                      nsName);
      }
  #endif
      return (ret);
  }
  
  /**
   * xmlSchemaGetAttributeDecl:
   * @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
  xmlSchemaGetAttributeDecl(xmlSchemaPtr schema, const xmlChar * name,
                   const xmlChar * nsName)
  {
      xmlSchemaAttributePtr ret = NULL;
  
      if ((name == NULL) || (schema == NULL))
          return (NULL);
      if (schema != NULL) {
  	WXS_FIND_GLOBAL_ITEM(attrDecl)
      }
  exit:
  #ifdef DEBUG
      if (ret == NULL) {
          if (nsName == NULL)
              fprintf(stderr, "Unable to lookup attribute %s", name);
          else
              fprintf(stderr, "Unable to lookup attribute %s:%s", name,
                      nsName);
      }
  #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 * nsName)
  {
      xmlSchemaAttributeGroupPtr ret = NULL;
  
      if ((name == NULL) || (schema == NULL))
          return (NULL);
      if (schema != NULL) {
  	WXS_FIND_GLOBAL_ITEM(attrgrpDecl)
      }
  exit:
      /* TODO:
      if ((ret != NULL) && (ret->redef != NULL)) {
  	* Return the last redefinition. *
  	ret = ret->redef;
      }
      */
  #ifdef DEBUG
      if (ret == NULL) {
          if (nsName == NULL)
              fprintf(stderr, "Unable to lookup attribute group %s", name);
          else
              fprintf(stderr, "Unable to lookup attribute group %s:%s", name,
                      nsName);
      }
  #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 xmlSchemaModelGroupDefPtr
  xmlSchemaGetGroup(xmlSchemaPtr schema, const xmlChar * name,
                   const xmlChar * nsName)
  {
      xmlSchemaModelGroupDefPtr ret = NULL;
  
      if ((name == NULL) || (schema == NULL))
          return (NULL);
      if (schema != NULL) {
  	WXS_FIND_GLOBAL_ITEM(groupDecl)
      }
  exit:
  
  #ifdef DEBUG
      if (ret == NULL) {
          if (nsName == NULL)
              fprintf(stderr, "Unable to lookup group %s", name);
          else
              fprintf(stderr, "Unable to lookup group %s:%s", name,
                      nsName);
      }
  #endif
      return (ret);
  }
  
  static xmlSchemaNotationPtr
  xmlSchemaGetNotation(xmlSchemaPtr schema,
  		     const xmlChar *name,
  		     const xmlChar *nsName)
  {
      xmlSchemaNotationPtr ret = NULL;
  
      if ((name == NULL) || (schema == NULL))
          return (NULL);
      if (schema != NULL) {
  	WXS_FIND_GLOBAL_ITEM(notaDecl)
      }
  exit:
      return (ret);
  }
  
  static xmlSchemaIDCPtr
  xmlSchemaGetIDC(xmlSchemaPtr schema,
  		const xmlChar *name,
  		const xmlChar *nsName)
  {
      xmlSchemaIDCPtr ret = NULL;
  
      if ((name == NULL) || (schema == NULL))
          return (NULL);
      if (schema != NULL) {
  	WXS_FIND_GLOBAL_ITEM(idcDef)
      }
  exit:
      return (ret);
  }
  
  /**
   * xmlSchemaGetNamedComponent:
   * @schema:  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 xmlSchemaBasicItemPtr
  xmlSchemaGetNamedComponent(xmlSchemaPtr schema,
  			   xmlSchemaTypeType itemType,
  			   const xmlChar *name,
  			   const xmlChar *targetNs)
  {
      switch (itemType) {
  	case XML_SCHEMA_TYPE_GROUP:
  	    return ((xmlSchemaBasicItemPtr) xmlSchemaGetGroup(schema,
  		name, targetNs));
  	case XML_SCHEMA_TYPE_ELEMENT:
  	    return ((xmlSchemaBasicItemPtr) xmlSchemaGetElem(schema,
  		name, targetNs));
  	default:
  	    TODO
  	    return (NULL);
      }
  }
  
  /************************************************************************
   *									*
   *			Parsing functions				*
   *									*
   ************************************************************************/
  
  #define IS_BLANK_NODE(n)						\
      (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content, -1)))
  
  /**
   * xmlSchemaIsBlank:
   * @str:  a string
   * @len: the length of the string or -1
   *
   * Check if a string is ignorable
   *
   * Returns 1 if the string is NULL or made of blanks chars, 0 otherwise
   */
  static int
  xmlSchemaIsBlank(xmlChar * str, int len)
  {
      if (str == NULL)
          return (1);
      if (len < 0) {
  	while (*str != 0) {
  	    if (!(IS_BLANK_CH(*str)))
  		return (0);
  	    str++;
  	}
      } else while ((*str != 0) && (len != 0)) {
  	if (!(IS_BLANK_CH(*str)))
  	    return (0);
  	str++;
  	len--;
      }
  
      return (1);
  }
  
  #define WXS_COMP_NAME(c, t) ((t) (c))->name
  #define WXS_COMP_TNS(c, t) ((t) (c))->targetNamespace
  /*
  * xmlSchemaFindRedefCompInGraph:
  * ATTENTION TODO: This uses pointer comp. for strings.
  */
  static xmlSchemaBasicItemPtr
  xmlSchemaFindRedefCompInGraph(xmlSchemaBucketPtr bucket,
  			      xmlSchemaTypeType type,
  			      const xmlChar *name,
  			      const xmlChar *nsName)
  {
      xmlSchemaBasicItemPtr ret;
      int i;
  
      if ((bucket == NULL) || (name == NULL))
  	return(NULL);
      if ((bucket->globals == NULL) ||
  	(bucket->globals->nbItems == 0))
  	goto subschemas;
      /*
      * Search in global components.
      */
      for (i = 0; i < bucket->globals->nbItems; i++) {
  	ret = bucket->globals->items[i];
  	if (ret->type == type) {
  	    switch (type) {
  		case XML_SCHEMA_TYPE_COMPLEX:
  		case XML_SCHEMA_TYPE_SIMPLE:
  		    if ((WXS_COMP_NAME(ret, xmlSchemaTypePtr) == name) &&
  			(WXS_COMP_TNS(ret, xmlSchemaTypePtr) ==
  			nsName))
  		    {
  			return(ret);
  		    }
  		    break;
  		case XML_SCHEMA_TYPE_GROUP:
  		    if ((WXS_COMP_NAME(ret,
  			    xmlSchemaModelGroupDefPtr) == name) &&
  			(WXS_COMP_TNS(ret,
  			    xmlSchemaModelGroupDefPtr) == nsName))
  		    {
  			return(ret);
  		    }
  		    break;
  		case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  		    if ((WXS_COMP_NAME(ret,
  			    xmlSchemaAttributeGroupPtr) == name) &&
  			(WXS_COMP_TNS(ret,
  			    xmlSchemaAttributeGroupPtr) == nsName))
  		    {
  			return(ret);
  		    }
  		    break;
  		default:
  		    /* Should not be hit. */
  		    return(NULL);
  	    }
  	}
      }
  subschemas:
      /*
      * Process imported/included schemas.
      */
      if (bucket->relations != NULL) {
  	xmlSchemaSchemaRelationPtr rel = bucket->relations;
  
  	/*
  	* TODO: Marking the bucket will not avoid multiple searches
  	* in the same schema, but avoids at least circularity.
  	*/
  	bucket->flags |= XML_SCHEMA_BUCKET_MARKED;
  	do {
  	    if ((rel->bucket != NULL) &&
  		((rel->bucket->flags & XML_SCHEMA_BUCKET_MARKED) == 0)) {
  		ret = xmlSchemaFindRedefCompInGraph(rel->bucket,
  		    type, name, nsName);
  		if (ret != NULL)
  		    return(ret);
  	    }
  	    rel = rel->next;
  	} while (rel != NULL);
  	 bucket->flags ^= XML_SCHEMA_BUCKET_MARKED;
      }
      return(NULL);
  }
  
  /**
   * xmlSchemaAddNotation:
   * @ctxt:  a schema parser context
   * @schema:  the schema being built
   * @name:  the item name
   *
   * Add an XML schema annotation declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaNotationPtr
  xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                       const xmlChar *name, const xmlChar *nsName,
  		     xmlNodePtr node ATTRIBUTE_UNUSED)
  {
      xmlSchemaNotationPtr ret = NULL;
  
      if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
          return (NULL);
  
      ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt, "add annotation", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaNotation));
      ret->type = XML_SCHEMA_TYPE_NOTATION;
      ret->name = name;
      ret->targetNamespace = nsName;
      /* TODO: do we need the node to be set?
      * ret->node = node;*/
      WXS_ADD_GLOBAL(ctxt, ret);
      return (ret);
  }
  
  /**
   * xmlSchemaAddAttribute:
   * @ctxt:  a schema parser context
   * @schema:  the schema being built
   * @name:  the item name
   * @namespace:  the namespace
   *
   * Add an XML schema Attribute declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaAttributePtr
  xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                        const xmlChar * name, const xmlChar * nsName,
  		      xmlNodePtr node, int topLevel)
  {
      xmlSchemaAttributePtr ret = NULL;
  
      if ((ctxt == NULL) || (schema == NULL))
          return (NULL);
  
      ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaAttribute));
      ret->type = XML_SCHEMA_TYPE_ATTRIBUTE;
      ret->node = node;
      ret->name = name;
      ret->targetNamespace = nsName;
  
      if (topLevel)
  	WXS_ADD_GLOBAL(ctxt, ret);
      else
  	WXS_ADD_LOCAL(ctxt, ret);
      WXS_ADD_PENDING(ctxt, ret);
      return (ret);
  }
  
  /**
   * xmlSchemaAddAttributeUse:
   * @ctxt:  a schema parser context
   * @schema:  the schema being built
   * @name:  the item name
   * @namespace:  the namespace
   *
   * Add an XML schema Attribute declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaAttributeUsePtr
  xmlSchemaAddAttributeUse(xmlSchemaParserCtxtPtr pctxt,
  			 xmlNodePtr node)
  {
      xmlSchemaAttributeUsePtr ret = NULL;
  
      if (pctxt == NULL)
          return (NULL);
  
      ret = (xmlSchemaAttributeUsePtr) xmlMalloc(sizeof(xmlSchemaAttributeUse));
      if (ret == NULL) {
          xmlSchemaPErrMemory(pctxt, "allocating attribute", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaAttributeUse));
      ret->type = XML_SCHEMA_TYPE_ATTRIBUTE_USE;
      ret->node = node;
  
      WXS_ADD_LOCAL(pctxt, ret);
      return (ret);
  }
  
  /*
  * xmlSchemaAddRedef:
  *
  * Adds a redefinition information. This is used at a later stage to:
  * resolve references to the redefined components and to check constraints.
  */
  static xmlSchemaRedefPtr
  xmlSchemaAddRedef(xmlSchemaParserCtxtPtr pctxt,
  		  xmlSchemaBucketPtr targetBucket,
  		  void *item,
  		  const xmlChar *refName,
  		  const xmlChar *refTargetNs)
  {
      xmlSchemaRedefPtr ret;
  
      ret = (xmlSchemaRedefPtr)
  	xmlMalloc(sizeof(xmlSchemaRedef));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(pctxt,
  	    "allocating redefinition info", NULL);
  	return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaRedef));
      ret->item = item;
      ret->targetBucket = targetBucket;
      ret->refName = refName;
      ret->refTargetNs = refTargetNs;
      if (WXS_CONSTRUCTOR(pctxt)->redefs == NULL)
  	WXS_CONSTRUCTOR(pctxt)->redefs = ret;
      else
  	WXS_CONSTRUCTOR(pctxt)->lastRedef->next = ret;
      WXS_CONSTRUCTOR(pctxt)->lastRedef = ret;
  
      return (ret);
  }
  
  /**
   * xmlSchemaAddAttributeGroupDefinition:
   * @ctxt:  a schema parser context
   * @schema:  the schema being built
   * @name:  the item name
   * @nsName:  the target namespace
   * @node: the corresponding node
   *
   * Add an XML schema Attribute Group definition.
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaAttributeGroupPtr
  xmlSchemaAddAttributeGroupDefinition(xmlSchemaParserCtxtPtr pctxt,
                             xmlSchemaPtr schema ATTRIBUTE_UNUSED,
  			   const xmlChar *name,
  			   const xmlChar *nsName,
  			   xmlNodePtr node)
  {
      xmlSchemaAttributeGroupPtr ret = NULL;
  
      if ((pctxt == NULL) || (name == NULL))
          return (NULL);
  
      ret = (xmlSchemaAttributeGroupPtr)
          xmlMalloc(sizeof(xmlSchemaAttributeGroup));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(pctxt, "allocating attribute group", NULL);
  	return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaAttributeGroup));
      ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP;
      ret->name = name;
      ret->targetNamespace = nsName;
      ret->node = node;
  
      /* TODO: Remove the flag. */
      ret->flags |= XML_SCHEMAS_ATTRGROUP_GLOBAL;
      if (pctxt->isRedefine) {
  	pctxt->redef = xmlSchemaAddRedef(pctxt, pctxt->redefined,
  	    ret, name, nsName);
  	if (pctxt->redef == NULL) {
  	    xmlFree(ret);
  	    return(NULL);
  	}
  	pctxt->redefCounter = 0;
      }
      WXS_ADD_GLOBAL(pctxt, ret);
      WXS_ADD_PENDING(pctxt, ret);
      return (ret);
  }
  
  /**
   * xmlSchemaAddElement:
   * @ctxt:  a schema parser context
   * @schema:  the schema being built
   * @name:  the type name
   * @namespace:  the type namespace
   *
   * Add an XML schema Element declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaElementPtr
  xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt,
                      const xmlChar * name, const xmlChar * nsName,
  		    xmlNodePtr node, int topLevel)
  {
      xmlSchemaElementPtr ret = NULL;
  
      if ((ctxt == NULL) || (name == NULL))
          return (NULL);
  
      ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt, "allocating element", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaElement));
      ret->type = XML_SCHEMA_TYPE_ELEMENT;
      ret->name = name;
      ret->targetNamespace = nsName;
      ret->node = node;
  
      if (topLevel)
  	WXS_ADD_GLOBAL(ctxt, ret);
      else
  	WXS_ADD_LOCAL(ctxt, ret);
      WXS_ADD_PENDING(ctxt, ret);
      return (ret);
  }
  
  /**
   * xmlSchemaAddType:
   * @ctxt:  a schema parser context
   * @schema:  the schema being built
   * @name:  the item name
   * @namespace:  the namespace
   *
   * Add an XML schema item
   * *WARNING* this interface is highly subject to change
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaTypePtr
  xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
  		 xmlSchemaTypeType type,
                   const xmlChar * name, const xmlChar * nsName,
  		 xmlNodePtr node, int topLevel)
  {
      xmlSchemaTypePtr ret = NULL;
  
      if ((ctxt == NULL) || (schema == NULL))
          return (NULL);
  
      ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt, "allocating type", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaType));
      ret->type = type;
      ret->name = name;
      ret->targetNamespace = nsName;
      ret->node = node;
      if (topLevel) {
  	if (ctxt->isRedefine) {
  	    ctxt->redef = xmlSchemaAddRedef(ctxt, ctxt->redefined,
  		ret, name, nsName);
  	    if (ctxt->redef == NULL) {
  		xmlFree(ret);
  		return(NULL);
  	    }
  	    ctxt->redefCounter = 0;
  	}
  	WXS_ADD_GLOBAL(ctxt, ret);
      } else
  	WXS_ADD_LOCAL(ctxt, ret);
      WXS_ADD_PENDING(ctxt, ret);
      return (ret);
  }
  
  static xmlSchemaQNameRefPtr
  xmlSchemaNewQNameRef(xmlSchemaParserCtxtPtr pctxt,
  		     xmlSchemaTypeType refType,
  		     const xmlChar *refName,
  		     const xmlChar *refNs)
  {
      xmlSchemaQNameRefPtr ret;
  
      ret = (xmlSchemaQNameRefPtr)
  	xmlMalloc(sizeof(xmlSchemaQNameRef));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(pctxt,
  	    "allocating QName reference item", NULL);
  	return (NULL);
      }
      ret->node = NULL;
      ret->type = XML_SCHEMA_EXTRA_QNAMEREF;
      ret->name = refName;
      ret->targetNamespace = refNs;
      ret->item = NULL;
      ret->itemType = refType;
      /*
      * Store the reference item in the schema.
      */
      WXS_ADD_LOCAL(pctxt, ret);
      return (ret);
  }
  
  static xmlSchemaAttributeUseProhibPtr
  xmlSchemaAddAttributeUseProhib(xmlSchemaParserCtxtPtr pctxt)
  {
      xmlSchemaAttributeUseProhibPtr ret;
  
      ret = (xmlSchemaAttributeUseProhibPtr)
  	xmlMalloc(sizeof(xmlSchemaAttributeUseProhib));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(pctxt,
  	    "allocating attribute use prohibition", NULL);
  	return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaAttributeUseProhib));
      ret->type = XML_SCHEMA_EXTRA_ATTR_USE_PROHIB;
      WXS_ADD_LOCAL(pctxt, ret);
      return (ret);
  }
  
  
  /**
   * xmlSchemaAddModelGroup:
   * @ctxt:  a schema parser context
   * @schema:  the schema being built
   * @type: the "compositor" type of the model group
   * @node: the node in the schema doc
   *
   * Adds a schema model group
   * *WARNING* this interface is highly subject to change
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaModelGroupPtr
  xmlSchemaAddModelGroup(xmlSchemaParserCtxtPtr ctxt,
  		       xmlSchemaPtr schema,
  		       xmlSchemaTypeType type,
  		       xmlNodePtr node)
  {
      xmlSchemaModelGroupPtr ret = NULL;
  
      if ((ctxt == NULL) || (schema == NULL))
          return (NULL);
  
      ret = (xmlSchemaModelGroupPtr)
  	xmlMalloc(sizeof(xmlSchemaModelGroup));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(ctxt, "allocating model group component",
  	    NULL);
  	return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaModelGroup));
      ret->type = type;
      ret->node = node;
      WXS_ADD_LOCAL(ctxt, ret);
      if ((type == XML_SCHEMA_TYPE_SEQUENCE) ||
  	(type == XML_SCHEMA_TYPE_CHOICE))
  	WXS_ADD_PENDING(ctxt, ret);
      return (ret);
  }
  
  
  /**
   * xmlSchemaAddParticle:
   * @ctxt:  a schema parser context
   * @schema:  the schema being built
   * @node: the corresponding node in the schema doc
   * @min: the minOccurs
   * @max: the maxOccurs
   *
   * Adds an XML schema particle component.
   * *WARNING* this interface is highly subject to change
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaParticlePtr
  xmlSchemaAddParticle(xmlSchemaParserCtxtPtr ctxt,
  		     xmlNodePtr node, int min, int max)
  {
      xmlSchemaParticlePtr ret = NULL;
      if (ctxt == NULL)
          return (NULL);
  
  #ifdef DEBUG
      fprintf(stderr, "Adding particle component\n");
  #endif
      ret = (xmlSchemaParticlePtr)
  	xmlMalloc(sizeof(xmlSchemaParticle));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(ctxt, "allocating particle component",
  	    NULL);
  	return (NULL);
      }
      ret->type = XML_SCHEMA_TYPE_PARTICLE;
      ret->annot = NULL;
      ret->node = node;
      ret->minOccurs = min;
      ret->maxOccurs = max;
      ret->next = NULL;
      ret->children = NULL;
  
      WXS_ADD_LOCAL(ctxt, ret);
      /*
      * Note that addition to pending components will be done locally
      * to the specific parsing function, since the most particles
      * need not to be fixed up (i.e. the reference to be resolved).
      * REMOVED: WXS_ADD_PENDING(ctxt, ret);
      */
      return (ret);
  }
  
  /**
   * xmlSchemaAddModelGroupDefinition:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @name:  the group name
   *
   * Add an XML schema Group definition
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaModelGroupDefPtr
  xmlSchemaAddModelGroupDefinition(xmlSchemaParserCtxtPtr ctxt,
  				 xmlSchemaPtr schema,
  				 const xmlChar *name,
  				 const xmlChar *nsName,
  				 xmlNodePtr node)
  {
      xmlSchemaModelGroupDefPtr ret = NULL;
  
      if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
          return (NULL);
  
      ret = (xmlSchemaModelGroupDefPtr)
  	xmlMalloc(sizeof(xmlSchemaModelGroupDef));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt, "adding group", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaModelGroupDef));
      ret->name = name;
      ret->type = XML_SCHEMA_TYPE_GROUP;
      ret->node = node;
      ret->targetNamespace = nsName;
  
      if (ctxt->isRedefine) {
  	ctxt->redef = xmlSchemaAddRedef(ctxt, ctxt->redefined,
  	    ret, name, nsName);
  	if (ctxt->redef == NULL) {
  	    xmlFree(ret);
  	    return(NULL);
  	}
  	ctxt->redefCounter = 0;
      }
      WXS_ADD_GLOBAL(ctxt, ret);
      WXS_ADD_PENDING(ctxt, ret);
      return (ret);
  }
  
  /**
   * xmlSchemaNewWildcardNs:
   * @ctxt:  a schema validation context
   *
   * Creates a new wildcard namespace constraint.
   *
   * Returns the new structure 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);
  }
  
  static xmlSchemaIDCPtr
  xmlSchemaAddIDC(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                    const xmlChar *name, const xmlChar *nsName,
  		  int category, xmlNodePtr node)
  {
      xmlSchemaIDCPtr ret = NULL;
  
      if ((ctxt == NULL) || (schema == NULL) || (name == NULL))
          return (NULL);
  
      ret = (xmlSchemaIDCPtr) xmlMalloc(sizeof(xmlSchemaIDC));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt,
  	    "allocating an identity-constraint definition", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaIDC));
      /* The target namespace of the parent element declaration. */
      ret->targetNamespace = nsName;
      ret->name = name;
      ret->type = category;
      ret->node = node;
  
      WXS_ADD_GLOBAL(ctxt, ret);
      /*
      * Only keyrefs need to be fixup up.
      */
      if (category == XML_SCHEMA_TYPE_IDC_KEYREF)
  	WXS_ADD_PENDING(ctxt, ret);
      return (ret);
  }
  
  /**
   * xmlSchemaAddWildcard:
   * @ctxt:  a schema validation context
   * @schema: a schema
   *
   * Adds a wildcard.
   * It corresponds to a xsd:anyAttribute and xsd:any.
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaWildcardPtr
  xmlSchemaAddWildcard(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
  		     xmlSchemaTypeType type, xmlNodePtr node)
  {
      xmlSchemaWildcardPtr ret = NULL;
  
      if ((ctxt == NULL) || (schema == NULL))
          return (NULL);
  
      ret = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard));
      if (ret == NULL) {
          xmlSchemaPErrMemory(ctxt, "adding wildcard", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaWildcard));
      ret->type = type;
      ret->node = node;
      WXS_ADD_LOCAL(ctxt, ret);
      return (ret);
  }
  
  static void
  xmlSchemaSubstGroupFree(xmlSchemaSubstGroupPtr group)
  {
      if (group == NULL)
  	return;
      if (group->members != NULL)
  	xmlSchemaItemListFree(group->members);
      xmlFree(group);
  }
  
  static void
  xmlSchemaSubstGroupFreeEntry(void *group, const xmlChar *name ATTRIBUTE_UNUSED)
  {
      xmlSchemaSubstGroupFree((xmlSchemaSubstGroupPtr) group);
  }
  
  static xmlSchemaSubstGroupPtr
  xmlSchemaSubstGroupAdd(xmlSchemaParserCtxtPtr pctxt,
  		       xmlSchemaElementPtr head)
  {
      xmlSchemaSubstGroupPtr ret;
  
      /* Init subst group hash. */
      if (WXS_SUBST_GROUPS(pctxt) == NULL) {
  	WXS_SUBST_GROUPS(pctxt) = xmlHashCreateDict(10, pctxt->dict);
  	if (WXS_SUBST_GROUPS(pctxt) == NULL)
  	    return(NULL);
      }
      /* Create a new substitution group. */
      ret = (xmlSchemaSubstGroupPtr) xmlMalloc(sizeof(xmlSchemaSubstGroup));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(NULL,
  	    "allocating a substitution group container", NULL);
  	return(NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaSubstGroup));
      ret->head = head;
      /* Create list of members. */
      ret->members = xmlSchemaItemListCreate();
      if (ret->members == NULL) {
  	xmlSchemaSubstGroupFree(ret);
  	return(NULL);
      }
      /* Add subst group to hash. */
      if (xmlHashAddEntry2(WXS_SUBST_GROUPS(pctxt),
  	head->name, head->targetNamespace, ret) != 0) {
  	PERROR_INT("xmlSchemaSubstGroupAdd",
  	    "failed to add a new substitution container");
  	xmlSchemaSubstGroupFree(ret);
  	return(NULL);
      }
      return(ret);
  }
  
  static xmlSchemaSubstGroupPtr
  xmlSchemaSubstGroupGet(xmlSchemaParserCtxtPtr pctxt,
  		       xmlSchemaElementPtr head)
  {
      if (WXS_SUBST_GROUPS(pctxt) == NULL)
  	return(NULL);
      return(xmlHashLookup2(WXS_SUBST_GROUPS(pctxt),
  	head->name, head->targetNamespace));
  
  }
  
  /**
   * xmlSchemaAddElementSubstitutionMember:
   * @pctxt:  a schema parser context
   * @head:  the head of the substitution group
   * @member: the new member of the substitution group
   *
   * Allocate a new annotation structure.
   *
   * Returns the newly allocated structure or NULL in case or error
   */
  static int
  xmlSchemaAddElementSubstitutionMember(xmlSchemaParserCtxtPtr pctxt,
  				      xmlSchemaElementPtr head,
  				      xmlSchemaElementPtr member)
  {
      xmlSchemaSubstGroupPtr substGroup = NULL;
  
      if ((pctxt == NULL) || (head == NULL) || (member == NULL))
  	return (-1);
  
      substGroup = xmlSchemaSubstGroupGet(pctxt, head);
      if (substGroup == NULL)
  	substGroup = xmlSchemaSubstGroupAdd(pctxt, head);
      if (substGroup == NULL)
  	return(-1);
      if (xmlSchemaItemListAdd(substGroup->members, member) == -1)
  	return(-1);
      return(0);
  }
  
  /************************************************************************
   *									*
   *		Utilities for parsing					*
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaPValAttrNodeQNameValue:
   * @ctxt:  a schema parser context
   * @schema: the schema context
   * @ownerItem: the parent as a schema object
   * @value:  the QName value
   * @uri:  the resulting namespace URI if found
   * @local: the resulting local part if found, the attribute value otherwise
   *
   * Extracts the local name and the URI of a QName value and validates it.
   * This one is intended to be used on attribute values that
   * should resolve to schema components.
   *
   * Returns 0, in case the QName is valid, a positive error code
   * if not valid and -1 if an internal error occurs.
   */
  static int
  xmlSchemaPValAttrNodeQNameValue(xmlSchemaParserCtxtPtr ctxt,
  				       xmlSchemaPtr schema,
  				       xmlSchemaBasicItemPtr ownerItem,
  				       xmlAttrPtr attr,
  				       const xmlChar *value,
  				       const xmlChar **uri,
  				       const xmlChar **local)
  {
      const xmlChar *pref;
      xmlNsPtr ns;
      int len, ret;
  
      *uri = NULL;
      *local = NULL;
      ret = xmlValidateQName(value, 1);
      if (ret > 0) {
  	xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    ownerItem, (xmlNodePtr) attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME),
  	    NULL, value, NULL, NULL, NULL);
  	*local = value;
  	return (ctxt->err);
      } else if (ret < 0)
  	return (-1);
  
      if (!strchr((char *) value, ':')) {
  	ns = xmlSearchNs(attr->doc, attr->parent, NULL);
  	if (ns)
  	    *uri = xmlDictLookup(ctxt->dict, ns->href, -1);
  	else if (schema->flags & XML_SCHEMAS_INCLUDING_CONVERT_NS) {
  	    /* TODO: move XML_SCHEMAS_INCLUDING_CONVERT_NS to the
  	    * parser context. */
  	    /*
  	    * This one takes care of included schemas with no
  	    * target namespace.
  	    */
  	    *uri = ctxt->targetNamespace;
  	}
  	*local = xmlDictLookup(ctxt->dict, value, -1);
  	return (0);
      }
      /*
      * At this point xmlSplitQName3 has to return a local name.
      */
      *local = xmlSplitQName3(value, &len);
      *local = xmlDictLookup(ctxt->dict, *local, -1);
      pref = xmlDictLookup(ctxt->dict, value, len);
      ns = xmlSearchNs(attr->doc, attr->parent, pref);
      if (ns == NULL) {
  	xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    ownerItem, (xmlNodePtr) attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME), NULL, value,
  	    "The value '%s' of simple type 'xs:QName' has no "
  	    "corresponding namespace declaration in scope", value, NULL);
  	return (ctxt->err);
      } else {
          *uri = xmlDictLookup(ctxt->dict, ns->href, -1);
      }
      return (0);
  }
  
  /**
   * xmlSchemaPValAttrNodeQName:
   * @ctxt:  a schema parser context
   * @schema: the schema context
   * @ownerItem: the owner as a schema object
   * @attr:  the attribute node
   * @uri:  the resulting namespace URI if found
   * @local: the resulting local part if found, the attribute value otherwise
   *
   * Extracts and validates the QName of an attribute value.
   * This one is intended to be used on attribute values that
   * should resolve to schema components.
   *
   * Returns 0, in case the QName is valid, a positive error code
   * if not valid and -1 if an internal error occurs.
   */
  static int
  xmlSchemaPValAttrNodeQName(xmlSchemaParserCtxtPtr ctxt,
  				       xmlSchemaPtr schema,
  				       xmlSchemaBasicItemPtr ownerItem,
  				       xmlAttrPtr attr,
  				       const xmlChar **uri,
  				       const xmlChar **local)
  {
      const xmlChar *value;
  
      value = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
      return (xmlSchemaPValAttrNodeQNameValue(ctxt, schema,
  	ownerItem, attr, value, uri, local));
  }
  
  /**
   * xmlSchemaPValAttrQName:
   * @ctxt:  a schema parser context
   * @schema: the schema context
   * @ownerItem: the owner as a schema object
   * @ownerElem:  the parent node of the attribute
   * @name:  the name of the attribute
   * @uri:  the resulting namespace URI if found
   * @local: the resulting local part if found, the attribute value otherwise
   *
   * Extracts and validates the QName of an attribute value.
   *
   * Returns 0, in case the QName is valid, a positive error code
   * if not valid and -1 if an internal error occurs.
   */
  static int
  xmlSchemaPValAttrQName(xmlSchemaParserCtxtPtr ctxt,
  				   xmlSchemaPtr schema,
  				   xmlSchemaBasicItemPtr ownerItem,
  				   xmlNodePtr ownerElem,
  				   const char *name,
  				   const xmlChar **uri,
  				   const xmlChar **local)
  {
      xmlAttrPtr attr;
  
      attr = xmlSchemaGetPropNode(ownerElem, name);
      if (attr == NULL) {
  	*local = NULL;
  	*uri = NULL;
  	return (0);
      }
      return (xmlSchemaPValAttrNodeQName(ctxt, schema,
  	ownerItem, attr, uri, local));
  }
  
  /**
   * xmlSchemaPValAttrID:
   * @ctxt:  a schema parser context
   *
   * Extracts and validates the ID of an attribute value.
   *
   * Returns 0, in case the ID is valid, a positive error code
   * if not valid and -1 if an internal error occurs.
   */
  static int
  xmlSchemaPValAttrNodeID(xmlSchemaParserCtxtPtr ctxt, xmlAttrPtr attr)
  {
      int ret;
      const xmlChar *value;
  
      if (attr == NULL)
  	return(0);
      value = xmlSchemaGetNodeContentNoDict((xmlNodePtr) attr);
      ret = xmlValidateNCName(value, 1);
      if (ret == 0) {
  	/*
  	* NOTE: the IDness might have already be declared in the DTD
  	*/
  	if (attr->atype != XML_ATTRIBUTE_ID) {
  	    xmlIDPtr res;
  	    xmlChar *strip;
  
  	    /*
  	    * TODO: Use xmlSchemaStrip here; it's not exported at this
  	    * moment.
  	    */
  	    strip = xmlSchemaCollapseString(value);
  	    if (strip != NULL) {
  		xmlFree((xmlChar *) value);
  		value = strip;
  	    }
  	    res = xmlAddID(NULL, attr->doc, value, attr);
  	    if (res == NULL) {
  		ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE;
  		xmlSchemaPSimpleTypeErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  		    NULL, (xmlNodePtr) attr,
  		    xmlSchemaGetBuiltInType(XML_SCHEMAS_ID),
  		    NULL, NULL, "Duplicate value '%s' of simple "
  		    "type 'xs:ID'", value, NULL);
  	    } else
  		attr->atype = XML_ATTRIBUTE_ID;
  	}
      } else if (ret > 0) {
  	ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE;
  	xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    NULL, (xmlNodePtr) attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_ID),
  	    NULL, NULL, "The value '%s' of simple type 'xs:ID' is "
  	    "not a valid 'xs:NCName'",
  	    value, NULL);
      }
      if (value != NULL)
  	xmlFree((xmlChar *)value);
  
      return (ret);
  }
  
  static int
  xmlSchemaPValAttrID(xmlSchemaParserCtxtPtr ctxt,
  		    xmlNodePtr ownerElem,
  		    const xmlChar *name)
  {
      xmlAttrPtr attr;
  
      attr = xmlSchemaGetPropNode(ownerElem, (const char *) name);
      if (attr == NULL)
  	return(0);
      return(xmlSchemaPValAttrNodeID(ctxt, attr));
  
  }
  
  /**
   * xmlGetMaxOccurs:
   * @ctxt:  a schema validation context
   * @node:  a subtree containing XML Schema informations
   *
   * Get the maxOccurs property
   *
   * Returns the default if not found, or the value
   */
  static int
  xmlGetMaxOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
  		int min, int max, int def, const char *expected)
  {
      const xmlChar *val, *cur;
      int ret = 0;
      xmlAttrPtr attr;
  
      attr = xmlSchemaGetPropNode(node, "maxOccurs");
      if (attr == NULL)
  	return (def);
      val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  
      if (xmlStrEqual(val, (const xmlChar *) "unbounded")) {
  	if (max != UNBOUNDED) {
  	    xmlSchemaPSimpleTypeErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  		/* XML_SCHEMAP_INVALID_MINOCCURS, */
  		NULL, (xmlNodePtr) attr, NULL, expected,
  		val, NULL, NULL, NULL);
  	    return (def);
  	} else
  	    return (UNBOUNDED);  /* encoding it with -1 might be another option */
      }
  
      cur = val;
      while (IS_BLANK_CH(*cur))
          cur++;
      if (*cur == 0) {
          xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    /* XML_SCHEMAP_INVALID_MINOCCURS, */
  	    NULL, (xmlNodePtr) attr, NULL, expected,
  	    val, NULL, NULL, NULL);
  	return (def);
      }
      while ((*cur >= '0') && (*cur <= '9')) {
          ret = ret * 10 + (*cur - '0');
          cur++;
      }
      while (IS_BLANK_CH(*cur))
          cur++;
      /*
      * TODO: Restrict the maximal value to Integer.
      */
      if ((*cur != 0) || (ret < min) || ((max != -1) && (ret > max))) {
  	xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    /* XML_SCHEMAP_INVALID_MINOCCURS, */
  	    NULL, (xmlNodePtr) attr, NULL, expected,
  	    val, NULL, NULL, NULL);
          return (def);
      }
      return (ret);
  }
  
  /**
   * xmlGetMinOccurs:
   * @ctxt:  a schema validation context
   * @node:  a subtree containing XML Schema informations
   *
   * Get the minOccurs property
   *
   * Returns the default if not found, or the value
   */
  static int
  xmlGetMinOccurs(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node,
  		int min, int max, int def, const char *expected)
  {
      const xmlChar *val, *cur;
      int ret = 0;
      xmlAttrPtr attr;
  
      attr = xmlSchemaGetPropNode(node, "minOccurs");
      if (attr == NULL)
  	return (def);
      val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
      cur = val;
      while (IS_BLANK_CH(*cur))
          cur++;
      if (*cur == 0) {
          xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    /* XML_SCHEMAP_INVALID_MINOCCURS, */
  	    NULL, (xmlNodePtr) attr, NULL, expected,
  	    val, NULL, NULL, NULL);
          return (def);
      }
      while ((*cur >= '0') && (*cur <= '9')) {
          ret = ret * 10 + (*cur - '0');
          cur++;
      }
      while (IS_BLANK_CH(*cur))
          cur++;
      /*
      * TODO: Restrict the maximal value to Integer.
      */
      if ((*cur != 0) || (ret < min) || ((max != -1) && (ret > max))) {
  	xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    /* XML_SCHEMAP_INVALID_MINOCCURS, */
  	    NULL, (xmlNodePtr) attr, NULL, expected,
  	    val, NULL, NULL, NULL);
          return (def);
      }
      return (ret);
  }
  
  /**
   * xmlSchemaPGetBoolNodeValue:
   * @ctxt:  a schema validation context
   * @ownerItem:  the owner as a schema item
   * @node: the node holding the value
   *
   * Converts a boolean string value into 1 or 0.
   *
   * Returns 0 or 1.
   */
  static int
  xmlSchemaPGetBoolNodeValue(xmlSchemaParserCtxtPtr ctxt,
  			   xmlSchemaBasicItemPtr ownerItem,
  			   xmlNodePtr node)
  {
      xmlChar *value = NULL;
      int res = 0;
  
      value = xmlNodeGetContent(node);
      /*
      * 3.2.2.1 Lexical representation
      * An instance of a datatype that is defined as `boolean`
      * can have the following legal literals {true, false, 1, 0}.
      */
      if (xmlStrEqual(BAD_CAST value, BAD_CAST "true"))
          res = 1;
      else if (xmlStrEqual(BAD_CAST value, BAD_CAST "false"))
          res = 0;
      else if (xmlStrEqual(BAD_CAST value, BAD_CAST "1"))
  	res = 1;
      else if (xmlStrEqual(BAD_CAST value, BAD_CAST "0"))
          res = 0;
      else {
          xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_INVALID_BOOLEAN,
  	    ownerItem, node,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_BOOLEAN),
  	    NULL, BAD_CAST value,
  	    NULL, NULL, NULL);
      }
      if (value != NULL)
  	xmlFree(value);
      return (res);
  }
  
  /**
   * xmlGetBooleanProp:
   * @ctxt:  a schema validation context
   * @node:  a subtree containing XML Schema informations
   * @name:  the attribute name
   * @def:  the default value
   *
   * Evaluate if a boolean property is set
   *
   * Returns the default if not found, 0 if found to be false,
   * 1 if found to be true
   */
  static int
  xmlGetBooleanProp(xmlSchemaParserCtxtPtr ctxt,
  		  xmlNodePtr node,
                    const char *name, int def)
  {
      const xmlChar *val;
  
      val = xmlSchemaGetProp(ctxt, node, name);
      if (val == NULL)
          return (def);
      /*
      * 3.2.2.1 Lexical representation
      * An instance of a datatype that is defined as `boolean`
      * can have the following legal literals {true, false, 1, 0}.
      */
      if (xmlStrEqual(val, BAD_CAST "true"))
          def = 1;
      else if (xmlStrEqual(val, BAD_CAST "false"))
          def = 0;
      else if (xmlStrEqual(val, BAD_CAST "1"))
  	def = 1;
      else if (xmlStrEqual(val, BAD_CAST "0"))
          def = 0;
      else {
          xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_INVALID_BOOLEAN,
  	    NULL,
  	    (xmlNodePtr) xmlSchemaGetPropNode(node, name),
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_BOOLEAN),
  	    NULL, val, NULL, NULL, NULL);
      }
      return (def);
  }
  
  /************************************************************************
   *									*
   *		Schema extraction from an Infoset			*
   *									*
   ************************************************************************/
  static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr
                                                   ctxt, xmlSchemaPtr schema,
                                                   xmlNodePtr node,
  						 int topLevel);
  static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr
                                                    ctxt,
                                                    xmlSchemaPtr schema,
                                                    xmlNodePtr node,
  						  int topLevel);
  static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr
                                                    ctxt,
                                                    xmlSchemaPtr schema,
                                                    xmlNodePtr node,
  						  xmlSchemaTypeType parentType);
  static xmlSchemaBasicItemPtr
  xmlSchemaParseLocalAttribute(xmlSchemaParserCtxtPtr pctxt,
  			     xmlSchemaPtr schema,
  			     xmlNodePtr node,
  			     xmlSchemaItemListPtr uses,
  			     int parentType);
  static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt,
                                             xmlSchemaPtr schema,
                                             xmlNodePtr node);
  static xmlSchemaWildcardPtr
  xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt,
                             xmlSchemaPtr schema, xmlNodePtr node);
  
  /**
   * xmlSchemaPValAttrNodeValue:
   *
   * @pctxt:  a schema parser context
   * @ownerItem: the schema object owner if existent
   * @attr:  the schema attribute node being validated
   * @value: the value
   * @type: the built-in type to be validated against
   *
   * 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
  xmlSchemaPValAttrNodeValue(xmlSchemaParserCtxtPtr pctxt,
  			   xmlSchemaBasicItemPtr ownerItem,
  			   xmlAttrPtr attr,
  			   const xmlChar *value,
  			   xmlSchemaTypePtr type)
  {
  
      int ret = 0;
  
      /*
      * NOTE: Should we move this to xmlschematypes.c? Hmm, but this
      * one is really meant to be used internally, so better not.
      */
      if ((pctxt == NULL) || (type == NULL) || (attr == NULL))
  	return (-1);
      if (type->type != XML_SCHEMA_TYPE_BASIC) {
  	PERROR_INT("xmlSchemaPValAttrNodeValue",
  	    "the given type is not a built-in type");
  	return (-1);
      }
      switch (type->builtInType) {
  	case XML_SCHEMAS_NCNAME:
  	case XML_SCHEMAS_QNAME:
  	case XML_SCHEMAS_ANYURI:
  	case XML_SCHEMAS_TOKEN:
  	case XML_SCHEMAS_LANGUAGE:
  	    ret = xmlSchemaValPredefTypeNode(type, value, NULL,
  		(xmlNodePtr) attr);
  	    break;
  	default: {
  	    PERROR_INT("xmlSchemaPValAttrNodeValue",
  		"validation using the given type is not supported while "
  		"parsing a schema");
  	    return (-1);
  	}
      }
      /*
      * TODO: Should we use the S4S error codes instead?
      */
      if (ret < 0) {
  	PERROR_INT("xmlSchemaPValAttrNodeValue",
  	    "failed to validate a schema attribute value");
  	return (-1);
      } else if (ret > 0) {
  	if (WXS_IS_LIST(type))
  	    ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2;
  	else
  	    ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1;
  	xmlSchemaPSimpleTypeErr(pctxt,
  	    ret, ownerItem, (xmlNodePtr) attr,
  	    type, NULL, value, NULL, NULL, NULL);
      }
      return (ret);
  }
  
  /**
   * xmlSchemaPValAttrNode:
   *
   * @ctxt:  a schema parser context
   * @ownerItem: the schema object owner if existent
   * @attr:  the schema attribute node being validated
   * @type: the built-in type to be validated against
   * @value: the resulting value if any
   *
   * Extracts and 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
  xmlSchemaPValAttrNode(xmlSchemaParserCtxtPtr ctxt,
  			   xmlSchemaBasicItemPtr ownerItem,
  			   xmlAttrPtr attr,
  			   xmlSchemaTypePtr type,
  			   const xmlChar **value)
  {
      const xmlChar *val;
  
      if ((ctxt == NULL) || (type == NULL) || (attr == NULL))
  	return (-1);
  
      val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
      if (value != NULL)
  	*value = val;
  
      return (xmlSchemaPValAttrNodeValue(ctxt, ownerItem, attr,
  	val, type));
  }
  
  /**
   * xmlSchemaPValAttr:
   *
   * @ctxt:  a schema parser context
   * @node: the element node of the attribute
   * @ownerItem: the schema object owner if existent
   * @ownerElem: the owner element node
   * @name:  the name of the schema attribute node
   * @type: the built-in type to be validated against
   * @value: the resulting value if any
   *
   * Extracts and 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
  xmlSchemaPValAttr(xmlSchemaParserCtxtPtr ctxt,
  		       xmlSchemaBasicItemPtr ownerItem,
  		       xmlNodePtr ownerElem,
  		       const char *name,
  		       xmlSchemaTypePtr type,
  		       const xmlChar **value)
  {
      xmlAttrPtr attr;
  
      if ((ctxt == NULL) || (type == NULL)) {
  	if (value != NULL)
  	    *value = NULL;
  	return (-1);
      }
      if (type->type != XML_SCHEMA_TYPE_BASIC) {
  	if (value != NULL)
  	    *value = NULL;
  	xmlSchemaPErr(ctxt, ownerElem,
  	    XML_SCHEMAP_INTERNAL,
  	    "Internal error: xmlSchemaPValAttr, the given "
  	    "type '%s' is not a built-in type.\n",
  	    type->name, NULL);
  	return (-1);
      }
      attr = xmlSchemaGetPropNode(ownerElem, name);
      if (attr == NULL) {
  	if (value != NULL)
  	    *value = NULL;
  	return (0);
      }
      return (xmlSchemaPValAttrNode(ctxt, ownerItem, attr,
  	type, value));
  }
  
  static int
  xmlSchemaCheckReference(xmlSchemaParserCtxtPtr pctxt,
  		  xmlSchemaPtr schema ATTRIBUTE_UNUSED,
  		  xmlNodePtr node,
  		  xmlAttrPtr attr,
  		  const xmlChar *namespaceName)
  {
      /* TODO: Pointer comparison instead? */
      if (xmlStrEqual(pctxt->targetNamespace, namespaceName))
  	return (0);
      if (xmlStrEqual(xmlSchemaNs, namespaceName))
  	return (0);
      /*
      * Check if the referenced namespace was <import>ed.
      */
      if (WXS_BUCKET(pctxt)->relations != NULL) {
  	xmlSchemaSchemaRelationPtr rel;
  
  	rel = WXS_BUCKET(pctxt)->relations;
  	do {
  	    if (WXS_IS_BUCKET_IMPMAIN(rel->type) &&
  		xmlStrEqual(namespaceName, rel->importNamespace))
  		return (0);
  	    rel = rel->next;
  	} while (rel != NULL);
      }
      /*
      * No matching <import>ed namespace found.
      */
      {
  	xmlNodePtr n = (attr != NULL) ? (xmlNodePtr) attr : node;
  
  	if (namespaceName == NULL)
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		XML_SCHEMAP_SRC_RESOLVE, n, NULL,
  		"References from this schema to components in no "
  		"namespace are not allowed, since not indicated by an "
  		"import statement", NULL, NULL);
  	else
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		XML_SCHEMAP_SRC_RESOLVE, n, NULL,
  		"References from this schema to components in the "
  		"namespace '%s' are not allowed, since not indicated by an "
  		"import statement", namespaceName, NULL);
      }
      return (XML_SCHEMAP_SRC_RESOLVE);
  }
  
  /**
   * xmlSchemaParseLocalAttributes:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   * @type:  the hosting type where the attributes will be anchored
   *
   * Parses attribute uses and attribute declarations and
   * attribute group references.
   */
  static int
  xmlSchemaParseLocalAttributes(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                          xmlNodePtr *child, xmlSchemaItemListPtr *list,
  			int parentType, int *hasRefs)
  {
      void *item;
  
      while ((IS_SCHEMA((*child), "attribute")) ||
             (IS_SCHEMA((*child), "attributeGroup"))) {
          if (IS_SCHEMA((*child), "attribute")) {
  	    item = xmlSchemaParseLocalAttribute(ctxt, schema, *child,
  		*list, parentType);
          } else {
              item = xmlSchemaParseAttributeGroupRef(ctxt, schema, *child);
  	    if ((item != NULL) && (hasRefs != NULL))
  		*hasRefs = 1;
          }
  	if (item != NULL) {
  	    if (*list == NULL) {
  		/* TODO: Customize grow factor. */
  		*list = xmlSchemaItemListCreate();
  		if (*list == NULL)
  		    return(-1);
  	    }
  	    if (xmlSchemaItemListAddSize(*list, 2, item) == -1)
  		return(-1);
  	}
          *child = (*child)->next;
      }
      return (0);
  }
  
  /**
   * xmlSchemaParseAnnotation:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema Attribute declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns -1 in case of error, 0 if the declaration is improper and
   *         1 in case of success.
   */
  static xmlSchemaAnnotPtr
  xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, int needed)
  {
      xmlSchemaAnnotPtr ret;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      int barked = 0;
  
      /*
      * INFO: S4S completed.
      */
      /*
      * id = ID
      * {any attributes with non-schema namespace . . .}>
      * Content: (appinfo | documentation)*
      */
      if ((ctxt == NULL) || (node == NULL))
          return (NULL);
      if (needed)
  	ret = xmlSchemaNewAnnot(ctxt, node);
      else
  	ret = NULL;
      attr = node->properties;
      while (attr != NULL) {
  	if (((attr->ns == NULL) &&
  	    (!xmlStrEqual(attr->name, BAD_CAST "id"))) ||
  	    ((attr->ns != NULL) &&
  	    xmlStrEqual(attr->ns->href, xmlSchemaNs))) {
  
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * And now for the children...
      */
      child = node->children;
      while (child != NULL) {
  	if (IS_SCHEMA(child, "appinfo")) {
  	    /* TODO: make available the content of "appinfo". */
  	    /*
  	    * source = anyURI
  	    * {any attributes with non-schema namespace . . .}>
  	    * Content: ({any})*
  	    */
  	    attr = child->properties;
  	    while (attr != NULL) {
  		if (((attr->ns == NULL) &&
  		     (!xmlStrEqual(attr->name, BAD_CAST "source"))) ||
  		     ((attr->ns != NULL) &&
  		      xmlStrEqual(attr->ns->href, xmlSchemaNs))) {
  
  		    xmlSchemaPIllegalAttrErr(ctxt,
  			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		}
  		attr = attr->next;
  	    }
  	    xmlSchemaPValAttr(ctxt, NULL, child, "source",
  		xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), NULL);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "documentation")) {
  	    /* TODO: make available the content of "documentation". */
  	    /*
  	    * source = anyURI
  	    * {any attributes with non-schema namespace . . .}>
  	    * Content: ({any})*
  	    */
  	    attr = child->properties;
  	    while (attr != NULL) {
  		if (attr->ns == NULL) {
  		    if (!xmlStrEqual(attr->name, BAD_CAST "source")) {
  			xmlSchemaPIllegalAttrErr(ctxt,
  			    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		    }
  		} else {
  		    if (xmlStrEqual(attr->ns->href, xmlSchemaNs) ||
  			(xmlStrEqual(attr->name, BAD_CAST "lang") &&
  			(!xmlStrEqual(attr->ns->href, XML_XML_NAMESPACE)))) {
  
  			xmlSchemaPIllegalAttrErr(ctxt,
  			    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		    }
  		}
  		attr = attr->next;
  	    }
  	    /*
  	    * Attribute "xml:lang".
  	    */
  	    attr = xmlSchemaGetPropNodeNs(child, (const char *) XML_XML_NAMESPACE, "lang");
  	    if (attr != NULL)
  		xmlSchemaPValAttrNode(ctxt, NULL, attr,
  		xmlSchemaGetBuiltInType(XML_SCHEMAS_LANGUAGE), NULL);
  	    child = child->next;
  	} else {
  	    if (!barked)
  		xmlSchemaPContentErr(ctxt,
  		    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		    NULL, node, child, NULL, "(appinfo | documentation)*");
  	    barked = 1;
  	    child = child->next;
  	}
      }
  
      return (ret);
  }
  
  /**
   * xmlSchemaParseFacet:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema Facet declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns the new type structure or NULL in case of error
   */
  static xmlSchemaFacetPtr
  xmlSchemaParseFacet(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                      xmlNodePtr node)
  {
      xmlSchemaFacetPtr facet;
      xmlNodePtr child = NULL;
      const xmlChar *value;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      facet = xmlSchemaNewFacet();
      if (facet == NULL) {
          xmlSchemaPErrMemory(ctxt, "allocating facet", node);
          return (NULL);
      }
      facet->node = node;
      value = xmlSchemaGetProp(ctxt, node, "value");
      if (value == NULL) {
          xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_FACET_NO_VALUE,
                         "Facet %s has no value\n", node->name, NULL);
          xmlSchemaFreeFacet(facet);
          return (NULL);
      }
      if (IS_SCHEMA(node, "minInclusive")) {
          facet->type = XML_SCHEMA_FACET_MININCLUSIVE;
      } else if (IS_SCHEMA(node, "minExclusive")) {
          facet->type = XML_SCHEMA_FACET_MINEXCLUSIVE;
      } else if (IS_SCHEMA(node, "maxInclusive")) {
          facet->type = XML_SCHEMA_FACET_MAXINCLUSIVE;
      } else if (IS_SCHEMA(node, "maxExclusive")) {
          facet->type = XML_SCHEMA_FACET_MAXEXCLUSIVE;
      } else if (IS_SCHEMA(node, "totalDigits")) {
          facet->type = XML_SCHEMA_FACET_TOTALDIGITS;
      } else if (IS_SCHEMA(node, "fractionDigits")) {
          facet->type = XML_SCHEMA_FACET_FRACTIONDIGITS;
      } else if (IS_SCHEMA(node, "pattern")) {
          facet->type = XML_SCHEMA_FACET_PATTERN;
      } else if (IS_SCHEMA(node, "enumeration")) {
          facet->type = XML_SCHEMA_FACET_ENUMERATION;
      } else if (IS_SCHEMA(node, "whiteSpace")) {
          facet->type = XML_SCHEMA_FACET_WHITESPACE;
      } else if (IS_SCHEMA(node, "length")) {
          facet->type = XML_SCHEMA_FACET_LENGTH;
      } else if (IS_SCHEMA(node, "maxLength")) {
          facet->type = XML_SCHEMA_FACET_MAXLENGTH;
      } else if (IS_SCHEMA(node, "minLength")) {
          facet->type = XML_SCHEMA_FACET_MINLENGTH;
      } else {
          xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_TYPE,
                         "Unknown facet type %s\n", node->name, NULL);
          xmlSchemaFreeFacet(facet);
          return (NULL);
      }
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "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")) {
          facet->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
          child = child->next;
      }
      if (child != NULL) {
          xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_FACET_CHILD,
                         "Facet %s has unexpected child content\n",
                         node->name, NULL);
      }
      return (facet);
  }
  
  /**
   * xmlSchemaParseWildcardNs:
   * @ctxt:  a schema parser context
   * @wildc:  the wildcard, already created
   * @node:  a subtree containing XML Schema informations
   *
   * Parses the attribute "processContents" and "namespace"
   * of a xsd:anyAttribute and xsd:any.
   * *WARNING* this interface is highly subject to change
   *
   * Returns 0 if everything goes fine, a positive error code
   * if something is not valid and -1 if an internal error occurs.
   */
  static int
  xmlSchemaParseWildcardNs(xmlSchemaParserCtxtPtr ctxt,
  			 xmlSchemaPtr schema ATTRIBUTE_UNUSED,
  			 xmlSchemaWildcardPtr wildc,
  			 xmlNodePtr node)
  {
      const xmlChar *pc, *ns, *dictnsItem;
      int ret = 0;
      xmlChar *nsItem;
      xmlSchemaWildcardNsPtr tmp, lastNs = NULL;
      xmlAttrPtr attr;
  
      pc = xmlSchemaGetProp(ctxt, node, "processContents");
      if ((pc == NULL)
          || (xmlStrEqual(pc, (const xmlChar *) "strict"))) {
          wildc->processContents = XML_SCHEMAS_ANY_STRICT;
      } else if (xmlStrEqual(pc, (const xmlChar *) "skip")) {
          wildc->processContents = XML_SCHEMAS_ANY_SKIP;
      } else if (xmlStrEqual(pc, (const xmlChar *) "lax")) {
          wildc->processContents = XML_SCHEMAS_ANY_LAX;
      } else {
          xmlSchemaPSimpleTypeErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    NULL, node,
  	    NULL, "(strict | skip | lax)", pc,
  	    NULL, NULL, NULL);
          wildc->processContents = XML_SCHEMAS_ANY_STRICT;
  	ret = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE;
      }
      /*
       * Build the namespace constraints.
       */
      attr = xmlSchemaGetPropNode(node, "namespace");
      ns = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
      if ((attr == NULL) || (xmlStrEqual(ns, BAD_CAST "##any")))
  	wildc->any = 1;
      else if (xmlStrEqual(ns, BAD_CAST "##other")) {
  	wildc->negNsSet = xmlSchemaNewWildcardNsConstraint(ctxt);
  	if (wildc->negNsSet == NULL) {
  	    return (-1);
  	}
  	wildc->negNsSet->value = ctxt->targetNamespace;
      } else {
  	const xmlChar *end, *cur;
  
  	cur = ns;
  	do {
  	    while (IS_BLANK_CH(*cur))
  		cur++;
  	    end = cur;
  	    while ((*end != 0) && (!(IS_BLANK_CH(*end))))
  		end++;
  	    if (end == cur)
  		break;
  	    nsItem = xmlStrndup(cur, end - cur);
  	    if ((xmlStrEqual(nsItem, BAD_CAST "##other")) ||
  		    (xmlStrEqual(nsItem, BAD_CAST "##any"))) {
  		xmlSchemaPSimpleTypeErr(ctxt,
  		    XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER,
  		    NULL, (xmlNodePtr) attr,
  		    NULL,
  		    "((##any | ##other) | List of (xs:anyURI | "
  		    "(##targetNamespace | ##local)))",
  		    nsItem, NULL, NULL, NULL);
  		ret = XML_SCHEMAP_WILDCARD_INVALID_NS_MEMBER;
  	    } else {
  		if (xmlStrEqual(nsItem, BAD_CAST "##targetNamespace")) {
  		    dictnsItem = ctxt->targetNamespace;
  		} else if (xmlStrEqual(nsItem, BAD_CAST "##local")) {
  		    dictnsItem = NULL;
  		} else {
  		    /*
  		    * Validate the item (anyURI).
  		    */
  		    xmlSchemaPValAttrNodeValue(ctxt, NULL, attr,
  			nsItem, xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI));
  		    dictnsItem = xmlDictLookup(ctxt->dict, nsItem, -1);
  		}
  		/*
  		* Avoid duplicate namespaces.
  		*/
  		tmp = wildc->nsSet;
  		while (tmp != NULL) {
  		    if (dictnsItem == tmp->value)
  			break;
  		    tmp = tmp->next;
  		}
  		if (tmp == NULL) {
  		    tmp = xmlSchemaNewWildcardNsConstraint(ctxt);
  		    if (tmp == NULL) {
  			xmlFree(nsItem);
  			return (-1);
  		    }
  		    tmp->value = dictnsItem;
  		    tmp->next = NULL;
  		    if (wildc->nsSet == NULL)
  			wildc->nsSet = tmp;
  		    else if (lastNs != NULL)
  			lastNs->next = tmp;
  		    lastNs = tmp;
  		}
  
  	    }
  	    xmlFree(nsItem);
  	    cur = end;
  	} while (*cur != 0);
      }
      return (ret);
  }
  
  static int
  xmlSchemaPCheckParticleCorrect_2(xmlSchemaParserCtxtPtr ctxt,
  				 xmlSchemaParticlePtr item ATTRIBUTE_UNUSED,
  				 xmlNodePtr node,
  				 int minOccurs,
  				 int maxOccurs) {
  
      if ((maxOccurs == 0) && ( minOccurs == 0))
  	return (0);
      if (maxOccurs != UNBOUNDED) {
  	/*
  	* TODO: Maybe we should better not create the particle,
  	* if min/max is invalid, since it could confuse the build of the
  	* content model.
  	*/
  	/*
  	* 3.9.6 Schema Component Constraint: Particle Correct
  	*
  	*/
  	if (maxOccurs < 1) {
  	    /*
  	    * 2.2 {max occurs} must be greater than or equal to 1.
  	    */
  	    xmlSchemaPCustomAttrErr(ctxt,
  		XML_SCHEMAP_P_PROPS_CORRECT_2_2,
  		NULL, NULL,
  		xmlSchemaGetPropNode(node, "maxOccurs"),
  		"The value must be greater than or equal to 1");
  	    return (XML_SCHEMAP_P_PROPS_CORRECT_2_2);
  	} else if (minOccurs > maxOccurs) {
  	    /*
  	    * 2.1 {min occurs} must not be greater than {max occurs}.
  	    */
  	    xmlSchemaPCustomAttrErr(ctxt,
  		XML_SCHEMAP_P_PROPS_CORRECT_2_1,
  		NULL, NULL,
  		xmlSchemaGetPropNode(node, "minOccurs"),
  		"The value must not be greater than the value of 'maxOccurs'");
  	    return (XML_SCHEMAP_P_PROPS_CORRECT_2_1);
  	}
      }
      return (0);
  }
  
  /**
   * xmlSchemaParseAny:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * Parsea a XML schema <any> element. A particle and wildcard
   * will be created (except if minOccurs==maxOccurs==0, in this case
   * nothing will be created).
   * *WARNING* this interface is highly subject to change
   *
   * Returns the particle or NULL in case of error or if minOccurs==maxOccurs==0
   */
  static xmlSchemaParticlePtr
  xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                    xmlNodePtr node)
  {
      xmlSchemaParticlePtr particle;
      xmlNodePtr child = NULL;
      xmlSchemaWildcardPtr wild;
      int min, max;
      xmlAttrPtr attr;
      xmlSchemaAnnotPtr annot = NULL;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "minOccurs")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "maxOccurs")) &&
  	        (!xmlStrEqual(attr->name, BAD_CAST "namespace")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "processContents"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * minOccurs/maxOccurs.
      */
      max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1,
  	"(xs:nonNegativeInteger | unbounded)");
      min = xmlGetMinOccurs(ctxt, node, 0, -1, 1,
  	"xs:nonNegativeInteger");
      xmlSchemaPCheckParticleCorrect_2(ctxt, NULL, node, min, max);
      /*
      * Create & parse the wildcard.
      */
      wild = xmlSchemaAddWildcard(ctxt, schema, XML_SCHEMA_TYPE_ANY, node);
      if (wild == NULL)
  	return (NULL);
      xmlSchemaParseWildcardNs(ctxt, schema, wild, node);
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          annot = xmlSchemaParseAnnotation(ctxt, child, 1);
          child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child,
  	    NULL, "(annotation?)");
      }
      /*
      * No component if minOccurs==maxOccurs==0.
      */
      if ((min == 0) && (max == 0)) {
  	/* Don't free the wildcard, since it's already on the list. */
  	return (NULL);
      }
      /*
      * Create the particle.
      */
      particle = xmlSchemaAddParticle(ctxt, node, min, max);
      if (particle == NULL)
          return (NULL);
      particle->annot = annot;
      particle->children = (xmlSchemaTreeItemPtr) wild;
  
      return (particle);
  }
  
  /**
   * xmlSchemaParseNotation:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema Notation declaration
   *
   * Returns the new structure or NULL in case of error
   */
  static xmlSchemaNotationPtr
  xmlSchemaParseNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                         xmlNodePtr node)
  {
      const xmlChar *name;
      xmlSchemaNotationPtr ret;
      xmlNodePtr child = NULL;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
      name = xmlSchemaGetProp(ctxt, node, "name");
      if (name == NULL) {
          xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_NOTATION_NO_NAME,
                         "Notation has no name\n", NULL, NULL);
          return (NULL);
      }
      ret = xmlSchemaAddNotation(ctxt, schema, name,
  	ctxt->targetNamespace, node);
      if (ret == NULL)
          return (NULL);
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
  
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          ret->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
          child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child,
  	    NULL, "(annotation?)");
      }
  
      return (ret);
  }
  
  /**
   * xmlSchemaParseAnyAttribute:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema AnyAttribute declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns a wildcard or NULL.
   */
  static xmlSchemaWildcardPtr
  xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt,
                             xmlSchemaPtr schema, xmlNodePtr node)
  {
      xmlSchemaWildcardPtr ret;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      ret = xmlSchemaAddWildcard(ctxt, schema, XML_SCHEMA_TYPE_ANY_ATTRIBUTE,
  	node);
      if (ret == NULL) {
          return (NULL);
      }
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  	        (!xmlStrEqual(attr->name, BAD_CAST "namespace")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "processContents"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * Parse the namespace list.
      */
      if (xmlSchemaParseWildcardNs(ctxt, schema, ret, node) != 0)
  	return (NULL);
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          ret->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
          child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child,
  	    NULL, "(annotation?)");
      }
  
      return (ret);
  }
  
  
  /**
   * xmlSchemaParseAttribute:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema Attribute declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns the attribute declaration.
   */
  static xmlSchemaBasicItemPtr
  xmlSchemaParseLocalAttribute(xmlSchemaParserCtxtPtr pctxt,
  			     xmlSchemaPtr schema,
  			     xmlNodePtr node,
  			     xmlSchemaItemListPtr uses,
  			     int parentType)
  {
      const xmlChar *attrValue, *name = NULL, *ns = NULL;
      xmlSchemaAttributeUsePtr use = NULL;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      const xmlChar *tmpNs = NULL, *tmpName = NULL, *defValue = NULL;
      int isRef = 0, occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL;
      int	nberrors, hasForm = 0, defValueType = 0;
  
  #define WXS_ATTR_DEF_VAL_DEFAULT 1
  #define WXS_ATTR_DEF_VAL_FIXED 2
  
      /*
       * 3.2.3 Constraints on XML Representations of Attribute Declarations
       */
  
      if ((pctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
      attr = xmlSchemaGetPropNode(node, "ref");
      if (attr != NULL) {
  	if (xmlSchemaPValAttrNodeQName(pctxt, schema,
  	    NULL, attr, &tmpNs, &tmpName) != 0) {
  	    return (NULL);
  	}
  	if (xmlSchemaCheckReference(pctxt, schema, node, attr, tmpNs) != 0)
  	    return(NULL);
  	isRef = 1;
      }
      nberrors = pctxt->nberrors;
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if (isRef) {
  		if (xmlStrEqual(attr->name, BAD_CAST "id")) {
  		    xmlSchemaPValAttrNodeID(pctxt, attr);
  		    goto attr_next;
  		} else if (xmlStrEqual(attr->name, BAD_CAST "ref")) {
  		    goto attr_next;
  		}
  	    } else {
  		if (xmlStrEqual(attr->name, BAD_CAST "name")) {
  		    goto attr_next;
  		} else if (xmlStrEqual(attr->name, BAD_CAST "id")) {
  		    xmlSchemaPValAttrNodeID(pctxt, attr);
  		    goto attr_next;
  		} else if (xmlStrEqual(attr->name, BAD_CAST "type")) {
  		    xmlSchemaPValAttrNodeQName(pctxt, schema, NULL,
  			attr, &tmpNs, &tmpName);
  		    goto attr_next;
  		} else if (xmlStrEqual(attr->name, BAD_CAST "form")) {
  		    /*
  		    * Evaluate the target namespace
  		    */
  		    hasForm = 1;
  		    attrValue = xmlSchemaGetNodeContent(pctxt,
  			(xmlNodePtr) attr);
  		    if (xmlStrEqual(attrValue, BAD_CAST "qualified")) {
  			ns = pctxt->targetNamespace;
  		    } else if (!xmlStrEqual(attrValue, BAD_CAST "unqualified"))
  		    {
  			xmlSchemaPSimpleTypeErr(pctxt,
  			    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  			    NULL, (xmlNodePtr) attr,
  			    NULL, "(qualified | unqualified)",
  			    attrValue, NULL, NULL, NULL);
  		    }
  		    goto attr_next;
  		}
  	    }
  	    if (xmlStrEqual(attr->name, BAD_CAST "use")) {
  
  		attrValue = xmlSchemaGetNodeContent(pctxt, (xmlNodePtr) attr);
  		/* TODO: Maybe we need to normalize the value beforehand. */
  		if (xmlStrEqual(attrValue, BAD_CAST "optional"))
  		    occurs = XML_SCHEMAS_ATTR_USE_OPTIONAL;
  		else if (xmlStrEqual(attrValue, BAD_CAST "prohibited"))
  		    occurs = XML_SCHEMAS_ATTR_USE_PROHIBITED;
  		else if (xmlStrEqual(attrValue, BAD_CAST "required"))
  		    occurs = XML_SCHEMAS_ATTR_USE_REQUIRED;
  		else {
  		    xmlSchemaPSimpleTypeErr(pctxt,
  			XML_SCHEMAP_INVALID_ATTR_USE,
  			NULL, (xmlNodePtr) attr,
  			NULL, "(optional | prohibited | required)",
  			attrValue, NULL, NULL, NULL);
  		}
  		goto attr_next;
  	    } else if (xmlStrEqual(attr->name, BAD_CAST "default")) {
  		/*
  		* 3.2.3 : 1
  		* default and fixed must not both be present.
  		*/
  		if (defValue) {
  		    xmlSchemaPMutualExclAttrErr(pctxt,
  			XML_SCHEMAP_SRC_ATTRIBUTE_1,
  			NULL, attr, "default", "fixed");
  		} else {
  		    defValue = xmlSchemaGetNodeContent(pctxt, (xmlNodePtr) attr);
  		    defValueType = WXS_ATTR_DEF_VAL_DEFAULT;
  		}
  		goto attr_next;
  	    } else if (xmlStrEqual(attr->name, BAD_CAST "fixed")) {
  		/*
  		* 3.2.3 : 1
  		* default and fixed must not both be present.
  		*/
  		if (defValue) {
  		    xmlSchemaPMutualExclAttrErr(pctxt,
  			XML_SCHEMAP_SRC_ATTRIBUTE_1,
  			NULL, attr, "default", "fixed");
  		} else {
  		    defValue = xmlSchemaGetNodeContent(pctxt, (xmlNodePtr) attr);
  		    defValueType = WXS_ATTR_DEF_VAL_FIXED;
  		}
  		goto attr_next;
  	    }
  	} else if (! xmlStrEqual(attr->ns->href, xmlSchemaNs))
  	    goto attr_next;
  
  	xmlSchemaPIllegalAttrErr(pctxt,
  	    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  
  attr_next:
  	attr = attr->next;
      }
      /*
      * 3.2.3 : 2
      * If default and use are both present, use must have
      * the actual value optional.
      */
      if ((defValueType == WXS_ATTR_DEF_VAL_DEFAULT) &&
  	(occurs != XML_SCHEMAS_ATTR_USE_OPTIONAL)) {
  	xmlSchemaPSimpleTypeErr(pctxt,
  	    XML_SCHEMAP_SRC_ATTRIBUTE_2,
  	    NULL, node, NULL,
  	    "(optional | prohibited | required)", NULL,
  	    "The value of the attribute 'use' must be 'optional' "
  	    "if the attribute 'default' is present",
  	    NULL, NULL);
      }
      /*
      * We want correct attributes.
      */
      if (nberrors != pctxt->nberrors)
  	return(NULL);
      if (! isRef) {
  	xmlSchemaAttributePtr attrDecl;
  
  	/* TODO: move XML_SCHEMAS_QUALIF_ATTR to the parser. */
  	if ((! hasForm) && (schema->flags & XML_SCHEMAS_QUALIF_ATTR))
  	    ns = pctxt->targetNamespace;
  	/*
  	* 3.2.6 Schema Component Constraint: xsi: Not Allowed
  	* TODO: Move this to the component layer.
  	*/
  	if (xmlStrEqual(ns, xmlSchemaInstanceNs)) {
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		XML_SCHEMAP_NO_XSI,
  		node, NULL,
  		"The target namespace must not match '%s'",
  		xmlSchemaInstanceNs, NULL);
  	}
  	attr = xmlSchemaGetPropNode(node, "name");
  	if (attr == NULL) {
  	    xmlSchemaPMissingAttrErr(pctxt, XML_SCHEMAP_S4S_ATTR_MISSING,
  		NULL, node, "name", NULL);
  	    return (NULL);
  	}
  	if (xmlSchemaPValAttrNode(pctxt, NULL, attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) {
  	    return (NULL);
  	}
  	/*
  	* 3.2.6 Schema Component Constraint: xmlns Not Allowed
  	* TODO: Move this to the component layer.
  	*/
  	if (xmlStrEqual(name, BAD_CAST "xmlns")) {
  	    xmlSchemaPSimpleTypeErr(pctxt,
  		XML_SCHEMAP_NO_XMLNS,
  		NULL, (xmlNodePtr) attr,
  		xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), NULL, NULL,
  		"The value of the attribute must not match 'xmlns'",
  		NULL, NULL);
  	    return (NULL);
  	}
  	if (occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED)
  	    goto check_children;
  	/*
  	* Create the attribute use component.
  	*/
  	use = xmlSchemaAddAttributeUse(pctxt, node);
  	if (use == NULL)
  	    return(NULL);
  	use->occurs = occurs;
  	/*
  	* Create the attribute declaration.
  	*/
  	attrDecl = xmlSchemaAddAttribute(pctxt, schema, name, ns, node, 0);
  	if (attrDecl == NULL)
  	    return (NULL);
  	if (tmpName != NULL) {
  	    attrDecl->typeName = tmpName;
  	    attrDecl->typeNs = tmpNs;
  	}
  	use->attrDecl = attrDecl;
  	/*
  	* Value constraint.
  	*/
  	if (defValue != NULL) {
  	    attrDecl->defValue = defValue;
  	    if (defValueType == WXS_ATTR_DEF_VAL_FIXED)
  		attrDecl->flags |= XML_SCHEMAS_ATTR_FIXED;
  	}
      } else if (occurs != XML_SCHEMAS_ATTR_USE_PROHIBITED) {
  	xmlSchemaQNameRefPtr ref;
  
  	/*
  	* Create the attribute use component.
  	*/
  	use = xmlSchemaAddAttributeUse(pctxt, node);
  	if (use == NULL)
  	    return(NULL);
  	/*
  	* We need to resolve the reference at later stage.
  	*/
  	WXS_ADD_PENDING(pctxt, use);
  	use->occurs = occurs;
  	/*
  	* Create a QName reference to the attribute declaration.
  	*/
  	ref = xmlSchemaNewQNameRef(pctxt, XML_SCHEMA_TYPE_ATTRIBUTE,
  	    tmpName, tmpNs);
  	if (ref == NULL)
  	    return(NULL);
  	/*
  	* Assign the reference. This will be substituted for the
  	* referenced attribute declaration when the QName is resolved.
  	*/
  	use->attrDecl = WXS_ATTR_CAST ref;
  	/*
  	* Value constraint.
  	*/
  	if (defValue != NULL)
  	    use->defValue = defValue;
  	if (defValueType == WXS_ATTR_DEF_VAL_FIXED)
  	    use->flags |= XML_SCHEMA_ATTR_USE_FIXED;
      }
  
  check_children:
      /*
      * And now for the children...
      */
      child = node->children;
      if (occurs == XML_SCHEMAS_ATTR_USE_PROHIBITED) {
  	xmlSchemaAttributeUseProhibPtr prohib;
  
  	if (IS_SCHEMA(child, "annotation")) {
  	    xmlSchemaParseAnnotation(pctxt, child, 0);
  	    child = child->next;
  	}
  	if (child != NULL) {
  	    xmlSchemaPContentErr(pctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"(annotation?)");
  	}
  	/*
  	* Check for pointlessness of attribute prohibitions.
  	*/
  	if (parentType == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) {
  	    xmlSchemaCustomWarning(ACTXT_CAST pctxt,
  		XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH,
  		node, NULL,
  		"Skipping attribute use prohibition, since it is "
  		"pointless inside an <attributeGroup>",
  		NULL, NULL, NULL);
  	    return(NULL);
  	} else if (parentType == XML_SCHEMA_TYPE_EXTENSION) {
  	    xmlSchemaCustomWarning(ACTXT_CAST pctxt,
  		XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH,
  		node, NULL,
  		"Skipping attribute use prohibition, since it is "
  		"pointless when extending a type",
  		NULL, NULL, NULL);
  	    return(NULL);
  	}
  	if (! isRef) {
  	    tmpName = name;
  	    tmpNs = ns;
  	}
  	/*
  	* Check for duplicate attribute prohibitions.
  	*/
  	if (uses) {
  	    int i;
  
  	    for (i = 0; i < uses->nbItems; i++) {
  		use = uses->items[i];
  		if ((use->type == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB) &&
  		    (tmpName == (WXS_ATTR_PROHIB_CAST use)->name) &&
  		    (tmpNs == (WXS_ATTR_PROHIB_CAST use)->targetNamespace))
  		{
  		    xmlChar *str = NULL;
  
  		    xmlSchemaCustomWarning(ACTXT_CAST pctxt,
  			XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH,
  			node, NULL,
  			"Skipping duplicate attribute use prohibition '%s'",
  			xmlSchemaFormatQName(&str, tmpNs, tmpName),
  			NULL, NULL);
  		    FREE_AND_NULL(str)
  		    return(NULL);
  		}
  	    }
  	}
  	/*
  	* Create the attribute prohibition helper component.
  	*/
  	prohib = xmlSchemaAddAttributeUseProhib(pctxt);
  	if (prohib == NULL)
  	    return(NULL);
  	prohib->node = node;
  	prohib->name = tmpName;
  	prohib->targetNamespace = tmpNs;
  	if (isRef) {
  	    /*
  	    * We need at least to resolve to the attribute declaration.
  	    */
  	    WXS_ADD_PENDING(pctxt, prohib);
  	}
  	return(WXS_BASIC_CAST prohib);
      } else {
  	if (IS_SCHEMA(child, "annotation")) {
  	    /*
  	    * TODO: Should this go into the attr decl?
  	    */
  	    use->annot = xmlSchemaParseAnnotation(pctxt, child, 1);
  	    child = child->next;
  	}
  	if (isRef) {
  	    if (child != NULL) {
  		if (IS_SCHEMA(child, "simpleType"))
  		    /*
  		    * 3.2.3 : 3.2
  		    * If ref is present, then all of <simpleType>,
  		    * form and type must be absent.
  		    */
  		    xmlSchemaPContentErr(pctxt,
  			XML_SCHEMAP_SRC_ATTRIBUTE_3_2,
  			NULL, node, child, NULL,
  			"(annotation?)");
  		else
  		    xmlSchemaPContentErr(pctxt,
  			XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  			NULL, node, child, NULL,
  			"(annotation?)");
  	    }
  	} else {
  	    if (IS_SCHEMA(child, "simpleType")) {
  		if (WXS_ATTRUSE_DECL(use)->typeName != NULL) {
  		    /*
  		    * 3.2.3 : 4
  		    * type and <simpleType> must not both be present.
  		    */
  		    xmlSchemaPContentErr(pctxt, XML_SCHEMAP_SRC_ATTRIBUTE_4,
  			NULL, node, child,
  			"The attribute 'type' and the <simpleType> child "
  			"are mutually exclusive", NULL);
  		} else
  		    WXS_ATTRUSE_TYPEDEF(use) =
  			xmlSchemaParseSimpleType(pctxt, schema, child, 0);
  		child = child->next;
  	    }
  	    if (child != NULL)
  		xmlSchemaPContentErr(pctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"(annotation?, simpleType?)");
  	}
      }
      return (WXS_BASIC_CAST use);
  }
  
  
  static xmlSchemaAttributePtr
  xmlSchemaParseGlobalAttribute(xmlSchemaParserCtxtPtr pctxt,
  			      xmlSchemaPtr schema,
  			      xmlNodePtr node)
  {
      const xmlChar *attrValue;
      xmlSchemaAttributePtr ret;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
  
      /*
       * Note that the w3c spec assumes the schema to be validated with schema
       * for schemas beforehand.
       *
       * 3.2.3 Constraints on XML Representations of Attribute Declarations
       */
      if ((pctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
      /*
      * 3.2.3 : 3.1
      * One of ref or name must be present, but not both
      */
      attr = xmlSchemaGetPropNode(node, "name");
      if (attr == NULL) {
  	xmlSchemaPMissingAttrErr(pctxt, XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node, "name", NULL);
  	return (NULL);
      }
      if (xmlSchemaPValAttrNode(pctxt, NULL, attr,
  	xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &attrValue) != 0) {
  	return (NULL);
      }
      /*
      * 3.2.6 Schema Component Constraint: xmlns Not Allowed
      * TODO: Move this to the component layer.
      */
      if (xmlStrEqual(attrValue, BAD_CAST "xmlns")) {
  	xmlSchemaPSimpleTypeErr(pctxt,
  	    XML_SCHEMAP_NO_XMLNS,
  	    NULL, (xmlNodePtr) attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), NULL, NULL,
  	    "The value of the attribute must not match 'xmlns'",
  	    NULL, NULL);
  	return (NULL);
      }
      /*
      * 3.2.6 Schema Component Constraint: xsi: Not Allowed
      * TODO: Move this to the component layer.
      *       Or better leave it here and add it to the component layer
      *       if we have a schema construction API.
      */
      if (xmlStrEqual(pctxt->targetNamespace, xmlSchemaInstanceNs)) {
  	xmlSchemaCustomErr(ACTXT_CAST pctxt,
  	    XML_SCHEMAP_NO_XSI, node, NULL,
  	    "The target namespace must not match '%s'",
  	    xmlSchemaInstanceNs, NULL);
      }
  
      ret = xmlSchemaAddAttribute(pctxt, schema, attrValue,
  	pctxt->targetNamespace, node, 1);
      if (ret == NULL)
  	return (NULL);
      ret->flags |= XML_SCHEMAS_ATTR_GLOBAL;
  
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "default")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "fixed")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "name")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "type")))
  	    {
  		xmlSchemaPIllegalAttrErr(pctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(pctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      xmlSchemaPValAttrQName(pctxt, schema, NULL,
  	node, "type", &ret->typeNs, &ret->typeName);
  
      xmlSchemaPValAttrID(pctxt, node, BAD_CAST "id");
      /*
      * Attribute "fixed".
      */
      ret->defValue = xmlSchemaGetProp(pctxt, node, "fixed");
      if (ret->defValue != NULL)
  	ret->flags |= XML_SCHEMAS_ATTR_FIXED;
      /*
      * Attribute "default".
      */
      attr = xmlSchemaGetPropNode(node, "default");
      if (attr != NULL) {
  	/*
  	* 3.2.3 : 1
  	* default and fixed must not both be present.
  	*/
  	if (ret->flags & XML_SCHEMAS_ATTR_FIXED) {
  	    xmlSchemaPMutualExclAttrErr(pctxt, XML_SCHEMAP_SRC_ATTRIBUTE_1,
  		WXS_BASIC_CAST ret, attr, "default", "fixed");
  	} else
  	    ret->defValue = xmlSchemaGetNodeContent(pctxt, (xmlNodePtr) attr);
      }
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          ret->annot = xmlSchemaParseAnnotation(pctxt, child, 1);
          child = child->next;
      }
      if (IS_SCHEMA(child, "simpleType")) {
  	if (ret->typeName != NULL) {
  	    /*
  	    * 3.2.3 : 4
  	    * type and <simpleType> must not both be present.
  	    */
  	    xmlSchemaPContentErr(pctxt, XML_SCHEMAP_SRC_ATTRIBUTE_4,
  		NULL, node, child,
  		"The attribute 'type' and the <simpleType> child "
  		"are mutually exclusive", NULL);
  	} else
  	    ret->subtypes = xmlSchemaParseSimpleType(pctxt, schema, child, 0);
  	child = child->next;
      }
      if (child != NULL)
  	xmlSchemaPContentErr(pctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL,
  	    "(annotation?, simpleType?)");
  
      return (ret);
  }
  
  /**
   * xmlSchemaParseAttributeGroupRef:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * Parse an attribute group definition reference.
   * Note that a reference to an attribute group does not
   * correspond to any component at all.
   * *WARNING* this interface is highly subject to change
   *
   * Returns the attribute group or NULL in case of error.
   */
  static xmlSchemaQNameRefPtr
  xmlSchemaParseAttributeGroupRef(xmlSchemaParserCtxtPtr pctxt,
  				xmlSchemaPtr schema,
  				xmlNodePtr node)
  {
      xmlSchemaQNameRefPtr ret;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      const xmlChar *refNs = NULL, *ref = NULL;
  
      if ((pctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      attr = xmlSchemaGetPropNode(node, "ref");
      if (attr == NULL) {
  	xmlSchemaPMissingAttrErr(pctxt,
  	    XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node, "ref", NULL);
  	return (NULL);
      }
      xmlSchemaPValAttrNodeQName(pctxt, schema,
  	NULL, attr, &refNs, &ref);
      if (xmlSchemaCheckReference(pctxt, schema, node, attr, refNs) != 0)
  	return(NULL);
  
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "ref")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "id")))
  	    {
  		xmlSchemaPIllegalAttrErr(pctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(pctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      /* Attribute ID */
      xmlSchemaPValAttrID(pctxt, node, BAD_CAST "id");
  
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	/*
  	* TODO: We do not have a place to store the annotation, do we?
  	*/
          xmlSchemaParseAnnotation(pctxt, child, 0);
          child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(pctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL,
  	    "(annotation?)");
      }
  
      /*
      * Handle attribute group redefinitions.
      */
      if (pctxt->isRedefine && pctxt->redef &&
  	(pctxt->redef->item->type ==
  	    XML_SCHEMA_TYPE_ATTRIBUTEGROUP) &&
  	(ref == pctxt->redef->refName) &&
  	(refNs == pctxt->redef->refTargetNs))
      {
  	/*
  	* SPEC src-redefine:
  	* (7.1) "If it has an <attributeGroup> among its contents
  	* the `actual value` of whose ref [attribute] is the same
  	* as the `actual value` of its own name attribute plus
  	* target namespace, then it must have exactly one such group."
  	*/
  	if (pctxt->redefCounter != 0) {
  	    xmlChar *str = NULL;
  
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		XML_SCHEMAP_SRC_REDEFINE, node, NULL,
  		"The redefining attribute group definition "
  		"'%s' must not contain more than one "
  		"reference to the redefined definition",
  		xmlSchemaFormatQName(&str, refNs, ref), NULL);
  	    FREE_AND_NULL(str);
  	    return(NULL);
  	}
  	pctxt->redefCounter++;
  	/*
  	* URGENT TODO: How to ensure that the reference will not be
  	* handled by the normal component resolution mechanism?
  	*/
  	ret = xmlSchemaNewQNameRef(pctxt,
  	    XML_SCHEMA_TYPE_ATTRIBUTEGROUP, ref, refNs);
  	if (ret == NULL)
  	    return(NULL);
  	ret->node = node;
  	pctxt->redef->reference = WXS_BASIC_CAST ret;
      } else {
  	/*
  	* Create a QName-reference helper component. We will substitute this
  	* component for the attribute uses of the referenced attribute group
  	* definition.
  	*/
  	ret = xmlSchemaNewQNameRef(pctxt,
  	    XML_SCHEMA_TYPE_ATTRIBUTEGROUP, ref, refNs);
  	if (ret == NULL)
  	    return(NULL);
  	ret->node = node;
  	/* Add to pending items, to be able to resolve the reference. */
  	WXS_ADD_PENDING(pctxt, ret);
      }
      return (ret);
  }
  
  /**
   * xmlSchemaParseAttributeGroupDefinition:
   * @pctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema Attribute Group declaration
   * *WARNING* this interface is highly subject to change
   *
   * Returns the attribute group definition or NULL in case of error.
   */
  static xmlSchemaAttributeGroupPtr
  xmlSchemaParseAttributeGroupDefinition(xmlSchemaParserCtxtPtr pctxt,
  				       xmlSchemaPtr schema,
  				       xmlNodePtr node)
  {
      const xmlChar *name;
      xmlSchemaAttributeGroupPtr ret;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      int hasRefs = 0;
  
      if ((pctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      attr = xmlSchemaGetPropNode(node, "name");
      if (attr == NULL) {
  	xmlSchemaPMissingAttrErr(pctxt,
  	    XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node, "name", NULL);
  	return (NULL);
      }
      /*
      * The name is crucial, exit if invalid.
      */
      if (xmlSchemaPValAttrNode(pctxt,
  	NULL, attr,
  	xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) {
  	return (NULL);
      }
      ret = xmlSchemaAddAttributeGroupDefinition(pctxt, schema,
  	name, pctxt->targetNamespace, node);
      if (ret == NULL)
  	return (NULL);
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "name")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "id")))
  	    {
  		xmlSchemaPIllegalAttrErr(pctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(pctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      /* Attribute ID */
      xmlSchemaPValAttrID(pctxt, node, BAD_CAST "id");
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          ret->annot = xmlSchemaParseAnnotation(pctxt, child, 1);
          child = child->next;
      }
      /*
      * Parse contained attribute decls/refs.
      */
      if (xmlSchemaParseLocalAttributes(pctxt, schema, &child,
  	(xmlSchemaItemListPtr *) &(ret->attrUses),
  	XML_SCHEMA_TYPE_ATTRIBUTEGROUP, &hasRefs) == -1)
  	return(NULL);
      if (hasRefs)
  	ret->flags |= XML_SCHEMAS_ATTRGROUP_HAS_REFS;
      /*
      * Parse the attribute wildcard.
      */
      if (IS_SCHEMA(child, "anyAttribute")) {
  	ret->attributeWildcard = xmlSchemaParseAnyAttribute(pctxt,
  	    schema, child);
  	child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(pctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL,
  	    "(annotation?, ((attribute | attributeGroup)*, anyAttribute?))");
      }
      return (ret);
  }
  
  /**
   * xmlSchemaPValAttrFormDefault:
   * @value:  the value
   * @flags: the flags to be modified
   * @flagQualified: the specific flag for "qualified"
   *
   * Returns 0 if the value is valid, 1 otherwise.
   */
  static int
  xmlSchemaPValAttrFormDefault(const xmlChar *value,
  			     int *flags,
  			     int flagQualified)
  {
      if (xmlStrEqual(value, BAD_CAST "qualified")) {
  	if  ((*flags & flagQualified) == 0)
  	    *flags |= flagQualified;
      } else if (!xmlStrEqual(value, BAD_CAST "unqualified"))
  	return (1);
  
      return (0);
  }
  
  /**
   * xmlSchemaPValAttrBlockFinal:
   * @value:  the value
   * @flags: the flags to be modified
   * @flagAll: the specific flag for "#all"
   * @flagExtension: the specific flag for "extension"
   * @flagRestriction: the specific flag for "restriction"
   * @flagSubstitution: the specific flag for "substitution"
   * @flagList: the specific flag for "list"
   * @flagUnion: the specific flag for "union"
   *
   * Validates the value of the attribute "final" and "block". The value
   * is converted into the specified flag values and returned in @flags.
   *
   * Returns 0 if the value is valid, 1 otherwise.
   */
  
  static int
  xmlSchemaPValAttrBlockFinal(const xmlChar *value,
  			    int *flags,
  			    int flagAll,
  			    int flagExtension,
  			    int flagRestriction,
  			    int flagSubstitution,
  			    int flagList,
  			    int flagUnion)
  {
      int ret = 0;
  
      /*
      * TODO: This does not check for duplicate entries.
      */
      if ((flags == NULL) || (value == NULL))
  	return (-1);
      if (value[0] == 0)
  	return (0);
      if (xmlStrEqual(value, BAD_CAST "#all")) {
  	if (flagAll != -1)
  	    *flags |= flagAll;
  	else {
  	    if (flagExtension != -1)
  		*flags |= flagExtension;
  	    if (flagRestriction != -1)
  		*flags |= flagRestriction;
  	    if (flagSubstitution != -1)
  		*flags |= flagSubstitution;
  	    if (flagList != -1)
  		*flags |= flagList;
  	    if (flagUnion != -1)
  		*flags |= flagUnion;
  	}
      } else {
  	const xmlChar *end, *cur = value;
  	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 (flagExtension != -1) {
  		    if ((*flags & flagExtension) == 0)
  			*flags |= flagExtension;
  		} else
  		    ret = 1;
  	    } else if (xmlStrEqual(item, BAD_CAST "restriction")) {
  		if (flagRestriction != -1) {
  		    if ((*flags & flagRestriction) == 0)
  			*flags |= flagRestriction;
  		} else
  		    ret = 1;
  	    } else if (xmlStrEqual(item, BAD_CAST "substitution")) {
  		if (flagSubstitution != -1) {
  		    if ((*flags & flagSubstitution) == 0)
  			*flags |= flagSubstitution;
  		} else
  		    ret = 1;
  	    } else if (xmlStrEqual(item, BAD_CAST "list")) {
  		if (flagList != -1) {
  		    if ((*flags & flagList) == 0)
  			*flags |= flagList;
  		} else
  		    ret = 1;
  	    } else if (xmlStrEqual(item, BAD_CAST "union")) {
  		if (flagUnion != -1) {
  		    if ((*flags & flagUnion) == 0)
  			*flags |= flagUnion;
  		} else
  		    ret = 1;
  	    } else
  		ret = 1;
  	    if (item != NULL)
  		xmlFree(item);
  	    cur = end;
  	} while ((ret == 0) && (*cur != 0));
      }
  
      return (ret);
  }
  
  static int
  xmlSchemaCheckCSelectorXPath(xmlSchemaParserCtxtPtr ctxt,
  			     xmlSchemaIDCPtr idc,
  			     xmlSchemaIDCSelectPtr selector,
  			     xmlAttrPtr attr,
  			     int isField)
  {
      xmlNodePtr node;
  
      /*
      * c-selector-xpath:
      * Schema Component Constraint: Selector Value OK
      *
      * TODO: 1 The {selector} must be a valid XPath expression, as defined
      * in [XPath].
      */
      if (selector == NULL) {
  	xmlSchemaPErr(ctxt, idc->node,
  	    XML_SCHEMAP_INTERNAL,
  	    "Internal error: xmlSchemaCheckCSelectorXPath, "
  	    "the selector is not specified.\n", NULL, NULL);
  	return (-1);
      }
      if (attr == NULL)
  	node = idc->node;
      else
  	node = (xmlNodePtr) attr;
      if (selector->xpath == NULL) {
  	xmlSchemaPCustomErr(ctxt,
  	    /* TODO: Adjust error code. */
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    NULL, node,
  	    "The XPath expression of the selector is not valid", NULL);
  	return (XML_SCHEMAP_S4S_ATTR_INVALID_VALUE);
      } else {
  	const xmlChar **nsArray = NULL;
  	xmlNsPtr *nsList = NULL;
  	/*
  	* Compile the XPath expression.
  	*/
  	/*
  	* TODO: We need the array of in-scope namespaces for compilation.
  	* TODO: Call xmlPatterncompile with different options for selector/
  	* field.
  	*/
  	if (attr == NULL)
  	    nsList = NULL;
  	else
  	    nsList = xmlGetNsList(attr->doc, attr->parent);
  	/*
  	* Build an array of prefixes and namespaces.
  	*/
  	if (nsList != NULL) {
  	    int i, count = 0;
  
  	    for (i = 0; nsList[i] != NULL; i++)
  		count++;
  
  	    nsArray = (const xmlChar **) xmlMalloc(
  		(count * 2 + 1) * sizeof(const xmlChar *));
  	    if (nsArray == NULL) {
  		xmlSchemaPErrMemory(ctxt, "allocating a namespace array",
  		    NULL);
  		xmlFree(nsList);
  		return (-1);
  	    }
  	    for (i = 0; i < count; i++) {
  		nsArray[2 * i] = nsList[i]->href;
  		nsArray[2 * i + 1] = nsList[i]->prefix;
  	    }
  	    nsArray[count * 2] = NULL;
  	    xmlFree(nsList);
  	}
  	/*
  	* TODO: Differentiate between "selector" and "field".
  	*/
  	if (isField)
  	    selector->xpathComp = (void *) xmlPatterncompile(selector->xpath,
  		NULL, XML_PATTERN_XSFIELD, nsArray);
  	else
  	    selector->xpathComp = (void *) xmlPatterncompile(selector->xpath,
  		NULL, XML_PATTERN_XSSEL, nsArray);
  	if (nsArray != NULL)
  	    xmlFree((xmlChar **) nsArray);
  
  	if (selector->xpathComp == NULL) {
  	    xmlSchemaPCustomErr(ctxt,
  		/* TODO: Adjust error code? */
  		XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  		NULL, node,
  		"The XPath expression '%s' could not be "
  		"compiled", selector->xpath);
  	    return (XML_SCHEMAP_S4S_ATTR_INVALID_VALUE);
  	}
      }
      return (0);
  }
  
  #define ADD_ANNOTATION(annot)   \
      xmlSchemaAnnotPtr cur = item->annot; \
      if (item->annot == NULL) {  \
  	item->annot = annot;    \
  	return (annot);         \
      }                           \
      cur = item->annot;          \
      if (cur->next != NULL) {    \
  	cur = cur->next;	\
      }                           \
      cur->next = annot;
  
  /**
   * xmlSchemaAssignAnnotation:
   * @item: the schema component
   * @annot: the annotation
   *
   * Adds the annotation to the given schema component.
   *
   * Returns the given annotation.
   */
  static xmlSchemaAnnotPtr
  xmlSchemaAddAnnotation(xmlSchemaAnnotItemPtr annItem,
  		       xmlSchemaAnnotPtr annot)
  {
      if ((annItem == NULL) || (annot == NULL))
  	return (NULL);
      switch (annItem->type) {
  	case XML_SCHEMA_TYPE_ELEMENT: {
  		xmlSchemaElementPtr item = (xmlSchemaElementPtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_ATTRIBUTE: {
  		xmlSchemaAttributePtr item = (xmlSchemaAttributePtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_ANY_ATTRIBUTE:
  	case XML_SCHEMA_TYPE_ANY: {
  		xmlSchemaWildcardPtr item = (xmlSchemaWildcardPtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_PARTICLE:
  	case XML_SCHEMA_TYPE_IDC_KEY:
  	case XML_SCHEMA_TYPE_IDC_KEYREF:
  	case XML_SCHEMA_TYPE_IDC_UNIQUE: {
  		xmlSchemaAnnotItemPtr item = (xmlSchemaAnnotItemPtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_ATTRIBUTEGROUP: {
  		xmlSchemaAttributeGroupPtr item =
  		    (xmlSchemaAttributeGroupPtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_NOTATION: {
  		xmlSchemaNotationPtr item = (xmlSchemaNotationPtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_FACET_MININCLUSIVE:
  	case XML_SCHEMA_FACET_MINEXCLUSIVE:
  	case XML_SCHEMA_FACET_MAXINCLUSIVE:
  	case XML_SCHEMA_FACET_MAXEXCLUSIVE:
  	case XML_SCHEMA_FACET_TOTALDIGITS:
  	case XML_SCHEMA_FACET_FRACTIONDIGITS:
  	case XML_SCHEMA_FACET_PATTERN:
  	case XML_SCHEMA_FACET_ENUMERATION:
  	case XML_SCHEMA_FACET_WHITESPACE:
  	case XML_SCHEMA_FACET_LENGTH:
  	case XML_SCHEMA_FACET_MAXLENGTH:
  	case XML_SCHEMA_FACET_MINLENGTH: {
  		xmlSchemaFacetPtr item = (xmlSchemaFacetPtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_SIMPLE:
  	case XML_SCHEMA_TYPE_COMPLEX: {
  		xmlSchemaTypePtr item = (xmlSchemaTypePtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_GROUP: {
  		xmlSchemaModelGroupDefPtr item = (xmlSchemaModelGroupDefPtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	case XML_SCHEMA_TYPE_SEQUENCE:
  	case XML_SCHEMA_TYPE_CHOICE:
  	case XML_SCHEMA_TYPE_ALL: {
  		xmlSchemaModelGroupPtr item = (xmlSchemaModelGroupPtr) annItem;
  		ADD_ANNOTATION(annot)
  	    }
  	    break;
  	default:
  	     xmlSchemaPCustomErr(NULL,
  		XML_SCHEMAP_INTERNAL,
  		NULL, NULL,
  		"Internal error: xmlSchemaAddAnnotation, "
  		"The item is not a annotated schema component", NULL);
  	     break;
      }
      return (annot);
  }
  
  /**
   * xmlSchemaParseIDCSelectorAndField:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * Parses a XML Schema identity-constraint definition's
   * <selector> and <field> elements.
   *
   * Returns the parsed identity-constraint definition.
   */
  static xmlSchemaIDCSelectPtr
  xmlSchemaParseIDCSelectorAndField(xmlSchemaParserCtxtPtr ctxt,
  			  xmlSchemaIDCPtr idc,
  			  xmlNodePtr node,
  			  int isField)
  {
      xmlSchemaIDCSelectPtr item;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
  
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "xpath"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      /*
      * Create the item.
      */
      item = (xmlSchemaIDCSelectPtr) xmlMalloc(sizeof(xmlSchemaIDCSelect));
      if (item == NULL) {
          xmlSchemaPErrMemory(ctxt,
  	    "allocating a 'selector' of an identity-constraint definition",
  	    NULL);
          return (NULL);
      }
      memset(item, 0, sizeof(xmlSchemaIDCSelect));
      /*
      * Attribute "xpath" (mandatory).
      */
      attr = xmlSchemaGetPropNode(node, "xpath");
      if (attr == NULL) {
  	xmlSchemaPMissingAttrErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node,
  	    "name", NULL);
      } else {
  	item->xpath = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  	/*
  	* URGENT TODO: "field"s have an other syntax than "selector"s.
  	*/
  
  	if (xmlSchemaCheckCSelectorXPath(ctxt, idc, item, attr,
  	    isField) == -1) {
  	    xmlSchemaPErr(ctxt,
  		(xmlNodePtr) attr,
  		XML_SCHEMAP_INTERNAL,
  		"Internal error: xmlSchemaParseIDCSelectorAndField, "
  		"validating the XPath expression of a IDC selector.\n",
  		NULL, NULL);
  	}
  
      }
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	/*
  	* Add the annotation to the parent IDC.
  	*/
  	xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) idc,
  	    xmlSchemaParseAnnotation(ctxt, child, 1));
  	child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child,
  	    NULL, "(annotation?)");
      }
  
      return (item);
  }
  
  /**
   * xmlSchemaParseIDC:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * Parses a XML Schema identity-constraint definition.
   *
   * Returns the parsed identity-constraint definition.
   */
  static xmlSchemaIDCPtr
  xmlSchemaParseIDC(xmlSchemaParserCtxtPtr ctxt,
  		  xmlSchemaPtr schema,
  		  xmlNodePtr node,
  		  xmlSchemaTypeType idcCategory,
  		  const xmlChar *targetNamespace)
  {
      xmlSchemaIDCPtr item = NULL;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      const xmlChar *name = NULL;
      xmlSchemaIDCSelectPtr field = NULL, lastField = NULL;
  
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "name")) &&
  		((idcCategory != XML_SCHEMA_TYPE_IDC_KEYREF) ||
  		 (!xmlStrEqual(attr->name, BAD_CAST "refer")))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      /*
      * Attribute "name" (mandatory).
      */
      attr = xmlSchemaGetPropNode(node, "name");
      if (attr == NULL) {
  	xmlSchemaPMissingAttrErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node,
  	    "name", NULL);
  	return (NULL);
      } else if (xmlSchemaPValAttrNode(ctxt,
  	NULL, attr,
  	xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) {
  	return (NULL);
      }
      /* Create the component. */
      item = xmlSchemaAddIDC(ctxt, schema, name, targetNamespace,
  	idcCategory, node);
      if (item == NULL)
  	return(NULL);
  
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      if (idcCategory == XML_SCHEMA_TYPE_IDC_KEYREF) {
  	/*
  	* Attribute "refer" (mandatory).
  	*/
  	attr = xmlSchemaGetPropNode(node, "refer");
  	if (attr == NULL) {
  	    xmlSchemaPMissingAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_MISSING,
  		NULL, node,
  		"refer", NULL);
  	} else {
  	    /*
  	    * Create a reference item.
  	    */
  	    item->ref = xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_IDC_KEY,
  		NULL, NULL);
  	    if (item->ref == NULL)
  		return (NULL);
  	    xmlSchemaPValAttrNodeQName(ctxt, schema,
  		NULL, attr,
  		&(item->ref->targetNamespace),
  		&(item->ref->name));
  	    xmlSchemaCheckReference(ctxt, schema, node, attr,
  		item->ref->targetNamespace);
  	}
      }
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	item->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
  	child = child->next;
      }
      if (child == NULL) {
  	xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_MISSING,
  		NULL, node, child,
  		"A child element is missing",
  		"(annotation?, (selector, field+))");
      }
      /*
      * Child element <selector>.
      */
      if (IS_SCHEMA(child, "selector")) {
  	item->selector = xmlSchemaParseIDCSelectorAndField(ctxt,
  	    item, child, 0);
  	child = child->next;
  	/*
  	* Child elements <field>.
  	*/
  	if (IS_SCHEMA(child, "field")) {
  	    do {
  		field = xmlSchemaParseIDCSelectorAndField(ctxt,
  		    item, child, 1);
  		if (field != NULL) {
  		    field->index = item->nbFields;
  		    item->nbFields++;
  		    if (lastField != NULL)
  			lastField->next = field;
  		    else
  			item->fields = field;
  		    lastField = field;
  		}
  		child = child->next;
  	    } while (IS_SCHEMA(child, "field"));
  	} else {
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child,
  		NULL, "(annotation?, (selector, field+))");
  	}
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child,
  	    NULL, "(annotation?, (selector, field+))");
      }
  
      return (item);
  }
  
  /**
   * xmlSchemaParseElement:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   * @topLevel: indicates if this is global declaration
   *
   * Parses a XML schema element declaration.
   * *WARNING* this interface is highly subject to change
   *
   * Returns the element declaration or a particle; NULL in case
   * of an error or if the particle has minOccurs==maxOccurs==0.
   */
  static xmlSchemaBasicItemPtr
  xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                        xmlNodePtr node, int *isElemRef, int topLevel)
  {
      xmlSchemaElementPtr decl = NULL;
      xmlSchemaParticlePtr particle = NULL;
      xmlSchemaAnnotPtr annot = NULL;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr, nameAttr;
      int min, max, isRef = 0;
      xmlChar *des = NULL;
  
      /* 3.3.3 Constraints on XML Representations of Element Declarations */
      /* TODO: Complete implementation of 3.3.6 */
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      if (isElemRef != NULL)
  	*isElemRef = 0;
      /*
      * If we get a "ref" attribute on a local <element> we will assume it's
      * a reference - even if there's a "name" attribute; this seems to be more
      * robust.
      */
      nameAttr = xmlSchemaGetPropNode(node, "name");
      attr = xmlSchemaGetPropNode(node, "ref");
      if ((topLevel) || (attr == NULL)) {
  	if (nameAttr == NULL) {
  	    xmlSchemaPMissingAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_MISSING,
  		NULL, node, "name", NULL);
  	    return (NULL);
  	}
      } else
  	isRef = 1;
  
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	annot = xmlSchemaParseAnnotation(ctxt, child, 1);
  	child = child->next;
      }
      /*
      * Skip particle part if a global declaration.
      */
      if (topLevel)
  	goto declaration_part;
      /*
      * The particle part ==================================================
      */
      min = xmlGetMinOccurs(ctxt, node, 0, -1, 1, "xs:nonNegativeInteger");
      max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1, "(xs:nonNegativeInteger | unbounded)");
      xmlSchemaPCheckParticleCorrect_2(ctxt, NULL, node, min, max);
      particle = xmlSchemaAddParticle(ctxt, node, min, max);
      if (particle == NULL)
  	goto return_null;
  
      /* ret->flags |= XML_SCHEMAS_ELEM_REF; */
  
      if (isRef) {
  	const xmlChar *refNs = NULL, *ref = NULL;
  	xmlSchemaQNameRefPtr refer = NULL;
  	/*
  	* The reference part =============================================
  	*/
  	if (isElemRef != NULL)
  	    *isElemRef = 1;
  
  	xmlSchemaPValAttrNodeQName(ctxt, schema,
  	    NULL, attr, &refNs, &ref);
  	xmlSchemaCheckReference(ctxt, schema, node, attr, refNs);
  	/*
  	* SPEC (3.3.3 : 2.1) "One of ref or name must be present, but not both"
  	*/
  	if (nameAttr != NULL) {
  	    xmlSchemaPMutualExclAttrErr(ctxt,
  		XML_SCHEMAP_SRC_ELEMENT_2_1, NULL, nameAttr, "ref", "name");
  	}
  	/*
  	* Check for illegal attributes.
  	*/
  	attr = node->properties;
  	while (attr != NULL) {
  	    if (attr->ns == NULL) {
  		if (xmlStrEqual(attr->name, BAD_CAST "ref") ||
  		    xmlStrEqual(attr->name, BAD_CAST "name") ||
  		    xmlStrEqual(attr->name, BAD_CAST "id") ||
  		    xmlStrEqual(attr->name, BAD_CAST "maxOccurs") ||
  		    xmlStrEqual(attr->name, BAD_CAST "minOccurs"))
  		{
  		    attr = attr->next;
  		    continue;
  		} else {
  		    /* SPEC (3.3.3 : 2.2) */
  		    xmlSchemaPCustomAttrErr(ctxt,
  			XML_SCHEMAP_SRC_ELEMENT_2_2,
  			NULL, NULL, attr,
  			"Only the attributes 'minOccurs', 'maxOccurs' and "
  			"'id' are allowed in addition to 'ref'");
  		    break;
  		}
  	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	    attr = attr->next;
  	}
  	/*
  	* No children except <annotation> expected.
  	*/
  	if (child != NULL) {
  	    xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL, "(annotation?)");
  	}
  	if ((min == 0) && (max == 0))
  	    goto return_null;
  	/*
  	* Create the reference item and attach it to the particle.
  	*/
  	refer = xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_ELEMENT,
  	    ref, refNs);
  	if (refer == NULL)
  	    goto return_null;
  	particle->children = (xmlSchemaTreeItemPtr) refer;
  	particle->annot = annot;
  	/*
  	* Add the particle to pending components, since the reference
  	* need to be resolved.
  	*/
  	WXS_ADD_PENDING(ctxt, particle);
  	return ((xmlSchemaBasicItemPtr) particle);
      }
      /*
      * The declaration part ===============================================
      */
  declaration_part:
      {
  	const xmlChar *ns = NULL, *fixed, *name, *attrValue;
  	xmlSchemaIDCPtr curIDC = NULL, lastIDC = NULL;
  
  	if (xmlSchemaPValAttrNode(ctxt, NULL, nameAttr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0)
  	    goto return_null;
  	/*
  	* Evaluate the target namespace.
  	*/
  	if (topLevel) {
  	    ns = ctxt->targetNamespace;
  	} else {
  	    attr = xmlSchemaGetPropNode(node, "form");
  	    if (attr != NULL) {
  		attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  		if (xmlStrEqual(attrValue, BAD_CAST "qualified")) {
  		    ns = ctxt->targetNamespace;
  		} else if (!xmlStrEqual(attrValue, BAD_CAST "unqualified")) {
  		    xmlSchemaPSimpleTypeErr(ctxt,
  			XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  			NULL, (xmlNodePtr) attr,
  			NULL, "(qualified | unqualified)",
  			attrValue, NULL, NULL, NULL);
  		}
  	    } else if (schema->flags & XML_SCHEMAS_QUALIF_ELEM)
  		ns = ctxt->targetNamespace;
  	}
  	decl = xmlSchemaAddElement(ctxt, name, ns, node, topLevel);
  	if (decl == NULL) {
  	    goto return_null;
  	}
  	/*
  	* Check for illegal attributes.
  	*/
  	attr = node->properties;
  	while (attr != NULL) {
  	    if (attr->ns == NULL) {
  		if ((!xmlStrEqual(attr->name, BAD_CAST "name")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "type")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "default")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "fixed")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "block")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "nillable")))
  		{
  		    if (topLevel == 0) {
  			if ((!xmlStrEqual(attr->name, BAD_CAST "maxOccurs")) &&
  			    (!xmlStrEqual(attr->name, BAD_CAST "minOccurs")) &&
  			    (!xmlStrEqual(attr->name, BAD_CAST "form")))
  			{
  			    xmlSchemaPIllegalAttrErr(ctxt,
  				XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  			}
  		    } else if ((!xmlStrEqual(attr->name, BAD_CAST "final")) &&
  			(!xmlStrEqual(attr->name, BAD_CAST "abstract")) &&
  			(!xmlStrEqual(attr->name, BAD_CAST "substitutionGroup"))) {
  
  			xmlSchemaPIllegalAttrErr(ctxt,
  			    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		    }
  		}
  	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	    attr = attr->next;
  	}
  	/*
  	* Extract/validate attributes.
  	*/
  	if (topLevel) {
  	    /*
  	    * Process top attributes of global element declarations here.
  	    */
  	    decl->flags |= XML_SCHEMAS_ELEM_GLOBAL;
  	    decl->flags |= XML_SCHEMAS_ELEM_TOPLEVEL;
  	    xmlSchemaPValAttrQName(ctxt, schema,
  		NULL, node, "substitutionGroup",
  		&(decl->substGroupNs), &(decl->substGroup));
  	    if (xmlGetBooleanProp(ctxt, node, "abstract", 0))
  		decl->flags |= XML_SCHEMAS_ELEM_ABSTRACT;
  	    /*
  	    * Attribute "final".
  	    */
  	    attr = xmlSchemaGetPropNode(node, "final");
  	    if (attr == NULL) {
  		if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_EXTENSION)
  		    decl->flags |= XML_SCHEMAS_ELEM_FINAL_EXTENSION;
  		if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION)
  		    decl->flags |= XML_SCHEMAS_ELEM_FINAL_RESTRICTION;
  	    } else {
  		attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  		if (xmlSchemaPValAttrBlockFinal(attrValue, &(decl->flags),
  		    -1,
  		    XML_SCHEMAS_ELEM_FINAL_EXTENSION,
  		    XML_SCHEMAS_ELEM_FINAL_RESTRICTION, -1, -1, -1) != 0) {
  		    xmlSchemaPSimpleTypeErr(ctxt,
  			XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  			NULL, (xmlNodePtr) attr,
  			NULL, "(#all | List of (extension | restriction))",
  			attrValue, NULL, NULL, NULL);
  		}
  	    }
  	}
  	/*
  	* Attribute "block".
  	*/
  	attr = xmlSchemaGetPropNode(node, "block");
  	if (attr == NULL) {
  	    /*
  	    * Apply default "block" values.
  	    */
  	    if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION)
  		decl->flags |= XML_SCHEMAS_ELEM_BLOCK_RESTRICTION;
  	    if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION)
  		decl->flags |= XML_SCHEMAS_ELEM_BLOCK_EXTENSION;
  	    if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION)
  		decl->flags |= XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION;
  	} else {
  	    attrValue = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  	    if (xmlSchemaPValAttrBlockFinal(attrValue, &(decl->flags),
  		-1,
  		XML_SCHEMAS_ELEM_BLOCK_EXTENSION,
  		XML_SCHEMAS_ELEM_BLOCK_RESTRICTION,
  		XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION, -1, -1) != 0) {
  		xmlSchemaPSimpleTypeErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  		    NULL, (xmlNodePtr) attr,
  		    NULL, "(#all | List of (extension | "
  		    "restriction | substitution))", attrValue,
  		    NULL, NULL, NULL);
  	    }
  	}
  	if (xmlGetBooleanProp(ctxt, node, "nillable", 0))
  	    decl->flags |= XML_SCHEMAS_ELEM_NILLABLE;
  
  	attr = xmlSchemaGetPropNode(node, "type");
  	if (attr != NULL) {
  	    xmlSchemaPValAttrNodeQName(ctxt, schema,
  		NULL, attr,
  		&(decl->namedTypeNs), &(decl->namedType));
  	    xmlSchemaCheckReference(ctxt, schema, node,
  		attr, decl->namedTypeNs);
  	}
  	decl->value = xmlSchemaGetProp(ctxt, node, "default");
  	attr = xmlSchemaGetPropNode(node, "fixed");
  	if (attr != NULL) {
  	    fixed = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  	    if (decl->value != NULL) {
  		/*
  		* 3.3.3 : 1
  		* default and fixed must not both be present.
  		*/
  		xmlSchemaPMutualExclAttrErr(ctxt,
  		    XML_SCHEMAP_SRC_ELEMENT_1,
  		    NULL, attr, "default", "fixed");
  	    } else {
  		decl->flags |= XML_SCHEMAS_ELEM_FIXED;
  		decl->value = fixed;
  	    }
  	}
  	/*
  	* And now for the children...
  	*/
  	if (IS_SCHEMA(child, "complexType")) {
  	    /*
  	    * 3.3.3 : 3
  	    * "type" and either <simpleType> or <complexType> are mutually
  	    * exclusive
  	    */
  	    if (decl->namedType != NULL) {
  		xmlSchemaPContentErr(ctxt,
  		    XML_SCHEMAP_SRC_ELEMENT_3,
  		    NULL, node, child,
  		    "The attribute 'type' and the <complexType> child are "
  		    "mutually exclusive", NULL);
  	    } else
  		WXS_ELEM_TYPEDEF(decl) = xmlSchemaParseComplexType(ctxt, schema, child, 0);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "simpleType")) {
  	    /*
  	    * 3.3.3 : 3
  	    * "type" and either <simpleType> or <complexType> are
  	    * mutually exclusive
  	    */
  	    if (decl->namedType != NULL) {
  		xmlSchemaPContentErr(ctxt,
  		    XML_SCHEMAP_SRC_ELEMENT_3,
  		    NULL, node, child,
  		    "The attribute 'type' and the <simpleType> child are "
  		    "mutually exclusive", NULL);
  	    } else
  		WXS_ELEM_TYPEDEF(decl) = xmlSchemaParseSimpleType(ctxt, schema, child, 0);
  	    child = child->next;
  	}
  	while ((IS_SCHEMA(child, "unique")) ||
  	    (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) {
  	    if (IS_SCHEMA(child, "unique")) {
  		curIDC = xmlSchemaParseIDC(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_IDC_UNIQUE, decl->targetNamespace);
  	    } else if (IS_SCHEMA(child, "key")) {
  		curIDC = xmlSchemaParseIDC(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_IDC_KEY, decl->targetNamespace);
  	    } else if (IS_SCHEMA(child, "keyref")) {
  		curIDC = xmlSchemaParseIDC(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_IDC_KEYREF, decl->targetNamespace);
  	    }
  	    if (lastIDC != NULL)
  		lastIDC->next = curIDC;
  	    else
  		decl->idcs = (void *) curIDC;
  	    lastIDC = curIDC;
  	    child = child->next;
  	}
  	if (child != NULL) {
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child,
  		NULL, "(annotation?, ((simpleType | complexType)?, "
  		"(unique | key | keyref)*))");
  	}
  	decl->annot = annot;
      }
      /*
      * NOTE: Element Declaration Representation OK 4. will be checked at a
      * different layer.
      */
      FREE_AND_NULL(des)
      if (topLevel)
  	return ((xmlSchemaBasicItemPtr) decl);
      else {
  	particle->children = (xmlSchemaTreeItemPtr) decl;
  	return ((xmlSchemaBasicItemPtr) particle);
      }
  
  return_null:
      FREE_AND_NULL(des);
      if (annot != NULL) {
  	if (particle != NULL)
  	    particle->annot = NULL;
  	if (decl != NULL)
  	    decl->annot = NULL;
  	xmlSchemaFreeAnnot(annot);
      }
      return (NULL);
  }
  
  /**
   * xmlSchemaParseUnion:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema Union definition
   * *WARNING* this interface is highly subject to change
   *
   * Returns -1 in case of internal error, 0 in case of success and a positive
   * error code otherwise.
   */
  static int
  xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                      xmlNodePtr node)
  {
      xmlSchemaTypePtr type;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      const xmlChar *cur = NULL;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (-1);
      /* Not a component, don't create it. */
      type = ctxt->ctxtType;
      /*
      * Mark the simple type as being of variety "union".
      */
      type->flags |= XML_SCHEMAS_TYPE_VARIETY_UNION;
      /*
      * SPEC (Base type) (2) "If the <list> or <union> alternative is chosen,
      * then the `simple ur-type definition`."
      */
      type->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE);
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "memberTypes"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * Attribute "memberTypes". This is a list of QNames.
      * TODO: Check the value to contain anything.
      */
      attr = xmlSchemaGetPropNode(node, "memberTypes");
      if (attr != NULL) {
  	const xmlChar *end;
  	xmlChar *tmp;
  	const xmlChar *localName, *nsName;
  	xmlSchemaTypeLinkPtr link, lastLink = NULL;
  	xmlSchemaQNameRefPtr ref;
  
  	cur = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  	type->base = cur;
  	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);
  	    if (xmlSchemaPValAttrNodeQNameValue(ctxt, schema,
  		NULL, attr, BAD_CAST tmp, &nsName, &localName) == 0) {
  		/*
  		* Create the member type link.
  		*/
  		link = (xmlSchemaTypeLinkPtr)
  		    xmlMalloc(sizeof(xmlSchemaTypeLink));
  		if (link == NULL) {
  		    xmlSchemaPErrMemory(ctxt, "xmlSchemaParseUnion, "
  			"allocating a type link", NULL);
  		    return (-1);
  		}
  		link->type = NULL;
  		link->next = NULL;
  		if (lastLink == NULL)
  		    type->memberTypes = link;
  		else
  		    lastLink->next = link;
  		lastLink = link;
  		/*
  		* Create a reference item.
  		*/
  		ref = xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_SIMPLE,
  		    localName, nsName);
  		if (ref == NULL) {
  		    FREE_AND_NULL(tmp)
  		    return (-1);
  		}
  		/*
  		* Assign the reference to the link, it will be resolved
  		* later during fixup of the union simple type.
  		*/
  		link->type = (xmlSchemaTypePtr) ref;
  	    }
  	    FREE_AND_NULL(tmp)
  	    cur = end;
  	} while (*cur != 0);
  
      }
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	/*
  	* Add the annotation to the simple type ancestor.
  	*/
  	xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type,
  	    xmlSchemaParseAnnotation(ctxt, child, 1));
          child = child->next;
      }
      if (IS_SCHEMA(child, "simpleType")) {
  	xmlSchemaTypePtr subtype, last = NULL;
  
  	/*
  	* Anchor the member types in the "subtypes" field of the
  	* simple type.
  	*/
  	while (IS_SCHEMA(child, "simpleType")) {
  	    subtype = (xmlSchemaTypePtr)
  		xmlSchemaParseSimpleType(ctxt, schema, child, 0);
  	    if (subtype != NULL) {
  		if (last == NULL) {
  		    type->subtypes = subtype;
  		    last = subtype;
  		} else {
  		    last->next = subtype;
  		    last = subtype;
  		}
  		last->next = NULL;
  	    }
  	    child = child->next;
  	}
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL, "(annotation?, simpleType*)");
      }
      if ((attr == NULL) && (type->subtypes == NULL)) {
  	 /*
  	* 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].
  	*/
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_SRC_UNION_MEMBERTYPES_OR_SIMPLETYPES,
  	    NULL, node,
  	    "Either the attribute 'memberTypes' or "
  	    "at least one <simpleType> child must be present", NULL);
      }
      return (0);
  }
  
  /**
   * xmlSchemaParseList:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema List definition
   * *WARNING* this interface is highly subject to change
   *
   * Returns -1 in case of error, 0 if the declaration is improper and
   *         1 in case of success.
   */
  static xmlSchemaTypePtr
  xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                     xmlNodePtr node)
  {
      xmlSchemaTypePtr type;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
      /* Not a component, don't create it. */
      type = ctxt->ctxtType;
      /*
      * Mark the type as being of variety "list".
      */
      type->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
      /*
      * SPEC (Base type) (2) "If the <list> or <union> alternative is chosen,
      * then the `simple ur-type definition`."
      */
      type->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE);
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "itemType"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
  
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
  
      /*
      * Attribute "itemType". NOTE that we will use the "ref" and "refNs"
      * fields for holding the reference to the itemType.
      *
      * REVAMP TODO: Use the "base" and "baseNs" fields, since we will remove
      * the "ref" fields.
      */
      xmlSchemaPValAttrQName(ctxt, schema, NULL,
  	node, "itemType", &(type->baseNs), &(type->base));
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type,
  	    xmlSchemaParseAnnotation(ctxt, child, 1));
          child = child->next;
      }
      if (IS_SCHEMA(child, "simpleType")) {
  	/*
  	* 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) {
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_SRC_SIMPLE_TYPE_1,
  		NULL, node,
  		"The attribute 'itemType' and the <simpleType> child "
  		"are mutually exclusive", NULL);
  	} else {
  	    type->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child, 0);
  	}
          child = child->next;
      } else if (type->base == NULL) {
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_SRC_SIMPLE_TYPE_1,
  	    NULL, node,
  	    "Either the attribute 'itemType' or the <simpleType> child "
  	    "must be present", NULL);
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL, "(annotation?, simpleType?)");
      }
      if ((type->base == NULL) &&
  	(type->subtypes == NULL) &&
  	(xmlSchemaGetPropNode(node, "itemType") == NULL)) {
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_SRC_SIMPLE_TYPE_1,
  	    NULL, node,
  	    "Either the attribute 'itemType' or the <simpleType> child "
  	    "must be present", NULL);
      }
      return (NULL);
  }
  
  /**
   * 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 improper and
   * 1 in case of success.
   */
  static xmlSchemaTypePtr
  xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                           xmlNodePtr node, int topLevel)
  {
      xmlSchemaTypePtr type, oldCtxtType;
      xmlNodePtr child = NULL;
      const xmlChar *attrValue = NULL;
      xmlAttrPtr attr;
      int hasRestriction = 0;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      if (topLevel) {
  	attr = xmlSchemaGetPropNode(node, "name");
  	if (attr == NULL) {
  	    xmlSchemaPMissingAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_MISSING,
  		NULL, node,
  		"name", NULL);
  	    return (NULL);
  	} else {
  	    if (xmlSchemaPValAttrNode(ctxt,
  		NULL, attr,
  		xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &attrValue) != 0)
  		return (NULL);
  	    /*
  	    * Skip built-in types.
  	    */
  	    if (ctxt->isS4S) {
  		xmlSchemaTypePtr biType;
  
  		if (ctxt->isRedefine) {
  		    /*
  		    * REDEFINE: Disallow redefinition of built-in-types.
  		    * TODO: It seems that the spec does not say anything
  		    * about this case.
  		    */
  		    xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_SRC_REDEFINE,
  			NULL, node,
  			"Redefinition of built-in simple types is not "
  			"supported", NULL);
  		    return(NULL);
  		}
  		biType = xmlSchemaGetPredefinedType(attrValue, xmlSchemaNs);
  		if (biType != NULL)
  		    return (biType);
  	    }
  	}
      }
      /*
      * TargetNamespace:
      * SPEC "The `actual value` of the targetNamespace [attribute]
      * of the <schema> ancestor element information item if present,
      * otherwise `absent`.
      */
      if (topLevel == 0) {
  #ifdef ENABLE_NAMED_LOCALS
          char buf[40];
  #endif
  	/*
  	* Parse as local simple type definition.
  	*/
  #ifdef ENABLE_NAMED_LOCALS
          snprintf(buf, 39, "#ST%d", ctxt->counter++ + 1);
  	type = xmlSchemaAddType(ctxt, schema,
  	    XML_SCHEMA_TYPE_SIMPLE,
  	    xmlDictLookup(ctxt->dict, (const xmlChar *)buf, -1),
  	    ctxt->targetNamespace, node, 0);
  #else
  	type = xmlSchemaAddType(ctxt, schema,
  	    XML_SCHEMA_TYPE_SIMPLE,
  	    NULL, ctxt->targetNamespace, node, 0);
  #endif
  	if (type == NULL)
  	    return (NULL);
  	type->type = XML_SCHEMA_TYPE_SIMPLE;
  	type->contentType = XML_SCHEMA_CONTENT_SIMPLE;
  	/*
  	* Check for illegal attributes.
  	*/
  	attr = node->properties;
  	while (attr != NULL) {
  	    if (attr->ns == NULL) {
  		if (!xmlStrEqual(attr->name, BAD_CAST "id")) {
  		    xmlSchemaPIllegalAttrErr(ctxt,
  			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		}
  	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  		    xmlSchemaPIllegalAttrErr(ctxt,
  			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	    attr = attr->next;
  	}
      } else {
  	/*
  	* Parse as global simple type definition.
  	*
  	* Note that attrValue is the value of the attribute "name" here.
  	*/
  	type = xmlSchemaAddType(ctxt, schema, XML_SCHEMA_TYPE_SIMPLE,
  	    attrValue, ctxt->targetNamespace, node, 1);
  	if (type == NULL)
  	    return (NULL);
  	type->type = XML_SCHEMA_TYPE_SIMPLE;
  	type->contentType = XML_SCHEMA_CONTENT_SIMPLE;
  	type->flags |= XML_SCHEMAS_TYPE_GLOBAL;
  	/*
  	* Check for illegal attributes.
  	*/
  	attr = node->properties;
  	while (attr != NULL) {
  	    if (attr->ns == NULL) {
  		if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "name")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "final"))) {
  		    xmlSchemaPIllegalAttrErr(ctxt,
  			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		}
  	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	    attr = attr->next;
  	}
  	/*
  	* Attribute "final".
  	*/
  	attr = xmlSchemaGetPropNode(node, "final");
  	if (attr == NULL) {
  	    if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION)
  		type->flags |= XML_SCHEMAS_TYPE_FINAL_RESTRICTION;
  	    if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_LIST)
  		type->flags |= XML_SCHEMAS_TYPE_FINAL_LIST;
  	    if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_UNION)
  		type->flags |= XML_SCHEMAS_TYPE_FINAL_UNION;
  	} else {
  	    attrValue = xmlSchemaGetProp(ctxt, node, "final");
  	    if (xmlSchemaPValAttrBlockFinal(attrValue, &(type->flags),
  		-1, -1, XML_SCHEMAS_TYPE_FINAL_RESTRICTION, -1,
  		XML_SCHEMAS_TYPE_FINAL_LIST,
  		XML_SCHEMAS_TYPE_FINAL_UNION) != 0) {
  
  		xmlSchemaPSimpleTypeErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  		    WXS_BASIC_CAST type, (xmlNodePtr) attr,
  		    NULL, "(#all | List of (list | union | restriction)",
  		    attrValue, NULL, NULL, NULL);
  	    }
  	}
      }
      type->targetNamespace = ctxt->targetNamespace;
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * And now for the children...
      */
      oldCtxtType = ctxt->ctxtType;
  
      ctxt->ctxtType = type;
  
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          type->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
          child = child->next;
      }
      if (child == NULL) {
  	xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_MISSING,
  	    NULL, node, child, NULL,
  	    "(annotation?, (restriction | list | union))");
      } else if (IS_SCHEMA(child, "restriction")) {
          xmlSchemaParseRestriction(ctxt, schema, child,
  	    XML_SCHEMA_TYPE_SIMPLE);
  	hasRestriction = 1;
          child = child->next;
      } else if (IS_SCHEMA(child, "list")) {
          xmlSchemaParseList(ctxt, schema, child);
          child = child->next;
      } else if (IS_SCHEMA(child, "union")) {
          xmlSchemaParseUnion(ctxt, schema, child);
          child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt, XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL,
  	    "(annotation?, (restriction | list | union))");
      }
      /*
      * REDEFINE: SPEC src-redefine (5)
      * "Within the [children], each <simpleType> must have a
      * <restriction> among its [children] ... the `actual value` of whose
      * base [attribute] must be the same as the `actual value` of its own
      * name attribute plus target namespace;"
      */
      if (topLevel && ctxt->isRedefine && (! hasRestriction)) {
  	xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_SRC_REDEFINE,
  	    NULL, node, "This is a redefinition, thus the "
  	    "<simpleType> must have a <restriction> child", NULL);
      }
  
      ctxt->ctxtType = oldCtxtType;
      return (type);
  }
  
  /**
   * xmlSchemaParseModelGroupDefRef:
   * @ctxt:  the parser context
   * @schema: the schema being built
   * @node:  the node
   *
   * Parses a reference to a model group definition.
   *
   * We will return a particle component with a qname-component or
   * NULL in case of an error.
   */
  static xmlSchemaTreeItemPtr
  xmlSchemaParseModelGroupDefRef(xmlSchemaParserCtxtPtr ctxt,
  			       xmlSchemaPtr schema,
  			       xmlNodePtr node)
  {
      xmlSchemaParticlePtr item;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      const xmlChar *ref = NULL, *refNs = NULL;
      int min, max;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      attr = xmlSchemaGetPropNode(node, "ref");
      if (attr == NULL) {
  	xmlSchemaPMissingAttrErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node, "ref", NULL);
  	return (NULL);
      } else if (xmlSchemaPValAttrNodeQName(ctxt, schema, NULL,
  	attr, &refNs, &ref) != 0) {
  	return (NULL);
      }
      xmlSchemaCheckReference(ctxt, schema, node, attr, refNs);
      min = xmlGetMinOccurs(ctxt, node, 0, -1, 1, "xs:nonNegativeInteger");
      max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1,
  	"(xs:nonNegativeInteger | unbounded)");
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "ref")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "minOccurs")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "maxOccurs"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      item = xmlSchemaAddParticle(ctxt, node, min, max);
      if (item == NULL)
  	return (NULL);
      /*
      * Create a qname-reference and set as the term; it will be substituted
      * for the model group after the reference has been resolved.
      */
      item->children = (xmlSchemaTreeItemPtr)
  	xmlSchemaNewQNameRef(ctxt, XML_SCHEMA_TYPE_GROUP, ref, refNs);
      xmlSchemaPCheckParticleCorrect_2(ctxt, item, node, min, max);
      /*
      * And now for the children...
      */
      child = node->children;
      /* TODO: Is annotation even allowed for a model group reference? */
      if (IS_SCHEMA(child, "annotation")) {
  	/*
  	* TODO: What to do exactly with the annotation?
  	*/
  	item->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
  	child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL,
  	    "(annotation?)");
      }
      /*
      * Corresponds to no component at all if minOccurs==maxOccurs==0.
      */
      if ((min == 0) && (max == 0))
  	return (NULL);
  
      return ((xmlSchemaTreeItemPtr) item);
  }
  
  /**
   * xmlSchemaParseModelGroupDefinition:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * Parses a XML schema model group definition.
   *
   * Note that the constraint src-redefine (6.2) can't be applied until
   * references have been resolved. So we will do this at the
   * component fixup level.
   *
   * *WARNING* this interface is highly subject to change
   *
   * Returns -1 in case of error, 0 if the declaration is improper and
   *         1 in case of success.
   */
  static xmlSchemaModelGroupDefPtr
  xmlSchemaParseModelGroupDefinition(xmlSchemaParserCtxtPtr ctxt,
  				   xmlSchemaPtr schema,
  				   xmlNodePtr node)
  {
      xmlSchemaModelGroupDefPtr item;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      const xmlChar *name;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      attr = xmlSchemaGetPropNode(node, "name");
      if (attr == NULL) {
  	xmlSchemaPMissingAttrErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node,
  	    "name", NULL);
  	return (NULL);
      } else if (xmlSchemaPValAttrNode(ctxt, NULL, attr,
  	xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) {
  	return (NULL);
      }
      item = xmlSchemaAddModelGroupDefinition(ctxt, schema, name,
  	ctxt->targetNamespace, node);
      if (item == NULL)
  	return (NULL);
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "name")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "id"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	item->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
  	child = child->next;
      }
      if (IS_SCHEMA(child, "all")) {
  	item->children = xmlSchemaParseModelGroup(ctxt, schema, child,
  	    XML_SCHEMA_TYPE_ALL, 0);
  	child = child->next;
      } else if (IS_SCHEMA(child, "choice")) {
  	item->children = xmlSchemaParseModelGroup(ctxt, schema, child,
  	    XML_SCHEMA_TYPE_CHOICE, 0);
  	child = child->next;
      } else if (IS_SCHEMA(child, "sequence")) {
  	item->children = xmlSchemaParseModelGroup(ctxt, schema, child,
  	    XML_SCHEMA_TYPE_SEQUENCE, 0);
  	child = child->next;
      }
  
  
  
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL,
  	    "(annotation?, (all | choice | sequence)?)");
      }
      return (item);
  }
  
  /**
   * xmlSchemaCleanupDoc:
   * @ctxt:  a schema validation context
   * @node:  the root of the document.
   *
   * removes unwanted nodes in a schemas document tree
   */
  static void
  xmlSchemaCleanupDoc(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr root)
  {
      xmlNodePtr delete, cur;
  
      if ((ctxt == NULL) || (root == NULL)) return;
  
      /*
       * Remove all the blank text nodes
       */
      delete = NULL;
      cur = root;
      while (cur != NULL) {
          if (delete != NULL) {
              xmlUnlinkNode(delete);
              xmlFreeNode(delete);
              delete = NULL;
          }
          if (cur->type == XML_TEXT_NODE) {
              if (IS_BLANK_NODE(cur)) {
                  if (xmlNodeGetSpacePreserve(cur) != 1) {
                      delete = cur;
                  }
              }
          } else if ((cur->type != XML_ELEMENT_NODE) &&
                     (cur->type != XML_CDATA_SECTION_NODE)) {
              delete = cur;
              goto skip_children;
          }
  
          /*
           * Skip to next node
           */
          if (cur->children != NULL) {
              if ((cur->children->type != XML_ENTITY_DECL) &&
                  (cur->children->type != XML_ENTITY_REF_NODE) &&
                  (cur->children->type != XML_ENTITY_NODE)) {
                  cur = cur->children;
                  continue;
              }
          }
        skip_children:
          if (cur->next != NULL) {
              cur = cur->next;
              continue;
          }
  
          do {
              cur = cur->parent;
              if (cur == NULL)
                  break;
              if (cur == root) {
                  cur = NULL;
                  break;
              }
              if (cur->next != NULL) {
                  cur = cur->next;
                  break;
              }
          } while (cur != NULL);
      }
      if (delete != NULL) {
          xmlUnlinkNode(delete);
          xmlFreeNode(delete);
          delete = NULL;
      }
  }
  
  
  static void
  xmlSchemaClearSchemaDefaults(xmlSchemaPtr schema)
  {
      if (schema->flags & XML_SCHEMAS_QUALIF_ELEM)
  	schema->flags ^= XML_SCHEMAS_QUALIF_ELEM;
  
      if (schema->flags & XML_SCHEMAS_QUALIF_ATTR)
  	schema->flags ^= XML_SCHEMAS_QUALIF_ATTR;
  
      if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_EXTENSION)
  	schema->flags ^= XML_SCHEMAS_FINAL_DEFAULT_EXTENSION;
      if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION)
  	schema->flags ^= XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION;
      if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_LIST)
  	schema->flags ^= XML_SCHEMAS_FINAL_DEFAULT_LIST;
      if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_UNION)
  	schema->flags ^= XML_SCHEMAS_FINAL_DEFAULT_UNION;
  
      if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION)
  	schema->flags ^= XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION;
      if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION)
  	schema->flags ^= XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION;
      if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION)
  	schema->flags ^= XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION;
  }
  
  static int
  xmlSchemaParseSchemaElement(xmlSchemaParserCtxtPtr ctxt,
  			     xmlSchemaPtr schema,
  			     xmlNodePtr node)
  {
      xmlAttrPtr attr;
      const xmlChar *val;
      int res = 0, oldErrs = ctxt->nberrors;
  
      /*
      * Those flags should be moved to the parser context flags,
      * since they are not visible at the component level. I.e.
      * they are used if processing schema *documents* only.
      */
      res = xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      HFAILURE;
  
      /*
      * Since the version is of type xs:token, we won't bother to
      * check it.
      */
      /* REMOVED:
      attr = xmlSchemaGetPropNode(node, "version");
      if (attr != NULL) {
  	res = xmlSchemaPValAttrNode(ctxt, NULL, NULL, attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_TOKEN), &val);
  	HFAILURE;
      }
      */
      attr = xmlSchemaGetPropNode(node, "targetNamespace");
      if (attr != NULL) {
  	res = xmlSchemaPValAttrNode(ctxt, NULL, attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI), NULL);
  	HFAILURE;
  	if (res != 0) {
  	    ctxt->stop = XML_SCHEMAP_S4S_ATTR_INVALID_VALUE;
  	    goto exit;
  	}
      }
      attr = xmlSchemaGetPropNode(node, "elementFormDefault");
      if (attr != NULL) {
  	val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  	res = xmlSchemaPValAttrFormDefault(val, &schema->flags,
  	    XML_SCHEMAS_QUALIF_ELEM);
  	HFAILURE;
  	if (res != 0) {
  	    xmlSchemaPSimpleTypeErr(ctxt,
  		XML_SCHEMAP_ELEMFORMDEFAULT_VALUE,
  		NULL, (xmlNodePtr) attr, NULL,
  		"(qualified | unqualified)", val, NULL, NULL, NULL);
  	}
      }
      attr = xmlSchemaGetPropNode(node, "attributeFormDefault");
      if (attr != NULL) {
  	val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  	res = xmlSchemaPValAttrFormDefault(val, &schema->flags,
  	    XML_SCHEMAS_QUALIF_ATTR);
  	HFAILURE;
  	if (res != 0) {
  	    xmlSchemaPSimpleTypeErr(ctxt,
  		XML_SCHEMAP_ATTRFORMDEFAULT_VALUE,
  		NULL, (xmlNodePtr) attr, NULL,
  		"(qualified | unqualified)", val, NULL, NULL, NULL);
  	}
      }
      attr = xmlSchemaGetPropNode(node, "finalDefault");
      if (attr != NULL) {
  	val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  	res = xmlSchemaPValAttrBlockFinal(val, &(schema->flags), -1,
  	    XML_SCHEMAS_FINAL_DEFAULT_EXTENSION,
  	    XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION,
  	    -1,
  	    XML_SCHEMAS_FINAL_DEFAULT_LIST,
  	    XML_SCHEMAS_FINAL_DEFAULT_UNION);
  	HFAILURE;
  	if (res != 0) {
  	    xmlSchemaPSimpleTypeErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  		NULL, (xmlNodePtr) attr, NULL,
  		"(#all | List of (extension | restriction | list | union))",
  		val, NULL, NULL, NULL);
  	}
      }
      attr = xmlSchemaGetPropNode(node, "blockDefault");
      if (attr != NULL) {
  	val = xmlSchemaGetNodeContent(ctxt, (xmlNodePtr) attr);
  	res = xmlSchemaPValAttrBlockFinal(val, &(schema->flags), -1,
  	    XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION,
  	    XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION,
  	    XML_SCHEMAS_BLOCK_DEFAULT_SUBSTITUTION, -1, -1);
  	HFAILURE;
  	if (res != 0) {
  	    xmlSchemaPSimpleTypeErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  		NULL, (xmlNodePtr) attr, NULL,
  		"(#all | List of (extension | restriction | substitution))",
  		val, NULL, NULL, NULL);
  	}
      }
  
  exit:
      if (oldErrs != ctxt->nberrors)
  	res = ctxt->err;
      return(res);
  exit_failure:
      return(-1);
  }
  
  /**
   * xmlSchemaParseSchemaTopLevel:
   * @ctxt:  a schema validation context
   * @schema:  the schemas
   * @nodes:  the list of top level nodes
   *
   * Returns the internal XML Schema structure built from the resource or
   *         NULL in case of error
   */
  static int
  xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt,
                               xmlSchemaPtr schema, xmlNodePtr nodes)
  {
      xmlNodePtr child;
      xmlSchemaAnnotPtr annot;
      int res = 0, oldErrs, tmpOldErrs;
  
      if ((ctxt == NULL) || (schema == NULL) || (nodes == NULL))
          return(-1);
  
      oldErrs = ctxt->nberrors;
      child = nodes;
      while ((IS_SCHEMA(child, "include")) ||
  	   (IS_SCHEMA(child, "import")) ||
  	   (IS_SCHEMA(child, "redefine")) ||
  	   (IS_SCHEMA(child, "annotation"))) {
  	if (IS_SCHEMA(child, "annotation")) {
  	    annot = xmlSchemaParseAnnotation(ctxt, child, 1);
  	    if (schema->annot == NULL)
  		schema->annot = annot;
  	    else
  		xmlSchemaFreeAnnot(annot);
  	} else if (IS_SCHEMA(child, "import")) {
  	    tmpOldErrs = ctxt->nberrors;
  	    res = xmlSchemaParseImport(ctxt, schema, child);
  	    HFAILURE;
  	    HSTOP(ctxt);
  	    if (tmpOldErrs != ctxt->nberrors)
  		goto exit;
  	} else if (IS_SCHEMA(child, "include")) {
  	    tmpOldErrs = ctxt->nberrors;
  	    res = xmlSchemaParseInclude(ctxt, schema, child);
  	    HFAILURE;
  	    HSTOP(ctxt);
  	    if (tmpOldErrs != ctxt->nberrors)
  		goto exit;
  	} else if (IS_SCHEMA(child, "redefine")) {
  	    tmpOldErrs = ctxt->nberrors;
  	    res = xmlSchemaParseRedefine(ctxt, schema, child);
  	    HFAILURE;
  	    HSTOP(ctxt);
  	    if (tmpOldErrs != ctxt->nberrors)
  		goto exit;
  	}
  	child = child->next;
      }
      /*
      * URGENT TODO: Change the functions to return int results.
      * We need especially to catch internal errors.
      */
      while (child != NULL) {
  	if (IS_SCHEMA(child, "complexType")) {
  	    xmlSchemaParseComplexType(ctxt, schema, child, 1);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "simpleType")) {
  	    xmlSchemaParseSimpleType(ctxt, schema, child, 1);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "element")) {
  	    xmlSchemaParseElement(ctxt, schema, child, NULL, 1);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "attribute")) {
  	    xmlSchemaParseGlobalAttribute(ctxt, schema, child);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "attributeGroup")) {
  	    xmlSchemaParseAttributeGroupDefinition(ctxt, schema, child);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "group")) {
  	    xmlSchemaParseModelGroupDefinition(ctxt, schema, child);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "notation")) {
  	    xmlSchemaParseNotation(ctxt, schema, child);
  	    child = child->next;
  	} else {
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, child->parent, child,
  		NULL, "((include | import | redefine | annotation)*, "
  		"(((simpleType | complexType | group | attributeGroup) "
  		"| element | attribute | notation), annotation*)*)");
  	    child = child->next;
  	}
  	while (IS_SCHEMA(child, "annotation")) {
  	    /*
  	    * TODO: We should add all annotations.
  	    */
  	    annot = xmlSchemaParseAnnotation(ctxt, child, 1);
  	    if (schema->annot == NULL)
  		schema->annot = annot;
  	    else
  		xmlSchemaFreeAnnot(annot);
  	    child = child->next;
  	}
      }
  exit:
      ctxt->ctxtType = NULL;
      if (oldErrs != ctxt->nberrors)
  	res = ctxt->err;
      return(res);
  exit_failure:
      return(-1);
  }
  
  static xmlSchemaSchemaRelationPtr
  xmlSchemaSchemaRelationCreate(void)
  {
      xmlSchemaSchemaRelationPtr ret;
  
      ret = (xmlSchemaSchemaRelationPtr)
  	xmlMalloc(sizeof(xmlSchemaSchemaRelation));
      if (ret == NULL) {
  	xmlSchemaPErrMemory(NULL, "allocating schema relation", NULL);
  	return(NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaSchemaRelation));
      return(ret);
  }
  
  #if 0
  static void
  xmlSchemaSchemaRelationFree(xmlSchemaSchemaRelationPtr rel)
  {
      xmlFree(rel);
  }
  #endif
  
  static void
  xmlSchemaRedefListFree(xmlSchemaRedefPtr redef)
  {
      xmlSchemaRedefPtr prev;
  
      while (redef != NULL) {
  	prev = redef;
  	redef = redef->next;
  	xmlFree(prev);
      }
  }
  
  static void
  xmlSchemaConstructionCtxtFree(xmlSchemaConstructionCtxtPtr con)
  {
      /*
      * After the construction context has been freed, there will be
      * no schema graph available any more. Only the schema buckets
      * will stay alive, which are put into the "schemasImports" and
      * "includes" slots of the xmlSchema.
      */
      if (con->buckets != NULL)
  	xmlSchemaItemListFree(con->buckets);
      if (con->pending != NULL)
  	xmlSchemaItemListFree(con->pending);
      if (con->substGroups != NULL)
  	xmlHashFree(con->substGroups, xmlSchemaSubstGroupFreeEntry);
      if (con->redefs != NULL)
  	xmlSchemaRedefListFree(con->redefs);
      if (con->dict != NULL)
  	xmlDictFree(con->dict);
      xmlFree(con);
  }
  
  static xmlSchemaConstructionCtxtPtr
  xmlSchemaConstructionCtxtCreate(xmlDictPtr dict)
  {
      xmlSchemaConstructionCtxtPtr ret;
  
      ret = (xmlSchemaConstructionCtxtPtr)
  	xmlMalloc(sizeof(xmlSchemaConstructionCtxt));
      if (ret == NULL) {
          xmlSchemaPErrMemory(NULL,
  	    "allocating schema construction context", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaConstructionCtxt));
  
      ret->buckets = xmlSchemaItemListCreate();
      if (ret->buckets == NULL) {
  	xmlSchemaPErrMemory(NULL,
  	    "allocating list of schema buckets", NULL);
  	xmlFree(ret);
          return (NULL);
      }
      ret->pending = xmlSchemaItemListCreate();
      if (ret->pending == NULL) {
  	xmlSchemaPErrMemory(NULL,
  	    "allocating list of pending global components", NULL);
  	xmlSchemaConstructionCtxtFree(ret);
          return (NULL);
      }
      ret->dict = dict;
      xmlDictReference(dict);
      return(ret);
  }
  
  static xmlSchemaParserCtxtPtr
  xmlSchemaParserCtxtCreate(void)
  {
      xmlSchemaParserCtxtPtr ret;
  
      ret = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt));
      if (ret == NULL) {
          xmlSchemaPErrMemory(NULL, "allocating schema parser context",
                              NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaParserCtxt));
      ret->type = XML_SCHEMA_CTXT_PARSER;
      ret->attrProhibs = xmlSchemaItemListCreate();
      if (ret->attrProhibs == NULL) {
  	xmlFree(ret);
  	return(NULL);
      }
      return(ret);
  }
  
  /**
   * xmlSchemaNewParserCtxtUseDict:
   * @URL:  the location of the schema
   * @dict: the dictionary to be used
   *
   * Create an XML Schemas parse context for that file/resource expected
   * to contain an XML Schemas file.
   *
   * Returns the parser context or NULL in case of error
   */
  static xmlSchemaParserCtxtPtr
  xmlSchemaNewParserCtxtUseDict(const char *URL, xmlDictPtr dict)
  {
      xmlSchemaParserCtxtPtr ret;
  
      ret = xmlSchemaParserCtxtCreate();
      if (ret == NULL)
          return (NULL);
      ret->dict = dict;
      xmlDictReference(dict);
      if (URL != NULL)
  	ret->URL = xmlDictLookup(dict, (const xmlChar *) URL, -1);
      return (ret);
  }
  
  static int
  xmlSchemaCreatePCtxtOnVCtxt(xmlSchemaValidCtxtPtr vctxt)
  {
      if (vctxt->pctxt == NULL) {
          if (vctxt->schema != NULL)
  	    vctxt->pctxt =
  		xmlSchemaNewParserCtxtUseDict("*", vctxt->schema->dict);
  	else
  	    vctxt->pctxt = xmlSchemaNewParserCtxt("*");
  	if (vctxt->pctxt == NULL) {
  	    VERROR_INT("xmlSchemaCreatePCtxtOnVCtxt",
  		"failed to create a temp. parser context");
  	    return (-1);
  	}
  	/* TODO: Pass user data. */
  	xmlSchemaSetParserErrors(vctxt->pctxt, vctxt->error,
  	    vctxt->warning, vctxt->errCtxt);
  	xmlSchemaSetParserStructuredErrors(vctxt->pctxt, vctxt->serror,
  	    vctxt->errCtxt);
      }
      return (0);
  }
  
  /**
   * xmlSchemaGetSchemaBucket:
   * @pctxt: the schema parser context
   * @schemaLocation: the URI of the schema document
   *
   * Returns a schema bucket if it was already parsed.
   *
   * Returns a schema bucket if it was already parsed from
   *         @schemaLocation, NULL otherwise.
   */
  static xmlSchemaBucketPtr
  xmlSchemaGetSchemaBucket(xmlSchemaParserCtxtPtr pctxt,
  			    const xmlChar *schemaLocation)
  {
      xmlSchemaBucketPtr cur;
      xmlSchemaItemListPtr list;
  
      list = pctxt->constructor->buckets;
      if (list->nbItems == 0)
  	return(NULL);
      else {
  	int i;
  	for (i = 0; i < list->nbItems; i++) {
  	    cur = (xmlSchemaBucketPtr) list->items[i];
  	    /* Pointer comparison! */
  	    if (cur->schemaLocation == schemaLocation)
  		return(cur);
  	}
      }
      return(NULL);
  }
  
  static xmlSchemaBucketPtr
  xmlSchemaGetChameleonSchemaBucket(xmlSchemaParserCtxtPtr pctxt,
  				     const xmlChar *schemaLocation,
  				     const xmlChar *targetNamespace)
  {
      xmlSchemaBucketPtr cur;
      xmlSchemaItemListPtr list;
  
      list = pctxt->constructor->buckets;
      if (list->nbItems == 0)
  	return(NULL);
      else {
  	int i;
  	for (i = 0; i < list->nbItems; i++) {
  	    cur = (xmlSchemaBucketPtr) list->items[i];
  	    /* Pointer comparison! */
  	    if ((cur->origTargetNamespace == NULL) &&
  		(cur->schemaLocation == schemaLocation) &&
  		(cur->targetNamespace == targetNamespace))
  		return(cur);
  	}
      }
      return(NULL);
  }
  
  
  #define IS_BAD_SCHEMA_DOC(b) \
      (((b)->doc == NULL) && ((b)->schemaLocation != NULL))
  
  static xmlSchemaBucketPtr
  xmlSchemaGetSchemaBucketByTNS(xmlSchemaParserCtxtPtr pctxt,
  				 const xmlChar *targetNamespace,
  				 int imported)
  {
      xmlSchemaBucketPtr cur;
      xmlSchemaItemListPtr list;
  
      list = pctxt->constructor->buckets;
      if (list->nbItems == 0)
  	return(NULL);
      else {
  	int i;
  	for (i = 0; i < list->nbItems; i++) {
  	    cur = (xmlSchemaBucketPtr) list->items[i];
  	    if ((! IS_BAD_SCHEMA_DOC(cur)) &&
  		(cur->origTargetNamespace == targetNamespace) &&
  		((imported && cur->imported) ||
  		 ((!imported) && (!cur->imported))))
  		return(cur);
  	}
      }
      return(NULL);
  }
  
  static int
  xmlSchemaParseNewDocWithContext(xmlSchemaParserCtxtPtr pctxt,
  		     xmlSchemaPtr schema,
  		     xmlSchemaBucketPtr bucket)
  {
      int oldFlags;
      xmlDocPtr oldDoc;
      xmlNodePtr node;
      int ret, oldErrs;
      xmlSchemaBucketPtr oldbucket = pctxt->constructor->bucket;
  
      /*
      * Save old values; reset the *main* schema.
      * URGENT TODO: This is not good; move the per-document information
      * to the parser. Get rid of passing the main schema to the
      * parsing functions.
      */
      oldFlags = schema->flags;
      oldDoc = schema->doc;
      if (schema->flags != 0)
  	xmlSchemaClearSchemaDefaults(schema);
      schema->doc = bucket->doc;
      pctxt->schema = schema;
      /*
      * Keep the current target namespace on the parser *not* on the
      * main schema.
      */
      pctxt->targetNamespace = bucket->targetNamespace;
      WXS_CONSTRUCTOR(pctxt)->bucket = bucket;
  
      if ((bucket->targetNamespace != NULL) &&
  	xmlStrEqual(bucket->targetNamespace, xmlSchemaNs)) {
  	/*
  	* We are parsing the schema for schemas!
  	*/
  	pctxt->isS4S = 1;
      }
      /* Mark it as parsed, even if parsing fails. */
      bucket->parsed++;
      /* Compile the schema doc. */
      node = xmlDocGetRootElement(bucket->doc);
      ret = xmlSchemaParseSchemaElement(pctxt, schema, node);
      if (ret != 0)
  	goto exit;
      /* An empty schema; just get out. */
      if (node->children == NULL)
  	goto exit;
      oldErrs = pctxt->nberrors;
      ret = xmlSchemaParseSchemaTopLevel(pctxt, schema, node->children);
      if (ret != 0)
  	goto exit;
      /*
      * TODO: Not nice, but I'm not 100% sure we will get always an error
      * as a result of the above functions; so better rely on pctxt->err
      * as well.
      */
      if ((ret == 0) && (oldErrs != pctxt->nberrors)) {
  	ret = pctxt->err;
  	goto exit;
      }
  
  exit:
      WXS_CONSTRUCTOR(pctxt)->bucket = oldbucket;
      /* Restore schema values. */
      schema->doc = oldDoc;
      schema->flags = oldFlags;
      return(ret);
  }
  
  static int
  xmlSchemaParseNewDoc(xmlSchemaParserCtxtPtr pctxt,
  		     xmlSchemaPtr schema,
  		     xmlSchemaBucketPtr bucket)
  {
      xmlSchemaParserCtxtPtr newpctxt;
      int res = 0;
  
      if (bucket == NULL)
  	return(0);
      if (bucket->parsed) {
  	PERROR_INT("xmlSchemaParseNewDoc",
  	    "reparsing a schema doc");
  	return(-1);
      }
      if (bucket->doc == NULL) {
  	PERROR_INT("xmlSchemaParseNewDoc",
  	    "parsing a schema doc, but there's no doc");
  	return(-1);
      }
      if (pctxt->constructor == NULL) {
  	PERROR_INT("xmlSchemaParseNewDoc",
  	    "no constructor");
  	return(-1);
      }
      /* Create and init the temporary parser context. */
      newpctxt = xmlSchemaNewParserCtxtUseDict(
  	(const char *) bucket->schemaLocation, pctxt->dict);
      if (newpctxt == NULL)
  	return(-1);
      newpctxt->constructor = pctxt->constructor;
      /*
      * TODO: Can we avoid that the parser knows about the main schema?
      * It would be better if he knows about the current schema bucket
      * only.
      */
      newpctxt->schema = schema;
      xmlSchemaSetParserErrors(newpctxt, pctxt->error, pctxt->warning,
  	pctxt->errCtxt);
      xmlSchemaSetParserStructuredErrors(newpctxt, pctxt->serror,
  	pctxt->errCtxt);
      newpctxt->counter = pctxt->counter;
  
  
      res = xmlSchemaParseNewDocWithContext(newpctxt, schema, bucket);
  
      /* Channel back errors and cleanup the temporary parser context. */
      if (res != 0)
  	pctxt->err = res;
      pctxt->nberrors += newpctxt->nberrors;
      pctxt->counter = newpctxt->counter;
      newpctxt->constructor = NULL;
      /* Free the parser context. */
      xmlSchemaFreeParserCtxt(newpctxt);
      return(res);
  }
  
  static void
  xmlSchemaSchemaRelationAddChild(xmlSchemaBucketPtr bucket,
  				xmlSchemaSchemaRelationPtr rel)
  {
      xmlSchemaSchemaRelationPtr cur = bucket->relations;
  
      if (cur == NULL) {
  	bucket->relations = rel;
  	return;
      }
      while (cur->next != NULL)
  	cur = cur->next;
      cur->next = rel;
  }
  
  
  static const xmlChar *
  xmlSchemaBuildAbsoluteURI(xmlDictPtr dict, const xmlChar* location,
  			  xmlNodePtr ctxtNode)
  {
      /*
      * Build an absolute location URI.
      */
      if (location != NULL) {
  	if (ctxtNode == NULL)
  	    return(location);
  	else {
  	    xmlChar *base, *URI;
  	    const xmlChar *ret = NULL;
  
  	    base = xmlNodeGetBase(ctxtNode->doc, ctxtNode);
  	    if (base == NULL) {
  		URI = xmlBuildURI(location, ctxtNode->doc->URL);
  	    } else {
  		URI = xmlBuildURI(location, base);
  		xmlFree(base);
  	    }
  	    if (URI != NULL) {
  		ret = xmlDictLookup(dict, URI, -1);
  		xmlFree(URI);
  		return(ret);
  	    }
  	}
      }
      return(NULL);
  }
  
  
  
  /**
   * xmlSchemaAddSchemaDoc:
   * @pctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * Parse an included (and to-be-redefined) XML schema document.
   *
   * Returns 0 on success, a positive error code on errors and
   *         -1 in case of an internal or API error.
   */
  
  static int
  xmlSchemaAddSchemaDoc(xmlSchemaParserCtxtPtr pctxt,
  		int type, /* import or include or redefine */
  		const xmlChar *schemaLocation,
  		xmlDocPtr schemaDoc,
  		const char *schemaBuffer,
  		int schemaBufferLen,
  		xmlNodePtr invokingNode,
  		const xmlChar *sourceTargetNamespace,
  		const xmlChar *importNamespace,
  		xmlSchemaBucketPtr *bucket)
  {
      const xmlChar *targetNamespace = NULL;
      xmlSchemaSchemaRelationPtr relation = NULL;
      xmlDocPtr doc = NULL;
      int res = 0, err = 0, located = 0, preserveDoc = 0;
      xmlSchemaBucketPtr bkt = NULL;
  
      if (bucket != NULL)
  	*bucket = NULL;
  
      switch (type) {
  	case XML_SCHEMA_SCHEMA_IMPORT:
  	case XML_SCHEMA_SCHEMA_MAIN:
  	    err = XML_SCHEMAP_SRC_IMPORT;
  	    break;
  	case XML_SCHEMA_SCHEMA_INCLUDE:
  	    err = XML_SCHEMAP_SRC_INCLUDE;
  	    break;
  	case XML_SCHEMA_SCHEMA_REDEFINE:
  	    err = XML_SCHEMAP_SRC_REDEFINE;
  	    break;
      }
  
  
      /* Special handling for the main schema:
      * skip the location and relation logic and just parse the doc.
      * We need just a bucket to be returned in this case.
      */
      if ((type == XML_SCHEMA_SCHEMA_MAIN) || (! WXS_HAS_BUCKETS(pctxt)))
  	goto doc_load;
  
      /* Note that we expect the location to be an absolute URI. */
      if (schemaLocation != NULL) {
  	bkt = xmlSchemaGetSchemaBucket(pctxt, schemaLocation);
  	if ((bkt != NULL) &&
  	    (pctxt->constructor->bucket == bkt)) {
  	    /* Report self-imports/inclusions/redefinitions. */
  
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt, err,
  		invokingNode, NULL,
  		"The schema must not import/include/redefine itself",
  		NULL, NULL);
  	    goto exit;
  	}
      }
      /*
      * Create a relation for the graph of schemas.
      */
      relation = xmlSchemaSchemaRelationCreate();
      if (relation == NULL)
  	return(-1);
      xmlSchemaSchemaRelationAddChild(pctxt->constructor->bucket,
  	relation);
      relation->type = type;
  
      /*
      * Save the namespace import information.
      */
      if (WXS_IS_BUCKET_IMPMAIN(type)) {
  	relation->importNamespace = importNamespace;
  	if (schemaLocation == NULL) {
  	    /*
  	    * No location; this is just an import of the namespace.
  	    * Note that we don't assign a bucket to the relation
  	    * in this case.
  	    */
  	    goto exit;
  	}
  	targetNamespace = importNamespace;
      }
  
      /* Did we already fetch the doc? */
      if (bkt != NULL) {
  	if ((WXS_IS_BUCKET_IMPMAIN(type)) && (! bkt->imported)) {
  	    /*
  	    * We included/redefined and then try to import a schema,
  	    * but the new location provided for import was different.
  	    */
  	    if (schemaLocation == NULL)
  		schemaLocation = BAD_CAST "in_memory_buffer";
  	    if (!xmlStrEqual(schemaLocation,
  		bkt->schemaLocation)) {
  		xmlSchemaCustomErr(ACTXT_CAST pctxt, err,
  		    invokingNode, NULL,
  		    "The schema document '%s' cannot be imported, since "
  		    "it was already included or redefined",
  		    schemaLocation, NULL);
  		goto exit;
  	    }
  	} else if ((! WXS_IS_BUCKET_IMPMAIN(type)) && (bkt->imported)) {
  	    /*
  	    * We imported and then try to include/redefine a schema,
  	    * but the new location provided for the include/redefine
  	    * was different.
  	    */
  	    if (schemaLocation == NULL)
  		schemaLocation = BAD_CAST "in_memory_buffer";
  	    if (!xmlStrEqual(schemaLocation,
  		bkt->schemaLocation)) {
  		xmlSchemaCustomErr(ACTXT_CAST pctxt, err,
  		    invokingNode, NULL,
  		    "The schema document '%s' cannot be included or "
  		    "redefined, since it was already imported",
  		    schemaLocation, NULL);
  		goto exit;
  	    }
  	}
      }
  
      if (WXS_IS_BUCKET_IMPMAIN(type)) {
  	/*
  	* Given that the schemaLocation [attribute] is only a hint, it is open
  	* to applications to ignore all but the first <import> for a given
  	* namespace, regardless of the `actual value` of schemaLocation, but
  	* such a strategy risks missing useful information when new
  	* schemaLocations are offered.
  	*
  	* We will use the first <import> that comes with a location.
  	* Further <import>s *with* a location, will result in an error.
  	* TODO: Better would be to just report a warning here, but
  	* we'll try it this way until someone complains.
  	*
  	* Schema Document Location Strategy:
  	* 3 Based on the namespace name, identify an existing schema document,
  	* either as a resource which is an XML document or a <schema> element
  	* information item, in some local schema repository;
  	* 5 Attempt to resolve the namespace name to locate such a resource.
  	*
  	* NOTE: (3) and (5) are not supported.
  	*/
  	if (bkt != NULL) {
  	    relation->bucket = bkt;
  	    goto exit;
  	}
  	bkt = xmlSchemaGetSchemaBucketByTNS(pctxt,
  	    importNamespace, 1);
  
  	if (bkt != NULL) {
  	    relation->bucket = bkt;
  	    if (bkt->schemaLocation == NULL) {
  		/* First given location of the schema; load the doc. */
  		bkt->schemaLocation = schemaLocation;
  	    } else {
  		if (!xmlStrEqual(schemaLocation,
  		    bkt->schemaLocation)) {
  		    /*
  		    * Additional location given; just skip it.
  		    * URGENT TODO: We should report a warning here.
  		    * res = XML_SCHEMAP_SRC_IMPORT;
  		    */
  		    if (schemaLocation == NULL)
  			schemaLocation = BAD_CAST "in_memory_buffer";
  
  		    xmlSchemaCustomWarning(ACTXT_CAST pctxt,
  			XML_SCHEMAP_WARN_SKIP_SCHEMA,
  			invokingNode, NULL,
  			"Skipping import of schema located at '%s' for the "
  			"namespace '%s', since this namespace was already "
  			"imported with the schema located at '%s'",
  			schemaLocation, importNamespace, bkt->schemaLocation);
  		}
  		goto exit;
  	    }
  	}
  	/*
  	* No bucket + first location: load the doc and create a
  	* bucket.
  	*/
      } else {
  	/* <include> and <redefine> */
  	if (bkt != NULL) {
  
  	    if ((bkt->origTargetNamespace == NULL) &&
  		(bkt->targetNamespace != sourceTargetNamespace)) {
  		xmlSchemaBucketPtr chamel;
  
  		/*
  		* Chameleon include/redefine: skip loading only if it was
  		* already build for the targetNamespace of the including
  		* schema.
  		*/
  		/*
  		* URGENT TODO: If the schema is a chameleon-include then copy
  		* the components into the including schema and modify the
  		* targetNamespace of those components, do nothing otherwise.
  		* NOTE: This is currently worked-around by compiling the
  		* chameleon for every distinct including targetNamespace; thus
  		* not performant at the moment.
  		* TODO: Check when the namespace in wildcards for chameleons
  		* needs to be converted: before we built wildcard intersections
  		* or after.
  		*   Answer: after!
  		*/
  		chamel = xmlSchemaGetChameleonSchemaBucket(pctxt,
  		    schemaLocation, sourceTargetNamespace);
  		if (chamel != NULL) {
  		    /* A fitting chameleon was already parsed; NOP. */
  		    relation->bucket = chamel;
  		    goto exit;
  		}
  		/*
  		* We need to parse the chameleon again for a different
  		* targetNamespace.
  		* CHAMELEON TODO: Optimize this by only parsing the
  		* chameleon once, and then copying the components to
  		* the new targetNamespace.
  		*/
  		bkt = NULL;
  	    } else {
  		relation->bucket = bkt;
  		goto exit;
  	    }
  	}
      }
      if ((bkt != NULL) && (bkt->doc != NULL)) {
  	PERROR_INT("xmlSchemaAddSchemaDoc",
  	    "trying to load a schema doc, but a doc is already "
  	    "assigned to the schema bucket");
  	goto exit_failure;
      }
  
  doc_load:
      /*
      * Load the document.
      */
      if (schemaDoc != NULL) {
  	doc = schemaDoc;
  	/* Don' free this one, since it was provided by the caller. */
  	preserveDoc = 1;
  	/* TODO: Does the context or the doc hold the location? */
  	if (schemaDoc->URL != NULL)
  	    schemaLocation = xmlDictLookup(pctxt->dict,
  		schemaDoc->URL, -1);
          else
  	    schemaLocation = BAD_CAST "in_memory_buffer";
      } else if ((schemaLocation != NULL) || (schemaBuffer != NULL)) {
  	xmlParserCtxtPtr parserCtxt;
  
  	parserCtxt = xmlNewParserCtxt();
  	if (parserCtxt == NULL) {
  	    xmlSchemaPErrMemory(NULL, "xmlSchemaGetDoc, "
  		"allocating a parser context", NULL);
  	    goto exit_failure;
  	}
  	if ((pctxt->dict != NULL) && (parserCtxt->dict != NULL)) {
  	    /*
  	    * TODO: Do we have to burden the schema parser dict with all
  	    * the content of the schema doc?
  	    */
  	    xmlDictFree(parserCtxt->dict);
  	    parserCtxt->dict = pctxt->dict;
  	    xmlDictReference(parserCtxt->dict);
  	}
  	if (schemaLocation != NULL) {
  	    /* Parse from file. */
  	    doc = xmlCtxtReadFile(parserCtxt, (const char *) schemaLocation,
  		NULL, SCHEMAS_PARSE_OPTIONS);
  	} else if (schemaBuffer != NULL) {
  	    /* Parse from memory buffer. */
  	    doc = xmlCtxtReadMemory(parserCtxt, schemaBuffer, schemaBufferLen,
  		NULL, NULL, SCHEMAS_PARSE_OPTIONS);
  	    schemaLocation = BAD_CAST "in_memory_buffer";
  	    if (doc != NULL)
  		doc->URL = xmlStrdup(schemaLocation);
  	}
  	/*
  	* For <import>:
  	* 2.1 The referent is (a fragment of) a resource which is an
  	* XML document (see clause 1.1), which in turn corresponds to
  	* a <schema> element information item in a well-formed information
  	* set, which in turn corresponds to a valid schema.
  	* TODO: (2.1) fragments of XML documents are not supported.
  	*
  	* 2.2 The referent is a <schema> element information item in
  	* a well-formed information set, which in turn corresponds
  	* to a valid schema.
  	* TODO: (2.2) is not supported.
  	*/
  	if (doc == NULL) {
  	    xmlErrorPtr lerr;
  	    lerr = xmlGetLastError();
  	    /*
  	    * Check if this a parser error, or if the document could
  	    * just not be located.
  	    * TODO: Try to find specific error codes to react only on
  	    * localisation failures.
  	    */
  	    if ((lerr == NULL) || (lerr->domain != XML_FROM_IO)) {
  		/*
  		* We assume a parser error here.
  		*/
  		located = 1;
  		/* TODO: Error code ?? */
  		res = XML_SCHEMAP_SRC_IMPORT_2_1;
  		xmlSchemaCustomErr(ACTXT_CAST pctxt, res,
  		    invokingNode, NULL,
  		    "Failed to parse the XML resource '%s'",
  		    schemaLocation, NULL);
  	    }
  	}
  	xmlFreeParserCtxt(parserCtxt);
  	if ((doc == NULL) && located)
  	    goto exit_error;
      } else {
  	xmlSchemaPErr(pctxt, NULL,
  	    XML_SCHEMAP_NOTHING_TO_PARSE,
  	    "No information for parsing was provided with the "
  	    "given schema parser context.\n",
  	    NULL, NULL);
  	goto exit_failure;
      }
      /*
      * Preprocess the document.
      */
      if (doc != NULL) {
  	xmlNodePtr docElem = NULL;
  
  	located = 1;
  	docElem = xmlDocGetRootElement(doc);
  	if (docElem == NULL) {
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt, XML_SCHEMAP_NOROOT,
  		invokingNode, NULL,
  		"The document '%s' has no document element",
  		schemaLocation, NULL);
  	    goto exit_error;
  	}
  	/*
  	* Remove all the blank text nodes.
  	*/
  	xmlSchemaCleanupDoc(pctxt, docElem);
  	/*
  	* Check the schema's top level element.
  	*/
  	if (!IS_SCHEMA(docElem, "schema")) {
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt, XML_SCHEMAP_NOT_SCHEMA,
  		invokingNode, NULL,
  		"The XML document '%s' is not a schema document",
  		schemaLocation, NULL);
  	    goto exit_error;
  	}
  	/*
  	* Note that we don't apply a type check for the
  	* targetNamespace value here.
  	*/
  	targetNamespace = xmlSchemaGetProp(pctxt, docElem,
  	    "targetNamespace");
      }
  
  /* after_doc_loading: */
      if ((bkt == NULL) && located) {
  	/* Only create a bucket if the schema was located. */
          bkt = xmlSchemaBucketCreate(pctxt, type,
  	    targetNamespace);
  	if (bkt == NULL)
  	    goto exit_failure;
      }
      if (bkt != NULL) {
  	bkt->schemaLocation = schemaLocation;
  	bkt->located = located;
  	if (doc != NULL) {
  	    bkt->doc = doc;
  	    bkt->targetNamespace = targetNamespace;
  	    bkt->origTargetNamespace = targetNamespace;
  	    if (preserveDoc)
  		bkt->preserveDoc = 1;
  	}
  	if (WXS_IS_BUCKET_IMPMAIN(type))
  	    bkt->imported++;
  	    /*
  	    * Add it to the graph of schemas.
  	    */
  	if (relation != NULL)
  	    relation->bucket = bkt;
      }
  
  exit:
      /*
      * Return the bucket explicitly; this is needed for the
      * main schema.
      */
      if (bucket != NULL)
  	*bucket = bkt;
      return (0);
  
  exit_error:
      if ((doc != NULL) && (! preserveDoc)) {
  	xmlFreeDoc(doc);
  	if (bkt != NULL)
  	    bkt->doc = NULL;
      }
      return(pctxt->err);
  
  exit_failure:
      if ((doc != NULL) && (! preserveDoc)) {
  	xmlFreeDoc(doc);
  	if (bkt != NULL)
  	    bkt->doc = NULL;
      }
      return (-1);
  }
  
  /**
   * xmlSchemaParseImport:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema Import definition
   * *WARNING* this interface is highly subject to change
   *
   * Returns 0 in case of success, a positive error code if
   * not valid and -1 in case of an internal error.
   */
  static int
  xmlSchemaParseImport(xmlSchemaParserCtxtPtr pctxt, xmlSchemaPtr schema,
                       xmlNodePtr node)
  {
      xmlNodePtr child;
      const xmlChar *namespaceName = NULL, *schemaLocation = NULL;
      const xmlChar *thisTargetNamespace;
      xmlAttrPtr attr;
      int ret = 0;
      xmlSchemaBucketPtr bucket = NULL;
  
      if ((pctxt == NULL) || (schema == NULL) || (node == NULL))
          return (-1);
  
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "namespace")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "schemaLocation"))) {
  		xmlSchemaPIllegalAttrErr(pctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(pctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      /*
      * Extract and validate attributes.
      */
      if (xmlSchemaPValAttr(pctxt, NULL, node,
  	"namespace", xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI),
  	&namespaceName) != 0) {
  	xmlSchemaPSimpleTypeErr(pctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    NULL, node,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI),
  	    NULL, namespaceName, NULL, NULL, NULL);
  	return (pctxt->err);
      }
  
      if (xmlSchemaPValAttr(pctxt, NULL, node,
  	"schemaLocation", xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI),
  	&schemaLocation) != 0) {
  	xmlSchemaPSimpleTypeErr(pctxt,
  	    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  	    NULL, node,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI),
  	    NULL, schemaLocation, NULL, NULL, NULL);
  	return (pctxt->err);
      }
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          /*
           * the annotation here is simply discarded ...
  	 * TODO: really?
           */
          child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(pctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL,
  	    "(annotation?)");
      }
      /*
      * Apply additional constraints.
      *
      * Note that it is important to use the original @targetNamespace
      * (or none at all), to rule out imports of schemas _with_ a
      * @targetNamespace if the importing schema is a chameleon schema
      * (with no @targetNamespace).
      */
      thisTargetNamespace = WXS_BUCKET(pctxt)->origTargetNamespace;
      if (namespaceName != NULL) {
  	/*
  	* 1.1 If the namespace [attribute] is present, then its `actual value`
  	* must not match the `actual value` of the enclosing <schema>'s
  	* targetNamespace [attribute].
  	*/
  	if (xmlStrEqual(thisTargetNamespace, namespaceName)) {
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_SRC_IMPORT_1_1,
  		NULL, node,
  		"The value of the attribute 'namespace' must not match "
  		"the target namespace '%s' of the importing schema",
  		thisTargetNamespace);
  	    return (pctxt->err);
  	}
      } else {
  	/*
  	* 1.2 If the namespace [attribute] is not present, then the enclosing
  	* <schema> must have a targetNamespace [attribute].
  	*/
  	if (thisTargetNamespace == NULL) {
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_SRC_IMPORT_1_2,
  		NULL, node,
  		"The attribute 'namespace' must be existent if "
  		"the importing schema has no target namespace",
  		NULL);
  	    return (pctxt->err);
  	}
      }
      /*
      * Locate and acquire the schema document.
      */
      if (schemaLocation != NULL)
  	schemaLocation = xmlSchemaBuildAbsoluteURI(pctxt->dict,
  	    schemaLocation, node);
      ret = xmlSchemaAddSchemaDoc(pctxt, XML_SCHEMA_SCHEMA_IMPORT,
  	schemaLocation, NULL, NULL, 0, node, thisTargetNamespace,
  	namespaceName, &bucket);
  
      if (ret != 0)
  	return(ret);
  
      /*
      * For <import>: "It is *not* an error for the application
      * schema reference strategy to fail."
      * So just don't parse if no schema document was found.
      * Note that we will get no bucket if the schema could not be
      * located or if there was no schemaLocation.
      */
      if ((bucket == NULL) && (schemaLocation != NULL)) {
  	xmlSchemaCustomWarning(ACTXT_CAST pctxt,
  	    XML_SCHEMAP_WARN_UNLOCATED_SCHEMA,
  	    node, NULL,
  	    "Failed to locate a schema at location '%s'. "
  	    "Skipping the import", schemaLocation, NULL, NULL);
      }
  
      if ((bucket != NULL) && CAN_PARSE_SCHEMA(bucket)) {
  	ret = xmlSchemaParseNewDoc(pctxt, schema, bucket);
      }
  
      return (ret);
  }
  
  static int
  xmlSchemaParseIncludeOrRedefineAttrs(xmlSchemaParserCtxtPtr pctxt,
  				     xmlSchemaPtr schema,
  				     xmlNodePtr node,
  				     xmlChar **schemaLocation,
  				     int type)
  {
      xmlAttrPtr attr;
  
      if ((pctxt == NULL) || (schema == NULL) || (node == NULL) ||
  	(schemaLocation == NULL))
          return (-1);
  
      *schemaLocation = NULL;
      /*
      * Check for illegal attributes.
      * Applies for both <include> and <redefine>.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "schemaLocation"))) {
  		xmlSchemaPIllegalAttrErr(pctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(pctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      xmlSchemaPValAttrID(pctxt, node, BAD_CAST "id");
      /*
      * Preliminary step, extract the URI-Reference and make an URI
      * from the base.
      */
      /*
      * Attribute "schemaLocation" is mandatory.
      */
      attr = xmlSchemaGetPropNode(node, "schemaLocation");
      if (attr != NULL) {
          xmlChar *base = NULL;
          xmlChar *uri = NULL;
  
  	if (xmlSchemaPValAttrNode(pctxt, NULL, attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYURI),
  	    (const xmlChar **) schemaLocation) != 0)
  	    goto exit_error;
  	base = xmlNodeGetBase(node->doc, node);
  	if (base == NULL) {
  	    uri = xmlBuildURI(*schemaLocation, node->doc->URL);
  	} else {
  	    uri = xmlBuildURI(*schemaLocation, base);
  	    xmlFree(base);
  	}
  	if (uri == NULL) {
  	    PERROR_INT("xmlSchemaParseIncludeOrRedefine",
  		"could not build an URI from the schemaLocation")
  	    goto exit_failure;
  	}
  	(*schemaLocation) = (xmlChar *) xmlDictLookup(pctxt->dict, uri, -1);
  	xmlFree(uri);
      } else {
  	xmlSchemaPMissingAttrErr(pctxt,
  	    XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node, "schemaLocation", NULL);
  	goto exit_error;
      }
      /*
      * Report self-inclusion and self-redefinition.
      */
      if (xmlStrEqual(*schemaLocation, pctxt->URL)) {
  	if (type == XML_SCHEMA_SCHEMA_REDEFINE) {
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_SRC_REDEFINE,
  		NULL, node,
  		"The schema document '%s' cannot redefine itself.",
  		*schemaLocation);
  	} else {
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_SRC_INCLUDE,
  		NULL, node,
  		"The schema document '%s' cannot include itself.",
  		*schemaLocation);
  	}
  	goto exit_error;
      }
  
      return(0);
  exit_error:
      return(pctxt->err);
  exit_failure:
      return(-1);
  }
  
  static int
  xmlSchemaParseIncludeOrRedefine(xmlSchemaParserCtxtPtr pctxt,
  				xmlSchemaPtr schema,
  				xmlNodePtr node,
  				int type)
  {
      xmlNodePtr child = NULL;
      const xmlChar *schemaLocation = NULL;
      int res = 0; /* hasRedefinitions = 0 */
      int isChameleon = 0, wasChameleon = 0;
      xmlSchemaBucketPtr bucket = NULL;
  
      if ((pctxt == NULL) || (schema == NULL) || (node == NULL))
          return (-1);
  
      /*
      * Parse attributes. Note that the returned schemaLocation will
      * be already converted to an absolute URI.
      */
      res = xmlSchemaParseIncludeOrRedefineAttrs(pctxt, schema,
  	node, (xmlChar **) (&schemaLocation), type);
      if (res != 0)
  	return(res);
      /*
      * Load and add the schema document.
      */
      res = xmlSchemaAddSchemaDoc(pctxt, type, schemaLocation, NULL,
  	NULL, 0, node, pctxt->targetNamespace, NULL, &bucket);
      if (res != 0)
  	return(res);
      /*
      * If we get no schema bucket back, then this means that the schema
      * document could not be located or was broken XML or was not
      * a schema document.
      */
      if ((bucket == NULL) || (bucket->doc == NULL)) {
  	if (type == XML_SCHEMA_SCHEMA_INCLUDE) {
  	    /*
  	    * WARNING for <include>:
  	    * We will raise an error if the schema cannot be located
  	    * for inclusions, since the that was the feedback from the
  	    * schema people. I.e. the following spec piece will *not* be
  	    * satisfied:
  	    * SPEC src-include: "It is not an error for the `actual value` of the
  	    * schemaLocation [attribute] to fail to resolve it all, in which
  	    * case no corresponding inclusion is performed.
  	    * So do we need a warning report here?"
  	    */
  	    res = XML_SCHEMAP_SRC_INCLUDE;
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt, res,
  		node, NULL,
  		"Failed to load the document '%s' for inclusion",
  		schemaLocation, NULL);
  	} else {
  	    /*
  	    * NOTE: This was changed to raise an error even if no redefinitions
  	    * are specified.
  	    *
  	    * SPEC src-redefine (1)
  	    * "If there are any element information items among the [children]
  	    * other than <annotation> then the `actual value` of the
  	    * schemaLocation [attribute] must successfully resolve."
  	    * TODO: Ask the WG if a the location has always to resolve
  	    * here as well!
  	    */
  	    res = XML_SCHEMAP_SRC_REDEFINE;
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt, res,
  		node, NULL,
  		"Failed to load the document '%s' for redefinition",
  		schemaLocation, NULL);
  	}
      } else {
  	/*
  	* Check targetNamespace sanity before parsing the new schema.
  	* TODO: Note that we won't check further content if the
  	* targetNamespace was bad.
  	*/
  	if (bucket->origTargetNamespace != NULL) {
  	    /*
  	    * SPEC src-include (2.1)
  	    * "SII has a targetNamespace [attribute], and its `actual
  	    * value` is identical to the `actual value` of the targetNamespace
  	    * [attribute] of SII' (which must have such an [attribute])."
  	    */
  	    if (pctxt->targetNamespace == NULL) {
  		xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		    XML_SCHEMAP_SRC_INCLUDE,
  		    node, NULL,
  		    "The target namespace of the included/redefined schema "
  		    "'%s' has to be absent, since the including/redefining "
  		    "schema has no target namespace",
  		    schemaLocation, NULL);
  		goto exit_error;
  	    } else if (!xmlStrEqual(bucket->origTargetNamespace,
  		pctxt->targetNamespace)) {
  		/* TODO: Change error function. */
  		xmlSchemaPCustomErrExt(pctxt,
  		    XML_SCHEMAP_SRC_INCLUDE,
  		    NULL, node,
  		    "The target namespace '%s' of the included/redefined "
  		    "schema '%s' differs from '%s' of the "
  		    "including/redefining schema",
  		    bucket->origTargetNamespace, schemaLocation,
  		    pctxt->targetNamespace);
  		goto exit_error;
  	    }
  	} else if (pctxt->targetNamespace != NULL) {
  	    /*
  	    * Chameleons: the original target namespace will
  	    * differ from the resulting namespace.
  	    */
  	    isChameleon = 1;
  	    if (bucket->parsed &&
  		bucket->origTargetNamespace != NULL) {
  		xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		    XML_SCHEMAP_SRC_INCLUDE,
  		    node, NULL,
  		    "The target namespace of the included/redefined schema "
  		    "'%s' has to be absent or the same as the "
  		    "including/redefining schema's target namespace",
  		    schemaLocation, NULL);
  		goto exit_error;
  	    }
  	    bucket->targetNamespace = pctxt->targetNamespace;
  	}
      }
      /*
      * Parse the schema.
      */
      if (bucket && (!bucket->parsed) && (bucket->doc != NULL)) {
  	if (isChameleon) {
  	    /* TODO: Get rid of this flag on the schema itself. */
  	    if ((schema->flags & XML_SCHEMAS_INCLUDING_CONVERT_NS) == 0) {
  		schema->flags |= XML_SCHEMAS_INCLUDING_CONVERT_NS;
  	    } else
  		wasChameleon = 1;
  	}
  	xmlSchemaParseNewDoc(pctxt, schema, bucket);
  	/* Restore chameleon flag. */
  	if (isChameleon && (!wasChameleon))
  	    schema->flags ^= XML_SCHEMAS_INCLUDING_CONVERT_NS;
      }
      /*
      * And now for the children...
      */
      child = node->children;
      if (type == XML_SCHEMA_SCHEMA_REDEFINE) {
  	/*
  	* Parse (simpleType | complexType | group | attributeGroup))*
  	*/
  	pctxt->redefined = bucket;
  	/*
  	* How to proceed if the redefined schema was not located?
  	*/
  	pctxt->isRedefine = 1;
  	while (IS_SCHEMA(child, "annotation") ||
  	    IS_SCHEMA(child, "simpleType") ||
  	    IS_SCHEMA(child, "complexType") ||
  	    IS_SCHEMA(child, "group") ||
  	    IS_SCHEMA(child, "attributeGroup")) {
  	    if (IS_SCHEMA(child, "annotation")) {
  		/*
  		* TODO: discard or not?
  		*/
  	    } else if (IS_SCHEMA(child, "simpleType")) {
  		xmlSchemaParseSimpleType(pctxt, schema, child, 1);
  	    } else if (IS_SCHEMA(child, "complexType")) {
  		xmlSchemaParseComplexType(pctxt, schema, child, 1);
  		/* hasRedefinitions = 1; */
  	    } else if (IS_SCHEMA(child, "group")) {
  		/* hasRedefinitions = 1; */
  		xmlSchemaParseModelGroupDefinition(pctxt,
  		    schema, child);
  	    } else if (IS_SCHEMA(child, "attributeGroup")) {
  		/* hasRedefinitions = 1; */
  		xmlSchemaParseAttributeGroupDefinition(pctxt, schema,
  		    child);
  	    }
  	    child = child->next;
  	}
  	pctxt->redefined = NULL;
  	pctxt->isRedefine = 0;
      } else {
  	if (IS_SCHEMA(child, "annotation")) {
  	    /*
  	    * TODO: discard or not?
  	    */
  	    child = child->next;
  	}
      }
      if (child != NULL) {
  	res = XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED;
  	if (type == XML_SCHEMA_SCHEMA_REDEFINE) {
  	    xmlSchemaPContentErr(pctxt, res,
  		NULL, node, child, NULL,
  		"(annotation | (simpleType | complexType | group | attributeGroup))*");
  	} else {
  	     xmlSchemaPContentErr(pctxt, res,
  		NULL, node, child, NULL,
  		"(annotation?)");
  	}
      }
      return(res);
  
  exit_error:
      return(pctxt->err);
  }
  
  static int
  xmlSchemaParseRedefine(xmlSchemaParserCtxtPtr pctxt, xmlSchemaPtr schema,
                         xmlNodePtr node)
  {
      int res;
  #ifndef ENABLE_REDEFINE
      TODO
      return(0);
  #endif
      res = xmlSchemaParseIncludeOrRedefine(pctxt, schema, node,
  	XML_SCHEMA_SCHEMA_REDEFINE);
      if (res != 0)
  	return(res);
      return(0);
  }
  
  static int
  xmlSchemaParseInclude(xmlSchemaParserCtxtPtr pctxt, xmlSchemaPtr schema,
                         xmlNodePtr node)
  {
      int res;
  
      res = xmlSchemaParseIncludeOrRedefine(pctxt, schema, node,
  	XML_SCHEMA_SCHEMA_INCLUDE);
      if (res != 0)
  	return(res);
      return(0);
  }
  
  /**
   * xmlSchemaParseModelGroup:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   * @type: the "compositor" type
   * @particleNeeded: if a a model group with a particle
   *
   * parse a XML schema Sequence definition.
   * Applies parts of:
   *   Schema Representation Constraint:
   *     Redefinition Constraints and Semantics (src-redefine)
   *     (6.1), (6.1.1), (6.1.2)
   *
   *   Schema Component Constraint:
   *     All Group Limited (cos-all-limited) (2)
   *     TODO: Actually this should go to component-level checks,
   *     but is done here due to performance. Move it to an other layer
   *     is schema construction via an API is implemented.
   *
   * *WARNING* this interface is highly subject to change
   *
   * Returns -1 in case of error, 0 if the declaration is improper and
   *         1 in case of success.
   */
  static xmlSchemaTreeItemPtr
  xmlSchemaParseModelGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
  			 xmlNodePtr node, xmlSchemaTypeType type,
  			 int withParticle)
  {
      xmlSchemaModelGroupPtr item;
      xmlSchemaParticlePtr particle = NULL;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
      int min = 1, max = 1, isElemRef, hasRefs = 0;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
      /*
      * Create a model group with the given compositor.
      */
      item = xmlSchemaAddModelGroup(ctxt, schema, type, node);
      if (item == NULL)
  	return (NULL);
  
      if (withParticle) {
  	if (type == XML_SCHEMA_TYPE_ALL) {
  	    min = xmlGetMinOccurs(ctxt, node, 0, 1, 1, "(0 | 1)");
  	    max = xmlGetMaxOccurs(ctxt, node, 1, 1, 1, "1");
  	} else {
  	    /* choice + sequence */
  	    min = xmlGetMinOccurs(ctxt, node, 0, -1, 1, "xs:nonNegativeInteger");
  	    max = xmlGetMaxOccurs(ctxt, node, 0, UNBOUNDED, 1,
  		"(xs:nonNegativeInteger | unbounded)");
  	}
  	xmlSchemaPCheckParticleCorrect_2(ctxt, NULL, node, min, max);
  	/*
  	* Create a particle
  	*/
  	particle = xmlSchemaAddParticle(ctxt, node, min, max);
  	if (particle == NULL)
  	    return (NULL);
  	particle->children = (xmlSchemaTreeItemPtr) item;
  	/*
  	* Check for illegal attributes.
  	*/
  	attr = node->properties;
  	while (attr != NULL) {
  	    if (attr->ns == NULL) {
  		if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "maxOccurs")) &&
  		    (!xmlStrEqual(attr->name, BAD_CAST "minOccurs"))) {
  		    xmlSchemaPIllegalAttrErr(ctxt,
  			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		}
  	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	    attr = attr->next;
  	}
      } else {
  	/*
  	* Check for illegal attributes.
  	*/
  	attr = node->properties;
  	while (attr != NULL) {
  	    if (attr->ns == NULL) {
  		if (!xmlStrEqual(attr->name, BAD_CAST "id")) {
  		    xmlSchemaPIllegalAttrErr(ctxt,
  			XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		}
  	    } else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	    attr = attr->next;
  	}
      }
  
      /*
      * Extract and validate attributes.
      */
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          item->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
          child = child->next;
      }
      if (type == XML_SCHEMA_TYPE_ALL) {
  	xmlSchemaParticlePtr part, last = NULL;
  
  	while (IS_SCHEMA(child, "element")) {
  	    part = (xmlSchemaParticlePtr) xmlSchemaParseElement(ctxt,
  		schema, child, &isElemRef, 0);
  	    /*
  	    * SPEC cos-all-limited (2)
  	    * "The {max occurs} of all the particles in the {particles}
  	    * of the ('all') group must be 0 or 1.
  	    */
  	    if (part != NULL) {
  		if (isElemRef)
  		    hasRefs++;
  		if (part->minOccurs > 1) {
  		    xmlSchemaPCustomErr(ctxt,
  			XML_SCHEMAP_COS_ALL_LIMITED,
  			NULL, child,
  			"Invalid value for minOccurs (must be 0 or 1)",
  			NULL);
  		    /* Reset to 1. */
  		    part->minOccurs = 1;
  		}
  		if (part->maxOccurs > 1) {
  		    xmlSchemaPCustomErr(ctxt,
  			XML_SCHEMAP_COS_ALL_LIMITED,
  			NULL, child,
  			"Invalid value for maxOccurs (must be 0 or 1)",
  			NULL);
  		    /* Reset to 1. */
  		    part->maxOccurs = 1;
  		}
  		if (last == NULL)
  		    item->children = (xmlSchemaTreeItemPtr) part;
  		else
  		    last->next = (xmlSchemaTreeItemPtr) part;
  		last = part;
  	    }
  	    child = child->next;
  	}
  	if (child != NULL) {
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"(annotation?, (annotation?, element*)");
  	}
      } else {
  	/* choice + sequence */
  	xmlSchemaTreeItemPtr part = NULL, last = NULL;
  
  	while ((IS_SCHEMA(child, "element")) ||
  	    (IS_SCHEMA(child, "group")) ||
  	    (IS_SCHEMA(child, "any")) ||
  	    (IS_SCHEMA(child, "choice")) ||
  	    (IS_SCHEMA(child, "sequence"))) {
  
  	    if (IS_SCHEMA(child, "element")) {
  		part = (xmlSchemaTreeItemPtr)
  		    xmlSchemaParseElement(ctxt, schema, child, &isElemRef, 0);
  		if (part && isElemRef)
  		    hasRefs++;
  	    } else if (IS_SCHEMA(child, "group")) {
  		part =
  		    xmlSchemaParseModelGroupDefRef(ctxt, schema, child);
  		if (part != NULL)
  		    hasRefs++;
  		/*
  		* Handle redefinitions.
  		*/
  		if (ctxt->isRedefine && ctxt->redef &&
  		    (ctxt->redef->item->type == XML_SCHEMA_TYPE_GROUP) &&
  		    part && part->children)
  		{
  		    if ((xmlSchemaGetQNameRefName(part->children) ==
  			    ctxt->redef->refName) &&
  			(xmlSchemaGetQNameRefTargetNs(part->children) ==
  			    ctxt->redef->refTargetNs))
  		    {
  			/*
  			* SPEC src-redefine:
  			* (6.1) "If it has a <group> among its contents at
  			* some level the `actual value` of whose ref
  			* [attribute] is the same as the `actual value` of
  			* its own name attribute plus target namespace, then
  			* all of the following must be true:"
  			* (6.1.1) "It must have exactly one such group."
  			*/
  			if (ctxt->redefCounter != 0) {
  			    xmlChar *str = NULL;
  
  			    xmlSchemaCustomErr(ACTXT_CAST ctxt,
  				XML_SCHEMAP_SRC_REDEFINE, child, NULL,
  				"The redefining model group definition "
  				"'%s' must not contain more than one "
  				"reference to the redefined definition",
  				xmlSchemaFormatQName(&str,
  				    ctxt->redef->refTargetNs,
  				    ctxt->redef->refName),
  				NULL);
  			    FREE_AND_NULL(str)
  			    part = NULL;
  			} else if (((WXS_PARTICLE(part))->minOccurs != 1) ||
  			    ((WXS_PARTICLE(part))->maxOccurs != 1))
  			{
  			    xmlChar *str = NULL;
  			    /*
  			    * SPEC src-redefine:
  			    * (6.1.2) "The `actual value` of both that
  			    * group's minOccurs and maxOccurs [attribute]
  			    * must be 1 (or `absent`).
  			    */
  			    xmlSchemaCustomErr(ACTXT_CAST ctxt,
  				XML_SCHEMAP_SRC_REDEFINE, child, NULL,
  				"The redefining model group definition "
  				"'%s' must not contain a reference to the "
  				"redefined definition with a "
  				"maxOccurs/minOccurs other than 1",
  				xmlSchemaFormatQName(&str,
  				    ctxt->redef->refTargetNs,
  				    ctxt->redef->refName),
  				NULL);
  			    FREE_AND_NULL(str)
  			    part = NULL;
  			}
  			ctxt->redef->reference = WXS_BASIC_CAST part;
  			ctxt->redefCounter++;
  		    }
  		}
  	    } else if (IS_SCHEMA(child, "any")) {
  		part = (xmlSchemaTreeItemPtr)
  		    xmlSchemaParseAny(ctxt, schema, child);
  	    } else if (IS_SCHEMA(child, "choice")) {
  		part = xmlSchemaParseModelGroup(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_CHOICE, 1);
  	    } else if (IS_SCHEMA(child, "sequence")) {
  		part = xmlSchemaParseModelGroup(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_SEQUENCE, 1);
  	    }
  	    if (part != NULL) {
  		if (last == NULL)
  		    item->children = part;
  		else
  		    last->next = part;
  		last = part;
  	    }
  	    child = child->next;
  	}
  	if (child != NULL) {
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"(annotation?, (element | group | choice | sequence | any)*)");
  	}
      }
      if ((max == 0) && (min == 0))
  	return (NULL);
      if (hasRefs) {
  	/*
  	* We need to resolve references.
  	*/
  	WXS_ADD_PENDING(ctxt, item);
      }
      if (withParticle)
  	return ((xmlSchemaTreeItemPtr) particle);
      else
  	return ((xmlSchemaTreeItemPtr) item);
  }
  
  /**
   * xmlSchemaParseRestriction:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema Restriction definition
   * *WARNING* this interface is highly subject to change
   *
   * Returns the type definition or NULL in case of error
   */
  static xmlSchemaTypePtr
  xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                            xmlNodePtr node, xmlSchemaTypeType parentType)
  {
      xmlSchemaTypePtr type;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
      /* Not a component, don't create it. */
      type = ctxt->ctxtType;
      type->flags |= XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION;
  
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "base"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      /*
      * Extract and validate attributes.
      */
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
      /*
      * Attribute
      */
      /*
      * Extract the base type. The "base" attribute is mandatory if inside
      * a complex type or if redefining.
      *
      * SPEC (1.2) "...otherwise (<restriction> has no <simpleType> "
      * among its [children]), the simple type definition which is
      * the {content type} of the type definition `resolved` to by
      * the `actual value` of the base [attribute]"
      */
      if (xmlSchemaPValAttrQName(ctxt, schema, NULL, node, "base",
  	&(type->baseNs), &(type->base)) == 0)
      {
  	if ((type->base == NULL) && (type->type == XML_SCHEMA_TYPE_COMPLEX)) {
  	    xmlSchemaPMissingAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_MISSING,
  		NULL, node, "base", NULL);
  	} else if ((ctxt->isRedefine) &&
  	    (type->flags & XML_SCHEMAS_TYPE_GLOBAL))
  	{
  	    if (type->base == NULL) {
  		xmlSchemaPMissingAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_MISSING,
  		    NULL, node, "base", NULL);
  	    } else if ((! xmlStrEqual(type->base, type->name)) ||
  		(! xmlStrEqual(type->baseNs, type->targetNamespace)))
  	    {
  		xmlChar *str1 = NULL, *str2 = NULL;
  		/*
  		* REDEFINE: SPEC src-redefine (5)
  		* "Within the [children], each <simpleType> must have a
  		* <restriction> among its [children] ... the `actual value` of
  		* whose base [attribute] must be the same as the `actual value`
  		* of its own name attribute plus target namespace;"
  		*/
  		xmlSchemaPCustomErrExt(ctxt, XML_SCHEMAP_SRC_REDEFINE,
  		    NULL, node, "This is a redefinition, but the QName "
  		    "value '%s' of the 'base' attribute does not match the "
  		    "type's designation '%s'",
  		    xmlSchemaFormatQName(&str1, type->baseNs, type->base),
  		    xmlSchemaFormatQName(&str2, type->targetNamespace,
  			type->name), NULL);
  		FREE_AND_NULL(str1);
  		FREE_AND_NULL(str2);
  		/* Avoid confusion and erase the values. */
  		type->base = NULL;
  		type->baseNs = NULL;
  	    }
  	}
      }
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	/*
  	* Add the annotation to the simple type ancestor.
  	*/
  	xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type,
  	    xmlSchemaParseAnnotation(ctxt, child, 1));
          child = child->next;
      }
      if (parentType == XML_SCHEMA_TYPE_SIMPLE) {
  	/*
  	* Corresponds to <simpleType><restriction><simpleType>.
  	*/
  	if (IS_SCHEMA(child, "simpleType")) {
  	    if (type->base != NULL) {
  		/*
  		* src-restriction-base-or-simpleType
  		* Either the base [attribute] or the simpleType [child] of the
  		* <restriction> element must be present, but not both.
  		*/
  		xmlSchemaPContentErr(ctxt,
  		    XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE,
  		    NULL, node, child,
  		    "The attribute 'base' and the <simpleType> child are "
  		    "mutually exclusive", NULL);
  	    } else {
  		type->baseType = (xmlSchemaTypePtr)
  		    xmlSchemaParseSimpleType(ctxt, schema, child, 0);
  	    }
  	    child = child->next;
  	} else if (type->base == NULL) {
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_SRC_RESTRICTION_BASE_OR_SIMPLETYPE,
  		NULL, node, child,
  		"Either the attribute 'base' or a <simpleType> child "
  		"must be present", NULL);
  	}
      } else if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) {
  	/*
  	* Corresponds to <complexType><complexContent><restriction>...
  	* followed by:
  	*
  	* Model groups <all>, <choice> and <sequence>.
  	*/
  	if (IS_SCHEMA(child, "all")) {
  	    type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_ALL, 1);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "choice")) {
  	    type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt,
  		    schema, child, XML_SCHEMA_TYPE_CHOICE, 1);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "sequence")) {
  	    type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_SEQUENCE, 1);
  	    child = child->next;
  	/*
  	* Model group reference <group>.
  	*/
  	} else if (IS_SCHEMA(child, "group")) {
  	    type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroupDefRef(ctxt, schema, child);
  	    /*
  	    * Note that the reference will be resolved in
  	    * xmlSchemaResolveTypeReferences();
  	    */
  	    child = child->next;
  	}
      } else if (parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT) {
  	/*
  	* Corresponds to <complexType><simpleContent><restriction>...
  	*
  	* "1.1 the simple type definition corresponding to the <simpleType>
  	* among the [children] of <restriction> if there is one;"
  	*/
  	if (IS_SCHEMA(child, "simpleType")) {
  	    /*
  	    * We will store the to-be-restricted simple type in
  	    * type->contentTypeDef *temporarily*.
  	    */
  	    type->contentTypeDef = (xmlSchemaTypePtr)
  		xmlSchemaParseSimpleType(ctxt, schema, child, 0);
  	    if ( type->contentTypeDef == NULL)
  		return (NULL);
  	    child = child->next;
  	}
      }
  
      if ((parentType == XML_SCHEMA_TYPE_SIMPLE) ||
  	(parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT)) {
  	xmlSchemaFacetPtr facet, lastfacet = NULL;
  	/*
  	* Corresponds to <complexType><simpleContent><restriction>...
  	* <simpleType><restriction>...
  	*/
  
  	/*
  	* Add the facets to the simple type ancestor.
  	*/
  	/*
  	* TODO: Datatypes: 4.1.3 Constraints on XML Representation of
  	* Simple Type Definition Schema Representation Constraint:
  	* *Single Facet Value*
  	*/
  	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;
  		else
  		    lastfacet->next = facet;
  		lastfacet = facet;
  		lastfacet->next = NULL;
  	    }
  	    child = child->next;
  	}
  	/*
  	* Create links for derivation and validation.
  	*/
  	if (type->facets != NULL) {
  	    xmlSchemaFacetLinkPtr facetLink, lastFacetLink = NULL;
  
  	    facet = type->facets;
  	    do {
  		facetLink = (xmlSchemaFacetLinkPtr)
  		    xmlMalloc(sizeof(xmlSchemaFacetLink));
  		if (facetLink == NULL) {
  		    xmlSchemaPErrMemory(ctxt, "allocating a facet link", NULL);
  		    xmlFree(facetLink);
  		    return (NULL);
  		}
  		facetLink->facet = facet;
  		facetLink->next = NULL;
  		if (lastFacetLink == NULL)
  		    type->facetSet = facetLink;
  		else
  		    lastFacetLink->next = facetLink;
  		lastFacetLink = facetLink;
  		facet = facet->next;
  	    } while (facet != NULL);
  	}
      }
      if (type->type == XML_SCHEMA_TYPE_COMPLEX) {
  	/*
  	* Attribute uses/declarations.
  	*/
  	if (xmlSchemaParseLocalAttributes(ctxt, schema, &child,
  	    (xmlSchemaItemListPtr *) &(type->attrUses),
  	    XML_SCHEMA_TYPE_RESTRICTION, NULL) == -1)
  	    return(NULL);
  	/*
  	* Attribute wildcard.
  	*/
  	if (IS_SCHEMA(child, "anyAttribute")) {
  	    type->attributeWildcard =
  		xmlSchemaParseAnyAttribute(ctxt, schema, child);
  	    child = child->next;
  	}
      }
      if (child != NULL) {
  	if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) {
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"annotation?, (group | all | choice | sequence)?, "
  		"((attribute | attributeGroup)*, anyAttribute?))");
  	} else if (parentType == XML_SCHEMA_TYPE_SIMPLE_CONTENT) {
  	     xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"(annotation?, (simpleType?, (minExclusive | minInclusive | "
  		"maxExclusive | maxInclusive | totalDigits | fractionDigits | "
  		"length | minLength | maxLength | enumeration | whiteSpace | "
  		"pattern)*)?, ((attribute | attributeGroup)*, anyAttribute?))");
  	} else {
  	    /* Simple type */
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"(annotation?, (simpleType?, (minExclusive | minInclusive | "
  		"maxExclusive | maxInclusive | totalDigits | fractionDigits | "
  		"length | minLength | maxLength | enumeration | whiteSpace | "
  		"pattern)*))");
  	}
      }
      return (NULL);
  }
  
  /**
   * xmlSchemaParseExtension:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * Parses an <extension>, which is found inside a
   * <simpleContent> or <complexContent>.
   * *WARNING* this interface is highly subject to change.
   *
   * TODO: Returns the type definition or NULL in case of error
   */
  static xmlSchemaTypePtr
  xmlSchemaParseExtension(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                          xmlNodePtr node, xmlSchemaTypeType parentType)
  {
      xmlSchemaTypePtr type;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
      /* Not a component, don't create it. */
      type = ctxt->ctxtType;
      type->flags |= XML_SCHEMAS_TYPE_DERIVATION_METHOD_EXTENSION;
  
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "base"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
  
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
  
      /*
      * Attribute "base" - mandatory.
      */
      if ((xmlSchemaPValAttrQName(ctxt, schema, NULL, node,
  	"base", &(type->baseNs), &(type->base)) == 0) &&
  	(type->base == NULL)) {
  	xmlSchemaPMissingAttrErr(ctxt,
  	    XML_SCHEMAP_S4S_ATTR_MISSING,
  	    NULL, node, "base", NULL);
      }
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	/*
  	* Add the annotation to the type ancestor.
  	*/
  	xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type,
  	    xmlSchemaParseAnnotation(ctxt, child, 1));
          child = child->next;
      }
      if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) {
  	/*
  	* Corresponds to <complexType><complexContent><extension>... and:
  	*
  	* Model groups <all>, <choice>, <sequence> and <group>.
  	*/
  	if (IS_SCHEMA(child, "all")) {
  	    type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt, schema,
  		    child, XML_SCHEMA_TYPE_ALL, 1);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "choice")) {
  	    type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt, schema,
  		    child, XML_SCHEMA_TYPE_CHOICE, 1);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "sequence")) {
  	    type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt, schema,
  		child, XML_SCHEMA_TYPE_SEQUENCE, 1);
  	    child = child->next;
  	} else if (IS_SCHEMA(child, "group")) {
  	    type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroupDefRef(ctxt, schema, child);
  	    /*
  	    * Note that the reference will be resolved in
  	    * xmlSchemaResolveTypeReferences();
  	    */
  	    child = child->next;
  	}
      }
      if (child != NULL) {
  	/*
  	* Attribute uses/declarations.
  	*/
  	if (xmlSchemaParseLocalAttributes(ctxt, schema, &child,
  	    (xmlSchemaItemListPtr *) &(type->attrUses),
  	    XML_SCHEMA_TYPE_EXTENSION, NULL) == -1)
  	    return(NULL);
  	/*
  	* Attribute wildcard.
  	*/
  	if (IS_SCHEMA(child, "anyAttribute")) {
  	    ctxt->ctxtType->attributeWildcard =
  		xmlSchemaParseAnyAttribute(ctxt, schema, child);
  	    child = child->next;
  	}
      }
      if (child != NULL) {
  	if (parentType == XML_SCHEMA_TYPE_COMPLEX_CONTENT) {
  	    /* Complex content extension. */
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"(annotation?, ((group | all | choice | sequence)?, "
  		"((attribute | attributeGroup)*, anyAttribute?)))");
  	} else {
  	    /* Simple content extension. */
  	    xmlSchemaPContentErr(ctxt,
  		XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  		NULL, node, child, NULL,
  		"(annotation?, ((attribute | attributeGroup)*, "
  		"anyAttribute?))");
  	}
      }
      return (NULL);
  }
  
  /**
   * xmlSchemaParseSimpleContent:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema SimpleContent definition
   * *WARNING* this interface is highly subject to change
   *
   * Returns the type definition or NULL in case of error
   */
  static int
  xmlSchemaParseSimpleContent(xmlSchemaParserCtxtPtr ctxt,
                              xmlSchemaPtr schema, xmlNodePtr node,
  			    int *hasRestrictionOrExtension)
  {
      xmlSchemaTypePtr type;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL) ||
  	(hasRestrictionOrExtension == NULL))
          return (-1);
      *hasRestrictionOrExtension = 0;
      /* Not a component, don't create it. */
      type = ctxt->ctxtType;
      type->contentType = XML_SCHEMA_CONTENT_SIMPLE;
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id"))) {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
  
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
  
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	/*
  	* Add the annotation to the complex type ancestor.
  	*/
  	xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type,
  	    xmlSchemaParseAnnotation(ctxt, child, 1));
          child = child->next;
      }
      if (child == NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_MISSING,
  	    NULL, node, NULL, NULL,
  	    "(annotation?, (restriction | extension))");
      }
      if (child == NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_MISSING,
  	    NULL, node, NULL, NULL,
  	    "(annotation?, (restriction | extension))");
      }
      if (IS_SCHEMA(child, "restriction")) {
          xmlSchemaParseRestriction(ctxt, schema, child,
  	    XML_SCHEMA_TYPE_SIMPLE_CONTENT);
  	(*hasRestrictionOrExtension) = 1;
          child = child->next;
      } else if (IS_SCHEMA(child, "extension")) {
          xmlSchemaParseExtension(ctxt, schema, child,
  	    XML_SCHEMA_TYPE_SIMPLE_CONTENT);
  	(*hasRestrictionOrExtension) = 1;
          child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child, NULL,
  	    "(annotation?, (restriction | extension))");
      }
      return (0);
  }
  
  /**
   * xmlSchemaParseComplexContent:
   * @ctxt:  a schema validation context
   * @schema:  the schema being built
   * @node:  a subtree containing XML Schema informations
   *
   * parse a XML schema ComplexContent definition
   * *WARNING* this interface is highly subject to change
   *
   * Returns the type definition or NULL in case of error
   */
  static int
  xmlSchemaParseComplexContent(xmlSchemaParserCtxtPtr ctxt,
                               xmlSchemaPtr schema, xmlNodePtr node,
  			     int *hasRestrictionOrExtension)
  {
      xmlSchemaTypePtr type;
      xmlNodePtr child = NULL;
      xmlAttrPtr attr;
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL) ||
  	(hasRestrictionOrExtension == NULL))
          return (-1);
      *hasRestrictionOrExtension = 0;
      /* Not a component, don't create it. */
      type = ctxt->ctxtType;
      /*
      * Check for illegal attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if ((!xmlStrEqual(attr->name, BAD_CAST "id")) &&
  		(!xmlStrEqual(attr->name, BAD_CAST "mixed")))
  	    {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
  
      xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
  
      /*
      * Set the 'mixed' on the complex type ancestor.
      */
      if (xmlGetBooleanProp(ctxt, node, "mixed", 0))  {
  	if ((type->flags & XML_SCHEMAS_TYPE_MIXED) == 0)
  	    type->flags |= XML_SCHEMAS_TYPE_MIXED;
      }
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
  	/*
  	* Add the annotation to the complex type ancestor.
  	*/
  	xmlSchemaAddAnnotation((xmlSchemaAnnotItemPtr) type,
  	    xmlSchemaParseAnnotation(ctxt, child, 1));
          child = child->next;
      }
      if (child == NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_MISSING,
  	    NULL, node, NULL,
  	    NULL, "(annotation?, (restriction | extension))");
      }
      if (child == NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_MISSING,
  	    NULL, node, NULL,
  	    NULL, "(annotation?, (restriction | extension))");
      }
      if (IS_SCHEMA(child, "restriction")) {
          xmlSchemaParseRestriction(ctxt, schema, child,
  	    XML_SCHEMA_TYPE_COMPLEX_CONTENT);
  	(*hasRestrictionOrExtension) = 1;
          child = child->next;
      } else if (IS_SCHEMA(child, "extension")) {
          xmlSchemaParseExtension(ctxt, schema, child,
  	    XML_SCHEMA_TYPE_COMPLEX_CONTENT);
  	(*hasRestrictionOrExtension) = 1;
          child = child->next;
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child,
  	    NULL, "(annotation?, (restriction | extension))");
      }
      return (0);
  }
  
  /**
   * 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 the type definition or NULL in case of error
   */
  static xmlSchemaTypePtr
  xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema,
                            xmlNodePtr node, int topLevel)
  {
      xmlSchemaTypePtr type, ctxtType;
      xmlNodePtr child = NULL;
      const xmlChar *name = NULL;
      xmlAttrPtr attr;
      const xmlChar *attrValue;
  #ifdef ENABLE_NAMED_LOCALS
      char buf[40];
  #endif
      int final = 0, block = 0, hasRestrictionOrExtension = 0;
  
  
      if ((ctxt == NULL) || (schema == NULL) || (node == NULL))
          return (NULL);
  
      ctxtType = ctxt->ctxtType;
  
      if (topLevel) {
  	attr = xmlSchemaGetPropNode(node, "name");
  	if (attr == NULL) {
  	    xmlSchemaPMissingAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_MISSING, NULL, node, "name", NULL);
  	    return (NULL);
  	} else if (xmlSchemaPValAttrNode(ctxt, NULL, attr,
  	    xmlSchemaGetBuiltInType(XML_SCHEMAS_NCNAME), &name) != 0) {
  	    return (NULL);
  	}
      }
  
      if (topLevel == 0) {
  	/*
  	* Parse as local complex type definition.
  	*/
  #ifdef ENABLE_NAMED_LOCALS
          snprintf(buf, 39, "#CT%d", ctxt->counter++ + 1);
  	type = xmlSchemaAddType(ctxt, schema,
  	    XML_SCHEMA_TYPE_COMPLEX,
  	    xmlDictLookup(ctxt->dict, (const xmlChar *)buf, -1),
  	    ctxt->targetNamespace, node, 0);
  #else
  	type = xmlSchemaAddType(ctxt, schema,
  	    XML_SCHEMA_TYPE_COMPLEX,
  	    NULL, ctxt->targetNamespace, node, 0);
  #endif
  	if (type == NULL)
  	    return (NULL);
  	name = type->name;
  	type->node = node;
  	type->type = XML_SCHEMA_TYPE_COMPLEX;
  	/*
  	* TODO: We need the target namespace.
  	*/
      } else {
  	/*
  	* Parse as global complex type definition.
  	*/
  	type = xmlSchemaAddType(ctxt, schema,
  	    XML_SCHEMA_TYPE_COMPLEX,
  	    name, ctxt->targetNamespace, node, 1);
  	if (type == NULL)
  	    return (NULL);
  	type->node = node;
  	type->type = XML_SCHEMA_TYPE_COMPLEX;
  	type->flags |= XML_SCHEMAS_TYPE_GLOBAL;
      }
      type->targetNamespace = ctxt->targetNamespace;
      /*
      * Handle attributes.
      */
      attr = node->properties;
      while (attr != NULL) {
  	if (attr->ns == NULL) {
  	    if (xmlStrEqual(attr->name, BAD_CAST "id")) {
  		/*
  		* Attribute "id".
  		*/
  		xmlSchemaPValAttrID(ctxt, node, BAD_CAST "id");
  	    } else if (xmlStrEqual(attr->name, BAD_CAST "mixed")) {
  		/*
  		* Attribute "mixed".
  		*/
  		if (xmlSchemaPGetBoolNodeValue(ctxt,
  			NULL, (xmlNodePtr) attr))
  		    type->flags |= XML_SCHEMAS_TYPE_MIXED;
  	    } else if (topLevel) {
  		/*
  		* Attributes of global complex type definitions.
  		*/
  		if (xmlStrEqual(attr->name, BAD_CAST "name")) {
  		    /* Pass. */
  		} else if (xmlStrEqual(attr->name, BAD_CAST "abstract")) {
  		    /*
  		    * Attribute "abstract".
  		    */
  		    if (xmlSchemaPGetBoolNodeValue(ctxt,
  			    NULL, (xmlNodePtr) attr))
  			type->flags |= XML_SCHEMAS_TYPE_ABSTRACT;
  		} else if (xmlStrEqual(attr->name, BAD_CAST "final")) {
  		    /*
  		    * Attribute "final".
  		    */
  		    attrValue = xmlSchemaGetNodeContent(ctxt,
  			(xmlNodePtr) attr);
  		    if (xmlSchemaPValAttrBlockFinal(attrValue,
  			&(type->flags),
  			-1,
  			XML_SCHEMAS_TYPE_FINAL_EXTENSION,
  			XML_SCHEMAS_TYPE_FINAL_RESTRICTION,
  			-1, -1, -1) != 0)
  		    {
  			xmlSchemaPSimpleTypeErr(ctxt,
  			    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  			    NULL, (xmlNodePtr) attr, NULL,
  			    "(#all | List of (extension | restriction))",
  			    attrValue, NULL, NULL, NULL);
  		    } else
  			final = 1;
  		} else if (xmlStrEqual(attr->name, BAD_CAST "block")) {
  		    /*
  		    * Attribute "block".
  		    */
  		    attrValue = xmlSchemaGetNodeContent(ctxt,
  			(xmlNodePtr) attr);
  		    if (xmlSchemaPValAttrBlockFinal(attrValue, &(type->flags),
  			-1,
  			XML_SCHEMAS_TYPE_BLOCK_EXTENSION,
  			XML_SCHEMAS_TYPE_BLOCK_RESTRICTION,
  			-1, -1, -1) != 0) {
  			xmlSchemaPSimpleTypeErr(ctxt,
  			    XML_SCHEMAP_S4S_ATTR_INVALID_VALUE,
  			    NULL, (xmlNodePtr) attr, NULL,
  			    "(#all | List of (extension | restriction)) ",
  			    attrValue, NULL, NULL, NULL);
  		    } else
  			block = 1;
  		} else {
  			xmlSchemaPIllegalAttrErr(ctxt,
  			    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  		}
  	    } else {
  		xmlSchemaPIllegalAttrErr(ctxt,
  		    XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	    }
  	} else if (xmlStrEqual(attr->ns->href, xmlSchemaNs)) {
  	    xmlSchemaPIllegalAttrErr(ctxt,
  		XML_SCHEMAP_S4S_ATTR_NOT_ALLOWED, NULL, attr);
  	}
  	attr = attr->next;
      }
      if (! block) {
  	/*
  	* Apply default "block" values.
  	*/
  	if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_RESTRICTION)
  	    type->flags |= XML_SCHEMAS_TYPE_BLOCK_RESTRICTION;
  	if (schema->flags & XML_SCHEMAS_BLOCK_DEFAULT_EXTENSION)
  	    type->flags |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION;
      }
      if (! final) {
  	/*
  	* Apply default "block" values.
  	*/
  	if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_RESTRICTION)
  	    type->flags |= XML_SCHEMAS_TYPE_FINAL_RESTRICTION;
  	if (schema->flags & XML_SCHEMAS_FINAL_DEFAULT_EXTENSION)
  	    type->flags |= XML_SCHEMAS_TYPE_FINAL_EXTENSION;
      }
      /*
      * And now for the children...
      */
      child = node->children;
      if (IS_SCHEMA(child, "annotation")) {
          type->annot = xmlSchemaParseAnnotation(ctxt, child, 1);
          child = child->next;
      }
      ctxt->ctxtType = type;
      if (IS_SCHEMA(child, "simpleContent")) {
  	/*
  	* <complexType><simpleContent>...
  	* 3.4.3 : 2.2
  	* Specifying mixed='true' when the <simpleContent>
  	* alternative is chosen has no effect
  	*/
  	if (type->flags & XML_SCHEMAS_TYPE_MIXED)
  	    type->flags ^= XML_SCHEMAS_TYPE_MIXED;
          xmlSchemaParseSimpleContent(ctxt, schema, child,
  	    &hasRestrictionOrExtension);
          child = child->next;
      } else if (IS_SCHEMA(child, "complexContent")) {
  	/*
  	* <complexType><complexContent>...
  	*/
  	type->contentType = XML_SCHEMA_CONTENT_EMPTY;
          xmlSchemaParseComplexContent(ctxt, schema, child,
  	    &hasRestrictionOrExtension);
          child = child->next;
      } else {
  	/*
  	* E.g <complexType><sequence>... or <complexType><attribute>... etc.
  	*
  	* SPEC
  	* "...the third alternative (neither <simpleContent> nor
  	* <complexContent>) is chosen. 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.
  	*/
  	type->baseType = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE);
  	type->flags |= XML_SCHEMAS_TYPE_DERIVATION_METHOD_RESTRICTION;
  	/*
  	* Parse model groups.
  	*/
          if (IS_SCHEMA(child, "all")) {
              type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_ALL, 1);
              child = child->next;
          } else if (IS_SCHEMA(child, "choice")) {
              type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_CHOICE, 1);
              child = child->next;
          } else if (IS_SCHEMA(child, "sequence")) {
              type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroup(ctxt, schema, child,
  		    XML_SCHEMA_TYPE_SEQUENCE, 1);
              child = child->next;
          } else if (IS_SCHEMA(child, "group")) {
              type->subtypes = (xmlSchemaTypePtr)
  		xmlSchemaParseModelGroupDefRef(ctxt, schema, child);
  	    /*
  	    * Note that the reference will be resolved in
  	    * xmlSchemaResolveTypeReferences();
  	    */
              child = child->next;
          }
  	/*
  	* Parse attribute decls/refs.
  	*/
          if (xmlSchemaParseLocalAttributes(ctxt, schema, &child,
  	    (xmlSchemaItemListPtr *) &(type->attrUses),
  	    XML_SCHEMA_TYPE_RESTRICTION, NULL) == -1)
  	    return(NULL);
  	/*
  	* Parse attribute wildcard.
  	*/
  	if (IS_SCHEMA(child, "anyAttribute")) {
  	    type->attributeWildcard = xmlSchemaParseAnyAttribute(ctxt, schema, child);
  	    child = child->next;
  	}
      }
      if (child != NULL) {
  	xmlSchemaPContentErr(ctxt,
  	    XML_SCHEMAP_S4S_ELEM_NOT_ALLOWED,
  	    NULL, node, child,
  	    NULL, "(annotation?, (simpleContent | complexContent | "
  	    "((group | all | choice | sequence)?, ((attribute | "
  	    "attributeGroup)*, anyAttribute?))))");
      }
      /*
      * REDEFINE: SPEC src-redefine (5)
      */
      if (topLevel && ctxt->isRedefine && (! hasRestrictionOrExtension)) {
  	xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_SRC_REDEFINE,
  	    NULL, node, "This is a redefinition, thus the "
  	    "<complexType> must have a <restriction> or <extension> "
  	    "grand-child", NULL);
      }
      ctxt->ctxtType = ctxtType;
      return (type);
  }
  
  /************************************************************************
   *									*
   *			Validating using Schemas			*
   *									*
   ************************************************************************/
  
  /************************************************************************
   *									*
   *			Reading/Writing Schemas				*
   *									*
   ************************************************************************/
  
  #if 0 /* Will be enabled if it is clear what options are needed. */
  /**
   * xmlSchemaParserCtxtSetOptions:
   * @ctxt:	a schema parser context
   * @options: a combination of xmlSchemaParserOption
   *
   * Sets the options to be used during the parse.
   *
   * Returns 0 in case of success, -1 in case of an
   * API error.
   */
  static int
  xmlSchemaParserCtxtSetOptions(xmlSchemaParserCtxtPtr ctxt,
  			      int options)
  
  {
      int i;
  
      if (ctxt == NULL)
  	return (-1);
      /*
      * WARNING: Change the start value if adding to the
      * xmlSchemaParseOption.
      */
      for (i = 1; i < (int) sizeof(int) * 8; i++) {
          if (options & 1<<i) {
  	    return (-1);
          }
      }
      ctxt->options = options;
      return (0);
  }
  
  /**
   * xmlSchemaValidCtxtGetOptions:
   * @ctxt: a schema parser context
   *
   * Returns the option combination of the parser context.
   */
  static int
  xmlSchemaParserCtxtGetOptions(xmlSchemaParserCtxtPtr ctxt)
  
  {
      if (ctxt == NULL)
  	return (-1);
      else
  	return (ctxt->options);
  }
  #endif
  
  /**
   * xmlSchemaNewParserCtxt:
   * @URL:  the location of the schema
   *
   * Create an XML Schemas parse context for that file/resource expected
   * to contain an XML Schemas file.
   *
   * Returns the parser context or NULL in case of error
   */
  xmlSchemaParserCtxtPtr
  xmlSchemaNewParserCtxt(const char *URL)
  {
      xmlSchemaParserCtxtPtr ret;
  
      if (URL == NULL)
          return (NULL);
  
      ret = xmlSchemaParserCtxtCreate();
      if (ret == NULL)
  	return(NULL);
      ret->dict = xmlDictCreate();
      ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
      return (ret);
  }
  
  /**
   * xmlSchemaNewMemParserCtxt:
   * @buffer:  a pointer to a char array containing the schemas
   * @size:  the size of the array
   *
   * Create an XML Schemas parse context for that memory buffer expected
   * to contain an XML Schemas file.
   *
   * Returns the parser context or NULL in case of error
   */
  xmlSchemaParserCtxtPtr
  xmlSchemaNewMemParserCtxt(const char *buffer, int size)
  {
      xmlSchemaParserCtxtPtr ret;
  
      if ((buffer == NULL) || (size <= 0))
          return (NULL);
      ret = xmlSchemaParserCtxtCreate();
      if (ret == NULL)
  	return(NULL);
      ret->buffer = buffer;
      ret->size = size;
      ret->dict = xmlDictCreate();
      return (ret);
  }
  
  /**
   * xmlSchemaNewDocParserCtxt:
   * @doc:  a preparsed document tree
   *
   * Create an XML Schemas parse context for that document.
   * NB. The document may be modified during the parsing process.
   *
   * Returns the parser context or NULL in case of error
   */
  xmlSchemaParserCtxtPtr
  xmlSchemaNewDocParserCtxt(xmlDocPtr doc)
  {
      xmlSchemaParserCtxtPtr ret;
  
      if (doc == NULL)
        return (NULL);
      ret = xmlSchemaParserCtxtCreate();
      if (ret == NULL)
  	return(NULL);
      ret->doc = doc;
      ret->dict = xmlDictCreate();
      /* The application has responsibility for the document */
      ret->preserve = 1;
  
      return (ret);
  }
  
  /**
   * xmlSchemaFreeParserCtxt:
   * @ctxt:  the schema parser context
   *
   * Free the resources associated to the schema parser context
   */
  void
  xmlSchemaFreeParserCtxt(xmlSchemaParserCtxtPtr ctxt)
  {
      if (ctxt == NULL)
          return;
      if (ctxt->doc != NULL && !ctxt->preserve)
          xmlFreeDoc(ctxt->doc);
      if (ctxt->vctxt != NULL) {
  	xmlSchemaFreeValidCtxt(ctxt->vctxt);
      }
      if (ctxt->ownsConstructor && (ctxt->constructor != NULL)) {
  	xmlSchemaConstructionCtxtFree(ctxt->constructor);
  	ctxt->constructor = NULL;
  	ctxt->ownsConstructor = 0;
      }
      if (ctxt->attrProhibs != NULL)
  	xmlSchemaItemListFree(ctxt->attrProhibs);
      xmlDictFree(ctxt->dict);
      xmlFree(ctxt);
  }
  
  /************************************************************************
   *									*
   *			Building the content models			*
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaBuildContentModelForSubstGroup:
   *
   * Returns 1 if nillable, 0 otherwise
   */
  static int
  xmlSchemaBuildContentModelForSubstGroup(xmlSchemaParserCtxtPtr pctxt,
  	xmlSchemaParticlePtr particle, int counter, xmlAutomataStatePtr end)
  {
      xmlAutomataStatePtr start, tmp;
      xmlSchemaElementPtr elemDecl, member;
      xmlSchemaSubstGroupPtr substGroup;
      int i;
      int ret = 0;
  
      elemDecl = (xmlSchemaElementPtr) particle->children;
      /*
      * Wrap the substitution group with a CHOICE.
      */
      start = pctxt->state;
      if (end == NULL)
  	end = xmlAutomataNewState(pctxt->am);
      substGroup = xmlSchemaSubstGroupGet(pctxt, elemDecl);
      if (substGroup == NULL) {
  	xmlSchemaPErr(pctxt, WXS_ITEM_NODE(particle),
  	    XML_SCHEMAP_INTERNAL,
  	    "Internal error: xmlSchemaBuildContentModelForSubstGroup, "
  	    "declaration is marked having a subst. group but none "
  	    "available.\n", elemDecl->name, NULL);
  	return(0);
      }
      if (counter >= 0) {
  	/*
  	* NOTE that we put the declaration in, even if it's abstract.
  	* However, an error will be raised during *validation* if an element
  	* information item shall be validated against an abstract element
  	* declaration.
  	*/
  	tmp = xmlAutomataNewCountedTrans(pctxt->am, start, NULL, counter);
          xmlAutomataNewTransition2(pctxt->am, tmp, end,
  	            elemDecl->name, elemDecl->targetNamespace, elemDecl);
  	/*
  	* Add subst. group members.
  	*/
  	for (i = 0; i < substGroup->members->nbItems; i++) {
  	    member = (xmlSchemaElementPtr) substGroup->members->items[i];
              xmlAutomataNewTransition2(pctxt->am, tmp, end,
  		               member->name, member->targetNamespace, member);
  	}
      } else if (particle->maxOccurs == 1) {
  	/*
  	* NOTE that we put the declaration in, even if it's abstract,
  	*/
  	xmlAutomataNewEpsilon(pctxt->am,
  	    xmlAutomataNewTransition2(pctxt->am,
  	    start, NULL,
  	    elemDecl->name, elemDecl->targetNamespace, elemDecl), end);
  	/*
  	* Add subst. group members.
  	*/
  	for (i = 0; i < substGroup->members->nbItems; i++) {
  	    member = (xmlSchemaElementPtr) substGroup->members->items[i];
  	    /*
  	    * NOTE: This fixes bug #341150. xmlAutomataNewOnceTrans2()
  	    *  was incorrectly used instead of xmlAutomataNewTransition2()
  	    *  (seems like a copy&paste bug from the XML_SCHEMA_TYPE_ALL
  	    *  section in xmlSchemaBuildAContentModel() ).
  	    * TODO: Check if xmlAutomataNewOnceTrans2() was instead
  	    *  intended for the above "counter" section originally. I.e.,
  	    *  check xs:all with subst-groups.
  	    *
  	    * tmp = xmlAutomataNewOnceTrans2(pctxt->am, start, NULL,
  	    *	               member->name, member->targetNamespace,
  	    *		       1, 1, member);
  	    */
  	    tmp = xmlAutomataNewTransition2(pctxt->am, start, NULL,
  		member->name, member->targetNamespace, member);
  	    xmlAutomataNewEpsilon(pctxt->am, tmp, end);
  	}
      } else {
  	xmlAutomataStatePtr hop;
  	int maxOccurs = particle->maxOccurs == UNBOUNDED ?
  	    UNBOUNDED : particle->maxOccurs - 1;
  	int minOccurs = particle->minOccurs < 1 ? 0 : particle->minOccurs - 1;
  
  	counter =
  	    xmlAutomataNewCounter(pctxt->am, minOccurs,
  	    maxOccurs);
  	hop = xmlAutomataNewState(pctxt->am);
  
  	xmlAutomataNewEpsilon(pctxt->am,
  	    xmlAutomataNewTransition2(pctxt->am,
  	    start, NULL,
  	    elemDecl->name, elemDecl->targetNamespace, elemDecl),
  	    hop);
  	/*
  	 * Add subst. group members.
  	 */
  	for (i = 0; i < substGroup->members->nbItems; i++) {
  	    member = (xmlSchemaElementPtr) substGroup->members->items[i];
  	    xmlAutomataNewEpsilon(pctxt->am,
  		xmlAutomataNewTransition2(pctxt->am,
  		start, NULL,
  		member->name, member->targetNamespace, member),
  		hop);
  	}
  	xmlAutomataNewCountedTrans(pctxt->am, hop, start, counter);
  	xmlAutomataNewCounterTrans(pctxt->am, hop, end, counter);
      }
      if (particle->minOccurs == 0) {
  	xmlAutomataNewEpsilon(pctxt->am, start, end);
          ret = 1;
      }
      pctxt->state = end;
      return(ret);
  }
  
  /**
   * xmlSchemaBuildContentModelForElement:
   *
   * Returns 1 if nillable, 0 otherwise
   */
  static int
  xmlSchemaBuildContentModelForElement(xmlSchemaParserCtxtPtr ctxt,
  				     xmlSchemaParticlePtr particle)
  {
      int ret = 0;
  
      if (((xmlSchemaElementPtr) particle->children)->flags &
  	XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD) {
  	/*
  	* Substitution groups.
  	*/
  	ret = xmlSchemaBuildContentModelForSubstGroup(ctxt, particle, -1, NULL);
      } else {
  	xmlSchemaElementPtr elemDecl;
  	xmlAutomataStatePtr start;
  
  	elemDecl = (xmlSchemaElementPtr) particle->children;
  
  	if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT)
  	    return(0);
  	if (particle->maxOccurs == 1) {
  	    start = ctxt->state;
  	    ctxt->state = xmlAutomataNewTransition2(ctxt->am, start, NULL,
  		    elemDecl->name, elemDecl->targetNamespace, elemDecl);
  	} else if ((particle->maxOccurs >= UNBOUNDED) &&
  	           (particle->minOccurs < 2)) {
  	    /* Special case. */
  	    start = ctxt->state;
  	    ctxt->state = xmlAutomataNewTransition2(ctxt->am, start, NULL,
  		elemDecl->name, elemDecl->targetNamespace, elemDecl);
  	    ctxt->state = xmlAutomataNewTransition2(ctxt->am, ctxt->state, ctxt->state,
  		elemDecl->name, elemDecl->targetNamespace, elemDecl);
  	} else {
  	    int counter;
  	    int maxOccurs = particle->maxOccurs == UNBOUNDED ?
  			    UNBOUNDED : particle->maxOccurs - 1;
  	    int minOccurs = particle->minOccurs < 1 ?
  			    0 : particle->minOccurs - 1;
  
  	    start = xmlAutomataNewEpsilon(ctxt->am, ctxt->state, NULL);
  	    counter = xmlAutomataNewCounter(ctxt->am, minOccurs, maxOccurs);
  	    ctxt->state = xmlAutomataNewTransition2(ctxt->am, start, NULL,
  		elemDecl->name, elemDecl->targetNamespace, elemDecl);
  	    xmlAutomataNewCountedTrans(ctxt->am, ctxt->state, start, counter);
  	    ctxt->state = xmlAutomataNewCounterTrans(ctxt->am, ctxt->state,
  		NULL, counter);
  	}
  	if (particle->minOccurs == 0) {
  	    xmlAutomataNewEpsilon(ctxt->am, start, ctxt->state);
              ret = 1;
          }
      }
      return(ret);
  }
  
  /**
   * xmlSchemaBuildAContentModel:
   * @ctxt:  the schema parser context
   * @particle:  the particle component
   * @name:  the complex type's name whose content is being built
   *
   * Create the automaton for the {content type} of a complex type.
   *
   * Returns 1 if the content is nillable, 0 otherwise
   */
  static int
  xmlSchemaBuildAContentModel(xmlSchemaParserCtxtPtr pctxt,
  			    xmlSchemaParticlePtr particle)
  {
      int ret = 0, tmp2;
  
      if (particle == NULL) {
  	PERROR_INT("xmlSchemaBuildAContentModel", "particle is NULL");
  	return(1);
      }
      if (particle->children == NULL) {
  	/*
  	* Just return in this case. A missing "term" of the particle
  	* might arise due to an invalid "term" component.
  	*/
  	return(1);
      }
  
      switch (particle->children->type) {
  	case XML_SCHEMA_TYPE_ANY: {
  	    xmlAutomataStatePtr start, end;
  	    xmlSchemaWildcardPtr wild;
  	    xmlSchemaWildcardNsPtr ns;
  
  	    wild = (xmlSchemaWildcardPtr) particle->children;
  
  	    start = pctxt->state;
  	    end = xmlAutomataNewState(pctxt->am);
  
  	    if (particle->maxOccurs == 1) {
  		if (wild->any == 1) {
  		    /*
  		    * We need to add both transitions:
  		    *
  		    * 1. the {"*", "*"} for elements in a namespace.
  		    */
  		    pctxt->state =
  			xmlAutomataNewTransition2(pctxt->am,
  			start, NULL, BAD_CAST "*", BAD_CAST "*", wild);
  		    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end);
  		    /*
  		    * 2. the {"*"} for elements in no namespace.
  		    */
  		    pctxt->state =
  			xmlAutomataNewTransition2(pctxt->am,
  			start, NULL, BAD_CAST "*", NULL, wild);
  		    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end);
  
  		} else if (wild->nsSet != NULL) {
  		    ns = wild->nsSet;
  		    do {
  			pctxt->state = start;
  			pctxt->state = xmlAutomataNewTransition2(pctxt->am,
  			    pctxt->state, NULL, BAD_CAST "*", ns->value, wild);
  			xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end);
  			ns = ns->next;
  		    } while (ns != NULL);
  
  		} else if (wild->negNsSet != NULL) {
  		    pctxt->state = xmlAutomataNewNegTrans(pctxt->am,
  			start, end, BAD_CAST "*", wild->negNsSet->value,
  			wild);
  		}
  	    } else {
  		int counter;
  		xmlAutomataStatePtr hop;
  		int maxOccurs =
  		    particle->maxOccurs == UNBOUNDED ? UNBOUNDED :
                                             particle->maxOccurs - 1;
  		int minOccurs =
  		    particle->minOccurs < 1 ? 0 : particle->minOccurs - 1;
  
  		counter = xmlAutomataNewCounter(pctxt->am, minOccurs, maxOccurs);
  		hop = xmlAutomataNewState(pctxt->am);
  		if (wild->any == 1) {
  		    pctxt->state =
  			xmlAutomataNewTransition2(pctxt->am,
  			start, NULL, BAD_CAST "*", BAD_CAST "*", wild);
  		    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop);
  		    pctxt->state =
  			xmlAutomataNewTransition2(pctxt->am,
  			start, NULL, BAD_CAST "*", NULL, wild);
  		    xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop);
  		} else if (wild->nsSet != NULL) {
  		    ns = wild->nsSet;
  		    do {
  			pctxt->state =
  			    xmlAutomataNewTransition2(pctxt->am,
  				start, NULL, BAD_CAST "*", ns->value, wild);
  			xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop);
  			ns = ns->next;
  		    } while (ns != NULL);
  
  		} else if (wild->negNsSet != NULL) {
  		    pctxt->state = xmlAutomataNewNegTrans(pctxt->am,
  			start, hop, BAD_CAST "*", wild->negNsSet->value,
  			wild);
  		}
  		xmlAutomataNewCountedTrans(pctxt->am, hop, start, counter);
  		xmlAutomataNewCounterTrans(pctxt->am, hop, end, counter);
  	    }
  	    if (particle->minOccurs == 0) {
  		xmlAutomataNewEpsilon(pctxt->am, start, end);
                  ret = 1;
  	    }
  	    pctxt->state = end;
              break;
  	}
          case XML_SCHEMA_TYPE_ELEMENT:
  	    ret = xmlSchemaBuildContentModelForElement(pctxt, particle);
  	    break;
          case XML_SCHEMA_TYPE_SEQUENCE:{
              xmlSchemaTreeItemPtr sub;
  
              ret = 1;
              /*
               * If max and min occurrences are default (1) then
               * simply iterate over the particles of the <sequence>.
               */
              if ((particle->minOccurs == 1) && (particle->maxOccurs == 1)) {
                  sub = particle->children->children;
  
                  while (sub != NULL) {
                      tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                          (xmlSchemaParticlePtr) sub);
                      if (tmp2 != 1) ret = 0;
                      sub = sub->next;
                  }
              } else {
                  xmlAutomataStatePtr oldstate = pctxt->state;
  
                  if (particle->maxOccurs >= UNBOUNDED) {
                      if (particle->minOccurs > 1) {
                          xmlAutomataStatePtr tmp;
                          int counter;
  
                          pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
                              oldstate, NULL);
                          oldstate = pctxt->state;
  
                          counter = xmlAutomataNewCounter(pctxt->am,
                              particle->minOccurs - 1, UNBOUNDED);
  
                          sub = particle->children->children;
                          while (sub != NULL) {
                              tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                              (xmlSchemaParticlePtr) sub);
                              if (tmp2 != 1) ret = 0;
                              sub = sub->next;
                          }
                          tmp = pctxt->state;
                          xmlAutomataNewCountedTrans(pctxt->am, tmp,
                                                     oldstate, counter);
                          pctxt->state =
                              xmlAutomataNewCounterTrans(pctxt->am, tmp,
                                                         NULL, counter);
                          if (ret == 1)
                              xmlAutomataNewEpsilon(pctxt->am,
                                                  oldstate, pctxt->state);
  
                      } else {
                          pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
                              oldstate, NULL);
                          oldstate = pctxt->state;
  
                          sub = particle->children->children;
                          while (sub != NULL) {
                              tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                          (xmlSchemaParticlePtr) sub);
                              if (tmp2 != 1) ret = 0;
                              sub = sub->next;
                          }
                          xmlAutomataNewEpsilon(pctxt->am, pctxt->state,
                                                oldstate);
                          /*
                           * epsilon needed to block previous trans from
                           * being allowed to enter back from another
                           * construct
                           */
                          pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
                                              pctxt->state, NULL);
                          if (particle->minOccurs == 0) {
                              xmlAutomataNewEpsilon(pctxt->am,
                                  oldstate, pctxt->state);
                              ret = 1;
                          }
                      }
                  } else if ((particle->maxOccurs > 1)
                             || (particle->minOccurs > 1)) {
                      xmlAutomataStatePtr tmp;
                      int counter;
  
                      pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
                          oldstate, NULL);
                      oldstate = pctxt->state;
  
                      counter = xmlAutomataNewCounter(pctxt->am,
                          particle->minOccurs - 1,
                          particle->maxOccurs - 1);
  
                      sub = particle->children->children;
                      while (sub != NULL) {
                          tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                          (xmlSchemaParticlePtr) sub);
                          if (tmp2 != 1) ret = 0;
                          sub = sub->next;
                      }
                      tmp = pctxt->state;
                      xmlAutomataNewCountedTrans(pctxt->am,
                          tmp, oldstate, counter);
                      pctxt->state =
                          xmlAutomataNewCounterTrans(pctxt->am, tmp, NULL,
                                                     counter);
                      if ((particle->minOccurs == 0) || (ret == 1)) {
                          xmlAutomataNewEpsilon(pctxt->am,
                                              oldstate, pctxt->state);
                          ret = 1;
                      }
                  } else {
                      sub = particle->children->children;
                      while (sub != NULL) {
                          tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                          (xmlSchemaParticlePtr) sub);
                          if (tmp2 != 1) ret = 0;
                          sub = sub->next;
                      }
  
  		    /*
  		     * epsilon needed to block previous trans from
  		     * being allowed to enter back from another
  		     * construct
  		     */
  		    pctxt->state = xmlAutomataNewEpsilon(pctxt->am,
  					pctxt->state, NULL);
  
                      if (particle->minOccurs == 0) {
                          xmlAutomataNewEpsilon(pctxt->am, oldstate,
                                                pctxt->state);
                          ret = 1;
                      }
                  }
              }
              break;
          }
          case XML_SCHEMA_TYPE_CHOICE:{
              xmlSchemaTreeItemPtr sub;
              xmlAutomataStatePtr start, end;
  
              ret = 0;
              start = pctxt->state;
              end = xmlAutomataNewState(pctxt->am);
  
              /*
               * iterate over the subtypes and remerge the end with an
               * epsilon transition
               */
              if (particle->maxOccurs == 1) {
                  sub = particle->children->children;
                  while (sub != NULL) {
                      pctxt->state = start;
                      tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                          (xmlSchemaParticlePtr) sub);
                      if (tmp2 == 1) ret = 1;
                      xmlAutomataNewEpsilon(pctxt->am, pctxt->state, end);
                      sub = sub->next;
                  }
              } else {
                  int counter;
                  xmlAutomataStatePtr hop, base;
                  int maxOccurs = particle->maxOccurs == UNBOUNDED ?
                      UNBOUNDED : particle->maxOccurs - 1;
                  int minOccurs =
                      particle->minOccurs < 1 ? 0 : particle->minOccurs - 1;
  
                  /*
                   * use a counter to keep track of the number of transitions
                   * which went through the choice.
                   */
                  counter =
                      xmlAutomataNewCounter(pctxt->am, minOccurs, maxOccurs);
                  hop = xmlAutomataNewState(pctxt->am);
                  base = xmlAutomataNewState(pctxt->am);
  
                  sub = particle->children->children;
                  while (sub != NULL) {
                      pctxt->state = base;
                      tmp2 = xmlSchemaBuildAContentModel(pctxt,
                                          (xmlSchemaParticlePtr) sub);
                      if (tmp2 == 1) ret = 1;
                      xmlAutomataNewEpsilon(pctxt->am, pctxt->state, hop);
                      sub = sub->next;
                  }
                  xmlAutomataNewEpsilon(pctxt->am, start, base);
                  xmlAutomataNewCountedTrans(pctxt->am, hop, base, counter);
                  xmlAutomataNewCounterTrans(pctxt->am, hop, end, counter);
                  if (ret == 1)
                      xmlAutomataNewEpsilon(pctxt->am, base, end);
              }
              if (particle->minOccurs == 0) {
                  xmlAutomataNewEpsilon(pctxt->am, start, end);
                  ret = 1;
              }
              pctxt->state = end;
              break;
          }
          case XML_SCHEMA_TYPE_ALL:{
              xmlAutomataStatePtr start, tmp;
              xmlSchemaParticlePtr sub;
              xmlSchemaElementPtr elemDecl;
  
              ret = 1;
  
              sub = (xmlSchemaParticlePtr) particle->children->children;
              if (sub == NULL)
                  break;
  
              ret = 0;
  
              start = pctxt->state;
              tmp = xmlAutomataNewState(pctxt->am);
              xmlAutomataNewEpsilon(pctxt->am, pctxt->state, tmp);
              pctxt->state = tmp;
              while (sub != NULL) {
                  pctxt->state = tmp;
  
                  elemDecl = (xmlSchemaElementPtr) sub->children;
                  if (elemDecl == NULL) {
                      PERROR_INT("xmlSchemaBuildAContentModel",
                          "<element> particle has no term");
                      return(ret);
                  };
                  /*
                  * NOTE: The {max occurs} of all the particles in the
                  * {particles} of the group must be 0 or 1; this is
                  * already ensured during the parse of the content of
                  * <all>.
                  */
                  if (elemDecl->flags & XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD) {
                      int counter;
  
                      /*
                       * This is an abstract group, we need to share
                       * the same counter for all the element transitions
                       * derived from the group
                       */
                      counter = xmlAutomataNewCounter(pctxt->am,
                                         sub->minOccurs, sub->maxOccurs);
                      xmlSchemaBuildContentModelForSubstGroup(pctxt,
                                         sub, counter, pctxt->state);
                  } else {
                      if ((sub->minOccurs == 1) &&
                          (sub->maxOccurs == 1)) {
                          xmlAutomataNewOnceTrans2(pctxt->am, pctxt->state,
                                                  pctxt->state,
                                                  elemDecl->name,
                                                  elemDecl->targetNamespace,
                                                  1, 1, elemDecl);
                      } else if ((sub->minOccurs == 0) &&
                          (sub->maxOccurs == 1)) {
  
                          xmlAutomataNewCountTrans2(pctxt->am, pctxt->state,
                                                   pctxt->state,
                                                   elemDecl->name,
                                                   elemDecl->targetNamespace,
                                                   0,
                                                   1,
                                                   elemDecl);
                      }
                  }
                  sub = (xmlSchemaParticlePtr) sub->next;
              }
              pctxt->state =
                  xmlAutomataNewAllTrans(pctxt->am, pctxt->state, NULL, 0);
              if (particle->minOccurs == 0) {
                  xmlAutomataNewEpsilon(pctxt->am, start, pctxt->state);
                  ret = 1;
              }
              break;
          }
  	case XML_SCHEMA_TYPE_GROUP:
  	    /*
  	    * If we hit a model group definition, then this means that
  	    * it was empty, thus was not substituted for the containing
  	    * model group. Just do nothing in this case.
  	    * TODO: But the group should be substituted and not occur at
  	    * all in the content model at this point. Fix this.
  	    */
              ret = 1;
  	    break;
          default:
  	    xmlSchemaInternalErr2(ACTXT_CAST pctxt,
  		"xmlSchemaBuildAContentModel",
  		"found unexpected term of type '%s' in content model",
  		WXS_ITEM_TYPE_NAME(particle->children), NULL);
              return(ret);
      }
      return(ret);
  }
  
  /**
   * xmlSchemaBuildContentModel:
   * @ctxt:  the schema parser context
   * @type:  the complex type definition
   * @name:  the element name
   *
   * Builds the content model of the complex type.
   */
  static void
  xmlSchemaBuildContentModel(xmlSchemaTypePtr type,
  			   xmlSchemaParserCtxtPtr ctxt)
  {
      if ((type->type != XML_SCHEMA_TYPE_COMPLEX) ||
  	(type->contModel != NULL) ||
  	((type->contentType != XML_SCHEMA_CONTENT_ELEMENTS) &&
  	(type->contentType != XML_SCHEMA_CONTENT_MIXED)))
  	return;
  
  #ifdef DEBUG_CONTENT
      xmlGenericError(xmlGenericErrorContext,
                      "Building content model for %s\n", name);
  #endif
      ctxt->am = NULL;
      ctxt->am = xmlNewAutomata();
      if (ctxt->am == NULL) {
          xmlGenericError(xmlGenericErrorContext,
  	    "Cannot create automata for complex type %s\n", type->name);
          return;
      }
      ctxt->state = xmlAutomataGetInitState(ctxt->am);
      /*
      * Build the automaton.
      */
      xmlSchemaBuildAContentModel(ctxt, WXS_TYPE_PARTICLE(type));
      xmlAutomataSetFinalState(ctxt->am, ctxt->state);
      type->contModel = xmlAutomataCompile(ctxt->am);
      if (type->contModel == NULL) {
          xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_INTERNAL,
  	    WXS_BASIC_CAST type, type->node,
  	    "Failed to compile the content model", NULL);
      } else if (xmlRegexpIsDeterminist(type->contModel) != 1) {
          xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_NOT_DETERMINISTIC,
  	    /* XML_SCHEMAS_ERR_NOTDETERMINIST, */
  	    WXS_BASIC_CAST type, type->node,
  	    "The content model is not determinist", NULL);
      } else {
  #ifdef DEBUG_CONTENT_REGEXP
          xmlGenericError(xmlGenericErrorContext,
                          "Content model of %s:\n", type->name);
          xmlRegexpPrint(stderr, type->contModel);
  #endif
      }
      ctxt->state = NULL;
      xmlFreeAutomata(ctxt->am);
      ctxt->am = NULL;
  }
  
  /**
   * xmlSchemaResolveElementReferences:
   * @elem:  the schema element context
   * @ctxt:  the schema parser context
   *
   * Resolves the references of an element declaration
   * or particle, which has an element declaration as it's
   * term.
   */
  static void
  xmlSchemaResolveElementReferences(xmlSchemaElementPtr elemDecl,
  				  xmlSchemaParserCtxtPtr ctxt)
  {
      if ((ctxt == NULL) || (elemDecl == NULL) ||
  	((elemDecl != NULL) &&
  	(elemDecl->flags & XML_SCHEMAS_ELEM_INTERNAL_RESOLVED)))
          return;
      elemDecl->flags |= XML_SCHEMAS_ELEM_INTERNAL_RESOLVED;
  
      if ((elemDecl->subtypes == NULL) && (elemDecl->namedType != NULL)) {
  	xmlSchemaTypePtr type;
  
  	/* (type definition) ... otherwise the type definition `resolved`
  	* to by the `actual value` of the type [attribute] ...
  	*/
  	type = xmlSchemaGetType(ctxt->schema, elemDecl->namedType,
  	    elemDecl->namedTypeNs);
  	if (type == NULL) {
  	    xmlSchemaPResCompAttrErr(ctxt,
  		XML_SCHEMAP_SRC_RESOLVE,
  		WXS_BASIC_CAST elemDecl, elemDecl->node,
  		"type", elemDecl->namedType, elemDecl->namedTypeNs,
  		XML_SCHEMA_TYPE_BASIC, "type definition");
  	} else
  	    elemDecl->subtypes = type;
      }
      if (elemDecl->substGroup != NULL) {
  	xmlSchemaElementPtr substHead;
  
  	/*
  	* FIXME TODO: Do we need a new field in _xmlSchemaElement for
  	* substitutionGroup?
  	*/
  	substHead = xmlSchemaGetElem(ctxt->schema, elemDecl->substGroup,
  	    elemDecl->substGroupNs);
  	if (substHead == NULL) {
  	    xmlSchemaPResCompAttrErr(ctxt,
  		XML_SCHEMAP_SRC_RESOLVE,
  		WXS_BASIC_CAST elemDecl, NULL,
  		"substitutionGroup", elemDecl->substGroup,
  		elemDecl->substGroupNs, XML_SCHEMA_TYPE_ELEMENT, NULL);
  	} else {
  	    xmlSchemaResolveElementReferences(substHead, ctxt);
  	    /*
  	    * Set the "substitution group affiliation".
  	    * NOTE that now we use the "refDecl" field for this.
  	    */
  	    WXS_SUBST_HEAD(elemDecl) = substHead;
  	    /*
  	    * The type definitions is set to:
  	    * SPEC "...the {type definition} of the element
  	    * declaration `resolved` to by the `actual value`
  	    * of the substitutionGroup [attribute], if present"
  	    */
  	    if (elemDecl->subtypes == NULL)
  		elemDecl->subtypes = substHead->subtypes;
  	}
      }
      /*
      * SPEC "The definition of anyType serves as the default type definition
      * for element declarations whose XML representation does not specify one."
      */
      if ((elemDecl->subtypes == NULL) &&
  	(elemDecl->namedType == NULL) &&
  	(elemDecl->substGroup == NULL))
  	elemDecl->subtypes = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE);
  }
  
  /**
   * xmlSchemaResolveUnionMemberTypes:
   * @ctxt:  the schema parser context
   * @type:  the schema simple type definition
   *
   * Checks and builds the "member type definitions" property of the union
   * simple type. This handles part (1), part (2) is done in
   * xmlSchemaFinishMemberTypeDefinitionsProperty()
   *
   * Returns -1 in case of an internal error, 0 otherwise.
   */
  static int
  xmlSchemaResolveUnionMemberTypes(xmlSchemaParserCtxtPtr ctxt,
  				 xmlSchemaTypePtr type)
  {
  
      xmlSchemaTypeLinkPtr link, lastLink, newLink;
      xmlSchemaTypePtr memberType;
  
      /*
      * SPEC (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."
      */
      /*
      * Resolve references.
      */
      link = type->memberTypes;
      lastLink = NULL;
      while (link != NULL) {
  	const xmlChar *name, *nsName;
  
  	name = ((xmlSchemaQNameRefPtr) link->type)->name;
  	nsName = ((xmlSchemaQNameRefPtr) link->type)->targetNamespace;
  
  	memberType = xmlSchemaGetType(ctxt->schema, name, nsName);
  	if ((memberType == NULL) || (! WXS_IS_SIMPLE(memberType))) {
  	    xmlSchemaPResCompAttrErr(ctxt, XML_SCHEMAP_SRC_RESOLVE,
  		WXS_BASIC_CAST type, type->node, "memberTypes",
  		name, nsName, XML_SCHEMA_TYPE_SIMPLE, NULL);
  	    /*
  	    * Remove the member type link.
  	    */
  	    if (lastLink == NULL)
  		type->memberTypes = link->next;
  	    else
  		lastLink->next = link->next;
  	    newLink = link;
  	    link = link->next;
  	    xmlFree(newLink);
  	} else {
  	    link->type = memberType;
  	    lastLink = link;
  	    link = link->next;
  	}
      }
      /*
      * Add local simple types,
      */
      memberType = type->subtypes;
      while (memberType != 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)
  	    type->memberTypes = link;
  	else
  	    lastLink->next = link;
  	lastLink = link;
  	memberType = memberType->next;
      }
      return (0);
  }
  
  /**
   * 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(xmlSchemaTypePtr type, int valType)
  {
      if (type == NULL)
  	return (0);
      if (WXS_IS_COMPLEX(type))
  	return (0);
      if (type->type == XML_SCHEMA_TYPE_BASIC) {
  	if (type->builtInType == valType)
  	    return(1);
  	if ((type->builtInType == XML_SCHEMAS_ANYSIMPLETYPE) ||
  	    (type->builtInType == XML_SCHEMAS_ANYTYPE))
  	    return (0);
  	return(xmlSchemaIsDerivedFromBuiltInType(type->subtypes, valType));
      }
      return(xmlSchemaIsDerivedFromBuiltInType(type->subtypes, valType));
  }
  
  #if 0
  /**
   * 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
  xmlSchemaIsUserDerivedFromBuiltInType(xmlSchemaTypePtr type, int valType)
  {
      if (type == NULL)
  	return (0);
      if (WXS_IS_COMPLEX(type))
  	return (0);
      if (type->type == XML_SCHEMA_TYPE_BASIC) {
  	if (type->builtInType == valType)
  	    return(1);
  	return (0);
      } else
  	return(xmlSchemaIsDerivedFromBuiltInType(type->subtypes, valType));
  
      return (0);
  }
  
  static xmlSchemaTypePtr
  xmlSchemaQueryBuiltInType(xmlSchemaTypePtr type)
  {
      if (type == NULL)
  	return (NULL);
      if (WXS_IS_COMPLEX(type))
  	return (NULL);
      if (type->type == XML_SCHEMA_TYPE_BASIC)
  	return(type);
      return(xmlSchemaQueryBuiltInType(type->subtypes));
  }
  #endif
  
  /**
   * xmlSchemaGetPrimitiveType:
   * @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) {
  	/*
  	* Note that anySimpleType is actually not a primitive type
  	* but we need that here.
  	*/
  	if ((type->builtInType == XML_SCHEMAS_ANYSIMPLETYPE) ||
  	   (type->flags & XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE))
  	    return (type);
  	type = type->baseType;
      }
  
      return (NULL);
  }
  
  #if 0
  /**
   * xmlSchemaGetBuiltInTypeAncestor:
   * @type:  the simpleType definition
   *
   * Returns the primitive type of the given type or
   * NULL in case of error.
   */
  static xmlSchemaTypePtr
  xmlSchemaGetBuiltInTypeAncestor(xmlSchemaTypePtr type)
  {
      if (WXS_IS_LIST(type) || WXS_IS_UNION(type))
  	return (0);
      while (type != NULL) {
  	if (type->type == XML_SCHEMA_TYPE_BASIC)
  	    return (type);
  	type = type->baseType;
      }
  
      return (NULL);
  }
  #endif
  
  /**
   * xmlSchemaCloneWildcardNsConstraints:
   * @ctxt:  the schema parser context
   * @dest:  the destination wildcard
   * @source: the source wildcard
   *
   * Clones the namespace constraints of source
   * and assigns 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 wildcard 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 wildcard 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
   * @sub:  the first wildcard
   * @super: the second wildcard
   *
   * Schema Component Constraint: Wildcard Subset (cos-ns-subset)
   *
   * Returns 0 if the namespace constraint of @sub is an intensional
   * subset of @super, 1 otherwise.
   */
  static int
  xmlSchemaCheckCOSNSSubset(xmlSchemaWildcardPtr sub,
  			  xmlSchemaWildcardPtr super)
  {
      /*
      * 1 super must be any.
      */
      if (super->any)
  	return (0);
      /*
      * 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 ((sub->negNsSet != NULL) &&
  	(super->negNsSet != NULL) &&
  	(sub->negNsSet->value == super->negNsSet->value))
  	return (0);
      /*
      * 3.1 sub must be a set whose members are either namespace names or `absent`.
      */
      if (sub->nsSet != NULL) {
  	/*
  	* 3.2.1 super must be the same set or a superset thereof.
  	*/
  	if (super->nsSet != NULL) {
  	    xmlSchemaWildcardNsPtr cur, curB;
  	    int found = 0;
  
  	    cur = sub->nsSet;
  	    while (cur != NULL) {
  		found = 0;
  		curB = super->nsSet;
  		while (curB != NULL) {
  		    if (cur->value == curB->value) {
  			found = 1;
  			break;
  		    }
  		    curB = curB->next;
  		}
  		if (!found)
  		    return (1);
  		cur = cur->next;
  	    }
  	    if (found)
  		return (0);
  	} else if (super->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 = sub->nsSet;
  	    while (cur != NULL) {
  		if (cur->value == super->negNsSet->value)
  		    return (1);
  		cur = cur->next;
  	    }
  	    return (0);
  	}
      }
      return (1);
  }
  
  static int
  xmlSchemaGetEffectiveValueConstraint(xmlSchemaAttributeUsePtr attruse,
  				     int *fixed,
  				     const xmlChar **value,
  				     xmlSchemaValPtr *val)
  {
      *fixed = 0;
      *value = NULL;
      if (val != 0)
  	*val = NULL;
  
      if (attruse->defValue != NULL) {
  	*value = attruse->defValue;
  	if (val != NULL)
  	    *val = attruse->defVal;
  	if (attruse->flags & XML_SCHEMA_ATTR_USE_FIXED)
  	    *fixed = 1;
  	return(1);
      } else if ((attruse->attrDecl != NULL) &&
  	(attruse->attrDecl->defValue != NULL)) {
  	*value = attruse->attrDecl->defValue;
  	if (val != NULL)
  	    *val = attruse->attrDecl->defVal;
  	if (attruse->attrDecl->flags & XML_SCHEMAS_ATTR_FIXED)
  	    *fixed = 1;
  	return(1);
      }
      return(0);
  }
  /**
   * xmlSchemaCheckCVCWildcardNamespace:
   * @wild:  the wildcard
   * @ns:  the namespace
   *
   * Validation Rule: Wildcard allows Namespace Name
   * (cvc-wildcard-namespace)
   *
   * Returns 0 if the given namespace matches the wildcard,
   * 1 otherwise and -1 on API errors.
   */
  static int
  xmlSchemaCheckCVCWildcardNamespace(xmlSchemaWildcardPtr wild,
  				   const xmlChar* ns)
  {
      if (wild == NULL)
  	return(-1);
  
      if (wild->any)
  	return(0);
      else if (wild->nsSet != NULL) {
  	xmlSchemaWildcardNsPtr cur;
  
  	cur = wild->nsSet;
  	while (cur != NULL) {
  	    if (xmlStrEqual(cur->value, ns))
  		return(0);
  	    cur = cur->next;
  	}
      } else if ((wild->negNsSet != NULL) && (ns != NULL) &&
  	(!xmlStrEqual(wild->negNsSet->value, ns)))
  	return(0);
  
      return(1);
  }
  
  #define XML_SCHEMA_ACTION_DERIVE 0
  #define XML_SCHEMA_ACTION_REDEFINE 1
  
  #define WXS_ACTION_STR(a) \
  ((a) == XML_SCHEMA_ACTION_DERIVE) ? (const xmlChar *) "base" : (const xmlChar *) "redefined"
  
  /*
  * Schema Component Constraint:
  *   Derivation Valid (Restriction, Complex)
  *   derivation-ok-restriction (2) - (4)
  *
  * ATTENTION:
  * In XML Schema 1.1 this will be:
  * Validation Rule:
  *     Checking complex type subsumption (practicalSubsumption) (1, 2 and 3)
  *
  */
  static int
  xmlSchemaCheckDerivationOKRestriction2to4(xmlSchemaParserCtxtPtr pctxt,
  				       int action,
  				       xmlSchemaBasicItemPtr item,
  				       xmlSchemaBasicItemPtr baseItem,
  				       xmlSchemaItemListPtr uses,
  				       xmlSchemaItemListPtr baseUses,
  				       xmlSchemaWildcardPtr wild,
  				       xmlSchemaWildcardPtr baseWild)
  {
      xmlSchemaAttributeUsePtr cur = NULL, bcur;
      int i, j, found; /* err = 0; */
      const xmlChar *bEffValue;
      int effFixed;
  
      if (uses != NULL) {
  	for (i = 0; i < uses->nbItems; i++) {
  	    cur = uses->items[i];
  	    found = 0;
  	    if (baseUses == NULL)
  		goto not_found;
  	    for (j = 0; j < baseUses->nbItems; j++) {
  		bcur = baseUses->items[j];
  		if ((WXS_ATTRUSE_DECL_NAME(cur) ==
  			WXS_ATTRUSE_DECL_NAME(bcur)) &&
  		    (WXS_ATTRUSE_DECL_TNS(cur) ==
  			WXS_ATTRUSE_DECL_TNS(bcur)))
  		{
  		    /*
  		    * (2.1) "If there is an attribute use in the {attribute
  		    * uses} of the {base type definition} (call this B) whose
  		    * {attribute declaration} has the same {name} and {target
  		    * namespace}, then  all of the following must be true:"
  		    */
  		    found = 1;
  
  		    if ((cur->occurs == XML_SCHEMAS_ATTR_USE_OPTIONAL) &&
  			(bcur->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED))
  		    {
  			xmlChar *str = NULL;
  			/*
  			* (2.1.1) "one of the following must be true:"
  			* (2.1.1.1) "B's {required} is false."
  			* (2.1.1.2) "R's {required} is true."
  			*/
  			xmlSchemaPAttrUseErr4(pctxt,
  			    XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_1,
  			    WXS_ITEM_NODE(item), item, cur,
  			    "The 'optional' attribute use is inconsistent "
  			    "with the corresponding 'required' attribute use of "
  			    "the %s %s",
  			    WXS_ACTION_STR(action),
  			    xmlSchemaGetComponentDesignation(&str, baseItem),
  			    NULL, NULL);
  			FREE_AND_NULL(str);
  			/* err = pctxt->err; */
  		    } else if (xmlSchemaCheckCOSSTDerivedOK(ACTXT_CAST pctxt,
  			WXS_ATTRUSE_TYPEDEF(cur),
  			WXS_ATTRUSE_TYPEDEF(bcur), 0) != 0)
  		    {
  			xmlChar *strA = NULL, *strB = NULL, *strC = NULL;
  
  			/*
  			* SPEC (2.1.2) "R's {attribute declaration}'s
  			* {type definition} must be validly derived from
  			* B's {type definition} given the empty set as
  			* defined in Type Derivation OK (Simple) ($3.14.6)."
  			*/
  			xmlSchemaPAttrUseErr4(pctxt,
  			    XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_2,
  			    WXS_ITEM_NODE(item), item, cur,
  			    "The attribute declaration's %s "
  			    "is not validly derived from "
  			    "the corresponding %s of the "
  			    "attribute declaration in the %s %s",
  			    xmlSchemaGetComponentDesignation(&strA,
  				WXS_ATTRUSE_TYPEDEF(cur)),
  			    xmlSchemaGetComponentDesignation(&strB,
  				WXS_ATTRUSE_TYPEDEF(bcur)),
  			    WXS_ACTION_STR(action),
  			    xmlSchemaGetComponentDesignation(&strC, baseItem));
  			    /* xmlSchemaGetComponentDesignation(&str, baseItem), */
  			FREE_AND_NULL(strA);
  			FREE_AND_NULL(strB);
  			FREE_AND_NULL(strC);
  			/* err = pctxt->err; */
  		    } else {
  			/*
  			* 2.1.3 [Definition:]  Let the effective value
  			* constraint of an attribute use be its {value
  			* constraint}, if present, otherwise its {attribute
  			* declaration}'s {value constraint} .
  			*/
  			xmlSchemaGetEffectiveValueConstraint(bcur,
  			    &effFixed, &bEffValue, NULL);
  			/*
  			* 2.1.3 ... one of the following must be true
  			*
  			* 2.1.3.1 B's `effective value constraint` is
  			* `absent` or default.
  			*/
  			if ((bEffValue != NULL) &&
  			    (effFixed == 1)) {
  			    const xmlChar *rEffValue = NULL;
  
  			    xmlSchemaGetEffectiveValueConstraint(bcur,
  				&effFixed, &rEffValue, NULL);
  			    /*
  			    * 2.1.3.2 R's `effective value constraint` is
  			    * fixed with the same string as B's.
  			    * MAYBE TODO: Compare the computed values.
  			    *       Hmm, it says "same string" so
  			    *       string-equality might really be sufficient.
  			    */
  			    if ((effFixed == 0) ||
  				(! WXS_ARE_DEFAULT_STR_EQUAL(rEffValue, bEffValue)))
  			    {
  				xmlChar *str = NULL;
  
  				xmlSchemaPAttrUseErr4(pctxt,
  				    XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_1_3,
  				    WXS_ITEM_NODE(item), item, cur,
  				    "The effective value constraint of the "
  				    "attribute use is inconsistent with "
  				    "its correspondent in the %s %s",
  				    WXS_ACTION_STR(action),
  				    xmlSchemaGetComponentDesignation(&str,
  					baseItem),
  				    NULL, NULL);
  				FREE_AND_NULL(str);
  				/* err = pctxt->err; */
  			    }
  			}
  		    }
  		    break;
  		}
  	    }
  not_found:
  	    if (!found) {
  		/*
  		* (2.2) "otherwise the {base type definition} must have an
  		* {attribute wildcard} and the {target namespace} of the
  		* R's {attribute declaration} must be `valid` with respect
  		* to that wildcard, as defined in Wildcard allows Namespace
  		* Name ($3.10.4)."
  		*/
  		if ((baseWild == NULL) ||
  		    (xmlSchemaCheckCVCWildcardNamespace(baseWild,
  		    (WXS_ATTRUSE_DECL(cur))->targetNamespace) != 0))
  		{
  		    xmlChar *str = NULL;
  
  		    xmlSchemaPAttrUseErr4(pctxt,
  			XML_SCHEMAP_DERIVATION_OK_RESTRICTION_2_2,
  			WXS_ITEM_NODE(item), item, cur,
  			"Neither a matching attribute use, "
  			"nor a matching wildcard exists in the %s %s",
  			WXS_ACTION_STR(action),
  			xmlSchemaGetComponentDesignation(&str, baseItem),
  			NULL, NULL);
  		    FREE_AND_NULL(str);
  		    /* err = pctxt->err; */
  		}
  	    }
  	}
      }
      /*
      * SPEC derivation-ok-restriction (3):
      * (3) "For each attribute use in the {attribute uses} of the {base type
      * definition} whose {required} is true, there must be an attribute
      * use with an {attribute declaration} with the same {name} and
      * {target namespace} as its {attribute declaration} in the {attribute
      * uses} of the complex type definition itself whose {required} is true.
      */
      if (baseUses != NULL) {
  	for (j = 0; j < baseUses->nbItems; j++) {
  	    bcur = baseUses->items[j];
  	    if (bcur->occurs != XML_SCHEMAS_ATTR_USE_REQUIRED)
  		continue;
  	    found = 0;
  	    if (uses != NULL) {
  		for (i = 0; i < uses->nbItems; i++) {
  		    cur = uses->items[i];
  		    if ((WXS_ATTRUSE_DECL_NAME(cur) ==
  			WXS_ATTRUSE_DECL_NAME(bcur)) &&
  			(WXS_ATTRUSE_DECL_TNS(cur) ==
  			WXS_ATTRUSE_DECL_TNS(bcur))) {
  			found = 1;
  			break;
  		    }
  		}
  	    }
  	    if (!found) {
  		xmlChar *strA = NULL, *strB = NULL;
  
  		xmlSchemaCustomErr4(ACTXT_CAST pctxt,
  		    XML_SCHEMAP_DERIVATION_OK_RESTRICTION_3,
  		    NULL, item,
  		    "A matching attribute use for the "
  		    "'required' %s of the %s %s is missing",
  		    xmlSchemaGetComponentDesignation(&strA, bcur),
  		    WXS_ACTION_STR(action),
  		    xmlSchemaGetComponentDesignation(&strB, baseItem),
  		    NULL);
  		FREE_AND_NULL(strA);
  		FREE_AND_NULL(strB);
  	    }
  	}
      }
      /*
      * derivation-ok-restriction (4)
      */
      if (wild != NULL) {
  	/*
  	* (4) "If there is an {attribute wildcard}, all of the
  	* following must be true:"
  	*/
  	if (baseWild == NULL) {
  	    xmlChar *str = NULL;
  
  	    /*
  	    * (4.1) "The {base type definition} must also have one."
  	    */
  	    xmlSchemaCustomErr4(ACTXT_CAST pctxt,
  		XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_1,
  		NULL, item,
  		"The %s has an attribute wildcard, "
  		"but the %s %s '%s' does not have one",
  		WXS_ITEM_TYPE_NAME(item),
  		WXS_ACTION_STR(action),
  		WXS_ITEM_TYPE_NAME(baseItem),
  		xmlSchemaGetComponentQName(&str, baseItem));
  	    FREE_AND_NULL(str);
  	    return(pctxt->err);
  	} else if ((baseWild->any == 0) &&
  		xmlSchemaCheckCOSNSSubset(wild, baseWild))
  	{
  	    xmlChar *str = NULL;
  	    /*
  	    * (4.2) "The complex type definition's {attribute wildcard}'s
  	    * {namespace constraint} must be a subset of the {base type
  	    * definition}'s {attribute wildcard}'s {namespace constraint},
  	    * as defined by Wildcard Subset ($3.10.6)."
  	    */
  	    xmlSchemaCustomErr4(ACTXT_CAST pctxt,
  		XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_2,
  		NULL, item,
  		"The attribute wildcard is not a valid "
  		"subset of the wildcard in the %s %s '%s'",
  		WXS_ACTION_STR(action),
  		WXS_ITEM_TYPE_NAME(baseItem),
  		xmlSchemaGetComponentQName(&str, baseItem),
  		NULL);
  	    FREE_AND_NULL(str);
  	    return(pctxt->err);
  	}
  	/* 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 ((! WXS_IS_ANYTYPE(baseItem)) &&
  	    (wild->processContents < baseWild->processContents)) {
  	    xmlChar *str = NULL;
  	    xmlSchemaCustomErr4(ACTXT_CAST pctxt,
  		XML_SCHEMAP_DERIVATION_OK_RESTRICTION_4_3,
  		NULL, baseItem,
  		"The {process contents} of the attribute wildcard is "
  		"weaker than the one in the %s %s '%s'",
  		WXS_ACTION_STR(action),
  		WXS_ITEM_TYPE_NAME(baseItem),
  		xmlSchemaGetComponentQName(&str, baseItem),
  		NULL);
  	    FREE_AND_NULL(str)
  		return(pctxt->err);
  	}
      }
      return(0);
  }
  
  
  static int
  xmlSchemaExpandAttributeGroupRefs(xmlSchemaParserCtxtPtr pctxt,
  				  xmlSchemaBasicItemPtr item,
  				  xmlSchemaWildcardPtr *completeWild,
  				  xmlSchemaItemListPtr list,
  				  xmlSchemaItemListPtr prohibs);
  /**
   * xmlSchemaFixupTypeAttributeUses:
   * @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.
   *
   * ATTENTION TODO: Experimentally this uses pointer comparisons for
   * strings, so recheck this if we start to hardcode some schemata, since
   * they might not be in the same dict.
   * NOTE: It is allowed to "extend" the xs:anyType type.
   */
  static int
  xmlSchemaFixupTypeAttributeUses(xmlSchemaParserCtxtPtr pctxt,
  				  xmlSchemaTypePtr type)
  {
      xmlSchemaTypePtr baseType = NULL;
      xmlSchemaAttributeUsePtr use;
      xmlSchemaItemListPtr uses, baseUses, prohibs = NULL;
  
      if (type->baseType == NULL) {
  	PERROR_INT("xmlSchemaFixupTypeAttributeUses",
  	    "no base type");
          return (-1);
      }
      baseType = type->baseType;
      if (WXS_IS_TYPE_NOT_FIXED(baseType))
  	if (xmlSchemaTypeFixup(baseType, ACTXT_CAST pctxt) == -1)
  	    return(-1);
  
      uses = type->attrUses;
      baseUses = baseType->attrUses;
      /*
      * Expand attribute group references. And build the 'complete'
      * wildcard, i.e. intersect multiple wildcards.
      * Move attribute prohibitions into a separate list.
      */
      if (uses != NULL) {
  	if (WXS_IS_RESTRICTION(type)) {
  	    /*
  	    * This one will transfer all attr. prohibitions
  	    * into pctxt->attrProhibs.
  	    */
  	    if (xmlSchemaExpandAttributeGroupRefs(pctxt,
  		WXS_BASIC_CAST type, &(type->attributeWildcard), uses,
  		pctxt->attrProhibs) == -1)
  	    {
  		PERROR_INT("xmlSchemaFixupTypeAttributeUses",
  		"failed to expand attributes");
  	    }
  	    if (pctxt->attrProhibs->nbItems != 0)
  		prohibs = pctxt->attrProhibs;
  	} else {
  	    if (xmlSchemaExpandAttributeGroupRefs(pctxt,
  		WXS_BASIC_CAST type, &(type->attributeWildcard), uses,
  		NULL) == -1)
  	    {
  		PERROR_INT("xmlSchemaFixupTypeAttributeUses",
  		"failed to expand attributes");
  	    }
  	}
      }
      /*
      * Inherit the attribute uses of the base type.
      */
      if (baseUses != NULL) {
  	int i, j;
  	xmlSchemaAttributeUseProhibPtr pro;
  
  	if (WXS_IS_RESTRICTION(type)) {
  	    int usesCount;
  	    xmlSchemaAttributeUsePtr tmp;
  
  	    if (uses != NULL)
  		usesCount = uses->nbItems;
  	    else
  		usesCount = 0;
  
  	    /* Restriction. */
  	    for (i = 0; i < baseUses->nbItems; i++) {
  		use = baseUses->items[i];
  		if (prohibs) {
  		    /*
  		    * Filter out prohibited uses.
  		    */
  		    for (j = 0; j < prohibs->nbItems; j++) {
  			pro = prohibs->items[j];
  			if ((WXS_ATTRUSE_DECL_NAME(use) == pro->name) &&
  			    (WXS_ATTRUSE_DECL_TNS(use) ==
  				pro->targetNamespace))
  			{
  			    goto inherit_next;
  			}
  		    }
  		}
  		if (usesCount) {
  		    /*
  		    * Filter out existing uses.
  		    */
  		    for (j = 0; j < usesCount; j++) {
  			tmp = uses->items[j];
  			if ((WXS_ATTRUSE_DECL_NAME(use) ==
  				WXS_ATTRUSE_DECL_NAME(tmp)) &&
  			    (WXS_ATTRUSE_DECL_TNS(use) ==
  				WXS_ATTRUSE_DECL_TNS(tmp)))
  			{
  			    goto inherit_next;
  			}
  		    }
  		}
  		if (uses == NULL) {
  		    type->attrUses = xmlSchemaItemListCreate();
  		    if (type->attrUses == NULL)
  			goto exit_failure;
  		    uses = type->attrUses;
  		}
  		xmlSchemaItemListAddSize(uses, 2, use);
  inherit_next: {}
  	    }
  	} else {
  	    /* Extension. */
  	    for (i = 0; i < baseUses->nbItems; i++) {
  		use = baseUses->items[i];
  		if (uses == NULL) {
  		    type->attrUses = xmlSchemaItemListCreate();
  		    if (type->attrUses == NULL)
  			goto exit_failure;
  		    uses = type->attrUses;
  		}
  		xmlSchemaItemListAddSize(uses, baseUses->nbItems, use);
  	    }
  	}
      }
      /*
      * Shrink attr. uses.
      */
      if (uses) {
  	if (uses->nbItems == 0) {
  	    xmlSchemaItemListFree(uses);
  	    type->attrUses = NULL;
  	}
  	/*
  	* TODO: We could shrink the size of the array
  	* to fit the actual number of items.
  	*/
      }
      /*
      * Compute the complete wildcard.
      */
      if (WXS_IS_EXTENSION(type)) {
  	if (baseType->attributeWildcard != NULL) {
  	    /*
  	    * (3.2.2.1) "If the `base wildcard` is non-`absent`, then
  	    * the appropriate case among the following:"
  	    */
  	    if (type->attributeWildcard != NULL) {
  		/*
  		* Union the complete wildcard with the base wildcard.
  		* SPEC {attribute wildcard}
  		* (3.2.2.1.2) "otherwise a wildcard whose {process contents}
  		* and {annotation} are those of the `complete wildcard`,
  		* and whose {namespace constraint} is the intensional union
  		* of the {namespace constraint} of the `complete wildcard`
  		* and of the `base wildcard`, as defined in Attribute
  		* Wildcard Union ($3.10.6)."
  		*/
  		if (xmlSchemaUnionWildcards(pctxt, type->attributeWildcard,
  		    baseType->attributeWildcard) == -1)
  		    goto exit_failure;
  	    } else {
  		/*
  		* (3.2.2.1.1) "If the `complete wildcard` is `absent`,
  		* then the `base wildcard`."
  		*/
  		type->attributeWildcard = baseType->attributeWildcard;
  	    }
  	} else {
  	    /*
  	    * (3.2.2.2) "otherwise (the `base wildcard` is `absent`) the
  	    * `complete wildcard`"
  	    * NOOP
  	    */
  	}
      } else {
  	/*
  	* SPEC {attribute wildcard}
  	* (3.1) "If the <restriction> alternative is chosen, then the
  	* `complete wildcard`;"
  	* NOOP
  	*/
      }
  
      return (0);
  
  exit_failure:
      return(-1);
  }
  
  /**
   * 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 contain the given "final",
   * 0 otherwise.
   */
  static int
  xmlSchemaTypeFinalContains(xmlSchemaTypePtr type, int final)
  {
      if (type == NULL)
  	return (0);
      if (type->flags & final)
  	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) && (type->type == XML_SCHEMA_TYPE_SIMPLE)) {
  	if (type->memberTypes != NULL)
  	    return (type->memberTypes);
  	else
  	    type = type->baseType;
      }
      return (NULL);
  }
  
  /**
   * xmlSchemaGetParticleTotalRangeMin:
   * @particle: the particle
   *
   * Schema Component Constraint: Effective Total Range
   * (all and sequence) + (choice)
   *
   * Returns the minimum Effective Total Range.
   */
  static int
  xmlSchemaGetParticleTotalRangeMin(xmlSchemaParticlePtr particle)
  {
      if ((particle->children == NULL) ||
  	(particle->minOccurs == 0))
  	return (0);
      if (particle->children->type == XML_SCHEMA_TYPE_CHOICE) {
  	int min = -1, cur;
  	xmlSchemaParticlePtr part =
  	    (xmlSchemaParticlePtr) particle->children->children;
  
  	if (part == NULL)
  	    return (0);
  	while (part != NULL) {
  	    if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) ||
  		(part->children->type == XML_SCHEMA_TYPE_ANY))
  		cur = part->minOccurs;
  	    else
  		cur = xmlSchemaGetParticleTotalRangeMin(part);
  	    if (cur == 0)
  		return (0);
  	    if ((min > cur) || (min == -1))
  		min = cur;
  	    part = (xmlSchemaParticlePtr) part->next;
  	}
  	return (particle->minOccurs * min);
      } else {
  	/* <all> and <sequence> */
  	int sum = 0;
  	xmlSchemaParticlePtr part =
  	    (xmlSchemaParticlePtr) particle->children->children;
  
  	if (part == NULL)
  	    return (0);
  	do {
  	    if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) ||
  		(part->children->type == XML_SCHEMA_TYPE_ANY))
  		sum += part->minOccurs;
  	    else
  		sum += xmlSchemaGetParticleTotalRangeMin(part);
  	    part = (xmlSchemaParticlePtr) part->next;
  	} while (part != NULL);
  	return (particle->minOccurs * sum);
      }
  }
  
  #if 0
  /**
   * xmlSchemaGetParticleTotalRangeMax:
   * @particle: the particle
   *
   * Schema Component Constraint: Effective Total Range
   * (all and sequence) + (choice)
   *
   * Returns the maximum Effective Total Range.
   */
  static int
  xmlSchemaGetParticleTotalRangeMax(xmlSchemaParticlePtr particle)
  {
      if ((particle->children == NULL) ||
  	(particle->children->children == NULL))
  	return (0);
      if (particle->children->type == XML_SCHEMA_TYPE_CHOICE) {
  	int max = -1, cur;
  	xmlSchemaParticlePtr part =
  	    (xmlSchemaParticlePtr) particle->children->children;
  
  	for (; part != NULL; part = (xmlSchemaParticlePtr) part->next) {
  	    if (part->children == NULL)
  		continue;
  	    if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) ||
  		(part->children->type == XML_SCHEMA_TYPE_ANY))
  		cur = part->maxOccurs;
  	    else
  		cur = xmlSchemaGetParticleTotalRangeMax(part);
  	    if (cur == UNBOUNDED)
  		return (UNBOUNDED);
  	    if ((max < cur) || (max == -1))
  		max = cur;
  	}
  	/* TODO: Handle overflows? */
  	return (particle->maxOccurs * max);
      } else {
  	/* <all> and <sequence> */
  	int sum = 0, cur;
  	xmlSchemaParticlePtr part =
  	    (xmlSchemaParticlePtr) particle->children->children;
  
  	for (; part != NULL; part = (xmlSchemaParticlePtr) part->next) {
  	    if (part->children == NULL)
  		continue;
  	    if ((part->children->type == XML_SCHEMA_TYPE_ELEMENT) ||
  		(part->children->type == XML_SCHEMA_TYPE_ANY))
  		cur = part->maxOccurs;
  	    else
  		cur = xmlSchemaGetParticleTotalRangeMax(part);
  	    if (cur == UNBOUNDED)
  		return (UNBOUNDED);
  	    if ((cur > 0) && (particle->maxOccurs == UNBOUNDED))
  		return (UNBOUNDED);
  	    sum += cur;
  	}
  	/* TODO: Handle overflows? */
  	return (particle->maxOccurs * sum);
      }
  }
  #endif
  
  /**
   * xmlSchemaIsParticleEmptiable:
   * @particle: the particle
   *
   * Schema Component Constraint: Particle Emptiable
   * Checks whether the given particle is emptiable.
   *
   * Returns 1 if emptiable, 0 otherwise.
   */
  static int
  xmlSchemaIsParticleEmptiable(xmlSchemaParticlePtr particle)
  {
      /*
      * SPEC (1) "Its {min occurs} is 0."
      */
      if ((particle == NULL) || (particle->minOccurs == 0) ||
  	(particle->children == NULL))
  	return (1);
      /*
      * SPEC (2) "Its {term} is a group and the minimum part of the
      * effective total range of that group, [...] is 0."
      */
      if (WXS_IS_MODEL_GROUP(particle->children)) {
  	if (xmlSchemaGetParticleTotalRangeMin(particle) == 0)
  	    return (1);
      }
      return (0);
  }
  
  /**
   * xmlSchemaCheckCOSSTDerivedOK:
   * @actxt: a context
   * @type:  the derived simple type definition
   * @baseType:  the base type definition
   * @subset: the subset of ('restriction', etc.)
   *
   * Schema Component Constraint:
   * Type Derivation OK (Simple) (cos-st-derived-OK)
   *
   * Checks whether @type can be validly
   * derived from @baseType.
   *
   * Returns 0 on success, an positive error code otherwise.
   */
  static int
  xmlSchemaCheckCOSSTDerivedOK(xmlSchemaAbstractCtxtPtr actxt,
  			     xmlSchemaTypePtr type,
  			     xmlSchemaTypePtr baseType,
  			     int subset)
  {
      /*
      * 1 They are the same type definition.
      * TODO: The identity 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};
      *
      * NOTE that this will be used also via "xsi:type".
      *
      * TODO: Revise this, it looks strange. How can the "type"
      * not be fixed or *in* fixing?
      */
      if (WXS_IS_TYPE_NOT_FIXED(type))
  	if (xmlSchemaTypeFixup(type, actxt) == -1)
  	    return(-1);
      if (WXS_IS_TYPE_NOT_FIXED(baseType))
  	if (xmlSchemaTypeFixup(baseType, actxt) == -1)
  	    return(-1);
      if ((subset & SUBSET_RESTRICTION) ||
  	(xmlSchemaTypeFinalContains(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 ((! WXS_IS_ANYTYPE(type->baseType)) &&
  	(xmlSchemaCheckCOSSTDerivedOK(actxt, 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 (WXS_IS_ANY_SIMPLE_TYPE(baseType) &&
  	(WXS_IS_LIST(type) || WXS_IS_UNION(type))) {
  	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 (WXS_IS_UNION(baseType)) {
  	xmlSchemaTypeLinkPtr cur;
  
  	cur = baseType->memberTypes;
  	while (cur != NULL) {
  	    if (WXS_IS_TYPE_NOT_FIXED(cur->type))
  		if (xmlSchemaTypeFixup(cur->type, actxt) == -1)
  		    return(-1);
  	    if (xmlSchemaCheckCOSSTDerivedOK(actxt,
  		    type, cur->type, subset) == 0)
  	    {
  		/*
  		* It just has to be validly derived from at least one
  		* member-type.
  		*/
  		return (0);
  	    }
  	    cur = cur->next;
  	}
      }
      return (XML_SCHEMAP_COS_ST_DERIVED_OK_2_2);
  }
  
  /**
   * xmlSchemaCheckTypeDefCircularInternal:
   * @pctxt:  the schema parser context
   * @ctxtType:  the type definition
   * @ancestor: an ancestor of @ctxtType
   *
   * Checks st-props-correct (2) + ct-props-correct (3).
   * Circular type definitions are not allowed.
   *
   * Returns XML_SCHEMAP_ST_PROPS_CORRECT_2 if the given type is
   * circular, 0 otherwise.
   */
  static int
  xmlSchemaCheckTypeDefCircularInternal(xmlSchemaParserCtxtPtr pctxt,
  			   xmlSchemaTypePtr ctxtType,
  			   xmlSchemaTypePtr ancestor)
  {
      int ret;
  
      if ((ancestor == NULL) || (ancestor->type == XML_SCHEMA_TYPE_BASIC))
  	return (0);
  
      if (ctxtType == ancestor) {
  	xmlSchemaPCustomErr(pctxt,
  	    XML_SCHEMAP_ST_PROPS_CORRECT_2,
  	    WXS_BASIC_CAST ctxtType, WXS_ITEM_NODE(ctxtType),
  	    "The definition is circular", NULL);
  	return (XML_SCHEMAP_ST_PROPS_CORRECT_2);
      }
      if (ancestor->flags & XML_SCHEMAS_TYPE_MARKED) {
  	/*
  	* Avoid inifinite recursion on circular types not yet checked.
  	*/
  	return (0);
      }
      ancestor->flags |= XML_SCHEMAS_TYPE_MARKED;
      ret = xmlSchemaCheckTypeDefCircularInternal(pctxt, ctxtType,
  	ancestor->baseType);
      ancestor->flags ^= XML_SCHEMAS_TYPE_MARKED;
      return (ret);
  }
  
  /**
   * xmlSchemaCheckTypeDefCircular:
   * @item:  the complex/simple type definition
   * @ctxt:  the parser context
   * @name:  the name
   *
   * Checks for circular type definitions.
   */
  static void
  xmlSchemaCheckTypeDefCircular(xmlSchemaTypePtr item,
  			      xmlSchemaParserCtxtPtr ctxt)
  {
      if ((item == NULL) ||
  	(item->type == XML_SCHEMA_TYPE_BASIC) ||
  	(item->baseType == NULL))
  	return;
      xmlSchemaCheckTypeDefCircularInternal(ctxt, item,
  	item->baseType);
  }
  
  /*
  * Simple Type Definition Representation OK (src-simple-type) 4
  *
  * "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>."
  *
  * Note that this should work on the *representation* of a component,
  * thus assumes any union types in the member types not being yet
  * substituted. At this stage we need the variety of the types
  * to be already computed.
  */
  static int
  xmlSchemaCheckUnionTypeDefCircularRecur(xmlSchemaParserCtxtPtr pctxt,
  					xmlSchemaTypePtr ctxType,
  					xmlSchemaTypeLinkPtr members)
  {
      xmlSchemaTypeLinkPtr member;
      xmlSchemaTypePtr memberType;
  
      member = members;
      while (member != NULL) {
  	memberType = member->type;
  	while ((memberType != NULL) &&
  	    (memberType->type != XML_SCHEMA_TYPE_BASIC)) {
  	    if (memberType == ctxType) {
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_SRC_SIMPLE_TYPE_4,
  		    WXS_BASIC_CAST ctxType, NULL,
  		    "The union type definition is circular", NULL);
  		return (XML_SCHEMAP_SRC_SIMPLE_TYPE_4);
  	    }
  	    if ((WXS_IS_UNION(memberType)) &&
  		((memberType->flags & XML_SCHEMAS_TYPE_MARKED) == 0))
  	    {
  		int res;
  		memberType->flags |= XML_SCHEMAS_TYPE_MARKED;
  		res = xmlSchemaCheckUnionTypeDefCircularRecur(pctxt,
  		    ctxType,
  		    xmlSchemaGetUnionSimpleTypeMemberTypes(memberType));
  		memberType->flags ^= XML_SCHEMAS_TYPE_MARKED;
  		if (res != 0)
  		    return(res);
  	    }
  	    memberType = memberType->baseType;
  	}
  	member = member->next;
      }
      return(0);
  }
  
  static int
  xmlSchemaCheckUnionTypeDefCircular(xmlSchemaParserCtxtPtr pctxt,
  				   xmlSchemaTypePtr type)
  {
      if (! WXS_IS_UNION(type))
  	return(0);
      return(xmlSchemaCheckUnionTypeDefCircularRecur(pctxt, type,
  	type->memberTypes));
  }
  
  /**
   * xmlSchemaResolveTypeReferences:
   * @item:  the complex/simple type definition
   * @ctxt:  the parser context
   * @name:  the name
   *
   * Resolves type definition references
   */
  static void
  xmlSchemaResolveTypeReferences(xmlSchemaTypePtr typeDef,
  			 xmlSchemaParserCtxtPtr ctxt)
  {
      if (typeDef == NULL)
  	return;
  
      /*
      * Resolve the base type.
      */
      if (typeDef->baseType == NULL) {
  	typeDef->baseType = xmlSchemaGetType(ctxt->schema,
  	    typeDef->base, typeDef->baseNs);
  	if (typeDef->baseType == NULL) {
  	    xmlSchemaPResCompAttrErr(ctxt,
  		XML_SCHEMAP_SRC_RESOLVE,
  		WXS_BASIC_CAST typeDef, typeDef->node,
  		"base", typeDef->base, typeDef->baseNs,
  		XML_SCHEMA_TYPE_SIMPLE, NULL);
  	    return;
  	}
      }
      if (WXS_IS_SIMPLE(typeDef)) {
  	if (WXS_IS_UNION(typeDef)) {
  	    /*
  	    * Resolve the memberTypes.
  	    */
  	    xmlSchemaResolveUnionMemberTypes(ctxt, typeDef);
  	    return;
  	} else if (WXS_IS_LIST(typeDef)) {
  	    /*
  	    * Resolve the itemType.
  	    */
  	    if ((typeDef->subtypes == NULL) && (typeDef->base != NULL)) {
  
  		typeDef->subtypes = xmlSchemaGetType(ctxt->schema,
  		    typeDef->base, typeDef->baseNs);
  
  		if ((typeDef->subtypes == NULL) ||
  		    (! WXS_IS_SIMPLE(typeDef->subtypes)))
  		{
  		    typeDef->subtypes = NULL;
  		    xmlSchemaPResCompAttrErr(ctxt,
  			XML_SCHEMAP_SRC_RESOLVE,
  			WXS_BASIC_CAST typeDef, typeDef->node,
  			"itemType", typeDef->base, typeDef->baseNs,
  			XML_SCHEMA_TYPE_SIMPLE, NULL);
  		}
  	    }
  	    return;
  	}
      }
      /*
      * The ball of letters below means, that if we have a particle
      * which has a QName-helper component as its {term}, we want
      * to resolve it...
      */
      else if ((WXS_TYPE_CONTENTTYPE(typeDef) != NULL) &&
  	((WXS_TYPE_CONTENTTYPE(typeDef))->type ==
  	    XML_SCHEMA_TYPE_PARTICLE) &&
  	(WXS_TYPE_PARTICLE_TERM(typeDef) != NULL) &&
  	((WXS_TYPE_PARTICLE_TERM(typeDef))->type ==
  	    XML_SCHEMA_EXTRA_QNAMEREF))
      {
  	xmlSchemaQNameRefPtr ref =
  	    WXS_QNAME_CAST WXS_TYPE_PARTICLE_TERM(typeDef);
  	xmlSchemaModelGroupDefPtr groupDef;
  
  	/*
  	* URGENT TODO: Test this.
  	*/
  	WXS_TYPE_PARTICLE_TERM(typeDef) = NULL;
  	/*
  	* Resolve the MG definition reference.
  	*/
  	groupDef =
  	    WXS_MODEL_GROUPDEF_CAST xmlSchemaGetNamedComponent(ctxt->schema,
  		ref->itemType, ref->name, ref->targetNamespace);
  	if (groupDef == NULL) {
  	    xmlSchemaPResCompAttrErr(ctxt, XML_SCHEMAP_SRC_RESOLVE,
  		NULL, WXS_ITEM_NODE(WXS_TYPE_PARTICLE(typeDef)),
  		"ref", ref->name, ref->targetNamespace, ref->itemType,
  		NULL);
  	    /* Remove the particle. */
  	    WXS_TYPE_CONTENTTYPE(typeDef) = NULL;
  	} else if (WXS_MODELGROUPDEF_MODEL(groupDef) == NULL)
  	    /* Remove the particle. */
  	    WXS_TYPE_CONTENTTYPE(typeDef) = NULL;
  	else {
  	    /*
  	    * Assign the MG definition's {model group} to the
  	    * particle's {term}.
  	    */
  	    WXS_TYPE_PARTICLE_TERM(typeDef) = WXS_MODELGROUPDEF_MODEL(groupDef);
  
  	    if (WXS_MODELGROUPDEF_MODEL(groupDef)->type == XML_SCHEMA_TYPE_ALL) {
  		/*
  		* SPEC cos-all-limited (1.2)
  		* "1.2 the {term} property of a particle with
  		* {max occurs}=1 which is part of a pair which constitutes
  		* the {content type} of a complex type definition."
  		*/
  		if ((WXS_TYPE_PARTICLE(typeDef))->maxOccurs != 1) {
  		    xmlSchemaCustomErr(ACTXT_CAST ctxt,
  			/* TODO: error code */
  			XML_SCHEMAP_COS_ALL_LIMITED,
  			WXS_ITEM_NODE(WXS_TYPE_PARTICLE(typeDef)), NULL,
  			"The particle's {max occurs} must be 1, since the "
  			"reference resolves to an 'all' model group",
  			NULL, NULL);
  		}
  	    }
  	}
      }
  }
  
  
  
  /**
   * 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;
      xmlChar *str = NULL;
  
      /* STATE: error funcs converted. */
      /*
      * 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.
      */
      /* 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) {
  	/*
  	* TODO: Think about: "modulo the impact of Missing
  	* Sub-components ($5.3)."
  	*/
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_ST_PROPS_CORRECT_1,
  	    WXS_BASIC_CAST type, NULL,
  	    "No base type existent", NULL);
  	return (XML_SCHEMAP_ST_PROPS_CORRECT_1);
  
      }
      if (! WXS_IS_SIMPLE(baseType)) {
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_ST_PROPS_CORRECT_1,
  	    WXS_BASIC_CAST type, NULL,
  	    "The base type '%s' is not a simple type",
  	    xmlSchemaGetComponentQName(&str, baseType));
  	FREE_AND_NULL(str)
  	return (XML_SCHEMAP_ST_PROPS_CORRECT_1);
      }
      if ((WXS_IS_LIST(type) || WXS_IS_UNION(type)) &&
  	(WXS_IS_RESTRICTION(type) == 0) &&
  	((! WXS_IS_ANY_SIMPLE_TYPE(baseType)) &&
           (baseType->type != XML_SCHEMA_TYPE_SIMPLE))) {
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_ST_PROPS_CORRECT_1,
  	    WXS_BASIC_CAST type, NULL,
  	    "A type, derived by list or union, must have "
  	    "the simple ur-type definition as base type, not '%s'",
  	    xmlSchemaGetComponentQName(&str, baseType));
  	FREE_AND_NULL(str)
  	return (XML_SCHEMAP_ST_PROPS_CORRECT_1);
      }
      /*
      * Variety: One of {atomic, list, union}.
      */
      if ((! WXS_IS_ATOMIC(type)) && (! WXS_IS_UNION(type)) &&
  	(! WXS_IS_LIST(type))) {
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_ST_PROPS_CORRECT_1,
  	    WXS_BASIC_CAST type, NULL,
  	    "The variety is absent", NULL);
  	return (XML_SCHEMAP_ST_PROPS_CORRECT_1);
      }
      /* TODO: Finish this. Hmm, is this finished? */
  
      /*
      * 3 The {final} of the {base type definition} must not contain restriction.
      */
      if (xmlSchemaTypeFinalContains(baseType,
  	XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) {
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_ST_PROPS_CORRECT_3,
  	    WXS_BASIC_CAST type, NULL,
  	    "The 'final' of its base type '%s' must not contain "
  	    "'restriction'",
  	    xmlSchemaGetComponentQName(&str, baseType));
  	FREE_AND_NULL(str)
  	return (XML_SCHEMAP_ST_PROPS_CORRECT_3);
      }
  
      /*
      * 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}.
      *
      * NOTE: this is done in xmlSchemaCheckTypeDefCircular().
      */
      return (0);
  }
  
  /**
   * xmlSchemaCheckCOSSTRestricts:
   * @ctxt:  the schema parser context
   * @type:  the simple type definition
   *
   * Schema Component Constraint:
   * Derivation Valid (Restriction, Simple) (cos-st-restricts)
  
   * Checks if the given @type (simpleType) is derived validly by restriction.
   * STATUS:
   *
   * Returns -1 on internal errors, 0 if the type is validly derived,
   * a positive error code otherwise.
   */
  static int
  xmlSchemaCheckCOSSTRestricts(xmlSchemaParserCtxtPtr pctxt,
  			     xmlSchemaTypePtr type)
  {
      xmlChar *str = NULL;
  
      if (type->type != XML_SCHEMA_TYPE_SIMPLE) {
  	PERROR_INT("xmlSchemaCheckCOSSTRestricts",
  	    "given type is not a user-derived simpleType");
  	return (-1);
      }
  
      if (WXS_IS_ATOMIC(type)) {
  	xmlSchemaTypePtr primitive;
  	/*
  	* 1.1 The {base type definition} must be an atomic simple
  	* type definition or a built-in primitive datatype.
  	*/
  	if (! WXS_IS_ATOMIC(type->baseType)) {
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_COS_ST_RESTRICTS_1_1,
  		WXS_BASIC_CAST type, NULL,
  		"The base type '%s' is not an atomic simple type",
  		xmlSchemaGetComponentQName(&str, type->baseType));
  	    FREE_AND_NULL(str)
  	    return (XML_SCHEMAP_COS_ST_RESTRICTS_1_1);
  	}
  	/* 1.2 The {final} of the {base type definition} must not contain
  	* restriction.
  	*/
  	/* OPTIMIZE TODO : This is already done in xmlSchemaCheckStPropsCorrect */
  	if (xmlSchemaTypeFinalContains(type->baseType,
  	    XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) {
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_COS_ST_RESTRICTS_1_2,
  		WXS_BASIC_CAST type, NULL,
  		"The final of its base type '%s' must not contain 'restriction'",
  		xmlSchemaGetComponentQName(&str, type->baseType));
  	    FREE_AND_NULL(str)
  	    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) {
  		PERROR_INT("xmlSchemaCheckCOSSTRestricts",
  		    "failed to get primitive type");
  		return (-1);
  	    }
  	    facet = type->facets;
  	    do {
  		if (xmlSchemaIsBuiltInTypeFacet(primitive, facet->type) == 0) {
  		    ok = 0;
  		    xmlSchemaPIllegalFacetAtomicErr(pctxt,
  			XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1,
  			type, primitive, facet);
  		}
  		facet = facet->next;
  	    } while (facet != NULL);
  	    if (ok == 0)
  		return (XML_SCHEMAP_COS_ST_RESTRICTS_1_3_1);
  	}
  	/*
  	* SPEC (1.3.2) "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]."
  	*
  	* NOTE (1.3.2) Facet derivation constraints are currently handled in
  	* xmlSchemaDeriveAndValidateFacets()
  	*/
      } else if (WXS_IS_LIST(type)) {
  	xmlSchemaTypePtr itemType = NULL;
  
  	itemType = type->subtypes;
  	if ((itemType == NULL) || (! WXS_IS_SIMPLE(itemType))) {
  	    PERROR_INT("xmlSchemaCheckCOSSTRestricts",
  		"failed to evaluate the item type");
  	    return (-1);
  	}
  	if (WXS_IS_TYPE_NOT_FIXED(itemType))
  	    xmlSchemaTypeFixup(itemType, ACTXT_CAST pctxt);
  	/*
  	* 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 ((! WXS_IS_ATOMIC(itemType)) &&
  	    (! WXS_IS_UNION(itemType))) {
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_COS_ST_RESTRICTS_2_1,
  		WXS_BASIC_CAST type, NULL,
  		"The item type '%s' does not have a variety of atomic or union",
  		xmlSchemaGetComponentQName(&str, itemType));
  	    FREE_AND_NULL(str)
  	    return (XML_SCHEMAP_COS_ST_RESTRICTS_2_1);
  	} else if (WXS_IS_UNION(itemType)) {
  	    xmlSchemaTypeLinkPtr member;
  
  	    member = itemType->memberTypes;
  	    while (member != NULL) {
  		if (! WXS_IS_ATOMIC(member->type)) {
  		    xmlSchemaPCustomErr(pctxt,
  			XML_SCHEMAP_COS_ST_RESTRICTS_2_1,
  			WXS_BASIC_CAST type, NULL,
  			"The item type is a union type, but the "
  			"member type '%s' of this item type is not atomic",
  			xmlSchemaGetComponentQName(&str, member->type));
  		    FREE_AND_NULL(str)
  		    return (XML_SCHEMAP_COS_ST_RESTRICTS_2_1);
  		}
  		member = member->next;
  	    }
  	}
  
  	if (WXS_IS_ANY_SIMPLE_TYPE(type->baseType)) {
  	    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(itemType,
  		XML_SCHEMAS_TYPE_FINAL_LIST)) {
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_1,
  		    WXS_BASIC_CAST type, NULL,
  		    "The final of its item type '%s' must not contain 'list'",
  		    xmlSchemaGetComponentQName(&str, itemType));
  		FREE_AND_NULL(str)
  		return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_1);
  	    }
  	    /*
  	    * 2.3.1.2 The {facets} must only contain the whiteSpace
  	    * facet component.
  	    * OPTIMIZE TODO: the S4S already disallows any facet
  	    * to be specified.
  	    */
  	    if (type->facets != NULL) {
  		facet = type->facets;
  		do {
  		    if (facet->type != XML_SCHEMA_FACET_WHITESPACE) {
  			xmlSchemaPIllegalFacetListUnionErr(pctxt,
  			    XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2,
  			    type, facet);
  			return (XML_SCHEMAP_COS_ST_RESTRICTS_2_3_1_2);
  		    }
  		    facet = facet->next;
  		} while (facet != NULL);
  	    }
  	    /*
  	    * MAYBE TODO: (Hmm, not really) 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 ...
  	    * I.e. the variety of "list" is inherited.
  	    */
  	    /*
  	    * 2.3.2
  	    * 2.3.2.1 The {base type definition} must have a {variety} of list.
  	    */
  	    if (! WXS_IS_LIST(type->baseType)) {
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_1,
  		    WXS_BASIC_CAST type, NULL,
  		    "The base type '%s' must be a list type",
  		    xmlSchemaGetComponentQName(&str, type->baseType));
  		FREE_AND_NULL(str)
  		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(type->baseType,
  		XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) {
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_2,
  		    WXS_BASIC_CAST type, NULL,
  		    "The 'final' of the base type '%s' must not contain 'restriction'",
  		    xmlSchemaGetComponentQName(&str, type->baseType));
  		FREE_AND_NULL(str)
  		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 = type->baseType->subtypes;
  		if ((baseItemType == NULL) || (! WXS_IS_SIMPLE(baseItemType))) {
  		    PERROR_INT("xmlSchemaCheckCOSSTRestricts",
  			"failed to eval the item type of a base type");
  		    return (-1);
  		}
  		if ((itemType != baseItemType) &&
  		    (xmlSchemaCheckCOSSTDerivedOK(ACTXT_CAST pctxt, itemType,
  			baseItemType, 0) != 0)) {
  		    xmlChar *strBIT = NULL, *strBT = NULL;
  		    xmlSchemaPCustomErrExt(pctxt,
  			XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_3,
  			WXS_BASIC_CAST type, NULL,
  			"The item type '%s' is not validly derived from "
  			"the item type '%s' of the base type '%s'",
  			xmlSchemaGetComponentQName(&str, itemType),
  			xmlSchemaGetComponentQName(&strBIT, baseItemType),
  			xmlSchemaGetComponentQName(&strBT, type->baseType));
  
  		    FREE_AND_NULL(str)
  		    FREE_AND_NULL(strBIT)
  		    FREE_AND_NULL(strBT)
  		    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: {
  			    xmlSchemaPIllegalFacetListUnionErr(pctxt,
  				XML_SCHEMAP_COS_ST_RESTRICTS_2_3_2_4,
  				type, facet);
  			    /*
  			    * 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);
  		/*
  		* SPEC (2.3.2.5) (same as 1.3.2)
  		*
  		* NOTE (2.3.2.5) This is currently done in
  		* xmlSchemaDeriveAndValidateFacets()
  		*/
  	    }
  	}
      } else if (WXS_IS_UNION(type)) {
  	/*
  	* 3.1 The {member type definitions} must all have {variety} of
  	* atomic or list.
  	*/
  	xmlSchemaTypeLinkPtr member;
  
  	member = type->memberTypes;
  	while (member != NULL) {
  	    if (WXS_IS_TYPE_NOT_FIXED(member->type))
  		xmlSchemaTypeFixup(member->type, ACTXT_CAST pctxt);
  
  	    if ((! WXS_IS_ATOMIC(member->type)) &&
  		(! WXS_IS_LIST(member->type))) {
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_COS_ST_RESTRICTS_3_1,
  		    WXS_BASIC_CAST type, NULL,
  		    "The member type '%s' is neither an atomic, nor a list type",
  		    xmlSchemaGetComponentQName(&str, member->type));
  		FREE_AND_NULL(str)
  		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->builtInType == 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(member->type,
  		    XML_SCHEMAS_TYPE_FINAL_UNION)) {
  		    xmlSchemaPCustomErr(pctxt,
  			XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1,
  			WXS_BASIC_CAST type, NULL,
  			"The 'final' of member type '%s' contains 'union'",
  			xmlSchemaGetComponentQName(&str, member->type));
  		    FREE_AND_NULL(str)
  		    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) {
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_COS_ST_RESTRICTS_3_3_1_2,
  		    WXS_BASIC_CAST type, NULL,
  		    "No facets allowed", 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.
  	    * I.e. the variety of "list" is inherited.
  	    */
  	    if (! WXS_IS_UNION(type->baseType)) {
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_1,
  		    WXS_BASIC_CAST type, NULL,
  		    "The base type '%s' is not a union type",
  		    xmlSchemaGetComponentQName(&str, type->baseType));
  		FREE_AND_NULL(str)
  		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(type->baseType,
  		XML_SCHEMAS_TYPE_FINAL_RESTRICTION)) {
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_2,
  		    WXS_BASIC_CAST type, NULL,
  		    "The 'final' of its base type '%s' must not contain 'restriction'",
  		    xmlSchemaGetComponentQName(&str, type->baseType));
  		FREE_AND_NULL(str)
  		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.
  		*/
  		/*
  		* 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.
  		* But necessary if constructing types with an API.
  		*/
  		if (type->memberTypes != NULL) {
  		    member = type->memberTypes;
  		    baseMember = xmlSchemaGetUnionSimpleTypeMemberTypes(type->baseType);
  		    if ((member == NULL) && (baseMember != NULL)) {
  			PERROR_INT("xmlSchemaCheckCOSSTRestricts",
  			    "different number of member types in base");
  		    }
  		    while (member != NULL) {
  			if (baseMember == NULL) {
  			    PERROR_INT("xmlSchemaCheckCOSSTRestricts",
  			    "different number of member types in base");
  			} else if ((member->type != baseMember->type) &&
  			    (xmlSchemaCheckCOSSTDerivedOK(ACTXT_CAST pctxt,
  				member->type, baseMember->type, 0) != 0)) {
  			    xmlChar *strBMT = NULL, *strBT = NULL;
  
  			    xmlSchemaPCustomErrExt(pctxt,
  				XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3,
  				WXS_BASIC_CAST type, NULL,
  				"The member type %s is not validly "
  				"derived from its corresponding member "
  				"type %s of the base type %s",
  				xmlSchemaGetComponentQName(&str, member->type),
  				xmlSchemaGetComponentQName(&strBMT, baseMember->type),
  				xmlSchemaGetComponentQName(&strBT, type->baseType));
  			    FREE_AND_NULL(str)
  			    FREE_AND_NULL(strBMT)
  			    FREE_AND_NULL(strBT)
  			    return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_3);
  			}
  			member = member->next;
                          if (baseMember != NULL)
                              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)) {
  			xmlSchemaPIllegalFacetListUnionErr(pctxt,
  				XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4,
  				type, facet);
  			ok = 0;
  		    }
  		    facet = facet->next;
  		} while (facet != NULL);
  		if (ok == 0)
  		    return (XML_SCHEMAP_COS_ST_RESTRICTS_3_3_2_4);
  
  	    }
  	    /*
  	    * SPEC (3.3.2.5) (same as 1.3.2)
  	    *
  	    * NOTE (3.3.2.5) This is currently done in
  	    * xmlSchemaDeriveAndValidateFacets()
  	    */
  	}
      }
  
      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.
   */
  #if 0
  static int
  xmlSchemaCheckSRCSimpleType(xmlSchemaParserCtxtPtr ctxt,
  			    xmlSchemaTypePtr type)
  {
      /*
      * 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 (WXS_IS_RESTRICTION(type)) {
  	/*
  	* 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."
  	* NOTE: This is checked in the parse function of <restriction>.
  	*/
  	/*
  	*
  	*/
      } else if (WXS_IS_LIST(type)) {
  	/* 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: This is checked in the parse function of <list>.
  	*/
      } else if (WXS_IS_UNION(type)) {
  	/*
  	* src-simple-type.4 is checked in xmlSchemaCheckUnionTypeDefCircular().
  	*/
      }
      return (0);
  }
  #endif
  
  static int
  xmlSchemaCreateVCtxtOnPCtxt(xmlSchemaParserCtxtPtr ctxt)
  {
     if (ctxt->vctxt == NULL) {
  	ctxt->vctxt = xmlSchemaNewValidCtxt(NULL);
  	if (ctxt->vctxt == NULL) {
  	    xmlSchemaPErr(ctxt, NULL,
  		XML_SCHEMAP_INTERNAL,
  		"Internal error: xmlSchemaCreateVCtxtOnPCtxt, "
  		"failed to create a temp. validation context.\n",
  		NULL, NULL);
  	    return (-1);
  	}
  	/* TODO: Pass user data. */
  	xmlSchemaSetValidErrors(ctxt->vctxt,
  	    ctxt->error, ctxt->warning, ctxt->errCtxt);
  	xmlSchemaSetValidStructuredErrors(ctxt->vctxt,
  	    ctxt->serror, ctxt->errCtxt);
      }
      return (0);
  }
  
  static int
  xmlSchemaVCheckCVCSimpleType(xmlSchemaAbstractCtxtPtr actxt,
  			     xmlNodePtr node,
  			     xmlSchemaTypePtr type,
  			     const xmlChar *value,
  			     xmlSchemaValPtr *retVal,
  			     int fireErrors,
  			     int normalize,
  			     int isNormalized);
  
  /**
   * xmlSchemaParseCheckCOSValidDefault:
   * @pctxt:  the schema parser context
   * @type:  the simple type definition
   * @value: the default value
   * @node: an optional node (the holder of the value)
   *
   * Schema Component Constraint: Element Default Valid (Immediate)
   * (cos-valid-default)
   * This will be used by the parser only. For the validator there's
   * an other version.
   *
   * Returns 0 if the constraints are satisfied,
   * if not, a positive error code and -1 on internal
   * errors.
   */
  static int
  xmlSchemaParseCheckCOSValidDefault(xmlSchemaParserCtxtPtr pctxt,
  				   xmlNodePtr node,
  				   xmlSchemaTypePtr type,
  				   const xmlChar *value,
  				   xmlSchemaValPtr *val)
  {
      int ret = 0;
  
      /*
      * cos-valid-default:
      * Schema Component Constraint: Element Default Valid (Immediate)
      * For a string to be a valid default with respect to a type
      * definition the appropriate case among the following must be true:
      */
      if WXS_IS_COMPLEX(type) {
  	/*
  	* Complex type.
  	*
  	* SPEC (2.1) "its {content type} must be a simple type definition
  	* or mixed."
  	* SPEC (2.2.2) "If the {content type} is mixed, then the {content
  	* type}'s particle must be `emptiable` as defined by
  	* Particle Emptiable ($3.9.6)."
  	*/
  	if ((! WXS_HAS_SIMPLE_CONTENT(type)) &&
  	    ((! WXS_HAS_MIXED_CONTENT(type)) || (! WXS_EMPTIABLE(type)))) {
  	    /* NOTE that this covers (2.2.2) as well. */
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_COS_VALID_DEFAULT_2_1,
  		WXS_BASIC_CAST type, type->node,
  		"For a string to be a valid default, the type definition "
  		"must be a simple type or a complex type with mixed content "
  		"and a particle emptiable", NULL);
  	    return(XML_SCHEMAP_COS_VALID_DEFAULT_2_1);
  	}
      }
      /*
      * 1 If the type definition is a simple type definition, then the string
      * must be `valid` with respect to that definition as defined by String
      * Valid ($3.14.4).
      *
      * AND
      *
      * 2.2.1 If the {content type} is a simple type definition, then the
      * string must be `valid` with respect to that simple type definition
      * as defined by String Valid ($3.14.4).
      */
      if (WXS_IS_SIMPLE(type))
  	ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST pctxt, node,
  	    type, value, val, 1, 1, 0);
      else if (WXS_HAS_SIMPLE_CONTENT(type))
  	ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST pctxt, node,
  	    type->contentTypeDef, value, val, 1, 1, 0);
      else
  	return (ret);
  
      if (ret < 0) {
  	PERROR_INT("xmlSchemaParseCheckCOSValidDefault",
  	    "calling xmlSchemaVCheckCVCSimpleType()");
      }
  
      return (ret);
  }
  
  /**
   * xmlSchemaCheckCTPropsCorrect:
   * @ctxt:  the schema parser context
   * @type:  the complex type definition
   *
   *.(4.6) Constraints on Complex Type Definition Schema Components
   * Schema Component Constraint:
   * Complex Type Definition Properties Correct (ct-props-correct)
   * STATUS: (seems) complete
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckCTPropsCorrect(xmlSchemaParserCtxtPtr pctxt,
  			     xmlSchemaTypePtr type)
  {
      /*
      * TODO: Correct the error code; XML_SCHEMAP_SRC_CT_1 is used temporarily.
      *
      * SPEC (1) "The values of the properties of a complex type definition must
      * be as described in the property tableau in The Complex Type Definition
      * Schema Component ($3.4.1), modulo the impact of Missing
      * Sub-components ($5.3)."
      */
      if ((type->baseType != NULL) &&
  	(WXS_IS_SIMPLE(type->baseType)) &&
  	(WXS_IS_EXTENSION(type) == 0)) {
  	/*
  	* SPEC (2) "If the {base type definition} is a simple type definition,
  	* the {derivation method} must be extension."
  	*/
  	xmlSchemaCustomErr(ACTXT_CAST pctxt,
  	    XML_SCHEMAP_SRC_CT_1,
  	    NULL, WXS_BASIC_CAST type,
  	    "If the base type is a simple type, the derivation method must be "
  	    "'extension'", NULL, NULL);
  	return (XML_SCHEMAP_SRC_CT_1);
      }
      /*
      * SPEC (3) "Circular definitions are disallowed, except for the `ur-type
      * definition`. That is, it must be possible to reach the `ur-type
      * definition` by repeatedly following the {base type definition}."
      *
      * NOTE (3) is done in xmlSchemaCheckTypeDefCircular().
      */
      /*
      * NOTE that (4) and (5) need the following:
      *   - attribute uses need to be already inherited (apply attr. prohibitions)
      *   - attribute group references need to be expanded already
      *   - simple types need to be typefixed already
      */
      if (type->attrUses &&
  	(((xmlSchemaItemListPtr) type->attrUses)->nbItems > 1))
      {
  	xmlSchemaItemListPtr uses = (xmlSchemaItemListPtr) type->attrUses;
  	xmlSchemaAttributeUsePtr use, tmp;
  	int i, j, hasId = 0;
  
  	for (i = uses->nbItems -1; i >= 0; i--) {
  	    use = uses->items[i];
  
  	    /*
  	    * SPEC ct-props-correct
  	    * (4) "Two distinct attribute declarations in the
  	    * {attribute uses} must not have identical {name}s and
  	    * {target namespace}s."
  	    */
  	    if (i > 0) {
  		for (j = i -1; j >= 0; j--) {
  		    tmp = uses->items[j];
  		    if ((WXS_ATTRUSE_DECL_NAME(use) ==
  			WXS_ATTRUSE_DECL_NAME(tmp)) &&
  			(WXS_ATTRUSE_DECL_TNS(use) ==
  			WXS_ATTRUSE_DECL_TNS(tmp)))
  		    {
  			xmlChar *str = NULL;
  
  			xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			    XML_SCHEMAP_AG_PROPS_CORRECT,
  			    NULL, WXS_BASIC_CAST type,
  			    "Duplicate %s",
  			    xmlSchemaGetComponentDesignation(&str, use),
  			    NULL);
  			FREE_AND_NULL(str);
  			/*
  			* Remove the duplicate.
  			*/
  			if (xmlSchemaItemListRemove(uses, i) == -1)
  			    goto exit_failure;
  			goto next_use;
  		    }
  		}
  	    }
  	    /*
  	    * SPEC ct-props-correct
  	    * (5) "Two distinct attribute declarations in the
  	    * {attribute uses} must not have {type definition}s which
  	    * are or are derived from ID."
  	    */
  	    if (WXS_ATTRUSE_TYPEDEF(use) != NULL) {
  		if (xmlSchemaIsDerivedFromBuiltInType(
  		    WXS_ATTRUSE_TYPEDEF(use), XML_SCHEMAS_ID))
  		{
  		    if (hasId) {
  			xmlChar *str = NULL;
  
  			xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			    XML_SCHEMAP_AG_PROPS_CORRECT,
  			    NULL, WXS_BASIC_CAST type,
  			    "There must not exist more than one attribute "
  			    "declaration of type 'xs:ID' "
  			    "(or derived from 'xs:ID'). The %s violates this "
  			    "constraint",
  			    xmlSchemaGetComponentDesignation(&str, use),
  			    NULL);
  			FREE_AND_NULL(str);
  			if (xmlSchemaItemListRemove(uses, i) == -1)
  			    goto exit_failure;
  		    }
  
  		    hasId = 1;
  		}
  	    }
  next_use: {}
  	}
      }
      return (0);
  exit_failure:
      return(-1);
  }
  
  static int
  xmlSchemaAreEqualTypes(xmlSchemaTypePtr typeA,
  		       xmlSchemaTypePtr typeB)
  {
      /*
      * TODO: This should implement component-identity
      * in the future.
      */
      if ((typeA == NULL) || (typeB == NULL))
  	return (0);
      return (typeA == typeB);
  }
  
  /**
   * xmlSchemaCheckCOSCTDerivedOK:
   * @ctxt:  the schema parser context
   * @type:  the to-be derived complex type definition
   * @baseType:  the base complex type definition
   * @set: the given set
   *
   * Schema Component Constraint:
   * Type Derivation OK (Complex) (cos-ct-derived-ok)
   *
   * STATUS: completed
   *
   * Returns 0 if the constraints are satisfied, or 1
   * if not.
   */
  static int
  xmlSchemaCheckCOSCTDerivedOK(xmlSchemaAbstractCtxtPtr actxt,
  			     xmlSchemaTypePtr type,
  			     xmlSchemaTypePtr baseType,
  			     int set)
  {
      int equal = xmlSchemaAreEqualTypes(type, baseType);
      /* TODO: Error codes. */
      /*
      * SPEC "For a complex type definition (call it D, for derived)
      * to be validly derived from a type definition (call this
      * B, for base) given a subset of {extension, restriction}
      * all of the following must be true:"
      */
      if (! equal) {
  	/*
  	* SPEC (1) "If B and D are not the same type definition, then the
  	* {derivation method} of D must not be in the subset."
  	*/
  	if (((set & SUBSET_EXTENSION) && (WXS_IS_EXTENSION(type))) ||
  	    ((set & SUBSET_RESTRICTION) && (WXS_IS_RESTRICTION(type))))
  	    return (1);
      } else {
  	/*
  	* SPEC (2.1) "B and D must be the same type definition."
  	*/
  	return (0);
      }
      /*
      * SPEC (2.2) "B must be D's {base type definition}."
      */
      if (type->baseType == baseType)
  	return (0);
      /*
      * SPEC (2.3.1) "D's {base type definition} must not be the `ur-type
      * definition`."
      */
      if (WXS_IS_ANYTYPE(type->baseType))
  	return (1);
  
      if (WXS_IS_COMPLEX(type->baseType)) {
  	/*
  	* SPEC (2.3.2.1) "If D's {base type definition} is complex, then it
  	* must be validly derived from B given the subset as defined by this
  	* constraint."
  	*/
  	return (xmlSchemaCheckCOSCTDerivedOK(actxt, type->baseType,
  	    baseType, set));
      } else {
  	/*
  	* SPEC (2.3.2.2) "If D's {base type definition} is simple, then it
  	* must be validly derived from B given the subset as defined in Type
  	* Derivation OK (Simple) ($3.14.6).
  	*/
  	return (xmlSchemaCheckCOSSTDerivedOK(actxt, type->baseType,
  	    baseType, set));
      }
  }
  
  /**
   * xmlSchemaCheckCOSDerivedOK:
   * @type:  the derived simple type definition
   * @baseType:  the base type definition
   *
   * Calls:
   * Type Derivation OK (Simple) AND Type Derivation OK (Complex)
   *
   * Checks whether @type can be validly derived from @baseType.
   *
   * Returns 0 on success, an positive error code otherwise.
   */
  static int
  xmlSchemaCheckCOSDerivedOK(xmlSchemaAbstractCtxtPtr actxt,
  			   xmlSchemaTypePtr type,
  			   xmlSchemaTypePtr baseType,
  			   int set)
  {
      if (WXS_IS_SIMPLE(type))
  	return (xmlSchemaCheckCOSSTDerivedOK(actxt, type, baseType, set));
      else
  	return (xmlSchemaCheckCOSCTDerivedOK(actxt, type, baseType, set));
  }
  
  /**
   * xmlSchemaCheckCOSCTExtends:
   * @ctxt:  the schema parser context
   * @type:  the complex type definition
   *
   * (3.4.6) Constraints on Complex Type Definition Schema Components
   * Schema Component Constraint:
   * Derivation Valid (Extension) (cos-ct-extends)
   *
   * STATUS:
   *   missing:
   *     (1.5)
   *     (1.4.3.2.2.2) "Particle Valid (Extension)"
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckCOSCTExtends(xmlSchemaParserCtxtPtr ctxt,
  			   xmlSchemaTypePtr type)
  {
      xmlSchemaTypePtr base = type->baseType;
      /*
      * TODO: Correct the error code; XML_SCHEMAP_COS_CT_EXTENDS_1_1 is used
      * temporarily only.
      */
      /*
      * SPEC (1) "If the {base type definition} is a complex type definition,
      * then all of the following must be true:"
      */
      if (WXS_IS_COMPLEX(base)) {
  	/*
  	* SPEC (1.1) "The {final} of the {base type definition} must not
  	* contain extension."
  	*/
  	if (base->flags & XML_SCHEMAS_TYPE_FINAL_EXTENSION) {
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_COS_CT_EXTENDS_1_1,
  		WXS_BASIC_CAST type, NULL,
  		"The 'final' of the base type definition "
  		"contains 'extension'", NULL);
  	    return (XML_SCHEMAP_COS_CT_EXTENDS_1_1);
  	}
  
  	/*
  	* ATTENTION: The constrains (1.2) and (1.3) are not applied,
  	* since they are automatically satisfied through the
  	* inheriting mechanism.
  	* Note that even if redefining components, the inheriting mechanism
  	* is used.
  	*/
  #if 0
  	/*
  	* SPEC (1.2) "Its {attribute uses} must be a subset of the {attribute
  	* uses}
  	* of the complex type definition itself, that is, for every attribute
  	* use in the {attribute uses} of the {base type definition}, there
  	* must be an attribute use in the {attribute uses} of the complex
  	* type definition itself whose {attribute declaration} has the same
  	* {name}, {target namespace} and {type definition} as its attribute
  	* declaration"
  	*/
  	if (base->attrUses != NULL) {
  	    int i, j, found;
  	    xmlSchemaAttributeUsePtr use, buse;
  
  	    for (i = 0; i < (WXS_LIST_CAST base->attrUses)->nbItems; i ++) {
  		buse = (WXS_LIST_CAST base->attrUses)->items[i];
  		found = 0;
  		if (type->attrUses != NULL) {
  		    use = (WXS_LIST_CAST type->attrUses)->items[j];
  		    for (j = 0; j < (WXS_LIST_CAST type->attrUses)->nbItems; j ++)
  		    {
  			if ((WXS_ATTRUSE_DECL_NAME(use) ==
  				WXS_ATTRUSE_DECL_NAME(buse)) &&
  			    (WXS_ATTRUSE_DECL_TNS(use) ==
  				WXS_ATTRUSE_DECL_TNS(buse)) &&
  			    (WXS_ATTRUSE_TYPEDEF(use) ==
  				WXS_ATTRUSE_TYPEDEF(buse))
  			{
  			    found = 1;
  			    break;
  			}
  		    }
  		}
  		if (! found) {
  		    xmlChar *str = NULL;
  
  		    xmlSchemaCustomErr(ACTXT_CAST ctxt,
  			XML_SCHEMAP_COS_CT_EXTENDS_1_2,
  			NULL, WXS_BASIC_CAST type,
  			/*
  			* TODO: The report does not indicate that also the
  			* type needs to be the same.
  			*/
  			"This type is missing a matching correspondent "
  			"for its {base type}'s %s in its {attribute uses}",
  			xmlSchemaGetComponentDesignation(&str,
  			    buse->children),
  			NULL);
  		    FREE_AND_NULL(str)
  		}
  	    }
  	}
  	/*
  	* SPEC (1.3) "If it has an {attribute wildcard}, the complex type
  	* definition must also have one, and the base type definition's
  	* {attribute  wildcard}'s {namespace constraint} must be a subset
  	* of the complex  type definition's {attribute wildcard}'s {namespace
  	* constraint}, as defined by Wildcard Subset ($3.10.6)."
  	*/
  
  	/*
  	* MAYBE TODO: Enable if ever needed. But this will be needed only
  	* if created the type via a schema construction API.
  	*/
  	if (base->attributeWildcard != NULL) {
  	    if (type->attributeWildcard == NULL) {
  		xmlChar *str = NULL;
  
  		xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		    XML_SCHEMAP_COS_CT_EXTENDS_1_3,
  		    NULL, type,
  		    "The base %s has an attribute wildcard, "
  		    "but this type is missing an attribute wildcard",
  		    xmlSchemaGetComponentDesignation(&str, base));
  		FREE_AND_NULL(str)
  
  	    } else if (xmlSchemaCheckCOSNSSubset(
  		base->attributeWildcard, type->attributeWildcard))
  	    {
  		xmlChar *str = NULL;
  
  		xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		    XML_SCHEMAP_COS_CT_EXTENDS_1_3,
  		    NULL, type,
  		    "The attribute wildcard is not a valid "
  		    "superset of the one in the base %s",
  		    xmlSchemaGetComponentDesignation(&str, base));
  		FREE_AND_NULL(str)
  	    }
  	}
  #endif
  	/*
  	* SPEC (1.4) "One of the following must be true:"
  	*/
  	if ((type->contentTypeDef != NULL) &&
  	    (type->contentTypeDef == base->contentTypeDef)) {
  	    /*
  	    * SPEC (1.4.1) "The {content type} of the {base type definition}
  	    * and the {content type} of the complex type definition itself
  	    * must be the same simple type definition"
  	    * PASS
  	    */
  	} else if ((type->contentType == XML_SCHEMA_CONTENT_EMPTY) &&
  	    (base->contentType == XML_SCHEMA_CONTENT_EMPTY) ) {
  	    /*
  	    * SPEC (1.4.2) "The {content type} of both the {base type
  	    * definition} and the complex type definition itself must
  	    * be empty."
  	    * PASS
  	    */
  	} else {
  	    /*
  	    * SPEC (1.4.3) "All of the following must be true:"
  	    */
  	    if (type->subtypes == NULL) {
  		/*
  		* SPEC 1.4.3.1 The {content type} of the complex type
  		* definition itself must specify a particle.
  		*/
  		xmlSchemaPCustomErr(ctxt,
  		    XML_SCHEMAP_COS_CT_EXTENDS_1_1,
  		    WXS_BASIC_CAST type, NULL,
  		    "The content type must specify a particle", NULL);
  		return (XML_SCHEMAP_COS_CT_EXTENDS_1_1);
  	    }
  	    /*
  	    * SPEC (1.4.3.2) "One of the following must be true:"
  	    */
  	    if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
  		/*
  		* SPEC (1.4.3.2.1) "The {content type} of the {base type
  		* definition} must be empty.
  		* PASS
  		*/
  	    } else {
  		/*
  		* SPEC (1.4.3.2.2) "All of the following must be true:"
  		*/
  		if ((type->contentType != base->contentType) ||
  		    ((type->contentType != XML_SCHEMA_CONTENT_MIXED) &&
  		    (type->contentType != XML_SCHEMA_CONTENT_ELEMENTS))) {
  		    /*
  		    * SPEC (1.4.3.2.2.1) "Both {content type}s must be mixed
  		    * or both must be element-only."
  		    */
  		    xmlSchemaPCustomErr(ctxt,
  			XML_SCHEMAP_COS_CT_EXTENDS_1_1,
  			WXS_BASIC_CAST type, NULL,
  			"The content type of both, the type and its base "
  			"type, must either 'mixed' or 'element-only'", NULL);
  		    return (XML_SCHEMAP_COS_CT_EXTENDS_1_1);
  		}
  		/*
  		* URGENT TODO SPEC (1.4.3.2.2.2) "The particle of the
  		* complex type definition must be a `valid extension`
  		* of the {base type definition}'s particle, as defined
  		* in Particle Valid (Extension) ($3.9.6)."
  		*
  		* NOTE that we won't check "Particle Valid (Extension)",
  		* since it is ensured by the derivation process in
  		* xmlSchemaTypeFixup(). We need to implement this when heading
  		* for a construction API
  		* TODO: !! This is needed to be checked if redefining a type !!
  		*/
  	    }
  	    /*
  	    * URGENT TODO (1.5)
  	    */
  	}
      } else {
  	/*
  	* SPEC (2) "If the {base type definition} is a simple type definition,
  	* then all of the following must be true:"
  	*/
  	if (type->contentTypeDef != base) {
  	    /*
  	    * SPEC (2.1) "The {content type} must be the same simple type
  	    * definition."
  	    */
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_COS_CT_EXTENDS_1_1,
  		WXS_BASIC_CAST type, NULL,
  		"The content type must be the simple base type", NULL);
  	    return (XML_SCHEMAP_COS_CT_EXTENDS_1_1);
  	}
  	if (base->flags & XML_SCHEMAS_TYPE_FINAL_EXTENSION) {
  	    /*
  	    * SPEC (2.2) "The {final} of the {base type definition} must not
  	    * contain extension"
  	    * NOTE that this is the same as (1.1).
  	    */
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_COS_CT_EXTENDS_1_1,
  		WXS_BASIC_CAST type, NULL,
  		"The 'final' of the base type definition "
  		"contains 'extension'", NULL);
  	    return (XML_SCHEMAP_COS_CT_EXTENDS_1_1);
  	}
      }
      return (0);
  }
  
  /**
   * xmlSchemaCheckDerivationOKRestriction:
   * @ctxt:  the schema parser context
   * @type:  the complex type definition
   *
   * (3.4.6) Constraints on Complex Type Definition Schema Components
   * Schema Component Constraint:
   * Derivation Valid (Restriction, Complex) (derivation-ok-restriction)
   *
   * STATUS:
   *   missing:
   *     (5.4.2) ???
   *
   * ATTENTION:
   * In XML Schema 1.1 this will be:
   * Validation Rule: Checking complex type subsumption
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckDerivationOKRestriction(xmlSchemaParserCtxtPtr ctxt,
  				      xmlSchemaTypePtr type)
  {
      xmlSchemaTypePtr base;
  
      /*
      * TODO: Correct the error code; XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1 is used
      * temporarily only.
      */
      base = type->baseType;
      if (! WXS_IS_COMPLEX(base)) {
  	xmlSchemaCustomErr(ACTXT_CAST ctxt,
  	    XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1,
  	    type->node, WXS_BASIC_CAST type,
  	    "The base type must be a complex type", NULL, NULL);
  	return(ctxt->err);
      }
      if (base->flags & XML_SCHEMAS_TYPE_FINAL_RESTRICTION) {
  	/*
  	* SPEC (1) "The {base type definition} must be a complex type
  	* definition whose {final} does not contain restriction."
  	*/
  	xmlSchemaCustomErr(ACTXT_CAST ctxt,
  	    XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1,
  	    type->node, WXS_BASIC_CAST type,
  	    "The 'final' of the base type definition "
  	    "contains 'restriction'", NULL, NULL);
  	return (ctxt->err);
      }
      /*
      * SPEC (2), (3) and (4)
      * Those are handled in a separate function, since the
      * same constraints are needed for redefinition of
      * attribute groups as well.
      */
      if (xmlSchemaCheckDerivationOKRestriction2to4(ctxt,
  	XML_SCHEMA_ACTION_DERIVE,
  	WXS_BASIC_CAST type, WXS_BASIC_CAST base,
  	type->attrUses, base->attrUses,
  	type->attributeWildcard,
  	base->attributeWildcard) == -1)
      {
  	return(-1);
      }
      /*
      * SPEC (5) "One of the following must be true:"
      */
      if (base->builtInType == XML_SCHEMAS_ANYTYPE) {
  	/*
  	* SPEC (5.1) "The {base type definition} must be the
  	* `ur-type definition`."
  	* PASS
  	*/
      } else if ((type->contentType == XML_SCHEMA_CONTENT_SIMPLE) ||
  	    (type->contentType == XML_SCHEMA_CONTENT_BASIC)) {
  	/*
  	* SPEC (5.2.1) "The {content type} of the complex type definition
  	* must be a simple type definition"
  	*
  	* SPEC (5.2.2) "One of the following must be true:"
  	*/
  	if ((base->contentType == XML_SCHEMA_CONTENT_SIMPLE) ||
  	    (base->contentType == XML_SCHEMA_CONTENT_BASIC))
  	{
  	    int err;
  	    /*
  	    * SPEC (5.2.2.1) "The {content type} of the {base type
  	    * definition} must be a simple type definition from which
  	    * the {content type} is validly derived given the empty
  	    * set as defined in Type Derivation OK (Simple) ($3.14.6)."
  	    *
  	    * ATTENTION TODO: This seems not needed if the type implicitly
  	    * derived from the base type.
  	    *
  	    */
  	    err = xmlSchemaCheckCOSSTDerivedOK(ACTXT_CAST ctxt,
  		type->contentTypeDef, base->contentTypeDef, 0);
  	    if (err != 0) {
  		xmlChar *strA = NULL, *strB = NULL;
  
  		if (err == -1)
  		    return(-1);
  		xmlSchemaCustomErr(ACTXT_CAST ctxt,
  		    XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1,
  		    NULL, WXS_BASIC_CAST type,
  		    "The {content type} %s is not validly derived from the "
  		    "base type's {content type} %s",
  		    xmlSchemaGetComponentDesignation(&strA,
  			type->contentTypeDef),
  		    xmlSchemaGetComponentDesignation(&strB,
  			base->contentTypeDef));
  		FREE_AND_NULL(strA);
  		FREE_AND_NULL(strB);
  		return(ctxt->err);
  	    }
  	} else if ((base->contentType == XML_SCHEMA_CONTENT_MIXED) &&
  	    (xmlSchemaIsParticleEmptiable(
  		(xmlSchemaParticlePtr) base->subtypes))) {
  	    /*
  	    * SPEC (5.2.2.2) "The {base type definition} must be mixed
  	    * and have a particle which is `emptiable` as defined in
  	    * Particle Emptiable ($3.9.6)."
  	    * PASS
  	    */
  	} else {
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1,
  		WXS_BASIC_CAST type, NULL,
  		"The content type of the base type must be either "
  		"a simple type or 'mixed' and an emptiable particle", NULL);
  	    return (ctxt->err);
  	}
      } else if (type->contentType == XML_SCHEMA_CONTENT_EMPTY) {
  	/*
  	* SPEC (5.3.1) "The {content type} of the complex type itself must
  	* be empty"
  	*/
  	if (base->contentType == XML_SCHEMA_CONTENT_EMPTY) {
  	    /*
  	    * SPEC (5.3.2.1) "The {content type} of the {base type
  	    * definition} must also be empty."
  	    * PASS
  	    */
  	} else if (((base->contentType == XML_SCHEMA_CONTENT_ELEMENTS) ||
  	    (base->contentType == XML_SCHEMA_CONTENT_MIXED)) &&
  	    xmlSchemaIsParticleEmptiable(
  		(xmlSchemaParticlePtr) base->subtypes)) {
  	    /*
  	    * SPEC (5.3.2.2) "The {content type} of the {base type
  	    * definition} must be elementOnly or mixed and have a particle
  	    * which is `emptiable` as defined in Particle Emptiable ($3.9.6)."
  	    * PASS
  	    */
  	} else {
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1,
  		WXS_BASIC_CAST type, NULL,
  		"The content type of the base type must be either "
  		"empty or 'mixed' (or 'elements-only') and an emptiable "
  		"particle", NULL);
  	    return (ctxt->err);
  	}
      } else if ((type->contentType == XML_SCHEMA_CONTENT_ELEMENTS) ||
  	WXS_HAS_MIXED_CONTENT(type)) {
  	/*
  	* SPEC (5.4.1.1) "The {content type} of the complex type definition
  	* itself must be element-only"
  	*/
  	if (WXS_HAS_MIXED_CONTENT(type) && (! WXS_HAS_MIXED_CONTENT(base))) {
  	    /*
  	    * SPEC (5.4.1.2) "The {content type} of the complex type
  	    * definition itself and of the {base type definition} must be
  	    * mixed"
  	    */
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1,
  		WXS_BASIC_CAST type, NULL,
  		"If the content type is 'mixed', then the content type of the "
  		"base type must also be 'mixed'", NULL);
  	    return (ctxt->err);
  	}
  	/*
  	* SPEC (5.4.2) "The particle of the complex type definition itself
  	* must be a `valid restriction` of the particle of the {content
  	* type} of the {base type definition} as defined in Particle Valid
  	* (Restriction) ($3.9.6).
  	*
  	* URGENT TODO: (5.4.2)
  	*/
      } else {
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_DERIVATION_OK_RESTRICTION_1,
  	    WXS_BASIC_CAST type, NULL,
  	    "The type is not a valid restriction of its base type", NULL);
  	return (ctxt->err);
      }
      return (0);
  }
  
  /**
   * xmlSchemaCheckCTComponent:
   * @ctxt:  the schema parser context
   * @type:  the complex type definition
   *
   * (3.4.6) Constraints on Complex Type Definition Schema Components
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckCTComponent(xmlSchemaParserCtxtPtr ctxt,
  			  xmlSchemaTypePtr type)
  {
      int ret;
      /*
      * Complex Type Definition Properties Correct
      */
      ret = xmlSchemaCheckCTPropsCorrect(ctxt, type);
      if (ret != 0)
  	return (ret);
      if (WXS_IS_EXTENSION(type))
  	ret = xmlSchemaCheckCOSCTExtends(ctxt, type);
      else
  	ret = xmlSchemaCheckDerivationOKRestriction(ctxt, type);
      return (ret);
  }
  
  /**
   * xmlSchemaCheckSRCCT:
   * @ctxt:  the schema parser context
   * @type:  the complex type definition
   *
   * (3.4.3) Constraints on XML Representations of Complex Type Definitions:
   * Schema Representation Constraint:
   * Complex Type Definition Representation OK (src-ct)
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckSRCCT(xmlSchemaParserCtxtPtr ctxt,
  		    xmlSchemaTypePtr type)
  {
      xmlSchemaTypePtr base;
      int ret = 0;
  
      /*
      * TODO: Adjust the error codes here, as I used
      * XML_SCHEMAP_SRC_CT_1 only yet.
      */
      base = type->baseType;
      if (! WXS_HAS_SIMPLE_CONTENT(type)) {
  	/*
  	* 1 If the <complexContent> alternative is chosen, the type definition
  	* `resolved` to by the `actual value` of the base [attribute]
  	* must be a complex type definition;
  	*/
  	if (! WXS_IS_COMPLEX(base)) {
  	    xmlChar *str = NULL;
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_SRC_CT_1,
  		WXS_BASIC_CAST type, type->node,
  		"If using <complexContent>, the base type is expected to be "
  		"a complex type. The base type '%s' is a simple type",
  		xmlSchemaFormatQName(&str, base->targetNamespace,
  		base->name));
  	    FREE_AND_NULL(str)
  	    return (XML_SCHEMAP_SRC_CT_1);
  	}
      } else {
  	/*
  	* SPEC
  	* 2 If the <simpleContent> alternative is chosen, all of the
  	* following must be true:
  	* 2.1 The type definition `resolved` to by the `actual value` of the
  	* base [attribute] must be one of the following:
  	*/
  	if (WXS_IS_SIMPLE(base)) {
  	    if (WXS_IS_EXTENSION(type) == 0) {
  		xmlChar *str = NULL;
  		/*
  		* 2.1.3 only if the <extension> alternative is also
  		* chosen, a simple type definition.
  		*/
  		/* TODO: Change error code to ..._SRC_CT_2_1_3. */
  		xmlSchemaPCustomErr(ctxt,
  		    XML_SCHEMAP_SRC_CT_1,
  		    WXS_BASIC_CAST type, NULL,
  		    "If using <simpleContent> and <restriction>, the base "
  		    "type must be a complex type. The base type '%s' is "
  		    "a simple type",
  		    xmlSchemaFormatQName(&str, base->targetNamespace,
  			base->name));
  		FREE_AND_NULL(str)
  		return (XML_SCHEMAP_SRC_CT_1);
  	    }
  	} else {
  	    /* Base type is a complex type. */
  	    if ((base->contentType == XML_SCHEMA_CONTENT_SIMPLE) ||
  		(base->contentType == XML_SCHEMA_CONTENT_BASIC)) {
  		/*
  		* 2.1.1 a complex type definition whose {content type} is a
  		* simple type definition;
  		* PASS
  		*/
  		if (base->contentTypeDef == NULL) {
  		    xmlSchemaPCustomErr(ctxt, XML_SCHEMAP_INTERNAL,
  			WXS_BASIC_CAST type, NULL,
  			"Internal error: xmlSchemaCheckSRCCT, "
  			"'%s', base type has no content type",
  			type->name);
  		    return (-1);
  		}
  	    } else if ((base->contentType == XML_SCHEMA_CONTENT_MIXED) &&
  		(WXS_IS_RESTRICTION(type))) {
  
  		/*
  		* 2.1.2 only if the <restriction> alternative is also
  		* chosen, a complex type definition whose {content type}
  		* is mixed and a particle emptiable.
  		*/
  		if (! xmlSchemaIsParticleEmptiable(
  		    (xmlSchemaParticlePtr) base->subtypes)) {
  		    ret = XML_SCHEMAP_SRC_CT_1;
  		} else
  		    /*
  		    * Attention: at this point the <simpleType> child is in
  		    * ->contentTypeDef (put there during parsing).
  		    */
  		    if (type->contentTypeDef == NULL) {
  		    xmlChar *str = NULL;
  		    /*
  		    * 2.2 If clause 2.1.2 above is satisfied, then there
  		    * must be a <simpleType> among the [children] of
  		    * <restriction>.
  		    */
  		    /* TODO: Change error code to ..._SRC_CT_2_2. */
  		    xmlSchemaPCustomErr(ctxt,
  			XML_SCHEMAP_SRC_CT_1,
  			WXS_BASIC_CAST type, NULL,
  			"A <simpleType> is expected among the children "
  			"of <restriction>, if <simpleContent> is used and "
  			"the base type '%s' is a complex type",
  			xmlSchemaFormatQName(&str, base->targetNamespace,
  			base->name));
  		    FREE_AND_NULL(str)
  		    return (XML_SCHEMAP_SRC_CT_1);
  		}
  	    } else {
  		ret = XML_SCHEMAP_SRC_CT_1;
  	    }
  	}
  	if (ret > 0) {
  	    xmlChar *str = NULL;
  	    if (WXS_IS_RESTRICTION(type)) {
  		xmlSchemaPCustomErr(ctxt,
  		    XML_SCHEMAP_SRC_CT_1,
  		    WXS_BASIC_CAST type, NULL,
  		    "If <simpleContent> and <restriction> is used, the "
  		    "base type must be a simple type or a complex type with "
  		    "mixed content and particle emptiable. The base type "
  		    "'%s' is none of those",
  		    xmlSchemaFormatQName(&str, base->targetNamespace,
  		    base->name));
  	    } else {
  		xmlSchemaPCustomErr(ctxt,
  		    XML_SCHEMAP_SRC_CT_1,
  		    WXS_BASIC_CAST type, NULL,
  		    "If <simpleContent> and <extension> is used, the "
  		    "base type must be a simple type. The base type '%s' "
  		    "is a complex type",
  		    xmlSchemaFormatQName(&str, base->targetNamespace,
  		    base->name));
  	    }
  	    FREE_AND_NULL(str)
  	}
      }
      /*
      * SPEC (3) "The corresponding complex type definition component must
      * satisfy the conditions set out in Constraints on Complex Type
      * Definition Schema Components ($3.4.6);"
      * NOTE (3) will be done in xmlSchemaTypeFixup().
      */
      /*
      * SPEC (4) If clause 2.2.1 or clause 2.2.2 in the correspondence specification
      * above for {attribute wildcard} is satisfied, the intensional
      * intersection must be expressible, as defined in Attribute Wildcard
      * Intersection ($3.10.6).
      * NOTE (4) is done in xmlSchemaFixupTypeAttributeUses().
      */
      return (ret);
  }
  
  #ifdef ENABLE_PARTICLE_RESTRICTION
  /**
   * xmlSchemaCheckParticleRangeOK:
   * @ctxt:  the schema parser context
   * @type:  the complex type definition
   *
   * (3.9.6) Constraints on Particle Schema Components
   * Schema Component Constraint:
   * Occurrence Range OK (range-ok)
   *
   * STATUS: complete
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckParticleRangeOK(int rmin, int rmax,
  			      int bmin, int bmax)
  {
      if (rmin < bmin)
  	return (1);
      if ((bmax != UNBOUNDED) &&
  	(rmax > bmax))
  	return (1);
      return (0);
  }
  
  /**
   * xmlSchemaCheckRCaseNameAndTypeOK:
   * @ctxt:  the schema parser context
   * @r: the restricting element declaration particle
   * @b: the base element declaration particle
   *
   * (3.9.6) Constraints on Particle Schema Components
   * Schema Component Constraint:
   * Particle Restriction OK (Elt:Elt -- NameAndTypeOK)
   * (rcase-NameAndTypeOK)
   *
   * STATUS:
   *   MISSING (3.2.3)
   *   CLARIFY: (3.2.2)
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckRCaseNameAndTypeOK(xmlSchemaParserCtxtPtr ctxt,
  				 xmlSchemaParticlePtr r,
  				 xmlSchemaParticlePtr b)
  {
      xmlSchemaElementPtr elemR, elemB;
  
      /* TODO: Error codes (rcase-NameAndTypeOK). */
      elemR = (xmlSchemaElementPtr) r->children;
      elemB = (xmlSchemaElementPtr) b->children;
      /*
      * SPEC (1) "The declarations' {name}s and {target namespace}s are
      * the same."
      */
      if ((elemR != elemB) &&
  	((! xmlStrEqual(elemR->name, elemB->name)) ||
  	(! xmlStrEqual(elemR->targetNamespace, elemB->targetNamespace))))
  	return (1);
      /*
      * SPEC (2) "R's occurrence range is a valid restriction of B's
      * occurrence range as defined by Occurrence Range OK ($3.9.6)."
      */
      if (xmlSchemaCheckParticleRangeOK(r->minOccurs, r->maxOccurs,
  	    b->minOccurs, b->maxOccurs) != 0)
  	return (1);
      /*
      * SPEC (3.1) "Both B's declaration's {scope} and R's declaration's
      * {scope} are global."
      */
      if (elemR == elemB)
  	return (0);
      /*
      * SPEC (3.2.1) "Either B's {nillable} is true or R's {nillable} is false."
      */
      if (((elemB->flags & XML_SCHEMAS_ELEM_NILLABLE) == 0) &&
  	(elemR->flags & XML_SCHEMAS_ELEM_NILLABLE))
  	 return (1);
      /*
      * SPEC (3.2.2) "either B's declaration's {value constraint} is absent,
      * or is not fixed, or R's declaration's {value constraint} is fixed
      * with the same value."
      */
      if ((elemB->value != NULL) && (elemB->flags & XML_SCHEMAS_ELEM_FIXED) &&
  	((elemR->value == NULL) ||
  	 ((elemR->flags & XML_SCHEMAS_ELEM_FIXED) == 0) ||
  	 /* TODO: Equality of the initial value or normalized or canonical? */
  	 (! xmlStrEqual(elemR->value, elemB->value))))
  	 return (1);
      /*
      * TODO: SPEC (3.2.3) "R's declaration's {identity-constraint
      * definitions} is a subset of B's declaration's {identity-constraint
      * definitions}, if any."
      */
      if (elemB->idcs != NULL) {
  	/* TODO */
      }
      /*
      * SPEC (3.2.4) "R's declaration's {disallowed substitutions} is a
      * superset of B's declaration's {disallowed substitutions}."
      */
      if (((elemB->flags & XML_SCHEMAS_ELEM_BLOCK_EXTENSION) &&
  	 ((elemR->flags & XML_SCHEMAS_ELEM_BLOCK_EXTENSION) == 0)) ||
  	((elemB->flags & XML_SCHEMAS_ELEM_BLOCK_RESTRICTION) &&
  	 ((elemR->flags & XML_SCHEMAS_ELEM_BLOCK_RESTRICTION) == 0)) ||
  	((elemB->flags & XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION) &&
  	 ((elemR->flags & XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION) == 0)))
  	 return (1);
      /*
      * SPEC (3.2.5) "R's {type definition} is validly derived given
      * {extension, list, union} from B's {type definition}"
      *
      * BADSPEC TODO: What's the point of adding "list" and "union" to the
      * set, if the corresponding constraints handle "restriction" and
      * "extension" only?
      *
      */
      {
  	int set = 0;
  
  	set |= SUBSET_EXTENSION;
  	set |= SUBSET_LIST;
  	set |= SUBSET_UNION;
  	if (xmlSchemaCheckCOSDerivedOK(ACTXT_CAST ctxt, elemR->subtypes,
  	    elemB->subtypes, set) != 0)
  	    return (1);
      }
      return (0);
  }
  
  /**
   * xmlSchemaCheckRCaseNSCompat:
   * @ctxt:  the schema parser context
   * @r: the restricting element declaration particle
   * @b: the base wildcard particle
   *
   * (3.9.6) Constraints on Particle Schema Components
   * Schema Component Constraint:
   * Particle Derivation OK (Elt:Any -- NSCompat)
   * (rcase-NSCompat)
   *
   * STATUS: complete
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckRCaseNSCompat(xmlSchemaParserCtxtPtr ctxt,
  			    xmlSchemaParticlePtr r,
  			    xmlSchemaParticlePtr b)
  {
      /* TODO:Error codes (rcase-NSCompat). */
      /*
      * SPEC "For an element declaration particle to be a `valid restriction`
      * of a wildcard particle all of the following must be true:"
      *
      * SPEC (1) "The element declaration's {target namespace} is `valid`
      * with respect to the wildcard's {namespace constraint} as defined by
      * Wildcard allows Namespace Name ($3.10.4)."
      */
      if (xmlSchemaCheckCVCWildcardNamespace((xmlSchemaWildcardPtr) b->children,
  	((xmlSchemaElementPtr) r->children)->targetNamespace) != 0)
  	return (1);
      /*
      * SPEC (2) "R's occurrence range is a valid restriction of B's
      * occurrence range as defined by Occurrence Range OK ($3.9.6)."
      */
      if (xmlSchemaCheckParticleRangeOK(r->minOccurs, r->maxOccurs,
  	    b->minOccurs, b->maxOccurs) != 0)
  	return (1);
  
      return (0);
  }
  
  /**
   * xmlSchemaCheckRCaseRecurseAsIfGroup:
   * @ctxt:  the schema parser context
   * @r: the restricting element declaration particle
   * @b: the base model group particle
   *
   * (3.9.6) Constraints on Particle Schema Components
   * Schema Component Constraint:
   * Particle Derivation OK (Elt:All/Choice/Sequence -- RecurseAsIfGroup)
   * (rcase-RecurseAsIfGroup)
   *
   * STATUS: TODO
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckRCaseRecurseAsIfGroup(xmlSchemaParserCtxtPtr ctxt,
  				    xmlSchemaParticlePtr r,
  				    xmlSchemaParticlePtr b)
  {
      /* TODO: Error codes (rcase-RecurseAsIfGroup). */
      TODO
      return (0);
  }
  
  /**
   * xmlSchemaCheckRCaseNSSubset:
   * @ctxt:  the schema parser context
   * @r: the restricting wildcard particle
   * @b: the base wildcard particle
   *
   * (3.9.6) Constraints on Particle Schema Components
   * Schema Component Constraint:
   * Particle Derivation OK (Any:Any -- NSSubset)
   * (rcase-NSSubset)
   *
   * STATUS: complete
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckRCaseNSSubset(xmlSchemaParserCtxtPtr ctxt,
  				    xmlSchemaParticlePtr r,
  				    xmlSchemaParticlePtr b,
  				    int isAnyTypeBase)
  {
      /* TODO: Error codes (rcase-NSSubset). */
      /*
      * SPEC (1) "R's occurrence range is a valid restriction of B's
      * occurrence range as defined by Occurrence Range OK ($3.9.6)."
      */
      if (xmlSchemaCheckParticleRangeOK(r->minOccurs, r->maxOccurs,
  	    b->minOccurs, b->maxOccurs))
  	return (1);
      /*
      * SPEC (2) "R's {namespace constraint} must be an intensional subset
      * of B's {namespace constraint} as defined by Wildcard Subset ($3.10.6)."
      */
      if (xmlSchemaCheckCOSNSSubset((xmlSchemaWildcardPtr) r->children,
  	(xmlSchemaWildcardPtr) b->children))
  	return (1);
      /*
      * SPEC (3) "Unless B is the content model wildcard of the `ur-type
      * definition`, R's {process contents} must be identical to or stronger
      * than B's {process contents}, where strict is stronger than lax is
      * stronger than skip."
      */
      if (! isAnyTypeBase) {
  	if ( ((xmlSchemaWildcardPtr) r->children)->processContents <
  	    ((xmlSchemaWildcardPtr) b->children)->processContents)
  	    return (1);
      }
  
      return (0);
  }
  
  /**
   * xmlSchemaCheckCOSParticleRestrict:
   * @ctxt:  the schema parser context
   * @type:  the complex type definition
   *
   * (3.9.6) Constraints on Particle Schema Components
   * Schema Component Constraint:
   * Particle Valid (Restriction) (cos-particle-restrict)
   *
   * STATUS: TODO
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckCOSParticleRestrict(xmlSchemaParserCtxtPtr ctxt,
  				  xmlSchemaParticlePtr r,
  				  xmlSchemaParticlePtr b)
  {
      int ret = 0;
  
      /*part = WXS_TYPE_PARTICLE(type);
      basePart = WXS_TYPE_PARTICLE(base);
      */
  
      TODO
  
      /*
      * SPEC (1) "They are the same particle."
      */
      if (r == b)
  	return (0);
  
  
      return (0);
  }
  
  #if 0
  /**
   * xmlSchemaCheckRCaseNSRecurseCheckCardinality:
   * @ctxt:  the schema parser context
   * @r: the model group particle
   * @b: the base wildcard particle
   *
   * (3.9.6) Constraints on Particle Schema Components
   * Schema Component Constraint:
   * Particle Derivation OK (All/Choice/Sequence:Any --
   *                         NSRecurseCheckCardinality)
   * (rcase-NSRecurseCheckCardinality)
   *
   * STATUS: TODO: subst-groups
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckRCaseNSRecurseCheckCardinality(xmlSchemaParserCtxtPtr ctxt,
  					     xmlSchemaParticlePtr r,
  					     xmlSchemaParticlePtr b)
  {
      xmlSchemaParticlePtr part;
      /* TODO: Error codes (rcase-NSRecurseCheckCardinality). */
      if ((r->children == NULL) || (r->children->children == NULL))
  	return (-1);
      /*
      * SPEC "For a group particle to be a `valid restriction` of a
      * wildcard particle..."
      *
      * SPEC (1) "Every member of the {particles} of the group is a `valid
      * restriction` of the wildcard as defined by
      * Particle Valid (Restriction) ($3.9.6)."
      */
      part = (xmlSchemaParticlePtr) r->children->children;
      do {
  	if (xmlSchemaCheckCOSParticleRestrict(ctxt, part, b))
  	    return (1);
  	part = (xmlSchemaParticlePtr) part->next;
      } while (part != NULL);
      /*
      * SPEC (2) "The effective total range of the group [...] is a
      * valid restriction of B's occurrence range as defined by
      * Occurrence Range OK ($3.9.6)."
      */
      if (xmlSchemaCheckParticleRangeOK(
  	    xmlSchemaGetParticleTotalRangeMin(r),
  	    xmlSchemaGetParticleTotalRangeMax(r),
  	    b->minOccurs, b->maxOccurs) != 0)
  	return (1);
      return (0);
  }
  #endif
  
  /**
   * xmlSchemaCheckRCaseRecurse:
   * @ctxt:  the schema parser context
   * @r: the <all> or <sequence> model group particle
   * @b: the base <all> or <sequence> model group particle
   *
   * (3.9.6) Constraints on Particle Schema Components
   * Schema Component Constraint:
   * Particle Derivation OK (All:All,Sequence:Sequence --
                             Recurse)
   * (rcase-Recurse)
   *
   * STATUS:  ?
   * TODO: subst-groups
   *
   * Returns 0 if the constraints are satisfied, a positive
   * error code if not and -1 if an internal error occurred.
   */
  static int
  xmlSchemaCheckRCaseRecurse(xmlSchemaParserCtxtPtr ctxt,
  			   xmlSchemaParticlePtr r,
  			   xmlSchemaParticlePtr b)
  {
      /* xmlSchemaParticlePtr part; */
      /* TODO: Error codes (rcase-Recurse). */
      if ((r->children == NULL) || (b->children == NULL) ||
  	(r->children->type != b->children->type))
  	return (-1);
      /*
      * SPEC "For an all or sequence group particle to be a `valid
      * restriction` of another group particle with the same {compositor}..."
      *
      * SPEC (1) "R's occurrence range is a valid restriction of B's
      * occurrence range as defined by Occurrence Range OK ($3.9.6)."
      */
      if (xmlSchemaCheckParticleRangeOK(r->minOccurs, r->maxOccurs,
  	    b->minOccurs, b->maxOccurs))
  	return (1);
  
  
      return (0);
  }
  
  #endif
  
  #define FACET_RESTR_MUTUAL_ERR(fac1, fac2) \
      xmlSchemaPCustomErrExt(pctxt,      \
  	XML_SCHEMAP_INVALID_FACET_VALUE, \
  	WXS_BASIC_CAST fac1, fac1->node, \
  	"It is an error for both '%s' and '%s' to be specified on the "\
  	"same type definition", \
  	BAD_CAST xmlSchemaFacetTypeToString(fac1->type), \
  	BAD_CAST xmlSchemaFacetTypeToString(fac2->type), NULL);
  
  #define FACET_RESTR_ERR(fac1, msg) \
      xmlSchemaPCustomErr(pctxt,      \
  	XML_SCHEMAP_INVALID_FACET_VALUE, \
  	WXS_BASIC_CAST fac1, fac1->node, \
  	msg, NULL);
  
  #define FACET_RESTR_FIXED_ERR(fac) \
      xmlSchemaPCustomErr(pctxt, \
  	XML_SCHEMAP_INVALID_FACET_VALUE, \
  	WXS_BASIC_CAST fac, fac->node, \
  	"The base type's facet is 'fixed', thus the value must not " \
  	"differ", NULL);
  
  static void
  xmlSchemaDeriveFacetErr(xmlSchemaParserCtxtPtr pctxt,
  			xmlSchemaFacetPtr facet1,
  			xmlSchemaFacetPtr facet2,
  			int lessGreater,
  			int orEqual,
  			int ofBase)
  {
      xmlChar *msg = NULL;
  
      msg = xmlStrdup(BAD_CAST "'");
      msg = xmlStrcat(msg, xmlSchemaFacetTypeToString(facet1->type));
      msg = xmlStrcat(msg, BAD_CAST "' has to be");
      if (lessGreater == 0)
  	msg = xmlStrcat(msg, BAD_CAST " equal to");
      if (lessGreater == 1)
  	msg = xmlStrcat(msg, BAD_CAST " greater than");
      else
  	msg = xmlStrcat(msg, BAD_CAST " less than");
  
      if (orEqual)
  	msg = xmlStrcat(msg, BAD_CAST " or equal to");
      msg = xmlStrcat(msg, BAD_CAST " '");
      msg = xmlStrcat(msg, xmlSchemaFacetTypeToString(facet2->type));
      if (ofBase)
  	msg = xmlStrcat(msg, BAD_CAST "' of the base type");
      else
  	msg = xmlStrcat(msg, BAD_CAST "'");
  
      xmlSchemaPCustomErr(pctxt,
  	XML_SCHEMAP_INVALID_FACET_VALUE,
  	WXS_BASIC_CAST facet1, NULL,
  	(const char *) msg, NULL);
  
      if (msg != NULL)
  	xmlFree(msg);
  }
  
  /*
  * xmlSchemaDeriveAndValidateFacets:
  *
  * Schema Component Constraint: Simple Type Restriction (Facets)
  * (st-restrict-facets)
  */
  static int
  xmlSchemaDeriveAndValidateFacets(xmlSchemaParserCtxtPtr pctxt,
  				 xmlSchemaTypePtr type)
  {
      xmlSchemaTypePtr base = type->baseType;
      xmlSchemaFacetLinkPtr link, cur, last = NULL;
      xmlSchemaFacetPtr facet, bfacet,
  	flength = NULL, ftotdig = NULL, ffracdig = NULL,
  	fmaxlen = NULL, fminlen = NULL, /* facets of the current type */
  	fmininc = NULL, fmaxinc = NULL,
  	fminexc = NULL, fmaxexc = NULL,
  	bflength = NULL, bftotdig = NULL, bffracdig = NULL,
  	bfmaxlen = NULL, bfminlen = NULL, /* facets of the base type */
  	bfmininc = NULL, bfmaxinc = NULL,
  	bfminexc = NULL, bfmaxexc = NULL;
      int res; /* err = 0, fixedErr; */
  
      /*
      * SPEC st-restrict-facets 1:
      * "The {variety} of R is the same as that of B."
      */
      /*
      * SPEC st-restrict-facets 2:
      * "If {variety} is atomic, the {primitive type definition}
      * of R is the same as that of B."
      *
      * NOTE: we leave 1 & 2 out for now, since this will be
      * satisfied by the derivation process.
      * CONSTRUCTION TODO: Maybe needed if using a construction API.
      */
      /*
      * SPEC st-restrict-facets 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 ((type->facetSet == NULL) && (base->facetSet == NULL))
  	return (0);
  
      last = type->facetSet;
      if (last != NULL)
  	while (last->next != NULL)
  	    last = last->next;
  
      for (cur = type->facetSet; cur != NULL; cur = cur->next) {
  	facet = cur->facet;
  	switch (facet->type) {
  	    case XML_SCHEMA_FACET_LENGTH:
  		flength = facet; break;
  	    case XML_SCHEMA_FACET_MINLENGTH:
  		fminlen = facet; break;
  	    case XML_SCHEMA_FACET_MININCLUSIVE:
  		fmininc = facet; break;
  	    case XML_SCHEMA_FACET_MINEXCLUSIVE:
  		fminexc = facet; break;
  	    case XML_SCHEMA_FACET_MAXLENGTH:
  		fmaxlen = facet; break;
  	    case XML_SCHEMA_FACET_MAXINCLUSIVE:
  		fmaxinc = facet; break;
  	    case XML_SCHEMA_FACET_MAXEXCLUSIVE:
  		fmaxexc = facet; break;
  	    case XML_SCHEMA_FACET_TOTALDIGITS:
  		ftotdig = facet; break;
  	    case XML_SCHEMA_FACET_FRACTIONDIGITS:
  		ffracdig = facet; break;
  	    default:
  		break;
  	}
      }
      for (cur = base->facetSet; cur != NULL; cur = cur->next) {
  	facet = cur->facet;
  	switch (facet->type) {
  	    case XML_SCHEMA_FACET_LENGTH:
  		bflength = facet; break;
  	    case XML_SCHEMA_FACET_MINLENGTH:
  		bfminlen = facet; break;
  	    case XML_SCHEMA_FACET_MININCLUSIVE:
  		bfmininc = facet; break;
  	    case XML_SCHEMA_FACET_MINEXCLUSIVE:
  		bfminexc = facet; break;
  	    case XML_SCHEMA_FACET_MAXLENGTH:
  		bfmaxlen = facet; break;
  	    case XML_SCHEMA_FACET_MAXINCLUSIVE:
  		bfmaxinc = facet; break;
  	    case XML_SCHEMA_FACET_MAXEXCLUSIVE:
  		bfmaxexc = facet; break;
  	    case XML_SCHEMA_FACET_TOTALDIGITS:
  		bftotdig = facet; break;
  	    case XML_SCHEMA_FACET_FRACTIONDIGITS:
  		bffracdig = facet; break;
  	    default:
  		break;
  	}
      }
      /*
      * length and minLength or maxLength (2.2) + (3.2)
      */
      if (flength && (fminlen || fmaxlen)) {
  	FACET_RESTR_ERR(flength, "It is an error for both 'length' and "
  	    "either of 'minLength' or 'maxLength' to be specified on "
  	    "the same type definition")
      }
      /*
      * Mutual exclusions in the same derivation step.
      */
      if ((fmaxinc) && (fmaxexc)) {
  	/*
  	* SCC "maxInclusive and maxExclusive"
  	*/
  	FACET_RESTR_MUTUAL_ERR(fmaxinc, fmaxexc)
      }
      if ((fmininc) && (fminexc)) {
  	/*
  	* SCC "minInclusive and minExclusive"
  	*/
  	FACET_RESTR_MUTUAL_ERR(fmininc, fminexc)
      }
  
      if (flength && bflength) {
  	/*
  	* SCC "length valid restriction"
  	* The values have to be equal.
  	*/
  	res = xmlSchemaCompareValues(flength->val, bflength->val);
  	if (res == -2)
  	    goto internal_error;
  	if (res != 0)
  	    xmlSchemaDeriveFacetErr(pctxt, flength, bflength, 0, 0, 1);
  	if ((res != 0) && (bflength->fixed)) {
  	    FACET_RESTR_FIXED_ERR(flength)
  	}
  
      }
      if (fminlen && bfminlen) {
  	/*
  	* SCC "minLength valid restriction"
  	* minLength >= BASE minLength
  	*/
  	res = xmlSchemaCompareValues(fminlen->val, bfminlen->val);
  	if (res == -2)
  	    goto internal_error;
  	if (res == -1)
  	    xmlSchemaDeriveFacetErr(pctxt, fminlen, bfminlen, 1, 1, 1);
  	if ((res != 0) && (bfminlen->fixed)) {
  	    FACET_RESTR_FIXED_ERR(fminlen)
  	}
      }
      if (fmaxlen && bfmaxlen) {
  	/*
  	* SCC "maxLength valid restriction"
  	* maxLength <= BASE minLength
  	*/
  	res = xmlSchemaCompareValues(fmaxlen->val, bfmaxlen->val);
  	if (res == -2)
  	    goto internal_error;
  	if (res == 1)
  	    xmlSchemaDeriveFacetErr(pctxt, fmaxlen, bfmaxlen, -1, 1, 1);
  	if ((res != 0) && (bfmaxlen->fixed)) {
  	    FACET_RESTR_FIXED_ERR(fmaxlen)
  	}
      }
      /*
      * SCC "length and minLength or maxLength"
      */
      if (! flength)
  	flength = bflength;
      if (flength) {
  	if (! fminlen)
  	    fminlen = bfminlen;
  	if (fminlen) {
  	    /* (1.1) length >= minLength */
  	    res = xmlSchemaCompareValues(flength->val, fminlen->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == -1)
  		xmlSchemaDeriveFacetErr(pctxt, flength, fminlen, 1, 1, 0);
  	}
  	if (! fmaxlen)
  	    fmaxlen = bfmaxlen;
  	if (fmaxlen) {
  	    /* (2.1) length <= maxLength */
  	    res = xmlSchemaCompareValues(flength->val, fmaxlen->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == 1)
  		xmlSchemaDeriveFacetErr(pctxt, flength, fmaxlen, -1, 1, 0);
  	}
      }
      if (fmaxinc) {
  	/*
  	* "maxInclusive"
  	*/
  	if (fmininc) {
  	    /* SCC "maxInclusive >= minInclusive" */
  	    res = xmlSchemaCompareValues(fmaxinc->val, fmininc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxinc, fmininc, 1, 1, 0);
  	    }
  	}
  	/*
  	* SCC "maxInclusive valid restriction"
  	*/
  	if (bfmaxinc) {
  	    /* maxInclusive <= BASE maxInclusive */
  	    res = xmlSchemaCompareValues(fmaxinc->val, bfmaxinc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == 1)
  		xmlSchemaDeriveFacetErr(pctxt, fmaxinc, bfmaxinc, -1, 1, 1);
  	    if ((res != 0) && (bfmaxinc->fixed)) {
  		FACET_RESTR_FIXED_ERR(fmaxinc)
  	    }
  	}
  	if (bfmaxexc) {
  	    /* maxInclusive < BASE maxExclusive */
  	    res = xmlSchemaCompareValues(fmaxinc->val, bfmaxexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxinc, bfmaxexc, -1, 0, 1);
  	    }
  	}
  	if (bfmininc) {
  	    /* maxInclusive >= BASE minInclusive */
  	    res = xmlSchemaCompareValues(fmaxinc->val, bfmininc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxinc, bfmininc, 1, 1, 1);
  	    }
  	}
  	if (bfminexc) {
  	    /* maxInclusive > BASE minExclusive */
  	    res = xmlSchemaCompareValues(fmaxinc->val, bfminexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != 1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxinc, bfminexc, 1, 0, 1);
  	    }
  	}
      }
      if (fmaxexc) {
  	/*
  	* "maxExclusive >= minExclusive"
  	*/
  	if (fminexc) {
  	    res = xmlSchemaCompareValues(fmaxexc->val, fminexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxexc, fminexc, 1, 1, 0);
  	    }
  	}
  	/*
  	* "maxExclusive valid restriction"
  	*/
  	if (bfmaxexc) {
  	    /* maxExclusive <= BASE maxExclusive */
  	    res = xmlSchemaCompareValues(fmaxexc->val, bfmaxexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == 1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxexc, bfmaxexc, -1, 1, 1);
  	    }
  	    if ((res != 0) && (bfmaxexc->fixed)) {
  		FACET_RESTR_FIXED_ERR(fmaxexc)
  	    }
  	}
  	if (bfmaxinc) {
  	    /* maxExclusive <= BASE maxInclusive */
  	    res = xmlSchemaCompareValues(fmaxexc->val, bfmaxinc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == 1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxexc, bfmaxinc, -1, 1, 1);
  	    }
  	}
  	if (bfmininc) {
  	    /* maxExclusive > BASE minInclusive */
  	    res = xmlSchemaCompareValues(fmaxexc->val, bfmininc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != 1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxexc, bfmininc, 1, 0, 1);
  	    }
  	}
  	if (bfminexc) {
  	    /* maxExclusive > BASE minExclusive */
  	    res = xmlSchemaCompareValues(fmaxexc->val, bfminexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != 1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmaxexc, bfminexc, 1, 0, 1);
  	    }
  	}
      }
      if (fminexc) {
  	/*
  	* "minExclusive < maxInclusive"
  	*/
  	if (fmaxinc) {
  	    res = xmlSchemaCompareValues(fminexc->val, fmaxinc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fminexc, fmaxinc, -1, 0, 0);
  	    }
  	}
  	/*
  	* "minExclusive valid restriction"
  	*/
  	if (bfminexc) {
  	    /* minExclusive >= BASE minExclusive */
  	    res = xmlSchemaCompareValues(fminexc->val, bfminexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fminexc, bfminexc, 1, 1, 1);
  	    }
  	    if ((res != 0) && (bfminexc->fixed)) {
  		FACET_RESTR_FIXED_ERR(fminexc)
  	    }
  	}
  	if (bfmaxinc) {
  	    /* minExclusive <= BASE maxInclusive */
  	    res = xmlSchemaCompareValues(fminexc->val, bfmaxinc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == 1) {
  		xmlSchemaDeriveFacetErr(pctxt, fminexc, bfmaxinc, -1, 1, 1);
  	    }
  	}
  	if (bfmininc) {
  	    /* minExclusive >= BASE minInclusive */
  	    res = xmlSchemaCompareValues(fminexc->val, bfmininc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fminexc, bfmininc, 1, 1, 1);
  	    }
  	}
  	if (bfmaxexc) {
  	    /* minExclusive < BASE maxExclusive */
  	    res = xmlSchemaCompareValues(fminexc->val, bfmaxexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fminexc, bfmaxexc, -1, 0, 1);
  	    }
  	}
      }
      if (fmininc) {
  	/*
  	* "minInclusive < maxExclusive"
  	*/
  	if (fmaxexc) {
  	    res = xmlSchemaCompareValues(fmininc->val, fmaxexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmininc, fmaxexc, -1, 0, 0);
  	    }
  	}
  	/*
  	* "minExclusive valid restriction"
  	*/
  	if (bfmininc) {
  	    /* minInclusive >= BASE minInclusive */
  	    res = xmlSchemaCompareValues(fmininc->val, bfmininc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == -1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmininc, bfmininc, 1, 1, 1);
  	    }
  	    if ((res != 0) && (bfmininc->fixed)) {
  		FACET_RESTR_FIXED_ERR(fmininc)
  	    }
  	}
  	if (bfmaxinc) {
  	    /* minInclusive <= BASE maxInclusive */
  	    res = xmlSchemaCompareValues(fmininc->val, bfmaxinc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res == 1) {
  		xmlSchemaDeriveFacetErr(pctxt, fmininc, bfmaxinc, -1, 1, 1);
  	    }
  	}
  	if (bfminexc) {
  	    /* minInclusive > BASE minExclusive */
  	    res = xmlSchemaCompareValues(fmininc->val, bfminexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != 1)
  		xmlSchemaDeriveFacetErr(pctxt, fmininc, bfminexc, 1, 0, 1);
  	}
  	if (bfmaxexc) {
  	    /* minInclusive < BASE maxExclusive */
  	    res = xmlSchemaCompareValues(fmininc->val, bfmaxexc->val);
  	    if (res == -2)
  		goto internal_error;
  	    if (res != -1)
  		xmlSchemaDeriveFacetErr(pctxt, fmininc, bfmaxexc, -1, 0, 1);
  	}
      }
      if (ftotdig && bftotdig) {
  	/*
  	* SCC " totalDigits valid restriction"
  	* totalDigits <= BASE totalDigits
  	*/
  	res = xmlSchemaCompareValues(ftotdig->val, bftotdig->val);
  	if (res == -2)
  	    goto internal_error;
  	if (res == 1)
  	    xmlSchemaDeriveFacetErr(pctxt, ftotdig, bftotdig,
  	    -1, 1, 1);
  	if ((res != 0) && (bftotdig->fixed)) {
  	    FACET_RESTR_FIXED_ERR(ftotdig)
  	}
      }
      if (ffracdig && bffracdig) {
  	/*
  	* SCC  "fractionDigits valid restriction"
  	* fractionDigits <= BASE fractionDigits
  	*/
  	res = xmlSchemaCompareValues(ffracdig->val, bffracdig->val);
  	if (res == -2)
  	    goto internal_error;
  	if (res == 1)
  	    xmlSchemaDeriveFacetErr(pctxt, ffracdig, bffracdig,
  	    -1, 1, 1);
  	if ((res != 0) && (bffracdig->fixed)) {
  	    FACET_RESTR_FIXED_ERR(ffracdig)
  	}
      }
      /*
      * SCC "fractionDigits less than or equal to totalDigits"
      */
      if (! ftotdig)
  	ftotdig = bftotdig;
      if (! ffracdig)
  	ffracdig = bffracdig;
      if (ftotdig && ffracdig) {
  	res = xmlSchemaCompareValues(ffracdig->val, ftotdig->val);
  	if (res == -2)
  	    goto internal_error;
  	if (res == 1)
  	    xmlSchemaDeriveFacetErr(pctxt, ffracdig, ftotdig,
  		-1, 1, 0);
      }
      /*
      * *Enumerations* won' be added here, since only the first set
      * of enumerations in the ancestor-or-self axis is used
      * for validation, plus we need to use the base type of those
      * enumerations for whitespace.
      *
      * *Patterns*: won't be add here, since they are ORed at
      * type level and ANDed at ancestor level. This will
      * happen during validation by walking the base axis
      * of the type.
      */
      for (cur = base->facetSet; cur != NULL; cur = cur->next) {
  	bfacet = cur->facet;
  	/*
  	* Special handling of enumerations and patterns.
  	* TODO: hmm, they should not appear in the set, so remove this.
  	*/
  	if ((bfacet->type == XML_SCHEMA_FACET_PATTERN) ||
  	    (bfacet->type == XML_SCHEMA_FACET_ENUMERATION))
  	    continue;
  	/*
  	* Search for a duplicate facet in the current type.
  	*/
  	link = type->facetSet;
  	/* err = 0; */
  	/* fixedErr = 0; */
  	while (link != NULL) {
  	    facet = link->facet;
  	    if (facet->type == bfacet->type) {
  		switch (facet->type) {
  		    case XML_SCHEMA_FACET_WHITESPACE:
  			/*
  			* The whitespace must be stronger.
  			*/
  			if (facet->whitespace < bfacet->whitespace) {
  			    FACET_RESTR_ERR(facet,
  				"The 'whitespace' value has to be equal to "
  				"or stronger than the 'whitespace' value of "
  				"the base type")
  			}
  			if ((bfacet->fixed) &&
  			    (facet->whitespace != bfacet->whitespace)) {
  			    FACET_RESTR_FIXED_ERR(facet)
  			}
  			break;
  		    default:
  			break;
  		}
  		/* Duplicate found. */
  		break;
  	    }
  	    link = link->next;
  	}
  	/*
  	* If no duplicate was found: add the base types's facet
  	* to the set.
  	*/
  	if (link == NULL) {
  	    link = (xmlSchemaFacetLinkPtr)
  		xmlMalloc(sizeof(xmlSchemaFacetLink));
  	    if (link == NULL) {
  		xmlSchemaPErrMemory(pctxt,
  		    "deriving facets, creating a facet link", NULL);
  		return (-1);
  	    }
  	    link->facet = cur->facet;
  	    link->next = NULL;
  	    if (last == NULL)
  		type->facetSet = link;
  	    else
  		last->next = link;
  	    last = link;
  	}
  
      }
  
      return (0);
  internal_error:
      PERROR_INT("xmlSchemaDeriveAndValidateFacets",
  	"an error occurred");
      return (-1);
  }
  
  static int
  xmlSchemaFinishMemberTypeDefinitionsProperty(xmlSchemaParserCtxtPtr pctxt,
  					     xmlSchemaTypePtr type)
  {
      xmlSchemaTypeLinkPtr link, lastLink, prevLink, subLink, newLink;
      /*
      * 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.
      *
      * TODO: There's a bug entry at
      * "http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005JulSep/0287.html"
      * which indicates that we'll keep the union types the future.
      */
      link = type->memberTypes;
      while (link != NULL) {
  
  	if (WXS_IS_TYPE_NOT_FIXED(link->type))
  	    xmlSchemaTypeFixup(link->type, ACTXT_CAST pctxt);
  
  	if (WXS_IS_UNION(link->type)) {
  	    subLink = xmlSchemaGetUnionSimpleTypeMemberTypes(link->type);
  	    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(pctxt, "allocating a type link",
  				NULL);
  			    return (-1);
  			}
  			newLink->type = subLink->type;
  			prevLink->next = newLink;
  			prevLink = newLink;
  			newLink->next = lastLink;
  
  			subLink = subLink->next;
  		    }
  		}
  	    }
  	}
  	link = link->next;
      }
      return (0);
  }
  
  static void
  xmlSchemaTypeFixupOptimFacets(xmlSchemaTypePtr type)
  {
      int has = 0, needVal = 0, normVal = 0;
  
      has	= (type->baseType->flags & XML_SCHEMAS_TYPE_HAS_FACETS) ? 1 : 0;
      if (has) {
  	needVal = (type->baseType->flags &
  	    XML_SCHEMAS_TYPE_FACETSNEEDVALUE) ? 1 : 0;
  	normVal = (type->baseType->flags &
  	    XML_SCHEMAS_TYPE_NORMVALUENEEDED) ? 1 : 0;
      }
      if (type->facets != NULL) {
  	xmlSchemaFacetPtr fac;
  
  	for (fac = type->facets; fac != NULL; fac = fac->next) {
  	    switch (fac->type) {
  		case XML_SCHEMA_FACET_WHITESPACE:
  		    break;
  		case XML_SCHEMA_FACET_PATTERN:
  		    normVal = 1;
  		    has = 1;
  		    break;
  		case XML_SCHEMA_FACET_ENUMERATION:
  		    needVal = 1;
  		    normVal = 1;
  		    has = 1;
  		    break;
  		default:
  		    has = 1;
  		    break;
  	    }
  	}
      }
      if (normVal)
  	type->flags |= XML_SCHEMAS_TYPE_NORMVALUENEEDED;
      if (needVal)
  	type->flags |= XML_SCHEMAS_TYPE_FACETSNEEDVALUE;
      if (has)
  	type->flags |= XML_SCHEMAS_TYPE_HAS_FACETS;
  
      if (has && (! needVal) && WXS_IS_ATOMIC(type)) {
  	xmlSchemaTypePtr prim = xmlSchemaGetPrimitiveType(type);
  	/*
  	* OPTIMIZE VAL TODO: Some facets need a computed value.
  	*/
  	if ((prim->builtInType != XML_SCHEMAS_ANYSIMPLETYPE) &&
  	    (prim->builtInType != XML_SCHEMAS_STRING)) {
  	    type->flags |= XML_SCHEMAS_TYPE_FACETSNEEDVALUE;
  	}
      }
  }
  
  static int
  xmlSchemaTypeFixupWhitespace(xmlSchemaTypePtr type)
  {
  
  
      /*
      * Evaluate the whitespace-facet value.
      */
      if (WXS_IS_LIST(type)) {
  	type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE;
  	return (0);
      } else if (WXS_IS_UNION(type))
  	return (0);
  
      if (type->facetSet != NULL) {
  	xmlSchemaFacetLinkPtr lin;
  
  	for (lin = type->facetSet; lin != NULL; lin = lin->next) {
  	    if (lin->facet->type == XML_SCHEMA_FACET_WHITESPACE) {
  		switch (lin->facet->whitespace) {
  		case XML_SCHEMAS_FACET_PRESERVE:
  		    type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE;
  		    break;
  		case XML_SCHEMAS_FACET_REPLACE:
  		    type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_REPLACE;
  		    break;
  		case XML_SCHEMAS_FACET_COLLAPSE:
  		    type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE;
  		    break;
  		default:
  		    return (-1);
  		}
  		return (0);
  	    }
  	}
      }
      /*
      * For all `atomic` datatypes other than string (and types `derived`
      * by `restriction` from it) the value of whiteSpace is fixed to
      * collapse
      */
      {
  	xmlSchemaTypePtr anc;
  
  	for (anc = type->baseType; anc != NULL &&
  		anc->builtInType != XML_SCHEMAS_ANYTYPE;
  		anc = anc->baseType) {
  
  	    if (anc->type == XML_SCHEMA_TYPE_BASIC) {
  		if (anc->builtInType == XML_SCHEMAS_NORMSTRING) {
  		    type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_REPLACE;
  
  		} else if ((anc->builtInType == XML_SCHEMAS_STRING) ||
  		    (anc->builtInType == XML_SCHEMAS_ANYSIMPLETYPE)) {
  		    type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE;
  
  		} else
  		    type->flags |= XML_SCHEMAS_TYPE_WHITESPACE_COLLAPSE;
  		break;
  	    }
  	}
      }
      return (0);
  }
  
  static int
  xmlSchemaFixupSimpleTypeStageOne(xmlSchemaParserCtxtPtr pctxt,
  			  xmlSchemaTypePtr type)
  {
      if (type->type != XML_SCHEMA_TYPE_SIMPLE)
  	return(0);
      if (! WXS_IS_TYPE_NOT_FIXED_1(type))
  	return(0);
      type->flags |= XML_SCHEMAS_TYPE_FIXUP_1;
  
      if (WXS_IS_LIST(type)) {
  	/*
  	* Corresponds to <simpleType><list>...
  	*/
  	if (type->subtypes == NULL) {
  	    /*
  	    * This one is really needed, so get out.
  	    */
  	    PERROR_INT("xmlSchemaFixupSimpleTypeStageOne",
  		"list type has no item-type assigned");
  	    return(-1);
  	}
      } else if (WXS_IS_UNION(type)) {
  	/*
  	* Corresponds to <simpleType><union>...
  	*/
  	if (type->memberTypes == NULL) {
  	    /*
  	    * This one is really needed, so get out.
  	    */
  	    PERROR_INT("xmlSchemaFixupSimpleTypeStageOne",
  		"union type has no member-types assigned");
  	    return(-1);
  	}
      } else {
  	/*
  	* Corresponds to <simpleType><restriction>...
  	*/
  	if (type->baseType == NULL) {
  	    PERROR_INT("xmlSchemaFixupSimpleTypeStageOne",
  		"type has no base-type assigned");
  	    return(-1);
  	}
  	if (WXS_IS_TYPE_NOT_FIXED_1(type->baseType))
  	    if (xmlSchemaFixupSimpleTypeStageOne(pctxt, type->baseType) == -1)
  		return(-1);
  	/*
  	* Variety
  	* If the <restriction> alternative is chosen, then the
  	* {variety} of the {base type definition}.
  	*/
  	if (WXS_IS_ATOMIC(type->baseType))
  	    type->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC;
  	else if (WXS_IS_LIST(type->baseType)) {
  	    type->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST;
  	    /*
  	    * Inherit the itemType.
  	    */
  	    type->subtypes = type->baseType->subtypes;
  	} else if (WXS_IS_UNION(type->baseType)) {
  	    type->flags |= XML_SCHEMAS_TYPE_VARIETY_UNION;
  	    /*
  	    * NOTE that we won't assign the memberTypes of the base,
  	    * since this will make trouble when freeing them; we will
  	    * use a lookup function to access them instead.
  	    */
  	}
      }
      return(0);
  }
  
  #ifdef DEBUG_TYPE
  static void
  xmlSchemaDebugFixedType(xmlSchemaParserCtxtPtr pctxt,
  		       xmlSchemaTypePtr type)
  {
      if (type->node != NULL) {
          xmlGenericError(xmlGenericErrorContext,
                          "Type of %s : %s:%d :", name,
                          type->node->doc->URL,
                          xmlGetLineNo(type->node));
      } else {
          xmlGenericError(xmlGenericErrorContext, "Type of %s :", name);
      }
      if ((WXS_IS_SIMPLE(type)) || (WXS_IS_COMPLEX(type))) {
  	switch (type->contentType) {
  	    case XML_SCHEMA_CONTENT_SIMPLE:
  		xmlGenericError(xmlGenericErrorContext, "simple\n");
  		break;
  	    case XML_SCHEMA_CONTENT_ELEMENTS:
  		xmlGenericError(xmlGenericErrorContext, "elements\n");
  		break;
  	    case XML_SCHEMA_CONTENT_UNKNOWN:
  		xmlGenericError(xmlGenericErrorContext, "unknown !!!\n");
  		break;
  	    case XML_SCHEMA_CONTENT_EMPTY:
  		xmlGenericError(xmlGenericErrorContext, "empty\n");
  		break;
  	    case XML_SCHEMA_CONTENT_MIXED:
  		if (xmlSchemaIsParticleEmptiable((xmlSchemaParticlePtr)
  		    type->subtypes))
  		    xmlGenericError(xmlGenericErrorContext,
  			"mixed as emptiable particle\n");
  		else
  		    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;
  	    default:
  		xmlGenericError(xmlGenericErrorContext,
  		    "not registered !!!\n");
  		break;
  	}
      }
  }
  #endif
  
  /*
  * 3.14.6 Constraints on Simple Type Definition Schema Components
  */
  static int
  xmlSchemaFixupSimpleTypeStageTwo(xmlSchemaParserCtxtPtr pctxt,
  				 xmlSchemaTypePtr type)
  {
      int res, olderrs = pctxt->nberrors;
  
      if (type->type != XML_SCHEMA_TYPE_SIMPLE)
  	return(-1);
  
      if (! WXS_IS_TYPE_NOT_FIXED(type))
  	return(0);
  
      type->flags |= XML_SCHEMAS_TYPE_INTERNAL_RESOLVED;
      type->contentType = XML_SCHEMA_CONTENT_SIMPLE;
  
      if (type->baseType == NULL) {
  	PERROR_INT("xmlSchemaFixupSimpleTypeStageTwo",
  	    "missing baseType");
  	goto exit_failure;
      }
      if (WXS_IS_TYPE_NOT_FIXED(type->baseType))
  	xmlSchemaTypeFixup(type->baseType, ACTXT_CAST pctxt);
      /*
      * If a member type of a union is a union itself, we need to substitute
      * that member type for its member types.
      * NOTE that this might change in WXS 1.1; i.e. we will keep the union
      * types in WXS 1.1.
      */
      if ((type->memberTypes != NULL) &&
  	(xmlSchemaFinishMemberTypeDefinitionsProperty(pctxt, type) == -1))
  	return(-1);
      /*
      * SPEC 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)."
      */
      /*
      * Schema Component Constraint: Simple Type Definition Properties Correct
      * (st-props-correct)
      */
      res = xmlSchemaCheckSTPropsCorrect(pctxt, type);
      HFAILURE HERROR
      /*
      * Schema Component Constraint: Derivation Valid (Restriction, Simple)
      * (cos-st-restricts)
      */
      res = xmlSchemaCheckCOSSTRestricts(pctxt, type);
      HFAILURE HERROR
      /*
      * TODO: Removed the error report, 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);
      */
      /*
      * Schema Component Constraint: Simple Type Restriction (Facets)
      * (st-restrict-facets)
      */
      res = xmlSchemaCheckFacetValues(type, pctxt);
      HFAILURE HERROR
      if ((type->facetSet != NULL) ||
  	(type->baseType->facetSet != NULL)) {
  	res = xmlSchemaDeriveAndValidateFacets(pctxt, type);
  	HFAILURE HERROR
      }
      /*
      * Whitespace value.
      */
      res = xmlSchemaTypeFixupWhitespace(type);
      HFAILURE HERROR
      xmlSchemaTypeFixupOptimFacets(type);
  
  exit_error:
  #ifdef DEBUG_TYPE
      xmlSchemaDebugFixedType(pctxt, type);
  #endif
      if (olderrs != pctxt->nberrors)
  	return(pctxt->err);
      return(0);
  
  exit_failure:
  #ifdef DEBUG_TYPE
      xmlSchemaDebugFixedType(pctxt, type);
  #endif
      return(-1);
  }
  
  static int
  xmlSchemaFixupComplexType(xmlSchemaParserCtxtPtr pctxt,
  			  xmlSchemaTypePtr type)
  {
      int res = 0, olderrs = pctxt->nberrors;
      xmlSchemaTypePtr baseType = type->baseType;
  
      if (! WXS_IS_TYPE_NOT_FIXED(type))
  	return(0);
      type->flags |= XML_SCHEMAS_TYPE_INTERNAL_RESOLVED;
      if (baseType == NULL) {
  	PERROR_INT("xmlSchemaFixupComplexType",
  	    "missing baseType");
  	goto exit_failure;
      }
      /*
      * Fixup the base type.
      */
      if (WXS_IS_TYPE_NOT_FIXED(baseType))
  	xmlSchemaTypeFixup(baseType, ACTXT_CAST pctxt);
      if (baseType->flags & XML_SCHEMAS_TYPE_INTERNAL_INVALID) {
  	/*
  	* Skip fixup if the base type is invalid.
  	* TODO: Generate a warning!
  	*/
  	return(0);
      }
      /*
      * This basically checks if the base type can be derived.
      */
      res = xmlSchemaCheckSRCCT(pctxt, type);
      HFAILURE HERROR
      /*
      * Fixup the content type.
      */
      if (type->contentType == XML_SCHEMA_CONTENT_SIMPLE) {
  	/*
  	* Corresponds to <complexType><simpleContent>...
  	*/
  	if ((WXS_IS_COMPLEX(baseType)) &&
  	    (baseType->contentTypeDef != NULL) &&
  	    (WXS_IS_RESTRICTION(type))) {
  	    xmlSchemaTypePtr contentBase, content;
  #ifdef ENABLE_NAMED_LOCALS
  	    char buf[30];
  	    const xmlChar *tmpname;
  #endif
  	    /*
  	    * SPEC (1) If <restriction> + base type is <complexType>,
  	    * "whose own {content type} is a simple type..."
  	    */
  	    if (type->contentTypeDef != NULL) {
  		/*
  		* SPEC (1.1) "the simple type definition corresponding to the
  		* <simpleType> among the [children] of <restriction> if there
  		* is one;"
  		* Note that this "<simpleType> among the [children]" was put
  		* into ->contentTypeDef during parsing.
  		*/
  		contentBase = type->contentTypeDef;
  		type->contentTypeDef = NULL;
  	    } else {
  		/*
  		* (1.2) "...otherwise (<restriction> has no <simpleType>
  		* among its [children]), the simple type definition which
  		* is the {content type} of the ... base type."
  		*/
  		contentBase = baseType->contentTypeDef;
  	    }
  	    /*
  	    * SPEC
  	    * "... a simple type definition which restricts the simple
  	    * type definition identified in clause 1.1 or clause 1.2
  	    * with a set of facet components"
  	    *
  	    * Create the anonymous simple type, which will be the content
  	    * type of the complex type.
  	    */
  #ifdef ENABLE_NAMED_LOCALS
  	    snprintf(buf, 29, "#scST%d", ++(pctxt->counter));
  	    tmpname = xmlDictLookup(pctxt->dict, BAD_CAST buf, -1);
  	    content = xmlSchemaAddType(pctxt, pctxt->schema,
  		XML_SCHEMA_TYPE_SIMPLE, tmpname, type->targetNamespace,
  		type->node, 0);
  #else
  	    content = xmlSchemaAddType(pctxt, pctxt->schema,
  		XML_SCHEMA_TYPE_SIMPLE, NULL, type->targetNamespace,
  		type->node, 0);
  #endif
  	    if (content == NULL)
  		goto exit_failure;
  	    /*
  	    * We will use the same node as for the <complexType>
  	    * to have it somehow anchored in the schema doc.
  	    */
  	    content->type = XML_SCHEMA_TYPE_SIMPLE;
  	    content->baseType = contentBase;
  	    /*
  	    * Move the facets, previously anchored on the
  	    * complexType during parsing.
  	    */
  	    content->facets = type->facets;
  	    type->facets = NULL;
  	    content->facetSet = type->facetSet;
  	    type->facetSet = NULL;
  
  	    type->contentTypeDef = content;
  	    if (WXS_IS_TYPE_NOT_FIXED(contentBase))
  		xmlSchemaTypeFixup(contentBase, ACTXT_CAST pctxt);
  	    /*
  	    * Fixup the newly created type. We don't need to check
  	    * for circularity here.
  	    */
  	    res = xmlSchemaFixupSimpleTypeStageOne(pctxt, content);
  	    HFAILURE HERROR
  	    res = xmlSchemaFixupSimpleTypeStageTwo(pctxt, content);
  	    HFAILURE HERROR
  
  	} else if ((WXS_IS_COMPLEX(baseType)) &&
  	    (baseType->contentType == XML_SCHEMA_CONTENT_MIXED) &&
  	    (WXS_IS_RESTRICTION(type))) {
  	    /*
  	    * SPEC (2) If <restriction> + base is a mixed <complexType> with
  	    * an emptiable particle, then a simple type definition which
  	    * restricts the <restriction>'s <simpleType> child.
  	    */
  	    if ((type->contentTypeDef == NULL) ||
  		(type->contentTypeDef->baseType == NULL)) {
  		/*
  		* TODO: Check if this ever happens.
  		*/
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_INTERNAL,
  		    WXS_BASIC_CAST type, NULL,
  		    "Internal error: xmlSchemaTypeFixup, "
  		    "complex type '%s': the <simpleContent><restriction> "
  		    "is missing a <simpleType> child, but was not caught "
  		    "by xmlSchemaCheckSRCCT()", type->name);
  		goto exit_failure;
  	    }
  	} else if ((WXS_IS_COMPLEX(baseType)) && WXS_IS_EXTENSION(type)) {
  	    /*
  	    * SPEC (3) If <extension> + base is <complexType> with
  	    * <simpleType> content, "...then the {content type} of that
  	    * complex type definition"
  	    */
  	    if (baseType->contentTypeDef == NULL) {
  		/*
  		* TODO: Check if this ever happens. xmlSchemaCheckSRCCT
  		* should have caught this already.
  		*/
  		xmlSchemaPCustomErr(pctxt,
  		    XML_SCHEMAP_INTERNAL,
  		    WXS_BASIC_CAST type, NULL,
  		    "Internal error: xmlSchemaTypeFixup, "
  		    "complex type '%s': the <extension>ed base type is "
  		    "a complex type with no simple content type",
  		    type->name);
  		goto exit_failure;
  	    }
  	    type->contentTypeDef = baseType->contentTypeDef;
  	} else if ((WXS_IS_SIMPLE(baseType)) && WXS_IS_EXTENSION(type)) {
  	    /*
  	    * SPEC (4) <extension> + base is <simpleType>
  	    * "... then that simple type definition"
  	    */
  	    type->contentTypeDef = baseType;
  	} else {
  	    /*
  	    * TODO: Check if this ever happens.
  	    */
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_INTERNAL,
  		WXS_BASIC_CAST type, NULL,
  		"Internal error: xmlSchemaTypeFixup, "
  		"complex type '%s' with <simpleContent>: unhandled "
  		"derivation case", type->name);
  	    goto exit_failure;
  	}
      } else {
  	int dummySequence = 0;
  	xmlSchemaParticlePtr particle =
  	    (xmlSchemaParticlePtr) type->subtypes;
  	/*
  	* Corresponds to <complexType><complexContent>...
  	*
  	* NOTE that the effective mixed was already set during parsing of
  	* <complexType> and <complexContent>; its flag value is
  	* XML_SCHEMAS_TYPE_MIXED.
  	*
  	* Compute the "effective content":
  	* (2.1.1) + (2.1.2) + (2.1.3)
  	*/
  	if ((particle == NULL) ||
  	    ((particle->type == XML_SCHEMA_TYPE_PARTICLE) &&
  	    ((particle->children->type == XML_SCHEMA_TYPE_ALL) ||
  	    (particle->children->type == XML_SCHEMA_TYPE_SEQUENCE) ||
  	    ((particle->children->type == XML_SCHEMA_TYPE_CHOICE) &&
  	    (particle->minOccurs == 0))) &&
  	    ( ((xmlSchemaTreeItemPtr) particle->children)->children == NULL))) {
  	    if (type->flags & XML_SCHEMAS_TYPE_MIXED) {
  		/*
  		* SPEC (2.1.4) "If the `effective mixed` is true, then
  		* a particle whose properties are as follows:..."
  		*
  		* Empty sequence model group with
  		* minOccurs/maxOccurs = 1 (i.e. a "particle emptiable").
  		* NOTE that we sill assign it the <complexType> node to
  		* somehow anchor it in the doc.
  		*/
  		if ((particle == NULL) ||
  		    (particle->children->type != XML_SCHEMA_TYPE_SEQUENCE)) {
  		    /*
  		    * Create the particle.
  		    */
  		    particle = xmlSchemaAddParticle(pctxt,
  			type->node, 1, 1);
  		    if (particle == NULL)
  			goto exit_failure;
  		    /*
  		    * Create the model group.
  		    */ /* URGENT TODO: avoid adding to pending items. */
  		    particle->children = (xmlSchemaTreeItemPtr)
  			xmlSchemaAddModelGroup(pctxt, pctxt->schema,
  			XML_SCHEMA_TYPE_SEQUENCE, type->node);
  		    if (particle->children == NULL)
  			goto exit_failure;
  
  		    type->subtypes = (xmlSchemaTypePtr) particle;
  		}
  		dummySequence = 1;
  		type->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
  	    } else {
  		/*
  		* SPEC (2.1.5) "otherwise empty"
  		*/
  		type->contentType = XML_SCHEMA_CONTENT_EMPTY;
  	    }
  	} else {
  	    /*
  	    * SPEC (2.2) "otherwise the particle corresponding to the
  	    * <all>, <choice>, <group> or <sequence> among the
  	    * [children]."
  	    */
  	    type->contentType = XML_SCHEMA_CONTENT_ELEMENTS;
  	}
  	/*
  	* Compute the "content type".
  	*/
  	if (WXS_IS_RESTRICTION(type)) {
  	    /*
  	    * SPEC (3.1) "If <restriction>..."
  	    * (3.1.1) + (3.1.2) */
  	    if (type->contentType != XML_SCHEMA_CONTENT_EMPTY) {
  		if (type->flags & XML_SCHEMAS_TYPE_MIXED)
  		    type->contentType = XML_SCHEMA_CONTENT_MIXED;
  	    }
  	} else {
  	    /*
  	    * SPEC (3.2) "If <extension>..."
  	    */
  	    if (type->contentType == XML_SCHEMA_CONTENT_EMPTY) {
  		/*
  		* SPEC (3.2.1)
  		* "If the `effective content` is empty, then the
  		*  {content type} of the [...] base ..."
  		*/
  		type->contentType = baseType->contentType;
  		type->subtypes = baseType->subtypes;
  		/*
  		* Fixes bug #347316:
  		* This is the case when the base type has a simple
  		* type definition as content.
  		*/
  		type->contentTypeDef = baseType->contentTypeDef;
  		/*
  		* NOTE that the effective mixed is ignored here.
  		*/
  	    } else if (baseType->contentType == XML_SCHEMA_CONTENT_EMPTY) {
  		/*
  		* SPEC (3.2.2)
  		*/
  		if (type->flags & XML_SCHEMAS_TYPE_MIXED)
  		    type->contentType = XML_SCHEMA_CONTENT_MIXED;
  	    } else {
  		/*
  		* SPEC (3.2.3)
  		*/
  		if (type->flags & XML_SCHEMAS_TYPE_MIXED)
  		    type->contentType = XML_SCHEMA_CONTENT_MIXED;
  		    /*
  		    * "A model group whose {compositor} is sequence and whose
  		    * {particles} are..."
  		    */
  		if ((WXS_TYPE_PARTICLE(type) != NULL) &&
  		    (WXS_TYPE_PARTICLE_TERM(type) != NULL) &&
  		    ((WXS_TYPE_PARTICLE_TERM(type))->type ==
  			XML_SCHEMA_TYPE_ALL))
  		{
  		    /*
  		    * SPEC cos-all-limited (1)
  		    */
  		    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			/* TODO: error code */
  			XML_SCHEMAP_COS_ALL_LIMITED,
  			WXS_ITEM_NODE(type), NULL,
  			"The type has an 'all' model group in its "
  			"{content type} and thus cannot be derived from "
  			"a non-empty type, since this would produce a "
  			"'sequence' model group containing the 'all' "
  			"model group; 'all' model groups are not "
  			"allowed to appear inside other model groups",
  			NULL, NULL);
  
  		} else if ((WXS_TYPE_PARTICLE(baseType) != NULL) &&
  		    (WXS_TYPE_PARTICLE_TERM(baseType) != NULL) &&
  		    ((WXS_TYPE_PARTICLE_TERM(baseType))->type ==
  			XML_SCHEMA_TYPE_ALL))
  		{
  		    /*
  		    * SPEC cos-all-limited (1)
  		    */
  		    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			/* TODO: error code */
  			XML_SCHEMAP_COS_ALL_LIMITED,
  			WXS_ITEM_NODE(type), NULL,
  			"A type cannot be derived by extension from a type "
  			"which has an 'all' model group in its "
  			"{content type}, since this would produce a "
  			"'sequence' model group containing the 'all' "
  			"model group; 'all' model groups are not "
  			"allowed to appear inside other model groups",
  			NULL, NULL);
  
  		} else if (! dummySequence) {
  		    xmlSchemaTreeItemPtr effectiveContent =
  			(xmlSchemaTreeItemPtr) type->subtypes;
  		    /*
  		    * Create the particle.
  		    */
  		    particle = xmlSchemaAddParticle(pctxt,
  			type->node, 1, 1);
  		    if (particle == NULL)
  			goto exit_failure;
  		    /*
  		    * Create the "sequence" model group.
  		    */
  		    particle->children = (xmlSchemaTreeItemPtr)
  			xmlSchemaAddModelGroup(pctxt, pctxt->schema,
  			XML_SCHEMA_TYPE_SEQUENCE, type->node);
  		    if (particle->children == NULL)
  			goto exit_failure;
  		    WXS_TYPE_CONTENTTYPE(type) = (xmlSchemaTypePtr) particle;
  		    /*
  		    * SPEC "the particle of the {content type} of
  		    * the ... base ..."
  		    * Create a duplicate of the base type's particle
  		    * and assign its "term" to it.
  		    */
  		    particle->children->children =
  			(xmlSchemaTreeItemPtr) xmlSchemaAddParticle(pctxt,
  			type->node,
  			((xmlSchemaParticlePtr) baseType->subtypes)->minOccurs,
  			((xmlSchemaParticlePtr) baseType->subtypes)->maxOccurs);
  		    if (particle->children->children == NULL)
  			goto exit_failure;
  		    particle = (xmlSchemaParticlePtr)
  			particle->children->children;
  		    particle->children =
  			((xmlSchemaParticlePtr) baseType->subtypes)->children;
  		    /*
  		    * SPEC "followed by the `effective content`."
  		    */
  		    particle->next = effectiveContent;
  		    /*
  		    * This all will result in:
  		    * new-particle
  		    *   --> new-sequence(
  		    *         new-particle
  		    *           --> base-model,
  		    *         this-particle
  		    *	        --> this-model
  		    *	    )
  		    */
  		} else {
  		    /*
  		    * This is the case when there is already an empty
  		    * <sequence> with minOccurs==maxOccurs==1.
  		    * Just add the base types's content type.
  		    * NOTE that, although we miss to add an intermediate
  		    * <sequence>, this should produce no difference to
  		    * neither the regex compilation of the content model,
  		    * nor to the complex type constraints.
  		    */
  		    particle->children->children =
  			(xmlSchemaTreeItemPtr) baseType->subtypes;
  		}
  	    }
  	}
      }
      /*
      * Now fixup attribute uses:
      *   - expand attr. group references
      *     - intersect attribute wildcards
      *   - inherit attribute uses of the base type
      *   - inherit or union attr. wildcards if extending
      *   - apply attr. use prohibitions if restricting
      */
      res = xmlSchemaFixupTypeAttributeUses(pctxt, type);
      HFAILURE HERROR
      /*
      * Apply the complex type component constraints; this will not
      * check attributes, since this is done in
      * xmlSchemaFixupTypeAttributeUses().
      */
      res = xmlSchemaCheckCTComponent(pctxt, type);
      HFAILURE HERROR
  
  #ifdef DEBUG_TYPE
      xmlSchemaDebugFixedType(pctxt, type);
  #endif
      if (olderrs != pctxt->nberrors)
  	return(pctxt->err);
      else
  	return(0);
  
  exit_error:
      type->flags |= XML_SCHEMAS_TYPE_INTERNAL_INVALID;
  #ifdef DEBUG_TYPE
      xmlSchemaDebugFixedType(pctxt, type);
  #endif
      return(pctxt->err);
  
  exit_failure:
      type->flags |= XML_SCHEMAS_TYPE_INTERNAL_INVALID;
  #ifdef DEBUG_TYPE
      xmlSchemaDebugFixedType(pctxt, type);
  #endif
      return(-1);
  }
  
  
  /**
   * xmlSchemaTypeFixup:
   * @typeDecl:  the schema type definition
   * @ctxt:  the schema parser context
   *
   * Fixes the content model of the type.
   * URGENT TODO: We need an int result!
   */
  static int
  xmlSchemaTypeFixup(xmlSchemaTypePtr type,
                     xmlSchemaAbstractCtxtPtr actxt)
  {
      if (type == NULL)
          return(0);
      if (actxt->type != XML_SCHEMA_CTXT_PARSER) {
  	AERROR_INT("xmlSchemaTypeFixup",
  	    "this function needs a parser context");
  	return(-1);
      }
      if (! WXS_IS_TYPE_NOT_FIXED(type))
  	return(0);
      if (type->type == XML_SCHEMA_TYPE_COMPLEX)
  	return(xmlSchemaFixupComplexType(PCTXT_CAST actxt, type));
      else if (type->type == XML_SCHEMA_TYPE_SIMPLE)
  	return(xmlSchemaFixupSimpleTypeStageTwo(PCTXT_CAST actxt, type));
      return(0);
  }
  
  /**
   * xmlSchemaCheckFacet:
   * @facet:  the facet
   * @typeDecl:  the schema type definition
   * @pctxt:  the schema parser context or NULL
   * @name: the optional name of the type
   *
   * Checks and computes the values of facets.
   *
   * Returns 0 if valid, a positive error code if not valid and
   *         -1 in case of an internal or API error.
   */
  int
  xmlSchemaCheckFacet(xmlSchemaFacetPtr facet,
                      xmlSchemaTypePtr typeDecl,
                      xmlSchemaParserCtxtPtr pctxt,
  		    const xmlChar * name ATTRIBUTE_UNUSED)
  {
      int ret = 0, ctxtGiven;
  
      if ((facet == NULL) || (typeDecl == NULL))
          return(-1);
      /*
      * TODO: will the parser context be given if used from
      * the relaxNG module?
      */
      if (pctxt == NULL)
  	ctxtGiven = 0;
      else
  	ctxtGiven = 1;
  
      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_ENUMERATION: {
                  /*
                   * Okay we need to validate the value
                   * at that point.
                   */
  		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 this implementation of XML Schemata the
  		* type holding a facet, won't 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) {
  			PERROR_INT("xmlSchemaCheckFacet",
  			    "a type user derived type has no base type");
  			return (-1);
  		    }
  		} else
  		    base = typeDecl;
  
  		if (! ctxtGiven) {
  		    /*
  		    * A context is needed if called from RelaxNG.
  		    */
  		    pctxt = xmlSchemaNewParserCtxt("*");
  		    if (pctxt == NULL)
  			return (-1);
  		}
  		/*
  		* NOTE: This call does not check the content nodes,
  		* since they are not available:
  		* facet->node is just the node holding the facet
  		* definition, *not* the attribute holding the *value*
  		* of the facet.
  		*/
  		ret = xmlSchemaVCheckCVCSimpleType(
  		    ACTXT_CAST pctxt, facet->node, base,
  		    facet->value, &(facet->val), 1, 1, 0);
                  if (ret != 0) {
  		    if (ret < 0) {
  			/* No error message for RelaxNG. */
  			if (ctxtGiven) {
  			    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  				XML_SCHEMAP_INTERNAL, facet->node, NULL,
  				"Internal error: xmlSchemaCheckFacet, "
  				"failed to validate the value '%s' of the "
  				"facet '%s' against the base type",
  				facet->value, xmlSchemaFacetTypeToString(facet->type));
  			}
  			goto internal_error;
  		    }
  		    ret = XML_SCHEMAP_INVALID_FACET_VALUE;
  		    /* No error message for RelaxNG. */
  		    if (ctxtGiven) {
  			xmlChar *str = NULL;
  
  			xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			    ret, facet->node, WXS_BASIC_CAST facet,
  			    "The value '%s' of the facet does not validate "
  			    "against the base type '%s'",
  			    facet->value,
  			    xmlSchemaFormatQName(&str,
  				base->targetNamespace, base->name));
  			FREE_AND_NULL(str);
  		    }
  		    goto exit;
                  } else if (facet->val == NULL) {
  		    if (ctxtGiven) {
  			PERROR_INT("xmlSchemaCheckFacet",
  			    "value was not computed");
  		    }
  		    TODO
  		}
                  break;
              }
          case XML_SCHEMA_FACET_PATTERN:
              facet->regexp = xmlRegexpCompile(facet->value);
              if (facet->regexp == NULL) {
  		ret = XML_SCHEMAP_REGEXP_INVALID;
  		/* No error message for RelaxNG. */
  		if (ctxtGiven) {
  		    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			ret, facet->node, WXS_BASIC_CAST typeDecl,
  			"The value '%s' of the facet 'pattern' is not a "
  			"valid regular expression",
  			facet->value, NULL);
  		}
              }
              break;
          case XML_SCHEMA_FACET_TOTALDIGITS:
          case XML_SCHEMA_FACET_FRACTIONDIGITS:
          case XML_SCHEMA_FACET_LENGTH:
          case XML_SCHEMA_FACET_MAXLENGTH:
          case XML_SCHEMA_FACET_MINLENGTH:
  
  	    if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) {
  		ret = xmlSchemaValidatePredefinedType(
  		    xmlSchemaGetBuiltInType(XML_SCHEMAS_PINTEGER),
  		    facet->value, &(facet->val));
  	    } else {
  		ret = xmlSchemaValidatePredefinedType(
  		    xmlSchemaGetBuiltInType(XML_SCHEMAS_NNINTEGER),
  		    facet->value, &(facet->val));
  	    }
  	    if (ret != 0) {
  		if (ret < 0) {
  		    /* No error message for RelaxNG. */
  		    if (ctxtGiven) {
  			PERROR_INT("xmlSchemaCheckFacet",
  			    "validating facet value");
  		    }
  		    goto internal_error;
  		}
  		ret = XML_SCHEMAP_INVALID_FACET_VALUE;
  		/* No error message for RelaxNG. */
  		if (ctxtGiven) {
  		    /* error code */
  		    xmlSchemaCustomErr4(ACTXT_CAST pctxt,
  			ret, facet->node, WXS_BASIC_CAST typeDecl,
  			"The value '%s' of the facet '%s' is not a valid '%s'",
  			facet->value,
  			xmlSchemaFacetTypeToString(facet->type),
  			(facet->type != XML_SCHEMA_FACET_TOTALDIGITS) ?
  			    BAD_CAST "nonNegativeInteger" :
  			    BAD_CAST "positiveInteger",
  			NULL);
  		}
  	    }
  	    break;
  
          case XML_SCHEMA_FACET_WHITESPACE:{
                  if (xmlStrEqual(facet->value, BAD_CAST "preserve")) {
                      facet->whitespace = XML_SCHEMAS_FACET_PRESERVE;
                  } else if (xmlStrEqual(facet->value, BAD_CAST "replace")) {
                      facet->whitespace = XML_SCHEMAS_FACET_REPLACE;
                  } else if (xmlStrEqual(facet->value, BAD_CAST "collapse")) {
                      facet->whitespace = XML_SCHEMAS_FACET_COLLAPSE;
                  } else {
  		    ret = XML_SCHEMAP_INVALID_FACET_VALUE;
                      /* No error message for RelaxNG. */
  		    if (ctxtGiven) {
  			/* error was previously: XML_SCHEMAP_INVALID_WHITE_SPACE */
  			xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			    ret, facet->node, WXS_BASIC_CAST typeDecl,
  			    "The value '%s' of the facet 'whitespace' is not "
  			    "valid", facet->value, NULL);
                      }
                  }
              }
          default:
              break;
      }
  exit:
      if ((! ctxtGiven) && (pctxt != NULL))
  	xmlSchemaFreeParserCtxt(pctxt);
      return (ret);
  internal_error:
      if ((! ctxtGiven) && (pctxt != NULL))
  	xmlSchemaFreeParserCtxt(pctxt);
      return (-1);
  }
  
  /**
   * xmlSchemaCheckFacetValues:
   * @typeDecl:  the schema type definition
   * @ctxt:  the schema parser context
   *
   * Checks the default values types, especially for facets
   */
  static int
  xmlSchemaCheckFacetValues(xmlSchemaTypePtr typeDecl,
  			  xmlSchemaParserCtxtPtr pctxt)
  {
      int res, olderrs = pctxt->nberrors;
      const xmlChar *name = typeDecl->name;
      /*
      * NOTE: It is intended to use the facets list, instead
      * of facetSet.
      */
      if (typeDecl->facets != NULL) {
  	xmlSchemaFacetPtr facet = typeDecl->facets;
  
  	/*
  	* Temporarily assign the "schema" to the validation context
  	* of the parser context. This is needed for NOTATION validation.
  	*/
  	if (pctxt->vctxt == NULL) {
  	    if (xmlSchemaCreateVCtxtOnPCtxt(pctxt) == -1)
  		return(-1);
  	}
  	pctxt->vctxt->schema = pctxt->schema;
  	while (facet != NULL) {
  	    res = xmlSchemaCheckFacet(facet, typeDecl, pctxt, name);
  	    HFAILURE
  	    facet = facet->next;
  	}
  	pctxt->vctxt->schema = NULL;
      }
      if (olderrs != pctxt->nberrors)
  	return(pctxt->err);
      return(0);
  exit_failure:
      return(-1);
  }
  
  /**
   * xmlSchemaGetCircModelGrDefRef:
   * @ctxtMGroup: the searched model group
   * @selfMGroup: the second searched model group
   * @particle: the first particle
   *
   * This one is intended to be used by
   * xmlSchemaCheckGroupDefCircular only.
   *
   * Returns the particle with the circular model group definition reference,
   * otherwise NULL.
   */
  static xmlSchemaTreeItemPtr
  xmlSchemaGetCircModelGrDefRef(xmlSchemaModelGroupDefPtr groupDef,
  			      xmlSchemaTreeItemPtr particle)
  {
      xmlSchemaTreeItemPtr circ = NULL;
      xmlSchemaTreeItemPtr term;
      xmlSchemaModelGroupDefPtr gdef;
  
      for (; particle != NULL; particle = particle->next) {
  	term = particle->children;
  	if (term == NULL)
  	    continue;
  	switch (term->type) {
  	    case XML_SCHEMA_TYPE_GROUP:
  		gdef = (xmlSchemaModelGroupDefPtr) term;
  		if (gdef == groupDef)
  		    return (particle);
  		/*
  		* Mark this model group definition to avoid infinite
  		* recursion on circular references not yet examined.
  		*/
  		if (gdef->flags & XML_SCHEMA_MODEL_GROUP_DEF_MARKED)
  		    continue;
  		if (gdef->children != NULL) {
  		    gdef->flags |= XML_SCHEMA_MODEL_GROUP_DEF_MARKED;
  		    circ = xmlSchemaGetCircModelGrDefRef(groupDef,
  			gdef->children->children);
  		    gdef->flags ^= XML_SCHEMA_MODEL_GROUP_DEF_MARKED;
  		    if (circ != NULL)
  			return (circ);
  		}
  		break;
  	    case XML_SCHEMA_TYPE_SEQUENCE:
  	    case XML_SCHEMA_TYPE_CHOICE:
  	    case XML_SCHEMA_TYPE_ALL:
  		circ = xmlSchemaGetCircModelGrDefRef(groupDef, term->children);
  		if (circ != NULL)
  		    return (circ);
  		break;
  	    default:
  		break;
  	}
      }
      return (NULL);
  }
  
  /**
   * xmlSchemaCheckGroupDefCircular:
   * @item:  the model group definition
   * @ctxt:  the parser context
   * @name:  the name
   *
   * Checks for circular references to model group definitions.
   */
  static void
  xmlSchemaCheckGroupDefCircular(xmlSchemaModelGroupDefPtr item,
  			       xmlSchemaParserCtxtPtr ctxt)
  {
      /*
      * Schema Component Constraint: Model Group Correct
      * 2 Circular groups are disallowed. That is, within the {particles}
      * of a group there must not be at any depth a particle whose {term}
      * is the group itself.
      */
      if ((item == NULL) ||
  	(item->type != XML_SCHEMA_TYPE_GROUP) ||
  	(item->children == NULL))
  	return;
      {
  	xmlSchemaTreeItemPtr circ;
  
  	circ = xmlSchemaGetCircModelGrDefRef(item, item->children->children);
  	if (circ != NULL) {
  	    xmlChar *str = NULL;
  	    /*
  	    * TODO: The error report is not adequate: this constraint
  	    * is defined for model groups but not definitions, but since
  	    * there cannot be any circular model groups without a model group
  	    * definition (if not using a construction API), we check those
  	    * definitions only.
  	    */
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_MG_PROPS_CORRECT_2,
  		NULL, WXS_ITEM_NODE(circ),
  		"Circular reference to the model group definition '%s' "
  		"defined", xmlSchemaFormatQName(&str,
  		    item->targetNamespace, item->name));
  	    FREE_AND_NULL(str)
  	    /*
  	    * NOTE: We will cut the reference to avoid further
  	    * confusion of the processor. This is a fatal error.
  	    */
  	    circ->children = NULL;
  	}
      }
  }
  
  /**
   * xmlSchemaModelGroupToModelGroupDefFixup:
   * @ctxt:  the parser context
   * @mg:  the model group
   *
   * Assigns the model group of model group definitions to the "term"
   * of the referencing particle.
   * In xmlSchemaResolveModelGroupParticleReferences the model group
   * definitions were assigned to the "term", since needed for the
   * circularity check.
   *
   * Schema Component Constraint:
   *     All Group Limited (cos-all-limited) (1.2)
   */
  static void
  xmlSchemaModelGroupToModelGroupDefFixup(
      xmlSchemaParserCtxtPtr ctxt ATTRIBUTE_UNUSED,
      xmlSchemaModelGroupPtr mg)
  {
      xmlSchemaParticlePtr particle = WXS_MODELGROUP_PARTICLE(mg);
  
      while (particle != NULL) {
  	if ((WXS_PARTICLE_TERM(particle) == NULL) ||
  	    ((WXS_PARTICLE_TERM(particle))->type !=
  		XML_SCHEMA_TYPE_GROUP))
  	{
  	    particle = WXS_PTC_CAST particle->next;
  	    continue;
  	}
  	if (WXS_MODELGROUPDEF_MODEL(WXS_PARTICLE_TERM(particle)) == NULL) {
  	    /*
  	    * TODO: Remove the particle.
  	    */
  	    WXS_PARTICLE_TERM(particle) = NULL;
  	    particle = WXS_PTC_CAST particle->next;
  	    continue;
  	}
  	/*
  	* Assign the model group to the {term} of the particle.
  	*/
  	WXS_PARTICLE_TERM(particle) =
  	    WXS_TREE_CAST WXS_MODELGROUPDEF_MODEL(WXS_PARTICLE_TERM(particle));
  
  	particle = WXS_PTC_CAST particle->next;
      }
  }
  
  /**
   * xmlSchemaCheckAttrGroupCircularRecur:
   * @ctxtGr: the searched attribute group
   * @attr: the current attribute list to be processed
   *
   * This one is intended to be used by
   * xmlSchemaCheckAttrGroupCircular only.
   *
   * Returns the circular attribute group reference, otherwise NULL.
   */
  static xmlSchemaQNameRefPtr
  xmlSchemaCheckAttrGroupCircularRecur(xmlSchemaAttributeGroupPtr ctxtGr,
  				     xmlSchemaItemListPtr list)
  {
      xmlSchemaAttributeGroupPtr gr;
      xmlSchemaQNameRefPtr ref, circ;
      int i;
      /*
      * We will search for an attribute group reference which
      * references the context attribute group.
      */
      for (i = 0; i < list->nbItems; i++) {
  	ref = list->items[i];
  	if ((ref->type == XML_SCHEMA_EXTRA_QNAMEREF) &&
  	    (ref->itemType == XML_SCHEMA_TYPE_ATTRIBUTEGROUP) &&
  	    (ref->item != NULL))
  	{
  	    gr = WXS_ATTR_GROUP_CAST ref->item;
  	    if (gr == ctxtGr)
  		return(ref);
  	    if (gr->flags & XML_SCHEMAS_ATTRGROUP_MARKED)
  		continue;
  	    /*
  	    * Mark as visited to avoid infinite recursion on
  	    * circular references not yet examined.
  	    */
  	    if ((gr->attrUses) &&
  		(gr->flags & XML_SCHEMAS_ATTRGROUP_HAS_REFS))
  	    {
  		gr->flags |= XML_SCHEMAS_ATTRGROUP_MARKED;
  		circ = xmlSchemaCheckAttrGroupCircularRecur(ctxtGr,
  		    (xmlSchemaItemListPtr) gr->attrUses);
  		gr->flags ^= XML_SCHEMAS_ATTRGROUP_MARKED;
  		if (circ != NULL)
  		    return (circ);
  	    }
  
  	}
      }
      return (NULL);
  }
  
  /**
   * xmlSchemaCheckAttrGroupCircular:
   * attrGr:  the attribute group definition
   * @ctxt:  the parser context
   * @name:  the name
   *
   * Checks for circular references of attribute groups.
   */
  static int
  xmlSchemaCheckAttrGroupCircular(xmlSchemaAttributeGroupPtr attrGr,
  				xmlSchemaParserCtxtPtr ctxt)
  {
      /*
      * Schema Representation Constraint:
      * Attribute Group Definition Representation OK
      * 3 Circular group reference is disallowed outside <redefine>.
      * That is, unless this element information item's parent is
      * <redefine>, then among the [children], if any, there must
      * not be an <attributeGroup> with ref [attribute] which resolves
      * to the component corresponding to this <attributeGroup>. Indirect
      * circularity is also ruled out. That is, when QName resolution
      * (Schema Document) ($3.15.3) is applied to a `QName` arising from
      * any <attributeGroup>s with a ref [attribute] among the [children],
      * it must not be the case that a `QName` is encountered at any depth
      * which resolves to the component corresponding to this <attributeGroup>.
      */
      if (attrGr->attrUses == NULL)
  	return(0);
      else if ((attrGr->flags & XML_SCHEMAS_ATTRGROUP_HAS_REFS) == 0)
  	return(0);
      else {
  	xmlSchemaQNameRefPtr circ;
  
  	circ = xmlSchemaCheckAttrGroupCircularRecur(attrGr,
  	    (xmlSchemaItemListPtr) attrGr->attrUses);
  	if (circ != NULL) {
  	    xmlChar *str = NULL;
  	    /*
  	    * TODO: Report the referenced attr group as QName.
  	    */
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_SRC_ATTRIBUTE_GROUP_3,
  		NULL, WXS_ITEM_NODE(WXS_BASIC_CAST circ),
  		"Circular reference to the attribute group '%s' "
  		"defined", xmlSchemaGetComponentQName(&str, attrGr));
  	    FREE_AND_NULL(str);
  	    /*
  	    * NOTE: We will cut the reference to avoid further
  	    * confusion of the processor.
  	    * BADSPEC TODO: The spec should define how to process in this case.
  	    */
  	    circ->item = NULL;
  	    return(ctxt->err);
  	}
      }
      return(0);
  }
  
  static int
  xmlSchemaAttributeGroupExpandRefs(xmlSchemaParserCtxtPtr pctxt,
  				  xmlSchemaAttributeGroupPtr attrGr);
  
  /**
   * xmlSchemaExpandAttributeGroupRefs:
   * @pctxt: the parser context
   * @node: the node of the component holding the attribute uses
   * @completeWild: the intersected wildcard to be returned
   * @list: the attribute uses
   *
   * Substitutes contained attribute group references
   * for their attribute uses. Wildcards are intersected.
   * Attribute use prohibitions are removed from the list
   * and returned via the @prohibs list.
   * Pointlessness of attr. prohibs, if a matching attr. decl
   * is existent a well, are checked.
   */
  static int
  xmlSchemaExpandAttributeGroupRefs(xmlSchemaParserCtxtPtr pctxt,
  				  xmlSchemaBasicItemPtr item,
  				  xmlSchemaWildcardPtr *completeWild,
  				  xmlSchemaItemListPtr list,
  				  xmlSchemaItemListPtr prohibs)
  {
      xmlSchemaAttributeGroupPtr gr;
      xmlSchemaAttributeUsePtr use;
      xmlSchemaItemListPtr sublist;
      int i, j;
      int created = (*completeWild == NULL) ? 0 : 1;
  
      if (prohibs)
  	prohibs->nbItems = 0;
  
      for (i = 0; i < list->nbItems; i++) {
  	use = list->items[i];
  
  	if (use->type == XML_SCHEMA_EXTRA_ATTR_USE_PROHIB) {
  	    if (prohibs == NULL) {
  		PERROR_INT("xmlSchemaExpandAttributeGroupRefs",
  		    "unexpected attr prohibition found");
  		return(-1);
  	    }
  	    /*
  	    * Remove from attribute uses.
  	    */
  	    if (xmlSchemaItemListRemove(list, i) == -1)
  		return(-1);
  	    i--;
  	    /*
  	    * Note that duplicate prohibitions were already
  	    * handled at parsing time.
  	    */
  	    /*
  	    * Add to list of prohibitions.
  	    */
  	    xmlSchemaItemListAddSize(prohibs, 2, use);
  	    continue;
  	}
  	if ((use->type == XML_SCHEMA_EXTRA_QNAMEREF) &&
  	    ((WXS_QNAME_CAST use)->itemType == XML_SCHEMA_TYPE_ATTRIBUTEGROUP))
  	{
  	    if ((WXS_QNAME_CAST use)->item == NULL)
  		return(-1);
  	    gr = WXS_ATTR_GROUP_CAST (WXS_QNAME_CAST use)->item;
  	    /*
  	    * Expand the referenced attr. group.
  	    * TODO: remove this, this is done in a previous step, so
  	    * already done here.
  	    */
  	    if ((gr->flags & XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED) == 0) {
  		if (xmlSchemaAttributeGroupExpandRefs(pctxt, gr) == -1)
  		    return(-1);
  	    }
  	    /*
  	    * Build the 'complete' wildcard; i.e. intersect multiple
  	    * wildcards.
  	    */
  	    if (gr->attributeWildcard != NULL) {
  		if (*completeWild == NULL) {
  		    *completeWild = gr->attributeWildcard;
  		} else {
  		    if (! created) {
  			xmlSchemaWildcardPtr tmpWild;
  
  			 /*
  			* Copy the first encountered wildcard as context,
  			* except for the annotation.
  			*
  			* Although the complete wildcard might not correspond
  			* to any node in the schema, we will anchor it on
  			* the node of the owner component.
  			*/
  			tmpWild =  xmlSchemaAddWildcard(pctxt, pctxt->schema,
  			    XML_SCHEMA_TYPE_ANY_ATTRIBUTE,
  			    WXS_ITEM_NODE(item));
  			if (tmpWild == NULL)
  			    return(-1);
  			if (xmlSchemaCloneWildcardNsConstraints(pctxt,
  			    tmpWild, *completeWild) == -1)
  			    return (-1);
  			tmpWild->processContents = (*completeWild)->processContents;
  			*completeWild = tmpWild;
  			created = 1;
  		    }
  
  		    if (xmlSchemaIntersectWildcards(pctxt, *completeWild,
  			gr->attributeWildcard) == -1)
  			return(-1);
  		}
  	    }
  	    /*
  	    * Just remove the reference if the referenced group does not
  	    * contain any attribute uses.
  	    */
  	    sublist = ((xmlSchemaItemListPtr) gr->attrUses);
  	    if ((sublist == NULL) || sublist->nbItems == 0) {
  		if (xmlSchemaItemListRemove(list, i) == -1)
  		    return(-1);
  		i--;
  		continue;
  	    }
  	    /*
  	    * Add the attribute uses.
  	    */
  	    list->items[i] = sublist->items[0];
  	    if (sublist->nbItems != 1) {
  		for (j = 1; j < sublist->nbItems; j++) {
  		    i++;
  		    if (xmlSchemaItemListInsert(list,
  			    sublist->items[j], i) == -1)
  			return(-1);
  		}
  	    }
  	}
  
      }
      /*
      * Handle pointless prohibitions of declared attributes.
      */
      if (prohibs && (prohibs->nbItems != 0) && (list->nbItems != 0)) {
  	xmlSchemaAttributeUseProhibPtr prohib;
  
  	for (i = prohibs->nbItems -1; i >= 0; i--) {
  	    prohib = prohibs->items[i];
  	    for (j = 0; j < list->nbItems; j++) {
  		use = list->items[j];
  
  		if ((prohib->name == WXS_ATTRUSE_DECL_NAME(use)) &&
  		    (prohib->targetNamespace == WXS_ATTRUSE_DECL_TNS(use)))
  		{
  		    xmlChar *str = NULL;
  
  		    xmlSchemaCustomWarning(ACTXT_CAST pctxt,
  			XML_SCHEMAP_WARN_ATTR_POINTLESS_PROH,
  			prohib->node, NULL,
  			"Skipping pointless attribute use prohibition "
  			"'%s', since a corresponding attribute use "
  			"exists already in the type definition",
  			xmlSchemaFormatQName(&str,
  			    prohib->targetNamespace, prohib->name),
  			NULL, NULL);
  		    FREE_AND_NULL(str);
  		    /*
  		    * Remove the prohibition.
  		    */
  		    if (xmlSchemaItemListRemove(prohibs, i) == -1)
  			return(-1);
  		    break;
  		}
  	    }
  	}
      }
      return(0);
  }
  
  /**
   * xmlSchemaAttributeGroupExpandRefs:
   * @pctxt:  the parser context
   * @attrGr:  the attribute group definition
   *
   * Computation of:
   * {attribute uses} property
   * {attribute wildcard} property
   *
   * Substitutes contained attribute group references
   * for their attribute uses. Wildcards are intersected.
   */
  static int
  xmlSchemaAttributeGroupExpandRefs(xmlSchemaParserCtxtPtr pctxt,
  				  xmlSchemaAttributeGroupPtr attrGr)
  {
      if ((attrGr->attrUses == NULL) ||
  	(attrGr->flags & XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED))
  	return(0);
  
      attrGr->flags |= XML_SCHEMAS_ATTRGROUP_WILDCARD_BUILDED;
      if (xmlSchemaExpandAttributeGroupRefs(pctxt, WXS_BASIC_CAST attrGr,
  	&(attrGr->attributeWildcard), attrGr->attrUses, NULL) == -1)
  	return(-1);
      return(0);
  }
  
  /**
   * xmlSchemaAttributeGroupExpandRefs:
   * @pctxt:  the parser context
   * @attrGr:  the attribute group definition
   *
   * Substitutes contained attribute group references
   * for their attribute uses. Wildcards are intersected.
   *
   * Schema Component Constraint:
   *    Attribute Group Definition Properties Correct (ag-props-correct)
   */
  static int
  xmlSchemaCheckAGPropsCorrect(xmlSchemaParserCtxtPtr pctxt,
  				  xmlSchemaAttributeGroupPtr attrGr)
  {
      /*
      * SPEC ag-props-correct
      * (1) "The values of the properties of an attribute group definition
      * must be as described in the property tableau in The Attribute
      * Group Definition Schema Component ($3.6.1), modulo the impact of
      * Missing Sub-components ($5.3);"
      */
  
      if ((attrGr->attrUses != NULL) &&
  	(WXS_LIST_CAST attrGr->attrUses)->nbItems > 1)
      {
  	xmlSchemaItemListPtr uses = WXS_LIST_CAST attrGr->attrUses;
  	xmlSchemaAttributeUsePtr use, tmp;
  	int i, j, hasId = 0;
  
  	for (i = uses->nbItems -1; i >= 0; i--) {
  	    use = uses->items[i];
  	    /*
  	    * SPEC ag-props-correct
  	    * (2) "Two distinct members of the {attribute uses} must not have
  	    * {attribute declaration}s both of whose {name}s match and whose
  	    * {target namespace}s are identical."
  	    */
  	    if (i > 0) {
  		for (j = i -1; j >= 0; j--) {
  		    tmp = uses->items[j];
  		    if ((WXS_ATTRUSE_DECL_NAME(use) ==
  			WXS_ATTRUSE_DECL_NAME(tmp)) &&
  			(WXS_ATTRUSE_DECL_TNS(use) ==
  			WXS_ATTRUSE_DECL_TNS(tmp)))
  		    {
  			xmlChar *str = NULL;
  
  			xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			    XML_SCHEMAP_AG_PROPS_CORRECT,
  			    attrGr->node, WXS_BASIC_CAST attrGr,
  			    "Duplicate %s",
  			    xmlSchemaGetComponentDesignation(&str, use),
  			    NULL);
  			FREE_AND_NULL(str);
  			/*
  			* Remove the duplicate.
  			*/
  			if (xmlSchemaItemListRemove(uses, i) == -1)
  			    return(-1);
  			goto next_use;
  		    }
  		}
  	    }
  	    /*
  	    * SPEC ag-props-correct
  	    * (3) "Two distinct members of the {attribute uses} must not have
  	    * {attribute declaration}s both of whose {type definition}s are or
  	    * are derived from ID."
  	    * TODO: Does 'derived' include member-types of unions?
  	    */
  	    if (WXS_ATTRUSE_TYPEDEF(use) != NULL) {
  		if (xmlSchemaIsDerivedFromBuiltInType(
  		    WXS_ATTRUSE_TYPEDEF(use), XML_SCHEMAS_ID))
  		{
  		    if (hasId) {
  			xmlChar *str = NULL;
  
  			xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			    XML_SCHEMAP_AG_PROPS_CORRECT,
  			    attrGr->node, WXS_BASIC_CAST attrGr,
  			    "There must not exist more than one attribute "
  			    "declaration of type 'xs:ID' "
  			    "(or derived from 'xs:ID'). The %s violates this "
  			    "constraint",
  			    xmlSchemaGetComponentDesignation(&str, use),
  			    NULL);
  			FREE_AND_NULL(str);
  			if (xmlSchemaItemListRemove(uses, i) == -1)
  			    return(-1);
  		    }
  		    hasId = 1;
  		}
  	    }
  next_use: {}
  	}
      }
      return(0);
  }
  
  /**
   * xmlSchemaResolveAttrGroupReferences:
   * @attrgrpDecl:  the schema attribute definition
   * @ctxt:  the schema parser context
   * @name:  the attribute name
   *
   * Resolves references to attribute group definitions.
   */
  static int
  xmlSchemaResolveAttrGroupReferences(xmlSchemaQNameRefPtr ref,
  				    xmlSchemaParserCtxtPtr ctxt)
  {
      xmlSchemaAttributeGroupPtr group;
  
      if (ref->item != NULL)
          return(0);
      group = xmlSchemaGetAttributeGroup(ctxt->schema,
  	ref->name,
  	ref->targetNamespace);
      if (group == NULL) {
  	xmlSchemaPResCompAttrErr(ctxt,
  	    XML_SCHEMAP_SRC_RESOLVE,
  	    NULL, ref->node,
  	    "ref", ref->name, ref->targetNamespace,
  	    ref->itemType, NULL);
  	return(ctxt->err);
      }
      ref->item = WXS_BASIC_CAST group;
      return(0);
  }
  
  /**
   * xmlSchemaCheckAttrPropsCorrect:
   * @item:  an schema attribute declaration/use
   * @ctxt:  a schema parser context
   * @name:  the name of the attribute
   *
   *
   * Schema Component Constraint:
   *    Attribute Declaration Properties Correct (a-props-correct)
   *
   * Validates the value constraints of an attribute declaration/use.
   * NOTE that this needs the simple type definitions to be already
   *   built and checked.
   */
  static int
  xmlSchemaCheckAttrPropsCorrect(xmlSchemaParserCtxtPtr pctxt,
  			       xmlSchemaAttributePtr attr)
  {
  
      /*
      * SPEC a-props-correct (1)
      * "The values of the properties of an attribute declaration must
      * be as described in the property tableau in The Attribute
      * Declaration Schema Component ($3.2.1), modulo the impact of
      * Missing Sub-components ($5.3)."
      */
  
      if (WXS_ATTR_TYPEDEF(attr) == NULL)
  	return(0);
  
      if (attr->defValue != NULL) {
  	int ret;
  
  	/*
  	* SPEC a-props-correct (3)
  	* "If the {type definition} is or is derived from ID then there
  	* must not be a {value constraint}."
  	*/
  	if (xmlSchemaIsDerivedFromBuiltInType(
  	    WXS_ATTR_TYPEDEF(attr), XML_SCHEMAS_ID))
  	{
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		XML_SCHEMAP_A_PROPS_CORRECT_3,
  		NULL, WXS_BASIC_CAST attr,
  		"Value constraints are not allowed if the type definition "
  		"is or is derived from xs:ID",
  		NULL, NULL);
  	    return(pctxt->err);
  	}
  	/*
  	* SPEC a-props-correct (2)
  	* "if there is a {value constraint}, the canonical lexical
  	* representation of its value must be `valid` with respect
  	* to the {type definition} as defined in String Valid ($3.14.4)."
  	* TODO: Don't care about the *canonical* stuff here, this requirement
  	* will be removed in WXS 1.1 anyway.
  	*/
  	ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST pctxt,
  	    attr->node, WXS_ATTR_TYPEDEF(attr),
  	    attr->defValue, &(attr->defVal),
  	    1, 1, 0);
  	if (ret != 0) {
  	    if (ret < 0) {
  		PERROR_INT("xmlSchemaCheckAttrPropsCorrect",
  		    "calling xmlSchemaVCheckCVCSimpleType()");
  		return(-1);
  	    }
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		XML_SCHEMAP_A_PROPS_CORRECT_2,
  		NULL, WXS_BASIC_CAST attr,
  		"The value of the value constraint is not valid",
  		NULL, NULL);
  	    return(pctxt->err);
  	}
      }
  
      return(0);
  }
  
  static xmlSchemaElementPtr
  xmlSchemaCheckSubstGroupCircular(xmlSchemaElementPtr elemDecl,
  				 xmlSchemaElementPtr ancestor)
  {
      xmlSchemaElementPtr ret;
  
      if (WXS_SUBST_HEAD(ancestor) == NULL)
  	return (NULL);
      if (WXS_SUBST_HEAD(ancestor) == elemDecl)
  	return (ancestor);
  
      if (WXS_SUBST_HEAD(ancestor)->flags & XML_SCHEMAS_ELEM_CIRCULAR)
  	return (NULL);
      WXS_SUBST_HEAD(ancestor)->flags |= XML_SCHEMAS_ELEM_CIRCULAR;
      ret = xmlSchemaCheckSubstGroupCircular(elemDecl,
  	WXS_SUBST_HEAD(ancestor));
      WXS_SUBST_HEAD(ancestor)->flags ^= XML_SCHEMAS_ELEM_CIRCULAR;
  
      return (ret);
  }
  
  /**
   * xmlSchemaCheckElemPropsCorrect:
   * @ctxt:  a schema parser context
   * @decl: the element declaration
   * @name:  the name of the attribute
   *
   * Schema Component Constraint:
   * Element Declaration Properties Correct (e-props-correct)
   *
   * STATUS:
   *   missing: (6)
   */
  static int
  xmlSchemaCheckElemPropsCorrect(xmlSchemaParserCtxtPtr pctxt,
  			       xmlSchemaElementPtr elemDecl)
  {
      int ret = 0;
      xmlSchemaTypePtr typeDef = WXS_ELEM_TYPEDEF(elemDecl);
      /*
      * SPEC (1) "The values of the properties of an element declaration
      * must be as described in the property tableau in The Element
      * Declaration Schema Component ($3.3.1), modulo the impact of Missing
      * Sub-components ($5.3)."
      */
      if (WXS_SUBST_HEAD(elemDecl) != NULL) {
  	xmlSchemaElementPtr head = WXS_SUBST_HEAD(elemDecl), circ;
  
  	xmlSchemaCheckElementDeclComponent(head, pctxt);
  	/*
  	* SPEC (3) "If there is a non-`absent` {substitution group
  	* affiliation}, then {scope} must be global."
  	*/
  	if ((elemDecl->flags & XML_SCHEMAS_ELEM_GLOBAL) == 0) {
  	    xmlSchemaPCustomErr(pctxt,
  		XML_SCHEMAP_E_PROPS_CORRECT_3,
  		WXS_BASIC_CAST elemDecl, NULL,
  		"Only global element declarations can have a "
  		"substitution group affiliation", NULL);
  	    ret = XML_SCHEMAP_E_PROPS_CORRECT_3;
  	}
  	/*
  	* TODO: SPEC (6) "Circular substitution groups are disallowed.
  	* That is, it must not be possible to return to an element declaration
  	* by repeatedly following the {substitution group affiliation}
  	* property."
  	*/
  	if (head == elemDecl)
  	    circ = head;
  	else if (WXS_SUBST_HEAD(head) != NULL)
  	    circ = xmlSchemaCheckSubstGroupCircular(head, head);
  	else
  	    circ = NULL;
  	if (circ != NULL) {
  	    xmlChar *strA = NULL, *strB = NULL;
  
  	    xmlSchemaPCustomErrExt(pctxt,
  		XML_SCHEMAP_E_PROPS_CORRECT_6,
  		WXS_BASIC_CAST circ, NULL,
  		"The element declaration '%s' defines a circular "
  		"substitution group to element declaration '%s'",
  		xmlSchemaGetComponentQName(&strA, circ),
  		xmlSchemaGetComponentQName(&strB, head),
  		NULL);
  	    FREE_AND_NULL(strA)
  	    FREE_AND_NULL(strB)
  	    ret = XML_SCHEMAP_E_PROPS_CORRECT_6;
  	}
  	/*
  	* SPEC (4) "If there is a {substitution group affiliation},
  	* the {type definition}
  	* of the element declaration must be validly derived from the {type
  	* definition} of the {substitution group affiliation}, given the value
  	* of the {substitution group exclusions} of the {substitution group
  	* affiliation}, as defined in Type Derivation OK (Complex) ($3.4.6)
  	* (if the {type definition} is complex) or as defined in
  	* Type Derivation OK (Simple) ($3.14.6) (if the {type definition} is
  	* simple)."
  	*
  	* NOTE: {substitution group exclusions} means the values of the
  	* attribute "final".
  	*/
  
  	if (typeDef != WXS_ELEM_TYPEDEF(WXS_SUBST_HEAD(elemDecl))) {
  	    int set = 0;
  
  	    if (head->flags & XML_SCHEMAS_ELEM_FINAL_EXTENSION)
  		set |= SUBSET_EXTENSION;
  	    if (head->flags & XML_SCHEMAS_ELEM_FINAL_RESTRICTION)
  		set |= SUBSET_RESTRICTION;
  
  	    if (xmlSchemaCheckCOSDerivedOK(ACTXT_CAST pctxt, typeDef,
  		WXS_ELEM_TYPEDEF(head), set) != 0) {
  		xmlChar *strA = NULL, *strB = NULL, *strC = NULL;
  
  		ret = XML_SCHEMAP_E_PROPS_CORRECT_4;
  		xmlSchemaPCustomErrExt(pctxt,
  		    XML_SCHEMAP_E_PROPS_CORRECT_4,
  		    WXS_BASIC_CAST elemDecl, NULL,
  		    "The type definition '%s' was "
  		    "either rejected by the substitution group "
  		    "affiliation '%s', or not validly derived from its type "
  		    "definition '%s'",
  		    xmlSchemaGetComponentQName(&strA, typeDef),
  		    xmlSchemaGetComponentQName(&strB, head),
  		    xmlSchemaGetComponentQName(&strC, WXS_ELEM_TYPEDEF(head)));
  		FREE_AND_NULL(strA)
  		FREE_AND_NULL(strB)
  		FREE_AND_NULL(strC)
  	    }
  	}
      }
      /*
      * SPEC (5) "If the {type definition} or {type definition}'s
      * {content type}
      * is or is derived from ID then there must not be a {value constraint}.
      * Note: The use of ID as a type definition for elements goes beyond
      * XML 1.0, and should be avoided if backwards compatibility is desired"
      */
      if ((elemDecl->value != NULL) &&
  	((WXS_IS_SIMPLE(typeDef) &&
  	  xmlSchemaIsDerivedFromBuiltInType(typeDef, XML_SCHEMAS_ID)) ||
  	 (WXS_IS_COMPLEX(typeDef) &&
  	  WXS_HAS_SIMPLE_CONTENT(typeDef) &&
  	  xmlSchemaIsDerivedFromBuiltInType(typeDef->contentTypeDef,
  	    XML_SCHEMAS_ID)))) {
  
  	ret = XML_SCHEMAP_E_PROPS_CORRECT_5;
  	xmlSchemaPCustomErr(pctxt,
  	    XML_SCHEMAP_E_PROPS_CORRECT_5,
  	    WXS_BASIC_CAST elemDecl, NULL,
  	    "The type definition (or type definition's content type) is or "
  	    "is derived from ID; value constraints are not allowed in "
  	    "conjunction with such a type definition", NULL);
      } else if (elemDecl->value != NULL) {
  	int vcret;
  	xmlNodePtr node = NULL;
  
  	/*
  	* SPEC (2) "If there is a {value constraint}, the canonical lexical
  	* representation of its value must be `valid` with respect to the
  	* {type definition} as defined in Element Default Valid (Immediate)
  	* ($3.3.6)."
  	*/
  	if (typeDef == NULL) {
  	    xmlSchemaPErr(pctxt, elemDecl->node,
  		XML_SCHEMAP_INTERNAL,
  		"Internal error: xmlSchemaCheckElemPropsCorrect, "
  		"type is missing... skipping validation of "
  		"the value constraint", NULL, NULL);
  	    return (-1);
  	}
  	if (elemDecl->node != NULL) {
  	    if (elemDecl->flags & XML_SCHEMAS_ELEM_FIXED)
  		node = (xmlNodePtr) xmlHasProp(elemDecl->node,
  		    BAD_CAST "fixed");
  	    else
  		node = (xmlNodePtr) xmlHasProp(elemDecl->node,
  		    BAD_CAST "default");
  	}
  	vcret = xmlSchemaParseCheckCOSValidDefault(pctxt, node,
  	    typeDef, elemDecl->value, &(elemDecl->defVal));
  	if (vcret != 0) {
  	    if (vcret < 0) {
  		PERROR_INT("xmlSchemaElemCheckValConstr",
  		    "failed to validate the value constraint of an "
  		    "element declaration");
  		return (-1);
  	    }
  	    return (vcret);
  	}
      }
  
      return (ret);
  }
  
  /**
   * xmlSchemaCheckElemSubstGroup:
   * @ctxt:  a schema parser context
   * @decl: the element declaration
   * @name:  the name of the attribute
   *
   * Schema Component Constraint:
   * Substitution Group (cos-equiv-class)
   *
   * In Libxml2 the subst. groups will be precomputed, in terms of that
   * a list will be built for each subst. group head, holding all direct
   * referents to this head.
   * NOTE that this function needs:
   *   1. circular subst. groups to be checked beforehand
   *   2. the declaration's type to be derived from the head's type
   *
   * STATUS:
   *
   */
  static void
  xmlSchemaCheckElemSubstGroup(xmlSchemaParserCtxtPtr ctxt,
  			     xmlSchemaElementPtr elemDecl)
  {
      if ((WXS_SUBST_HEAD(elemDecl) == NULL) ||
  	/* SPEC (1) "Its {abstract} is false." */
  	(elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT))
  	return;
      {
  	xmlSchemaElementPtr head;
  	xmlSchemaTypePtr headType, type;
  	int set, methSet;
  	/*
  	* SPEC (2) "It is validly substitutable for HEAD subject to HEAD's
  	* {disallowed substitutions} as the blocking constraint, as defined in
  	* Substitution Group OK (Transitive) ($3.3.6)."
  	*/
  	for (head = WXS_SUBST_HEAD(elemDecl); head != NULL;
  	    head = WXS_SUBST_HEAD(head)) {
  	    set = 0;
  	    methSet = 0;
  	    /*
  	    * The blocking constraints.
  	    */
  	    if (head->flags & XML_SCHEMAS_ELEM_BLOCK_SUBSTITUTION)
  		continue;
  	    headType = head->subtypes;
  	    type = elemDecl->subtypes;
  	    if (headType == type)
  		goto add_member;
  	    if (head->flags & XML_SCHEMAS_ELEM_BLOCK_RESTRICTION)
  		set |= XML_SCHEMAS_TYPE_BLOCK_RESTRICTION;
  	    if (head->flags & XML_SCHEMAS_ELEM_BLOCK_EXTENSION)
  		set |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION;
  	    /*
  	    * SPEC: Substitution Group OK (Transitive) (2.3)
  	    * "The set of all {derivation method}s involved in the
  	    * derivation of D's {type definition} from C's {type definition}
  	    * does not intersect with the union of the blocking constraint,
  	    * C's {prohibited substitutions} (if C is complex, otherwise the
  	    * empty set) and the {prohibited substitutions} (respectively the
  	    * empty set) of any intermediate {type definition}s in the
  	    * derivation of D's {type definition} from C's {type definition}."
  	    */
  	    /*
  	    * OPTIMIZE TODO: Optimize this a bit, since, if traversing the
  	    * subst.head axis, the methSet does not need to be computed for
  	    * the full depth over and over.
  	    */
  	    /*
  	    * The set of all {derivation method}s involved in the derivation
  	    */
  	    while ((type != NULL) && (type != headType)) {
  		if ((WXS_IS_EXTENSION(type)) &&
  		    ((methSet & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) == 0))
  		    methSet |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION;
  
  		if (WXS_IS_RESTRICTION(type) &&
  		    ((methSet & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) == 0))
  		    methSet |= XML_SCHEMAS_TYPE_BLOCK_RESTRICTION;
  
  		type = type->baseType;
  	    }
  	    /*
  	    * The {prohibited substitutions} of all intermediate types +
  	    * the head's type.
  	    */
  	    type = elemDecl->subtypes->baseType;
  	    while (type != NULL) {
  		if (WXS_IS_COMPLEX(type)) {
  		    if ((type->flags &
  			    XML_SCHEMAS_TYPE_BLOCK_EXTENSION) &&
  			((set & XML_SCHEMAS_TYPE_BLOCK_EXTENSION) == 0))
  		    set |= XML_SCHEMAS_TYPE_BLOCK_EXTENSION;
  		    if ((type->flags &
  			    XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) &&
  			((set & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) == 0))
  		    set |= XML_SCHEMAS_TYPE_BLOCK_RESTRICTION;
  		} else
  		    break;
  		if (type == headType)
  		    break;
  		type = type->baseType;
  	    }
  	    if ((set != 0) &&
  		(((set & XML_SCHEMAS_TYPE_BLOCK_EXTENSION) &&
  		(methSet & XML_SCHEMAS_TYPE_BLOCK_EXTENSION)) ||
  		((set & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION) &&
  		(methSet & XML_SCHEMAS_TYPE_BLOCK_RESTRICTION)))) {
  		continue;
  	    }
  add_member:
  	    xmlSchemaAddElementSubstitutionMember(ctxt, head, elemDecl);
  	    if ((head->flags & XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD) == 0)
  		head->flags |= XML_SCHEMAS_ELEM_SUBST_GROUP_HEAD;
  	}
      }
  }
  
  #ifdef WXS_ELEM_DECL_CONS_ENABLED /* enable when finished */
  /**
   * xmlSchemaCheckElementDeclComponent
   * @pctxt: the schema parser context
   * @ctxtComponent: the context component (an element declaration)
   * @ctxtParticle: the first particle of the context component
   * @searchParticle: the element declaration particle to be analysed
   *
   * Schema Component Constraint: Element Declarations Consistent
   */
  static int
  xmlSchemaCheckElementDeclConsistent(xmlSchemaParserCtxtPtr pctxt,
  				    xmlSchemaBasicItemPtr ctxtComponent,
  				    xmlSchemaParticlePtr ctxtParticle,
  				    xmlSchemaParticlePtr searchParticle,
  				    xmlSchemaParticlePtr curParticle,
  				    int search)
  {
      return(0);
  
      int ret = 0;
      xmlSchemaParticlePtr cur = curParticle;
      if (curParticle == NULL) {
  	return(0);
      }
      if (WXS_PARTICLE_TERM(curParticle) == NULL) {
  	/*
  	* Just return in this case. A missing "term" of the particle
  	* might arise due to an invalid "term" component.
  	*/
  	return(0);
      }
      while (cur != NULL) {
  	switch (WXS_PARTICLE_TERM(cur)->type) {
  	    case XML_SCHEMA_TYPE_ANY:
  		break;
  	    case XML_SCHEMA_TYPE_ELEMENT:
  		if (search == 0) {
  		    ret = xmlSchemaCheckElementDeclConsistent(pctxt,
  			ctxtComponent, ctxtParticle, cur, ctxtParticle, 1);
  		    if (ret != 0)
  			return(ret);
  		} else {
  		    xmlSchemaElementPtr elem =
  			WXS_ELEM_CAST(WXS_PARTICLE_TERM(cur));
  		    /*
  		    * SPEC Element Declarations Consistent:
  		    * "If the {particles} contains, either directly,
  		    * indirectly (that is, within the {particles} of a
  		    * contained model group, recursively) or `implicitly`
  		    * two or more element declaration particles with
  		    * the same {name} and {target namespace}, then
  		    * all their type definitions must be the same
  		    * top-level definition [...]"
  		    */
  		    if (xmlStrEqual(WXS_PARTICLE_TERM_AS_ELEM(cur)->name,
  			    WXS_PARTICLE_TERM_AS_ELEM(searchParticle)->name) &&
  			xmlStrEqual(WXS_PARTICLE_TERM_AS_ELEM(cur)->targetNamespace,
  			    WXS_PARTICLE_TERM_AS_ELEM(searchParticle)->targetNamespace))
  		    {
  			xmlChar *strA = NULL, *strB = NULL;
  
  			xmlSchemaCustomErr(ACTXT_CAST pctxt,
  			    /* TODO: error code */
  			    XML_SCHEMAP_COS_NONAMBIG,
  			    WXS_ITEM_NODE(cur), NULL,
  			    "In the content model of %s, there are multiple "
  			    "element declarations for '%s' with different "
  			    "type definitions",
  			    xmlSchemaGetComponentDesignation(&strA,
  				ctxtComponent),
  			    xmlSchemaFormatQName(&strB,
  				WXS_PARTICLE_TERM_AS_ELEM(cur)->targetNamespace,
  				WXS_PARTICLE_TERM_AS_ELEM(cur)->name));
  			FREE_AND_NULL(strA);
  			FREE_AND_NULL(strB);
  			return(XML_SCHEMAP_COS_NONAMBIG);
  		    }
  		}
  		break;
  	    case XML_SCHEMA_TYPE_SEQUENCE: {
  		break;
  		}
  	    case XML_SCHEMA_TYPE_CHOICE:{
  		/*
  		xmlSchemaTreeItemPtr sub;
  
  		sub = WXS_PARTICLE_TERM(particle)->children;  (xmlSchemaParticlePtr)
  		while (sub != NULL) {
  		    ret = xmlSchemaCheckElementDeclConsistent(pctxt, ctxtComponent,
  			ctxtParticle, ctxtElem);
  		    if (ret != 0)
  			return(ret);
  		    sub = sub->next;
  		}
  		*/
  		break;
  		}
  	    case XML_SCHEMA_TYPE_ALL:
  		break;
  	    case XML_SCHEMA_TYPE_GROUP:
  		break;
  	    default:
  		xmlSchemaInternalErr2(ACTXT_CAST pctxt,
  		    "xmlSchemaCheckElementDeclConsistent",
  		    "found unexpected term of type '%s' in content model",
  		    WXS_ITEM_TYPE_NAME(WXS_PARTICLE_TERM(cur)), NULL);
  		return(-1);
  	}
  	cur = (xmlSchemaParticlePtr) cur->next;
      }
  
  exit:
      return(ret);
  }
  #endif
  
  /**
   * xmlSchemaCheckElementDeclComponent
   * @item:  an schema element declaration/particle
   * @ctxt:  a schema parser context
   * @name:  the name of the attribute
   *
   * Validates the value constraints of an element declaration.
   * Adds substitution group members.
   */
  static void
  xmlSchemaCheckElementDeclComponent(xmlSchemaElementPtr elemDecl,
  				   xmlSchemaParserCtxtPtr ctxt)
  {
      if (elemDecl == NULL)
  	return;
      if (elemDecl->flags & XML_SCHEMAS_ELEM_INTERNAL_CHECKED)
  	return;
      elemDecl->flags |= XML_SCHEMAS_ELEM_INTERNAL_CHECKED;
      if (xmlSchemaCheckElemPropsCorrect(ctxt, elemDecl) == 0) {
  	/*
  	* Adds substitution group members.
  	*/
  	xmlSchemaCheckElemSubstGroup(ctxt, elemDecl);
      }
  }
  
  /**
   * xmlSchemaResolveModelGroupParticleReferences:
   * @particle:  a particle component
   * @ctxt:  a parser context
   *
   * Resolves references of a model group's {particles} to
   * model group definitions and to element declarations.
   */
  static void
  xmlSchemaResolveModelGroupParticleReferences(
      xmlSchemaParserCtxtPtr ctxt,
      xmlSchemaModelGroupPtr mg)
  {
      xmlSchemaParticlePtr particle = WXS_MODELGROUP_PARTICLE(mg);
      xmlSchemaQNameRefPtr ref;
      xmlSchemaBasicItemPtr refItem;
  
      /*
      * URGENT TODO: Test this.
      */
      while (particle != NULL) {
  	if ((WXS_PARTICLE_TERM(particle) == NULL) ||
  	    ((WXS_PARTICLE_TERM(particle))->type !=
  		XML_SCHEMA_EXTRA_QNAMEREF))
  	{
  	    goto next_particle;
  	}
  	ref = WXS_QNAME_CAST WXS_PARTICLE_TERM(particle);
  	/*
  	* Resolve the reference.
  	* NULL the {term} by default.
  	*/
  	particle->children = NULL;
  
  	refItem = xmlSchemaGetNamedComponent(ctxt->schema,
  	    ref->itemType, ref->name, ref->targetNamespace);
  	if (refItem == NULL) {
  	    xmlSchemaPResCompAttrErr(ctxt, XML_SCHEMAP_SRC_RESOLVE,
  		NULL, WXS_ITEM_NODE(particle), "ref", ref->name,
  		ref->targetNamespace, ref->itemType, NULL);
  	    /* TODO: remove the particle. */
  	    goto next_particle;
  	}
  	if (refItem->type == XML_SCHEMA_TYPE_GROUP) {
  	    if (WXS_MODELGROUPDEF_MODEL(refItem) == NULL)
  		/* TODO: remove the particle. */
  		goto next_particle;
  	    /*
  	    * NOTE that we will assign the model group definition
  	    * itself to the "term" of the particle. This will ease
  	    * the check for circular model group definitions. After
  	    * that the "term" will be assigned the model group of the
  	    * model group definition.
  	    */
  	    if ((WXS_MODELGROUPDEF_MODEL(refItem))->type ==
  		    XML_SCHEMA_TYPE_ALL) {
  		/*
  		* SPEC cos-all-limited (1)
  		* SPEC cos-all-limited (1.2)
  		* "It appears only as the value of one or both of the
  		* following properties:"
  		* (1.1) "the {model group} property of a model group
  		*        definition."
  		* (1.2) "the {term} property of a particle [... of] the "
  		* {content type} of a complex type definition."
  		*/
  		xmlSchemaCustomErr(ACTXT_CAST ctxt,
  		    /* TODO: error code */
  		    XML_SCHEMAP_COS_ALL_LIMITED,
  		    WXS_ITEM_NODE(particle), NULL,
  		    "A model group definition is referenced, but "
  		    "it contains an 'all' model group, which "
  		    "cannot be contained by model groups",
  		    NULL, NULL);
  		/* TODO: remove the particle. */
  		goto next_particle;
  	    }
  	    particle->children = (xmlSchemaTreeItemPtr) refItem;
  	} else {
  	    /*
  	    * TODO: Are referenced element declarations the only
  	    * other components we expect here?
  	    */
  	    particle->children = (xmlSchemaTreeItemPtr) refItem;
  	}
  next_particle:
  	particle = WXS_PTC_CAST particle->next;
      }
  }
  
  static int
  xmlSchemaAreValuesEqual(xmlSchemaValPtr x,
  		       xmlSchemaValPtr y)
  {
      xmlSchemaTypePtr tx, ty, ptx, pty;
      int ret;
  
      while (x != NULL) {
  	/* Same types. */
  	tx = xmlSchemaGetBuiltInType(xmlSchemaGetValType(x));
  	ty = xmlSchemaGetBuiltInType(xmlSchemaGetValType(y));
  	ptx = xmlSchemaGetPrimitiveType(tx);
  	pty = xmlSchemaGetPrimitiveType(ty);
  	/*
  	* (1) if a datatype T' is `derived` by `restriction` from an
  	* atomic datatype T then the `value space` of T' is a subset of
  	* the `value space` of T. */
  	/*
  	* (2) if datatypes T' and T'' are `derived` by `restriction`
  	* from a common atomic ancestor T then the `value space`s of T'
  	* and T'' may overlap.
  	*/
  	if (ptx != pty)
  	    return(0);
  	/*
  	* We assume computed values to be normalized, so do a fast
  	* string comparison for string based types.
  	*/
  	if ((ptx->builtInType == XML_SCHEMAS_STRING) ||
  	    WXS_IS_ANY_SIMPLE_TYPE(ptx)) {
  	    if (! xmlStrEqual(
  		xmlSchemaValueGetAsString(x),
  		xmlSchemaValueGetAsString(y)))
  		return (0);
  	} else {
  	    ret = xmlSchemaCompareValuesWhtsp(
  		x, XML_SCHEMA_WHITESPACE_PRESERVE,
  		y, XML_SCHEMA_WHITESPACE_PRESERVE);
  	    if (ret == -2)
  		return(-1);
  	    if (ret != 0)
  		return(0);
  	}
  	/*
  	* Lists.
  	*/
  	x = xmlSchemaValueGetNext(x);
  	if (x != NULL) {
  	    y = xmlSchemaValueGetNext(y);
  	    if (y == NULL)
  		return (0);
  	} else if (xmlSchemaValueGetNext(y) != NULL)
  	    return (0);
  	else
  	    return (1);
      }
      return (0);
  }
  
  /**
   * xmlSchemaResolveAttrUseReferences:
   * @item:  an attribute use
   * @ctxt:  a parser context
   *
   * Resolves the referenced attribute declaration.
   */
  static int
  xmlSchemaResolveAttrUseReferences(xmlSchemaAttributeUsePtr ause,
  				  xmlSchemaParserCtxtPtr ctxt)
  {
      if ((ctxt == NULL) || (ause == NULL))
  	return(-1);
      if ((ause->attrDecl == NULL) ||
  	(ause->attrDecl->type != XML_SCHEMA_EXTRA_QNAMEREF))
  	return(0);
  
      {
  	xmlSchemaQNameRefPtr ref = WXS_QNAME_CAST ause->attrDecl;
  
  	/*
  	* TODO: Evaluate, what errors could occur if the declaration is not
  	* found.
  	*/
  	ause->attrDecl = xmlSchemaGetAttributeDecl(ctxt->schema,
  	    ref->name, ref->targetNamespace);
          if (ause->attrDecl == NULL) {
  	    xmlSchemaPResCompAttrErr(ctxt,
  		XML_SCHEMAP_SRC_RESOLVE,
  		WXS_BASIC_CAST ause, ause->node,
  		"ref", ref->name, ref->targetNamespace,
  		XML_SCHEMA_TYPE_ATTRIBUTE, NULL);
              return(ctxt->err);;
          }
      }
      return(0);
  }
  
  /**
   * xmlSchemaCheckAttrUsePropsCorrect:
   * @ctxt:  a parser context
   * @use:  an attribute use
   *
   * Schema Component Constraint:
   * Attribute Use Correct (au-props-correct)
   *
   */
  static int
  xmlSchemaCheckAttrUsePropsCorrect(xmlSchemaParserCtxtPtr ctxt,
  			     xmlSchemaAttributeUsePtr use)
  {
      if ((ctxt == NULL) || (use == NULL))
  	return(-1);
      if ((use->defValue == NULL) || (WXS_ATTRUSE_DECL(use) == NULL) ||
  	((WXS_ATTRUSE_DECL(use))->type != XML_SCHEMA_TYPE_ATTRIBUTE))
  	return(0);
  
      /*
      * SPEC au-props-correct (1)
      * "The values of the properties of an attribute use must be as
      * described in the property tableau in The Attribute Use Schema
      * Component ($3.5.1), modulo the impact of Missing
      * Sub-components ($5.3)."
      */
  
      if (((WXS_ATTRUSE_DECL(use))->defValue != NULL) &&
  	((WXS_ATTRUSE_DECL(use))->flags & XML_SCHEMAS_ATTR_FIXED) &&
          ((use->flags & XML_SCHEMA_ATTR_USE_FIXED) == 0))
      {
  	xmlSchemaPCustomErr(ctxt,
  	    XML_SCHEMAP_AU_PROPS_CORRECT_2,
  	    WXS_BASIC_CAST use, NULL,
  	    "The attribute declaration has a 'fixed' value constraint "
  	    ", thus the attribute use must also have a 'fixed' value "
  	    "constraint",
  	    NULL);
  	return(ctxt->err);
      }
      /*
      * Compute and check the value constraint's value.
      */
      if ((use->defVal != NULL) && (WXS_ATTRUSE_TYPEDEF(use) != NULL)) {
  	int ret;
  	/*
  	* TODO: The spec seems to be missing a check of the
  	* value constraint of the attribute use. We will do it here.
  	*/
  	/*
  	* SPEC a-props-correct (3)
  	*/
  	if (xmlSchemaIsDerivedFromBuiltInType(
  	    WXS_ATTRUSE_TYPEDEF(use), XML_SCHEMAS_ID))
  	{
  	    xmlSchemaCustomErr(ACTXT_CAST ctxt,
  		XML_SCHEMAP_AU_PROPS_CORRECT,
  		NULL, WXS_BASIC_CAST use,
  		"Value constraints are not allowed if the type definition "
  		"is or is derived from xs:ID",
  		NULL, NULL);
  	    return(ctxt->err);
  	}
  
  	ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST ctxt,
  	    use->node, WXS_ATTRUSE_TYPEDEF(use),
  	    use->defValue, &(use->defVal),
  	    1, 1, 0);
  	if (ret != 0) {
  	    if (ret < 0) {
  		PERROR_INT2("xmlSchemaCheckAttrUsePropsCorrect",
  		    "calling xmlSchemaVCheckCVCSimpleType()");
  		return(-1);
  	    }
  	    xmlSchemaCustomErr(ACTXT_CAST ctxt,
  		XML_SCHEMAP_AU_PROPS_CORRECT,
  		NULL, WXS_BASIC_CAST use,
  		"The value of the value constraint is not valid",
  		NULL, NULL);
  	    return(ctxt->err);
  	}
      }
      /*
      * SPEC au-props-correct (2)
      * "If the {attribute declaration} has a fixed
      * {value constraint}, then if the attribute use itself has a
      * {value constraint}, it must also be fixed and its value must match
      * that of the {attribute declaration}'s {value constraint}."
      */
      if (((WXS_ATTRUSE_DECL(use))->defVal != NULL) &&
  	(((WXS_ATTRUSE_DECL(use))->flags & XML_SCHEMA_ATTR_USE_FIXED) == 0))
      {
  	if (! xmlSchemaAreValuesEqual(use->defVal,
  		(WXS_ATTRUSE_DECL(use))->defVal))
  	{
  	    xmlSchemaPCustomErr(ctxt,
  		XML_SCHEMAP_AU_PROPS_CORRECT_2,
  		WXS_BASIC_CAST use, NULL,
  		"The 'fixed' value constraint of the attribute use "
  		"must match the attribute declaration's value "
  		"constraint '%s'",
  		(WXS_ATTRUSE_DECL(use))->defValue);
  	}
  	return(ctxt->err);
      }
      return(0);
  }
  
  
  
  
  /**
   * xmlSchemaResolveAttrTypeReferences:
   * @item:  an attribute declaration
   * @ctxt:  a parser context
   *
   * Resolves the referenced type definition component.
   */
  static int
  xmlSchemaResolveAttrTypeReferences(xmlSchemaAttributePtr item,
  				   xmlSchemaParserCtxtPtr ctxt)
  {
      /*
      * 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 (item->flags & XML_SCHEMAS_ATTR_INTERNAL_RESOLVED)
  	return(0);
      item->flags |= XML_SCHEMAS_ATTR_INTERNAL_RESOLVED;
      if (item->subtypes != NULL)
          return(0);
      if (item->typeName != NULL) {
          xmlSchemaTypePtr type;
  
  	type = xmlSchemaGetType(ctxt->schema, item->typeName,
  	    item->typeNs);
  	if ((type == NULL) || (! WXS_IS_SIMPLE(type))) {
  	    xmlSchemaPResCompAttrErr(ctxt,
  		XML_SCHEMAP_SRC_RESOLVE,
  		WXS_BASIC_CAST item, item->node,
  		"type", item->typeName, item->typeNs,
  		XML_SCHEMA_TYPE_SIMPLE, NULL);
  	    return(ctxt->err);
  	} else
  	    item->subtypes = type;
  
      } else {
  	/*
  	* The type defaults to the xs:anySimpleType.
  	*/
  	item->subtypes = xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYSIMPLETYPE);
      }
      return(0);
  }
  
  /**
   * xmlSchemaResolveIDCKeyReferences:
   * @idc:  the identity-constraint definition
   * @ctxt:  the schema parser context
   * @name:  the attribute name
   *
   * Resolve keyRef references to key/unique IDCs.
   * Schema Component Constraint:
   *   Identity-constraint Definition Properties Correct (c-props-correct)
   */
  static int
  xmlSchemaResolveIDCKeyReferences(xmlSchemaIDCPtr idc,
  			  xmlSchemaParserCtxtPtr pctxt)
  {
      if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF)
          return(0);
      if (idc->ref->name != NULL) {
  	idc->ref->item = (xmlSchemaBasicItemPtr)
  	    xmlSchemaGetIDC(pctxt->schema, idc->ref->name,
  		idc->ref->targetNamespace);
          if (idc->ref->item == NULL) {
  	    /*
  	    * TODO: It is actually not an error to fail to resolve
  	    * at this stage. BUT we need to be that strict!
  	    */
  	    xmlSchemaPResCompAttrErr(pctxt,
  		XML_SCHEMAP_SRC_RESOLVE,
  		WXS_BASIC_CAST idc, idc->node,
  		"refer", idc->ref->name,
  		idc->ref->targetNamespace,
  		XML_SCHEMA_TYPE_IDC_KEY, NULL);
              return(pctxt->err);
  	} else if (idc->ref->item->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
  	    /*
  	    * SPEC c-props-correct (1)
  	    */
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		XML_SCHEMAP_C_PROPS_CORRECT,
  		NULL, WXS_BASIC_CAST idc,
  		"The keyref references a keyref",
  		NULL, NULL);
  	    idc->ref->item = NULL;
  	    return(pctxt->err);
  	} else {
  	    if (idc->nbFields !=
  		((xmlSchemaIDCPtr) idc->ref->item)->nbFields) {
  		xmlChar *str = NULL;
  		xmlSchemaIDCPtr refer;
  
  		refer = (xmlSchemaIDCPtr) idc->ref->item;
  		/*
  		* SPEC c-props-correct(2)
  		* "If the {identity-constraint category} is keyref,
  		* the cardinality of the {fields} must equal that of
  		* the {fields} of the {referenced key}.
  		*/
  		xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		    XML_SCHEMAP_C_PROPS_CORRECT,
  		    NULL, WXS_BASIC_CAST idc,
  		    "The cardinality of the keyref differs from the "
  		    "cardinality of the referenced key/unique '%s'",
  		    xmlSchemaFormatQName(&str, refer->targetNamespace,
  			refer->name),
  		    NULL);
  		FREE_AND_NULL(str)
  		return(pctxt->err);
  	    }
  	}
      }
      return(0);
  }
  
  static int
  xmlSchemaResolveAttrUseProhibReferences(xmlSchemaAttributeUseProhibPtr prohib,
  				       xmlSchemaParserCtxtPtr pctxt)
  {
      if (xmlSchemaGetAttributeDecl(pctxt->schema, prohib->name,
  	prohib->targetNamespace) == NULL) {
  
  	xmlSchemaPResCompAttrErr(pctxt,
  	    XML_SCHEMAP_SRC_RESOLVE,
  	    NULL, prohib->node,
  	    "ref", prohib->name, prohib->targetNamespace,
  	    XML_SCHEMA_TYPE_ATTRIBUTE, NULL);
  	return(XML_SCHEMAP_SRC_RESOLVE);
      }
      return(0);
  }
  
  #define WXS_REDEFINED_TYPE(c) \
  (((xmlSchemaTypePtr) item)->flags & XML_SCHEMAS_TYPE_REDEFINED)
  
  #define WXS_REDEFINED_MODEL_GROUP_DEF(c) \
  (((xmlSchemaModelGroupDefPtr) item)->flags & XML_SCHEMA_MODEL_GROUP_DEF_REDEFINED)
  
  #define WXS_REDEFINED_ATTR_GROUP(c) \
  (((xmlSchemaAttributeGroupPtr) item)->flags & XML_SCHEMAS_ATTRGROUP_REDEFINED)
  
  static int
  xmlSchemaCheckSRCRedefineFirst(xmlSchemaParserCtxtPtr pctxt)
  {
      int err = 0;
      xmlSchemaRedefPtr redef = WXS_CONSTRUCTOR(pctxt)->redefs;
      xmlSchemaBasicItemPtr prev, item;
      int wasRedefined;
  
      if (redef == NULL)
  	return(0);
  
      do {
  	item = redef->item;
  	/*
  	* First try to locate the redefined component in the
  	* schema graph starting with the redefined schema.
  	* NOTE: According to this schema bug entry:
  	*   http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005OctDec/0019.html
  	*   it's not clear if the referenced component needs to originate
  	*   from the <redefine>d schema _document_ or the schema; the latter
  	*   would include all imported and included sub-schemas of the
  	*   <redefine>d schema. Currently the latter approach is used.
  	*   SUPPLEMENT: It seems that the WG moves towards the latter
  	*   approach, so we are doing it right.
  	*
  	*/
  	prev = xmlSchemaFindRedefCompInGraph(
  	    redef->targetBucket, item->type,
  	    redef->refName, redef->refTargetNs);
  	if (prev == NULL) {
  	    xmlChar *str = NULL;
  	    xmlNodePtr node;
  
  	    /*
  	    * SPEC src-redefine:
  	    * (6.2.1) "The `actual value` of its own name attribute plus
  	    * target namespace must successfully `resolve` to a model
  	    * group definition in I."
  	    * (7.2.1) "The `actual value` of its own name attribute plus
  	    * target namespace must successfully `resolve` to an attribute
  	    * group definition in I."
  
  	    *
  	    * Note that, if we are redefining with the use of references
  	    * to components, the spec assumes the src-resolve to be used;
  	    * but this won't assure that we search only *inside* the
  	    * redefined schema.
  	    */
  	    if (redef->reference)
  		node = WXS_ITEM_NODE(redef->reference);
  	    else
  		node = WXS_ITEM_NODE(item);
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		/*
  		* TODO: error code.
  		* Probably XML_SCHEMAP_SRC_RESOLVE, if this is using the
  		* reference kind.
  		*/
  		XML_SCHEMAP_SRC_REDEFINE, node, NULL,
  		"The %s '%s' to be redefined could not be found in "
  		"the redefined schema",
  		WXS_ITEM_TYPE_NAME(item),
  		xmlSchemaFormatQName(&str, redef->refTargetNs,
  		    redef->refName));
  	    FREE_AND_NULL(str);
  	    err = pctxt->err;
  	    redef = redef->next;
  	    continue;
  	}
  	/*
  	* TODO: Obtaining and setting the redefinition state is really
  	* clumsy.
  	*/
  	wasRedefined = 0;
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_COMPLEX:
  	    case XML_SCHEMA_TYPE_SIMPLE:
  		if ((WXS_TYPE_CAST prev)->flags &
  		    XML_SCHEMAS_TYPE_REDEFINED)
  		{
  		    wasRedefined = 1;
  		    break;
  		}
  		/* Mark it as redefined. */
  		(WXS_TYPE_CAST prev)->flags |= XML_SCHEMAS_TYPE_REDEFINED;
  		/*
  		* Assign the redefined type to the
  		* base type of the redefining type.
  		* TODO: How
  		*/
  		((xmlSchemaTypePtr) item)->baseType =
  		    (xmlSchemaTypePtr) prev;
  		break;
  	    case XML_SCHEMA_TYPE_GROUP:
  		if ((WXS_MODEL_GROUPDEF_CAST prev)->flags &
  		    XML_SCHEMA_MODEL_GROUP_DEF_REDEFINED)
  		{
  		    wasRedefined = 1;
  		    break;
  		}
  		/* Mark it as redefined. */
  		(WXS_MODEL_GROUPDEF_CAST prev)->flags |=
  		    XML_SCHEMA_MODEL_GROUP_DEF_REDEFINED;
  		if (redef->reference != NULL) {
  		    /*
  		    * Overwrite the QName-reference with the
  		    * referenced model group def.
  		    */
  		    (WXS_PTC_CAST redef->reference)->children =
  			WXS_TREE_CAST prev;
  		}
  		redef->target = prev;
  		break;
  	    case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  		if ((WXS_ATTR_GROUP_CAST prev)->flags &
  		    XML_SCHEMAS_ATTRGROUP_REDEFINED)
  		{
  		    wasRedefined = 1;
  		    break;
  		}
  		(WXS_ATTR_GROUP_CAST prev)->flags |=
  		    XML_SCHEMAS_ATTRGROUP_REDEFINED;
  		if (redef->reference != NULL) {
  		    /*
  		    * Assign the redefined attribute group to the
  		    * QName-reference component.
  		    * This is the easy case, since we will just
  		    * expand the redefined group.
  		    */
  		    (WXS_QNAME_CAST redef->reference)->item = prev;
  		    redef->target = NULL;
  		} else {
  		    /*
  		    * This is the complicated case: we need
  		    * to apply src-redefine (7.2.2) at a later
  		    * stage, i.e. when attribute group references
  		    * have been expanded and simple types have
  		    * been fixed.
  		    */
  		    redef->target = prev;
  		}
  		break;
  	    default:
  		PERROR_INT("xmlSchemaResolveRedefReferences",
  		    "Unexpected redefined component type");
  		return(-1);
  	}
  	if (wasRedefined) {
  	    xmlChar *str = NULL;
  	    xmlNodePtr node;
  
  	    if (redef->reference)
  		node = WXS_ITEM_NODE(redef->reference);
  	    else
  		node = WXS_ITEM_NODE(redef->item);
  
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		/* TODO: error code. */
  		XML_SCHEMAP_SRC_REDEFINE,
  		node, NULL,
  		"The referenced %s was already redefined. Multiple "
  		"redefinition of the same component is not supported",
  		xmlSchemaGetComponentDesignation(&str, prev),
  		NULL);
  	    FREE_AND_NULL(str)
  	    err = pctxt->err;
  	    redef = redef->next;
  	    continue;
  	}
  	redef = redef->next;
      } while (redef != NULL);
  
      return(err);
  }
  
  static int
  xmlSchemaCheckSRCRedefineSecond(xmlSchemaParserCtxtPtr pctxt)
  {
      int err = 0;
      xmlSchemaRedefPtr redef = WXS_CONSTRUCTOR(pctxt)->redefs;
      xmlSchemaBasicItemPtr item;
  
      if (redef == NULL)
  	return(0);
  
      do {
  	if (redef->target == NULL) {
  	    redef = redef->next;
  	    continue;
  	}
  	item = redef->item;
  
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_SIMPLE:
  	    case XML_SCHEMA_TYPE_COMPLEX:
  		/*
  		* Since the spec wants the {name} of the redefined
  		* type to be 'absent', we'll NULL it.
  		*/
  		(WXS_TYPE_CAST redef->target)->name = NULL;
  
  		/*
  		* TODO: Seems like there's nothing more to do. The normal
  		* inheritance mechanism is used. But not 100% sure.
  		*/
  		break;
  	    case XML_SCHEMA_TYPE_GROUP:
  		/*
  		* URGENT TODO:
  		* SPEC src-redefine:
  		* (6.2.2) "The {model group} of the model group definition
  		* which corresponds to it per XML Representation of Model
  		* Group Definition Schema Components ($3.7.2) must be a
  		* `valid restriction` of the {model group} of that model
  		* group definition in I, as defined in Particle Valid
  		* (Restriction) ($3.9.6)."
  		*/
  		break;
  	    case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  		/*
  		* SPEC src-redefine:
  		* (7.2.2) "The {attribute uses} and {attribute wildcard} of
  		* the attribute group definition which corresponds to it
  		* per XML Representation of Attribute Group Definition Schema
  		* Components ($3.6.2) must be `valid restrictions` of the
  		* {attribute uses} and {attribute wildcard} of that attribute
  		* group definition in I, as defined in clause 2, clause 3 and
  		* clause 4 of Derivation Valid (Restriction, Complex)
  		* ($3.4.6) (where references to the base type definition are
  		* understood as references to the attribute group definition
  		* in I)."
  		*/
  		err = xmlSchemaCheckDerivationOKRestriction2to4(pctxt,
  		    XML_SCHEMA_ACTION_REDEFINE,
  		    item, redef->target,
  		    (WXS_ATTR_GROUP_CAST item)->attrUses,
  		    (WXS_ATTR_GROUP_CAST redef->target)->attrUses,
  		    (WXS_ATTR_GROUP_CAST item)->attributeWildcard,
  		    (WXS_ATTR_GROUP_CAST redef->target)->attributeWildcard);
  		if (err == -1)
  		    return(-1);
  		break;
  	    default:
  		break;
  	}
  	redef = redef->next;
      } while (redef != NULL);
      return(0);
  }
  
  
  static int
  xmlSchemaAddComponents(xmlSchemaParserCtxtPtr pctxt,
  		       xmlSchemaBucketPtr bucket)
  {
      xmlSchemaBasicItemPtr item;
      int err;
      xmlHashTablePtr *table;
      const xmlChar *name;
      int i;
  
  #define WXS_GET_GLOBAL_HASH(c, slot) { \
      if (WXS_IS_BUCKET_IMPMAIN((c)->type)) \
  	table = &(WXS_IMPBUCKET((c))->schema->slot); \
      else \
  	table = &(WXS_INCBUCKET((c))->ownerImport->schema->slot); }
  
      /*
      * Add global components to the schema's hash tables.
      * This is the place where duplicate components will be
      * detected.
      * TODO: I think normally we should support imports of the
      *   same namespace from multiple locations. We don't do currently,
      *   but if we do then according to:
      *   http://www.w3.org/Bugs/Public/show_bug.cgi?id=2224
      *   we would need, if imported directly, to import redefined
      *   components as well to be able to catch clashing components.
      *   (I hope I'll still know what this means after some months :-()
      */
      if (bucket == NULL)
  	return(-1);
      if (bucket->flags & XML_SCHEMA_BUCKET_COMPS_ADDED)
  	return(0);
      bucket->flags |= XML_SCHEMA_BUCKET_COMPS_ADDED;
  
      for (i = 0; i < bucket->globals->nbItems; i++) {
  	item = bucket->globals->items[i];
  	table = NULL;
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_COMPLEX:
  	    case XML_SCHEMA_TYPE_SIMPLE:
  		if (WXS_REDEFINED_TYPE(item))
  		    continue;
  		name = (WXS_TYPE_CAST item)->name;
  		WXS_GET_GLOBAL_HASH(bucket, typeDecl)
  		break;
  	    case XML_SCHEMA_TYPE_ELEMENT:
  		name = (WXS_ELEM_CAST item)->name;
  		WXS_GET_GLOBAL_HASH(bucket, elemDecl)
  		break;
  	    case XML_SCHEMA_TYPE_ATTRIBUTE:
  		name = (WXS_ATTR_CAST item)->name;
  		WXS_GET_GLOBAL_HASH(bucket, attrDecl)
  		break;
  	    case XML_SCHEMA_TYPE_GROUP:
  		if (WXS_REDEFINED_MODEL_GROUP_DEF(item))
  		    continue;
  		name = (WXS_MODEL_GROUPDEF_CAST item)->name;
  		WXS_GET_GLOBAL_HASH(bucket, groupDecl)
  		break;
  	    case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  		if (WXS_REDEFINED_ATTR_GROUP(item))
  		    continue;
  		name = (WXS_ATTR_GROUP_CAST item)->name;
  		WXS_GET_GLOBAL_HASH(bucket, attrgrpDecl)
  		break;
  	    case XML_SCHEMA_TYPE_IDC_KEY:
  	    case XML_SCHEMA_TYPE_IDC_UNIQUE:
  	    case XML_SCHEMA_TYPE_IDC_KEYREF:
  		name = (WXS_IDC_CAST item)->name;
  		WXS_GET_GLOBAL_HASH(bucket, idcDef)
  		break;
  	    case XML_SCHEMA_TYPE_NOTATION:
  		name = ((xmlSchemaNotationPtr) item)->name;
  		WXS_GET_GLOBAL_HASH(bucket, notaDecl)
  		break;
  	    default:
  		PERROR_INT("xmlSchemaAddComponents",
  		    "Unexpected global component type");
  		continue;
  	}
  	if (*table == NULL) {
  	    *table = xmlHashCreateDict(10, pctxt->dict);
  	    if (*table == NULL) {
  		PERROR_INT("xmlSchemaAddComponents",
  		    "failed to create a component hash table");
  		return(-1);
  	    }
  	}
  	err = xmlHashAddEntry(*table, name, item);
  	if (err != 0) {
  	    xmlChar *str = NULL;
  
  	    xmlSchemaCustomErr(ACTXT_CAST pctxt,
  		XML_SCHEMAP_REDEFINED_TYPE,
  		WXS_ITEM_NODE(item),
  		WXS_BASIC_CAST item,
  		"A global %s '%s' does already exist",
  		WXS_ITEM_TYPE_NAME(item),
  		xmlSchemaGetComponentQName(&str, item));
  	    FREE_AND_NULL(str);
  	}
      }
      /*
      * Process imported/included schemas.
      */
      if (bucket->relations != NULL) {
  	xmlSchemaSchemaRelationPtr rel = bucket->relations;
  	do {
  	    if ((rel->bucket != NULL) &&
  		((rel->bucket->flags & XML_SCHEMA_BUCKET_COMPS_ADDED) == 0)) {
  		if (xmlSchemaAddComponents(pctxt, rel->bucket) == -1)
  		    return(-1);
  	    }
  	    rel = rel->next;
  	} while (rel != NULL);
      }
      return(0);
  }
  
  static int
  xmlSchemaFixupComponents(xmlSchemaParserCtxtPtr pctxt,
  			 xmlSchemaBucketPtr rootBucket)
  {
      xmlSchemaConstructionCtxtPtr con = pctxt->constructor;
      xmlSchemaTreeItemPtr item, *items;
      int nbItems, i, ret = 0;
      xmlSchemaBucketPtr oldbucket = con->bucket;
      xmlSchemaElementPtr elemDecl;
  
  #define FIXHFAILURE if (pctxt->err == XML_SCHEMAP_INTERNAL) goto exit_failure;
  
      if ((con->pending == NULL) ||
  	(con->pending->nbItems == 0))
  	return(0);
  
      /*
      * Since xmlSchemaFixupComplexType() will create new particles
      * (local components), and those particle components need a bucket
      * on the constructor, we'll assure here that the constructor has
      * a bucket.
      * TODO: Think about storing locals _only_ on the main bucket.
      */
      if (con->bucket == NULL)
  	con->bucket = rootBucket;
  
      /* TODO:
      * SPEC (src-redefine):
      * (6.2) "If it has no such self-reference, then all of the
      * following must be true:"
  
      * (6.2.2) The {model group} of the model group definition which
      * corresponds to it per XML Representation of Model Group
      * Definition Schema Components ($3.7.2) must be a `valid
      * restriction` of the {model group} of that model group definition
      * in I, as defined in Particle Valid (Restriction) ($3.9.6)."
      */
      xmlSchemaCheckSRCRedefineFirst(pctxt);
  
      /*
      * Add global components to the schemata's hash tables.
      */
      xmlSchemaAddComponents(pctxt, rootBucket);
  
      pctxt->ctxtType = NULL;
      items = (xmlSchemaTreeItemPtr *) con->pending->items;
      nbItems = con->pending->nbItems;
      /*
      * Now that we have parsed *all* the schema document(s) and converted
      * them to schema components, we can resolve references, apply component
      * constraints, create the FSA from the content model, etc.
      */
      /*
      * Resolve references of..
      *
      * 1. element declarations:
      *   - the type definition
      *   - the substitution group affiliation
      * 2. simple/complex types:
      *   - the base type definition
      *   - the memberTypes of union types
      *   - the itemType of list types
      * 3. attributes declarations and attribute uses:
      *   - the type definition
      *   - if an attribute use, then the attribute declaration
      * 4. attribute group references:
      *   - the attribute group definition
      * 5. particles:
      *   - the term of the particle (e.g. a model group)
      * 6. IDC key-references:
      *   - the referenced IDC 'key' or 'unique' definition
      * 7. Attribute prohibitions which had a "ref" attribute.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_ELEMENT:
  		xmlSchemaResolveElementReferences(
  		    (xmlSchemaElementPtr) item, pctxt);
  		FIXHFAILURE;
  		break;
  	    case XML_SCHEMA_TYPE_COMPLEX:
  	    case XML_SCHEMA_TYPE_SIMPLE:
  		xmlSchemaResolveTypeReferences(
  		    (xmlSchemaTypePtr) item, pctxt);
  		FIXHFAILURE;
  		break;
  	    case XML_SCHEMA_TYPE_ATTRIBUTE:
  		xmlSchemaResolveAttrTypeReferences(
  		    (xmlSchemaAttributePtr) item, pctxt);
  		FIXHFAILURE;
  		break;
  	    case XML_SCHEMA_TYPE_ATTRIBUTE_USE:
  		xmlSchemaResolveAttrUseReferences(
  		    (xmlSchemaAttributeUsePtr) item, pctxt);
  		FIXHFAILURE;
  		break;
  	    case XML_SCHEMA_EXTRA_QNAMEREF:
  		if ((WXS_QNAME_CAST item)->itemType ==
  		    XML_SCHEMA_TYPE_ATTRIBUTEGROUP)
  		{
  		    xmlSchemaResolveAttrGroupReferences(
  			WXS_QNAME_CAST item, pctxt);
  		}
  		FIXHFAILURE;
  		break;
  	    case XML_SCHEMA_TYPE_SEQUENCE:
  	    case XML_SCHEMA_TYPE_CHOICE:
  	    case XML_SCHEMA_TYPE_ALL:
  		xmlSchemaResolveModelGroupParticleReferences(pctxt,
  		    WXS_MODEL_GROUP_CAST item);
  		FIXHFAILURE;
  		break;
  	    case XML_SCHEMA_TYPE_IDC_KEY:
  	    case XML_SCHEMA_TYPE_IDC_UNIQUE:
  	    case XML_SCHEMA_TYPE_IDC_KEYREF:
  		xmlSchemaResolveIDCKeyReferences(
  		    (xmlSchemaIDCPtr) item, pctxt);
  		FIXHFAILURE;
  		break;
  	    case XML_SCHEMA_EXTRA_ATTR_USE_PROHIB:
  		/*
  		* Handle attribue prohibition which had a
  		* "ref" attribute.
  		*/
  		xmlSchemaResolveAttrUseProhibReferences(
  		    WXS_ATTR_PROHIB_CAST item, pctxt);
  		FIXHFAILURE;
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
  
      /*
      * Now that all references are resolved we
      * can check for circularity of...
      * 1. the base axis of type definitions
      * 2. nested model group definitions
      * 3. nested attribute group definitions
      * TODO: check for circular substitution groups.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	/*
  	* Let's better stop on the first error here.
  	*/
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_COMPLEX:
  	    case XML_SCHEMA_TYPE_SIMPLE:
  		xmlSchemaCheckTypeDefCircular(
  		    (xmlSchemaTypePtr) item, pctxt);
  		FIXHFAILURE;
  		if (pctxt->nberrors != 0)
  		    goto exit_error;
  		break;
  	    case XML_SCHEMA_TYPE_GROUP:
  		xmlSchemaCheckGroupDefCircular(
  		    (xmlSchemaModelGroupDefPtr) item, pctxt);
  		FIXHFAILURE;
  		if (pctxt->nberrors != 0)
  		    goto exit_error;
  		break;
  	    case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  		xmlSchemaCheckAttrGroupCircular(
  		    (xmlSchemaAttributeGroupPtr) item, pctxt);
  		FIXHFAILURE;
  		if (pctxt->nberrors != 0)
  		    goto exit_error;
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
      /*
      * Model group definition references:
      * Such a reference is reflected by a particle at the component
      * level. Until now the 'term' of such particles pointed
      * to the model group definition; this was done, in order to
      * ease circularity checks. Now we need to set the 'term' of
      * such particles to the model group of the model group definition.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_SEQUENCE:
  	    case XML_SCHEMA_TYPE_CHOICE:
  		xmlSchemaModelGroupToModelGroupDefFixup(pctxt,
  		    WXS_MODEL_GROUP_CAST item);
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
      /*
      * Expand attribute group references of attribute group definitions.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
              case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  		if ((! WXS_ATTR_GROUP_EXPANDED(item)) &&
  		    WXS_ATTR_GROUP_HAS_REFS(item))
  		{
  		    xmlSchemaAttributeGroupExpandRefs(pctxt,
  			WXS_ATTR_GROUP_CAST item);
  		    FIXHFAILURE;
  		}
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
      /*
      * First compute the variety of simple types. This is needed as
      * a separate step, since otherwise we won't be able to detect
      * circular union types in all cases.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
              case XML_SCHEMA_TYPE_SIMPLE:
  		if (WXS_IS_TYPE_NOT_FIXED_1((xmlSchemaTypePtr) item)) {
  		    xmlSchemaFixupSimpleTypeStageOne(pctxt,
  			(xmlSchemaTypePtr) item);
  		    FIXHFAILURE;
  		}
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
      /*
      * Detect circular union types. Note that this needs the variety to
      * be already computed.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
              case XML_SCHEMA_TYPE_SIMPLE:
  		if (((xmlSchemaTypePtr) item)->memberTypes != NULL) {
  		    xmlSchemaCheckUnionTypeDefCircular(pctxt,
  			(xmlSchemaTypePtr) item);
  		    FIXHFAILURE;
  		}
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
  
      /*
      * Do the complete type fixup for simple types.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
              case XML_SCHEMA_TYPE_SIMPLE:
  		if (WXS_IS_TYPE_NOT_FIXED(WXS_TYPE_CAST item)) {
  		    xmlSchemaFixupSimpleTypeStageTwo(pctxt, WXS_TYPE_CAST item);
  		    FIXHFAILURE;
  		}
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
      /*
      * At this point we need build and check all simple types.
      */
      /*
      * Apply constraints for attribute declarations.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_ATTRIBUTE:
  		xmlSchemaCheckAttrPropsCorrect(pctxt, WXS_ATTR_CAST item);
  		FIXHFAILURE;
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
      /*
      * Apply constraints for attribute uses.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_ATTRIBUTE_USE:
  		if (((xmlSchemaAttributeUsePtr)item)->defValue != NULL) {
  		    xmlSchemaCheckAttrUsePropsCorrect(pctxt,
  			WXS_ATTR_USE_CAST item);
  		    FIXHFAILURE;
  		}
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
  
      /*
      * Apply constraints for attribute group definitions.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
  	case XML_SCHEMA_TYPE_ATTRIBUTEGROUP:
  	    if (( (WXS_ATTR_GROUP_CAST item)->attrUses != NULL) &&
  		( (WXS_LIST_CAST (WXS_ATTR_GROUP_CAST item)->attrUses)->nbItems > 1))
  	    {
  		xmlSchemaCheckAGPropsCorrect(pctxt, WXS_ATTR_GROUP_CAST item);
  		FIXHFAILURE;
  	    }
  	    break;
  	default:
  	    break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
  
      /*
      * Apply constraints for redefinitions.
      */
      if (WXS_CONSTRUCTOR(pctxt)->redefs != NULL)
  	xmlSchemaCheckSRCRedefineSecond(pctxt);
      if (pctxt->nberrors != 0)
  	goto exit_error;
  
      /*
      * Complex types are built and checked.
      */
      for (i = 0; i < nbItems; i++) {
  	item = con->pending->items[i];
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_COMPLEX:
  		if (WXS_IS_TYPE_NOT_FIXED(WXS_TYPE_CAST item)) {
  		    xmlSchemaFixupComplexType(pctxt, WXS_TYPE_CAST item);
  		    FIXHFAILURE;
  		}
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
  
      /*
      * The list could have changed, since xmlSchemaFixupComplexType()
      * will create particles and model groups in some cases.
      */
      items = (xmlSchemaTreeItemPtr *) con->pending->items;
      nbItems = con->pending->nbItems;
  
      /*
      * Apply some constraints for element declarations.
      */
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_ELEMENT:
  		elemDecl = (xmlSchemaElementPtr) item;
  
  		if ((elemDecl->flags & XML_SCHEMAS_ELEM_INTERNAL_CHECKED) == 0)
  		{
  		    xmlSchemaCheckElementDeclComponent(
  			(xmlSchemaElementPtr) elemDecl, pctxt);
  		    FIXHFAILURE;
  		}
  
  #ifdef WXS_ELEM_DECL_CONS_ENABLED
  		/*
  		* Schema Component Constraint: Element Declarations Consistent
  		* Apply this constraint to local types of element declarations.
  		*/
  		if ((WXS_ELEM_TYPEDEF(elemDecl) != NULL) &&
  		    (WXS_IS_COMPLEX(WXS_ELEM_TYPEDEF(elemDecl))) &&
  		    (WXS_TYPE_IS_LOCAL(WXS_ELEM_TYPEDEF(elemDecl))))
  		{
  		    xmlSchemaCheckElementDeclConsistent(pctxt,
  			WXS_BASIC_CAST elemDecl,
  			WXS_TYPE_PARTICLE(WXS_ELEM_TYPEDEF(elemDecl)),
  			NULL, NULL, 0);
  		}
  #endif
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
  
      /*
      * Finally we can build the automaton from the content model of
      * complex types.
      */
  
      for (i = 0; i < nbItems; i++) {
  	item = items[i];
  	switch (item->type) {
  	    case XML_SCHEMA_TYPE_COMPLEX:
  		xmlSchemaBuildContentModel((xmlSchemaTypePtr) item, pctxt);
  		/* FIXHFAILURE; */
  		break;
  	    default:
  		break;
  	}
      }
      if (pctxt->nberrors != 0)
  	goto exit_error;
      /*
      * URGENT TODO: cos-element-consistent
      */
      goto exit;
  
  exit_error:
      ret = pctxt->err;
      goto exit;
  
  exit_failure:
      ret = -1;
  
  exit:
      /*
      * Reset the constructor. This is needed for XSI acquisition, since
      * those items will be processed over and over again for every XSI
      * if not cleared here.
      */
      con->bucket = oldbucket;
      con->pending->nbItems = 0;
      if (con->substGroups != NULL) {
  	xmlHashFree(con->substGroups, xmlSchemaSubstGroupFreeEntry);
  	con->substGroups = NULL;
      }
      if (con->redefs != NULL) {
  	xmlSchemaRedefListFree(con->redefs);
  	con->redefs = NULL;
      }
      return(ret);
  }
  /**
   * xmlSchemaParse:
   * @ctxt:  a schema validation context
   *
   * parse a schema definition resource and build an internal
   * XML Schema structure which can be used to validate instances.
   *
   * Returns the internal XML Schema structure built from the resource or
   *         NULL in case of error
   */
  xmlSchemaPtr
  xmlSchemaParse(xmlSchemaParserCtxtPtr ctxt)
  {
      xmlSchemaPtr mainSchema = NULL;
      xmlSchemaBucketPtr bucket = NULL;
      int res;
  
      /*
      * This one is used if the schema to be parsed was specified via
      * the API; i.e. not automatically by the validated instance document.
      */
  
      xmlSchemaInitTypes();
  
      if (ctxt == NULL)
          return (NULL);
  
      /* TODO: Init the context. Is this all we need?*/
      ctxt->nberrors = 0;
      ctxt->err = 0;
      ctxt->counter = 0;
  
      /* Create the *main* schema. */
      mainSchema = xmlSchemaNewSchema(ctxt);
      if (mainSchema == NULL)
  	goto exit_failure;
      /*
      * Create the schema constructor.
      */
      if (ctxt->constructor == NULL) {
  	ctxt->constructor = xmlSchemaConstructionCtxtCreate(ctxt->dict);
  	if (ctxt->constructor == NULL)
  	    return(NULL);
  	/* Take ownership of the constructor to be able to free it. */
  	ctxt->ownsConstructor = 1;
      }
      ctxt->constructor->mainSchema = mainSchema;
      /*
      * Locate and add the schema document.
      */
      res = xmlSchemaAddSchemaDoc(ctxt, XML_SCHEMA_SCHEMA_MAIN,
  	ctxt->URL, ctxt->doc, ctxt->buffer, ctxt->size, NULL,
  	NULL, NULL, &bucket);
      if (res == -1)
  	goto exit_failure;
      if (res != 0)
  	goto exit;
  
      if (bucket == NULL) {
  	/* TODO: Error code, actually we failed to *locate* the schema. */
  	if (ctxt->URL)
  	    xmlSchemaCustomErr(ACTXT_CAST ctxt, XML_SCHEMAP_FAILED_LOAD,
  		NULL, NULL,
  		"Failed to locate the main schema resource at '%s'",
  		ctxt->URL, NULL);
  	else
  	    xmlSchemaCustomErr(ACTXT_CAST ctxt, XML_SCHEMAP_FAILED_LOAD,
  		NULL, NULL,
  		"Failed to locate the main schema resource",
  		    NULL, NULL);
  	goto exit;
      }
      /* Then do the parsing for good. */
      if (xmlSchemaParseNewDocWithContext(ctxt, mainSchema, bucket) == -1)
  	goto exit_failure;
      if (ctxt->nberrors != 0)
  	goto exit;
  
      mainSchema->doc = bucket->doc;
      mainSchema->preserve = ctxt->preserve;
  
      ctxt->schema = mainSchema;
  
      if (xmlSchemaFixupComponents(ctxt, WXS_CONSTRUCTOR(ctxt)->mainBucket) == -1)
  	goto exit_failure;
  
      /*
      * TODO: This is not nice, since we cannot distinguish from the
      * result if there was an internal error or not.
      */
  exit:
      if (ctxt->nberrors != 0) {
  	if (mainSchema) {
  	    xmlSchemaFree(mainSchema);
  	    mainSchema = NULL;
  	}
  	if (ctxt->constructor) {
  	    xmlSchemaConstructionCtxtFree(ctxt->constructor);
  	    ctxt->constructor = NULL;
  	    ctxt->ownsConstructor = 0;
  	}
      }
      ctxt->schema = NULL;
      return(mainSchema);
  exit_failure:
      /*
      * Quite verbose, but should catch internal errors, which were
      * not communicated.
      */
      if (mainSchema) {
          xmlSchemaFree(mainSchema);
  	mainSchema = NULL;
      }
      if (ctxt->constructor) {
  	xmlSchemaConstructionCtxtFree(ctxt->constructor);
  	ctxt->constructor = NULL;
  	ctxt->ownsConstructor = 0;
      }
      PERROR_INT2("xmlSchemaParse",
  	"An internal error occurred");
      ctxt->schema = NULL;
      return(NULL);
  }
  
  /**
   * xmlSchemaSetParserErrors:
   * @ctxt:  a schema validation context
   * @err:  the error callback
   * @warn:  the warning callback
   * @ctx:  contextual data for the callbacks
   *
   * Set the callback functions used to handle errors for a validation context
   */
  void
  xmlSchemaSetParserErrors(xmlSchemaParserCtxtPtr ctxt,
                           xmlSchemaValidityErrorFunc err,
                           xmlSchemaValidityWarningFunc warn, void *ctx)
  {
      if (ctxt == NULL)
          return;
      ctxt->error = err;
      ctxt->warning = warn;
      ctxt->errCtxt = ctx;
      if (ctxt->vctxt != NULL)
  	xmlSchemaSetValidErrors(ctxt->vctxt, err, warn, ctx);
  }
  
  /**
   * xmlSchemaSetParserStructuredErrors:
   * @ctxt:  a schema parser context
   * @serror:  the structured error function
   * @ctx: the functions context
   *
   * Set the structured error callback
   */
  void
  xmlSchemaSetParserStructuredErrors(xmlSchemaParserCtxtPtr ctxt,
  				   xmlStructuredErrorFunc serror,
  				   void *ctx)
  {
      if (ctxt == NULL)
  	return;
      ctxt->serror = serror;
      ctxt->errCtxt = ctx;
      if (ctxt->vctxt != NULL)
  	xmlSchemaSetValidStructuredErrors(ctxt->vctxt, serror, ctx);
  }
  
  /**
   * xmlSchemaGetParserErrors:
   * @ctxt:  a XMl-Schema parser context
   * @err: the error callback result
   * @warn: the warning callback result
   * @ctx: contextual data for the callbacks result
   *
   * Get the callback information used to handle errors for a parser context
   *
   * Returns -1 in case of failure, 0 otherwise
   */
  int
  xmlSchemaGetParserErrors(xmlSchemaParserCtxtPtr ctxt,
  			 xmlSchemaValidityErrorFunc * err,
  			 xmlSchemaValidityWarningFunc * warn, void **ctx)
  {
  	if (ctxt == NULL)
  		return(-1);
  	if (err != NULL)
  		*err = ctxt->error;
  	if (warn != NULL)
  		*warn = ctxt->warning;
  	if (ctx != NULL)
  		*ctx = ctxt->errCtxt;
  	return(0);
  }
  
  /**
   * xmlSchemaFacetTypeToString:
   * @type:  the facet type
   *
   * Convert the xmlSchemaTypeType to a char string.
   *
   * Returns the char string representation of the facet type if the
   *     type is a facet and an "Internal Error" string otherwise.
   */
  static const xmlChar *
  xmlSchemaFacetTypeToString(xmlSchemaTypeType type)
  {
      switch (type) {
          case XML_SCHEMA_FACET_PATTERN:
              return (BAD_CAST "pattern");
          case XML_SCHEMA_FACET_MAXEXCLUSIVE:
              return (BAD_CAST "maxExclusive");
          case XML_SCHEMA_FACET_MAXINCLUSIVE:
              return (BAD_CAST "maxInclusive");
          case XML_SCHEMA_FACET_MINEXCLUSIVE:
              return (BAD_CAST "minExclusive");
          case XML_SCHEMA_FACET_MININCLUSIVE:
              return (BAD_CAST "minInclusive");
          case XML_SCHEMA_FACET_WHITESPACE:
              return (BAD_CAST "whiteSpace");
          case XML_SCHEMA_FACET_ENUMERATION:
              return (BAD_CAST "enumeration");
          case XML_SCHEMA_FACET_LENGTH:
              return (BAD_CAST "length");
          case XML_SCHEMA_FACET_MAXLENGTH:
              return (BAD_CAST "maxLength");
          case XML_SCHEMA_FACET_MINLENGTH:
              return (BAD_CAST "minLength");
          case XML_SCHEMA_FACET_TOTALDIGITS:
              return (BAD_CAST "totalDigits");
          case XML_SCHEMA_FACET_FRACTIONDIGITS:
              return (BAD_CAST "fractionDigits");
          default:
              break;
      }
      return (BAD_CAST "Internal Error");
  }
  
  static xmlSchemaWhitespaceValueType
  xmlSchemaGetWhiteSpaceFacetValue(xmlSchemaTypePtr type)
  {
      /*
      * The normalization type can be changed only for types which are derived
      * from xsd:string.
      */
      if (type->type == XML_SCHEMA_TYPE_BASIC) {
  	/*
  	* Note that we assume a whitespace of preserve for anySimpleType.
  	*/
  	if ((type->builtInType == XML_SCHEMAS_STRING) ||
  	    (type->builtInType == XML_SCHEMAS_ANYSIMPLETYPE))
  	    return(XML_SCHEMA_WHITESPACE_PRESERVE);
  	else if (type->builtInType == XML_SCHEMAS_NORMSTRING)
  	    return(XML_SCHEMA_WHITESPACE_REPLACE);
  	else {
  	    /*
  	    * For all `atomic` datatypes other than string (and types `derived`
  	    * by `restriction` from it) the value of whiteSpace is fixed to
  	    * collapse
  	    * Note that this includes built-in list datatypes.
  	    */
  	    return(XML_SCHEMA_WHITESPACE_COLLAPSE);
  	}
      } else if (WXS_IS_LIST(type)) {
  	/*
  	* For list types the facet "whiteSpace" is fixed to "collapse".
  	*/
  	return (XML_SCHEMA_WHITESPACE_COLLAPSE);
      } else if (WXS_IS_UNION(type)) {
  	return (XML_SCHEMA_WHITESPACE_UNKNOWN);
      } else if (WXS_IS_ATOMIC(type)) {
  	if (type->flags & XML_SCHEMAS_TYPE_WHITESPACE_PRESERVE)
  	    return (XML_SCHEMA_WHITESPACE_PRESERVE);
  	else if (type->flags & XML_SCHEMAS_TYPE_WHITESPACE_REPLACE)
  	    return (XML_SCHEMA_WHITESPACE_REPLACE);
  	else
  	    return (XML_SCHEMA_WHITESPACE_COLLAPSE);
      }
      return (-1);
  }
  
  /************************************************************************
   *									*
   *			Simple type validation				*
   *									*
   ************************************************************************/
  
  
  /************************************************************************
   *									*
   *			DOM Validation code				*
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaAssembleByLocation:
   * @pctxt:  a schema parser context
   * @vctxt:  a schema validation context
   * @schema: the existing schema
   * @node: the node that fired the assembling
   * @nsName: the namespace name of the new schema
   * @location: the location of the schema
   *
   * Expands an existing schema by an additional schema.
   *
   * Returns 0 if the new schema is correct, a positive error code
   * number otherwise and -1 in case of an internal or API error.
   */
  static int
  xmlSchemaAssembleByLocation(xmlSchemaValidCtxtPtr vctxt,
  			    xmlSchemaPtr schema,
  			    xmlNodePtr node,
  			    const xmlChar *nsName,
  			    const xmlChar *location)
  {
      int ret = 0;
      xmlSchemaParserCtxtPtr pctxt;
      xmlSchemaBucketPtr bucket = NULL;
  
      if ((vctxt == NULL) || (schema == NULL))
  	return (-1);
  
      if (vctxt->pctxt == NULL) {
  	VERROR_INT("xmlSchemaAssembleByLocation",
  	    "no parser context available");
  	return(-1);
      }
      pctxt = vctxt->pctxt;
      if (pctxt->constructor == NULL) {
  	PERROR_INT("xmlSchemaAssembleByLocation",
  	    "no constructor");
  	return(-1);
      }
      /*
      * Acquire the schema document.
      */
      location = xmlSchemaBuildAbsoluteURI(pctxt->dict,
  	location, node);
      /*
      * Note that we pass XML_SCHEMA_SCHEMA_IMPORT here;
      * the process will automatically change this to
      * XML_SCHEMA_SCHEMA_MAIN if it is the first schema document.
      */
      ret = xmlSchemaAddSchemaDoc(pctxt, XML_SCHEMA_SCHEMA_IMPORT,
  	location, NULL, NULL, 0, node, NULL, nsName,
  	&bucket);
      if (ret != 0)
  	return(ret);
      if (bucket == NULL) {
  	/*
  	* Generate a warning that the document could not be located.
  	*/
  	xmlSchemaCustomWarning(ACTXT_CAST vctxt, XML_SCHEMAV_MISC,
  	    node, NULL,
  	    "The document at location '%s' could not be acquired",
  	    location, NULL, NULL);
  	return(ret);
      }
      /*
      * The first located schema will be handled as if all other
      * schemas imported by XSI were imported by this first schema.
      */
      if ((bucket != NULL) &&
  	(WXS_CONSTRUCTOR(pctxt)->bucket == NULL))
  	WXS_CONSTRUCTOR(pctxt)->bucket = bucket;
      /*
      * TODO: Is this handled like an import? I.e. is it not an error
      * if the schema cannot be located?
      */
      if ((bucket == NULL) || (! CAN_PARSE_SCHEMA(bucket)))
  	return(0);
      /*
      * We will reuse the parser context for every schema imported
      * directly via XSI. So reset the context.
      */
      pctxt->nberrors = 0;
      pctxt->err = 0;
      pctxt->doc = bucket->doc;
  
      ret = xmlSchemaParseNewDocWithContext(pctxt, schema, bucket);
      if (ret == -1) {
  	pctxt->doc = NULL;
  	goto exit_failure;
      }
      /* Paranoid error channelling. */
      if ((ret == 0) && (pctxt->nberrors != 0))
  	ret = pctxt->err;
      if (pctxt->nberrors == 0) {
  	/*
  	* Only bother to fixup pending components, if there was
  	* no error yet.
  	* For every XSI acquired schema (and its sub-schemata) we will
  	* fixup the components.
  	*/
  	xmlSchemaFixupComponents(pctxt, bucket);
  	ret = pctxt->err;
  	/*
  	* Not nice, but we need somehow to channel the schema parser
  	* error to the validation context.
  	*/
  	if ((ret != 0) && (vctxt->err == 0))
  	    vctxt->err = ret;
  	vctxt->nberrors += pctxt->nberrors;
      } else {
  	/* Add to validation error sum. */
  	vctxt->nberrors += pctxt->nberrors;
      }
      pctxt->doc = NULL;
      return(ret);
  exit_failure:
      pctxt->doc = NULL;
      return (-1);
  }
  
  static xmlSchemaAttrInfoPtr
  xmlSchemaGetMetaAttrInfo(xmlSchemaValidCtxtPtr vctxt,
  			 int metaType)
  {
      if (vctxt->nbAttrInfos == 0)
  	return (NULL);
      {
  	int i;
  	xmlSchemaAttrInfoPtr iattr;
  
  	for (i = 0; i < vctxt->nbAttrInfos; i++) {
  	    iattr = vctxt->attrInfos[i];
  	    if (iattr->metaType == metaType)
  		return (iattr);
  	}
  
      }
      return (NULL);
  }
  
  /**
   * xmlSchemaAssembleByXSI:
   * @vctxt:  a schema validation context
   *
   * Expands an existing schema by an additional schema using
   * the xsi:schemaLocation or xsi:noNamespaceSchemaLocation attribute
   * of an instance. If xsi:noNamespaceSchemaLocation is used, @noNamespace
   * must be set to 1.
   *
   * Returns 0 if the new schema is correct, a positive error code
   * number otherwise and -1 in case of an internal or API error.
   */
  static int
  xmlSchemaAssembleByXSI(xmlSchemaValidCtxtPtr vctxt)
  {
      const xmlChar *cur, *end;
      const xmlChar *nsname = NULL, *location;
      int count = 0;
      int ret = 0;
      xmlSchemaAttrInfoPtr iattr;
  
      /*
      * Parse the value; we will assume an even number of values
      * to be given (this is how Xerces and XSV work).
      *
      * URGENT TODO: !! This needs to work for both
      * @noNamespaceSchemaLocation AND @schemaLocation on the same
      * element !!
      */
      iattr = xmlSchemaGetMetaAttrInfo(vctxt,
  	XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC);
      if (iattr == NULL)
  	iattr = xmlSchemaGetMetaAttrInfo(vctxt,
  	XML_SCHEMA_ATTR_INFO_META_XSI_NO_NS_SCHEMA_LOC);
      if (iattr == NULL)
  	return (0);
      cur = iattr->value;
      do {
  	/*
  	* TODO: Move the string parsing mechanism away from here.
  	*/
  	if (iattr->metaType == XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC) {
  	    /*
  	    * Get the namespace name.
  	    */
  	    while (IS_BLANK_CH(*cur))
  		cur++;
  	    end = cur;
  	    while ((*end != 0) && (!(IS_BLANK_CH(*end))))
  		end++;
  	    if (end == cur)
  		break;
  	    count++; /* TODO: Don't use the schema's dict. */
  	    nsname = xmlDictLookup(vctxt->schema->dict, cur, end - cur);
  	    cur = end;
  	}
  	/*
  	* Get the URI.
  	*/
  	while (IS_BLANK_CH(*cur))
  	    cur++;
  	end = cur;
  	while ((*end != 0) && (!(IS_BLANK_CH(*end))))
  	    end++;
  	if (end == cur) {
  	    if (iattr->metaType ==
  		XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC)
  	    {
  		/*
  		* If using @schemaLocation then tuples are expected.
  		* I.e. the namespace name *and* the document's URI.
  		*/
  		xmlSchemaCustomWarning(ACTXT_CAST vctxt, XML_SCHEMAV_MISC,
  		    iattr->node, NULL,
  		    "The value must consist of tuples: the target namespace "
  		    "name and the document's URI", NULL, NULL, NULL);
  	    }
  	    break;
  	}
  	count++; /* TODO: Don't use the schema's dict. */
  	location = xmlDictLookup(vctxt->schema->dict, cur, end - cur);
  	cur = end;
  	ret = xmlSchemaAssembleByLocation(vctxt, vctxt->schema,
  	    iattr->node, nsname, location);
  	if (ret == -1) {
  	    VERROR_INT("xmlSchemaAssembleByXSI",
  		"assembling schemata");
  	    return (-1);
  	}
      } while (*cur != 0);
      return (ret);
  }
  
  static const xmlChar *
  xmlSchemaLookupNamespace(xmlSchemaValidCtxtPtr vctxt,
  			 const xmlChar *prefix)
  {
      if (vctxt->sax != NULL) {
  	int i, j;
  	xmlSchemaNodeInfoPtr inode;
  
  	for (i = vctxt->depth; i >= 0; i--) {
  	    if (vctxt->elemInfos[i]->nbNsBindings != 0) {
  		inode = vctxt->elemInfos[i];
  		for (j = 0; j < inode->nbNsBindings * 2; j += 2) {
  		    if (((prefix == NULL) &&
  			    (inode->nsBindings[j] == NULL)) ||
  			((prefix != NULL) && xmlStrEqual(prefix,
  			    inode->nsBindings[j]))) {
  
  			/*
  			* Note that the namespace bindings are already
  			* in a string dict.
  			*/
  			return (inode->nsBindings[j+1]);
  		    }
  		}
  	    }
  	}
  	return (NULL);
  #ifdef LIBXML_READER_ENABLED
      } else if (vctxt->reader != NULL) {
  	xmlChar *nsName;
  
  	nsName = xmlTextReaderLookupNamespace(vctxt->reader, prefix);
  	if (nsName != NULL) {
  	    const xmlChar *ret;
  
  	    ret = xmlDictLookup(vctxt->dict, nsName, -1);
  	    xmlFree(nsName);
  	    return (ret);
  	} else
  	    return (NULL);
  #endif
      } else {
  	xmlNsPtr ns;
  
  	if ((vctxt->inode->node == NULL) ||
  	    (vctxt->inode->node->doc == NULL)) {
  	    VERROR_INT("xmlSchemaLookupNamespace",
  		"no node or node's doc available");
  	    return (NULL);
  	}
  	ns = xmlSearchNs(vctxt->inode->node->doc,
  	    vctxt->inode->node, prefix);
  	if (ns != NULL)
  	    return (ns->href);
  	return (NULL);
      }
  }
  
  /*
  * This one works on the schema of the validation context.
  */
  static int
  xmlSchemaValidateNotation(xmlSchemaValidCtxtPtr vctxt,
  			  xmlSchemaPtr schema,
  			  xmlNodePtr node,
  			  const xmlChar *value,
  			  xmlSchemaValPtr *val,
  			  int valNeeded)
  {
      int ret;
  
      if (vctxt && (vctxt->schema == NULL)) {
  	VERROR_INT("xmlSchemaValidateNotation",
  	    "a schema is needed on the validation context");
  	return (-1);
      }
      ret = xmlValidateQName(value, 1);
      if (ret != 0)
  	return (ret);
      {
  	xmlChar *localName = NULL;
  	xmlChar *prefix = NULL;
  
  	localName = xmlSplitQName2(value, &prefix);
  	if (prefix != NULL) {
  	    const xmlChar *nsName = NULL;
  
  	    if (vctxt != NULL)
  		nsName = xmlSchemaLookupNamespace(vctxt, BAD_CAST prefix);
  	    else if (node != NULL) {
  		xmlNsPtr ns = xmlSearchNs(node->doc, node, prefix);
  		if (ns != NULL)
  		    nsName = ns->href;
  	    } else {
  		xmlFree(prefix);
  		xmlFree(localName);
  		return (1);
  	    }
  	    if (nsName == NULL) {
  		xmlFree(prefix);
  		xmlFree(localName);
  		return (1);
  	    }
  	    if (xmlSchemaGetNotation(schema, localName, nsName) != NULL) {
  		if ((valNeeded) && (val != NULL)) {
  		    (*val) = xmlSchemaNewNOTATIONValue(xmlStrdup(localName),
  						       xmlStrdup(nsName));
  		    if (*val == NULL)
  			ret = -1;
  		}
  	    } else
  		ret = 1;
  	    xmlFree(prefix);
  	    xmlFree(localName);
  	} else {
  	    if (xmlSchemaGetNotation(schema, value, NULL) != NULL) {
  		if (valNeeded && (val != NULL)) {
  		    (*val) = xmlSchemaNewNOTATIONValue(
  			BAD_CAST xmlStrdup(value), NULL);
  		    if (*val == NULL)
  			ret = -1;
  		}
  	    } else
  		return (1);
  	}
      }
      return (ret);
  }
  
  static int
  xmlSchemaVAddNodeQName(xmlSchemaValidCtxtPtr vctxt,
  		       const xmlChar* lname,
  		       const xmlChar* nsname)
  {
      int i;
  
      lname = xmlDictLookup(vctxt->dict, lname, -1);
      if (lname == NULL)
  	return(-1);
      if (nsname != NULL) {
  	nsname = xmlDictLookup(vctxt->dict, nsname, -1);
  	if (nsname == NULL)
  	    return(-1);
      }
      for (i = 0; i < vctxt->nodeQNames->nbItems; i += 2) {
  	if ((vctxt->nodeQNames->items [i] == lname) &&
  	    (vctxt->nodeQNames->items[i +1] == nsname))
  	    /* Already there */
  	    return(i);
      }
      /* Add new entry. */
      i = vctxt->nodeQNames->nbItems;
      xmlSchemaItemListAdd(vctxt->nodeQNames, (void *) lname);
      xmlSchemaItemListAdd(vctxt->nodeQNames, (void *) nsname);
      return(i);
  }
  
  /************************************************************************
   *									*
   *  Validation of identity-constraints (IDC)                            *
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaAugmentIDC:
   * @idcDef: the IDC definition
   *
   * Creates an augmented IDC definition item.
   *
   * Returns the item, or NULL on internal errors.
   */
  static void
  xmlSchemaAugmentIDC(void *payload, void *data,
                      const xmlChar *name ATTRIBUTE_UNUSED)
  {
      xmlSchemaIDCPtr idcDef = (xmlSchemaIDCPtr) payload;
      xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) data;
      xmlSchemaIDCAugPtr aidc;
  
      aidc = (xmlSchemaIDCAugPtr) xmlMalloc(sizeof(xmlSchemaIDCAug));
      if (aidc == NULL) {
  	xmlSchemaVErrMemory(vctxt,
  	    "xmlSchemaAugmentIDC: allocating an augmented IDC definition",
  	    NULL);
  	return;
      }
      aidc->keyrefDepth = -1;
      aidc->def = idcDef;
      aidc->next = NULL;
      if (vctxt->aidcs == NULL)
  	vctxt->aidcs = aidc;
      else {
  	aidc->next = vctxt->aidcs;
  	vctxt->aidcs = aidc;
      }
      /*
      * Save if we have keyrefs at all.
      */
      if ((vctxt->hasKeyrefs == 0) &&
  	(idcDef->type == XML_SCHEMA_TYPE_IDC_KEYREF))
  	vctxt->hasKeyrefs = 1;
  }
  
  /**
   * xmlSchemaAugmentImportedIDC:
   * @imported: the imported schema
   *
   * Creates an augmented IDC definition for the imported schema.
   */
  static void
  xmlSchemaAugmentImportedIDC(void *payload, void *data,
                              const xmlChar *name ATTRIBUTE_UNUSED) {
      xmlSchemaImportPtr imported = (xmlSchemaImportPtr) payload;
      xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) data;
      if (imported->schema->idcDef != NULL) {
  	    xmlHashScan(imported->schema->idcDef, xmlSchemaAugmentIDC, vctxt);
      }
  }
  
  /**
   * xmlSchemaIDCNewBinding:
   * @idcDef: the IDC definition of this binding
   *
   * Creates a new IDC binding.
   *
   * Returns the new IDC binding, NULL on internal errors.
   */
  static xmlSchemaPSVIIDCBindingPtr
  xmlSchemaIDCNewBinding(xmlSchemaIDCPtr idcDef)
  {
      xmlSchemaPSVIIDCBindingPtr ret;
  
      ret = (xmlSchemaPSVIIDCBindingPtr) xmlMalloc(
  	    sizeof(xmlSchemaPSVIIDCBinding));
      if (ret == NULL) {
  	xmlSchemaVErrMemory(NULL,
  	    "allocating a PSVI IDC binding item", NULL);
  	return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaPSVIIDCBinding));
      ret->definition = idcDef;
      return (ret);
  }
  
  /**
   * xmlSchemaIDCStoreNodeTableItem:
   * @vctxt: the WXS validation context
   * @item: the IDC node table item
   *
   * The validation context is used to store IDC node table items.
   * They are stored to avoid copying them if IDC node-tables are merged
   * with corresponding parent IDC node-tables (bubbling).
   *
   * Returns 0 if succeeded, -1 on internal errors.
   */
  static int
  xmlSchemaIDCStoreNodeTableItem(xmlSchemaValidCtxtPtr vctxt,
  			       xmlSchemaPSVIIDCNodePtr item)
  {
      /*
      * Add to global list.
      */
      if (vctxt->idcNodes == NULL) {
  	vctxt->idcNodes = (xmlSchemaPSVIIDCNodePtr *)
  	    xmlMalloc(20 * sizeof(xmlSchemaPSVIIDCNodePtr));
  	if (vctxt->idcNodes == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"allocating the IDC node table item list", NULL);
  	    return (-1);
  	}
  	vctxt->sizeIdcNodes = 20;
      } else if (vctxt->sizeIdcNodes <= vctxt->nbIdcNodes) {
  	vctxt->sizeIdcNodes *= 2;
  	vctxt->idcNodes = (xmlSchemaPSVIIDCNodePtr *)
  	    xmlRealloc(vctxt->idcNodes, vctxt->sizeIdcNodes *
  	    sizeof(xmlSchemaPSVIIDCNodePtr));
  	if (vctxt->idcNodes == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"re-allocating the IDC node table item list", NULL);
  	    return (-1);
  	}
      }
      vctxt->idcNodes[vctxt->nbIdcNodes++] = item;
  
      return (0);
  }
  
  /**
   * xmlSchemaIDCStoreKey:
   * @vctxt: the WXS validation context
   * @item: the IDC key
   *
   * The validation context is used to store an IDC key.
   *
   * Returns 0 if succeeded, -1 on internal errors.
   */
  static int
  xmlSchemaIDCStoreKey(xmlSchemaValidCtxtPtr vctxt,
  		     xmlSchemaPSVIIDCKeyPtr key)
  {
      /*
      * Add to global list.
      */
      if (vctxt->idcKeys == NULL) {
  	vctxt->idcKeys = (xmlSchemaPSVIIDCKeyPtr *)
  	    xmlMalloc(40 * sizeof(xmlSchemaPSVIIDCKeyPtr));
  	if (vctxt->idcKeys == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"allocating the IDC key storage list", NULL);
  	    return (-1);
  	}
  	vctxt->sizeIdcKeys = 40;
      } else if (vctxt->sizeIdcKeys <= vctxt->nbIdcKeys) {
  	vctxt->sizeIdcKeys *= 2;
  	vctxt->idcKeys = (xmlSchemaPSVIIDCKeyPtr *)
  	    xmlRealloc(vctxt->idcKeys, vctxt->sizeIdcKeys *
  	    sizeof(xmlSchemaPSVIIDCKeyPtr));
  	if (vctxt->idcKeys == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"re-allocating the IDC key storage list", NULL);
  	    return (-1);
  	}
      }
      vctxt->idcKeys[vctxt->nbIdcKeys++] = key;
  
      return (0);
  }
  
  /**
   * xmlSchemaIDCAppendNodeTableItem:
   * @bind: the IDC binding
   * @ntItem: the node-table item
   *
   * Appends the IDC node-table item to the binding.
   *
   * Returns 0 on success and -1 on internal errors.
   */
  static int
  xmlSchemaIDCAppendNodeTableItem(xmlSchemaPSVIIDCBindingPtr bind,
  				xmlSchemaPSVIIDCNodePtr ntItem)
  {
      if (bind->nodeTable == NULL) {
  	bind->sizeNodes = 10;
  	bind->nodeTable = (xmlSchemaPSVIIDCNodePtr *)
  	    xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr));
  	if (bind->nodeTable == NULL) {
  	    xmlSchemaVErrMemory(NULL,
  		"allocating an array of IDC node-table items", NULL);
  	    return(-1);
  	}
      } else if (bind->sizeNodes <= bind->nbNodes) {
  	bind->sizeNodes *= 2;
  	bind->nodeTable = (xmlSchemaPSVIIDCNodePtr *)
  	    xmlRealloc(bind->nodeTable, bind->sizeNodes *
  		sizeof(xmlSchemaPSVIIDCNodePtr));
  	if (bind->nodeTable == NULL) {
  	    xmlSchemaVErrMemory(NULL,
  		"re-allocating an array of IDC node-table items", NULL);
  	    return(-1);
  	}
      }
      bind->nodeTable[bind->nbNodes++] = ntItem;
      return(0);
  }
  
  /**
   * xmlSchemaIDCAcquireBinding:
   * @vctxt: the WXS validation context
   * @matcher: the IDC matcher
   *
   * Looks up an PSVI IDC binding, for the IDC definition and
   * of the given matcher. If none found, a new one is created
   * and added to the IDC table.
   *
   * Returns an IDC binding or NULL on internal errors.
   */
  static xmlSchemaPSVIIDCBindingPtr
  xmlSchemaIDCAcquireBinding(xmlSchemaValidCtxtPtr vctxt,
  			  xmlSchemaIDCMatcherPtr matcher)
  {
      xmlSchemaNodeInfoPtr ielem;
  
      ielem = vctxt->elemInfos[matcher->depth];
  
      if (ielem->idcTable == NULL) {
  	ielem->idcTable = xmlSchemaIDCNewBinding(matcher->aidc->def);
  	if (ielem->idcTable == NULL)
  	    return (NULL);
  	return(ielem->idcTable);
      } else {
  	xmlSchemaPSVIIDCBindingPtr bind = NULL;
  
  	bind = ielem->idcTable;
  	do {
  	    if (bind->definition == matcher->aidc->def)
  		return(bind);
  	    if (bind->next == NULL) {
  		bind->next = xmlSchemaIDCNewBinding(matcher->aidc->def);
  		if (bind->next == NULL)
  		    return (NULL);
  		return(bind->next);
  	    }
  	    bind = bind->next;
  	} while (bind != NULL);
      }
      return (NULL);
  }
  
  static xmlSchemaItemListPtr
  xmlSchemaIDCAcquireTargetList(xmlSchemaValidCtxtPtr vctxt ATTRIBUTE_UNUSED,
  			     xmlSchemaIDCMatcherPtr matcher)
  {
      if (matcher->targets == NULL)
  	matcher->targets = xmlSchemaItemListCreate();
      return(matcher->targets);
  }
  
  /**
   * xmlSchemaIDCFreeKey:
   * @key: the IDC key
   *
   * Frees an IDC key together with its compiled value.
   */
  static void
  xmlSchemaIDCFreeKey(xmlSchemaPSVIIDCKeyPtr key)
  {
      if (key->val != NULL)
  	xmlSchemaFreeValue(key->val);
      xmlFree(key);
  }
  
  /**
   * xmlSchemaIDCFreeBinding:
   *
   * Frees an IDC binding. Note that the node table-items
   * are not freed.
   */
  static void
  xmlSchemaIDCFreeBinding(xmlSchemaPSVIIDCBindingPtr bind)
  {
      if (bind->nodeTable != NULL)
  	xmlFree(bind->nodeTable);
      if (bind->dupls != NULL)
  	xmlSchemaItemListFree(bind->dupls);
      xmlFree(bind);
  }
  
  /**
   * xmlSchemaIDCFreeIDCTable:
   * @bind: the first IDC binding in the list
   *
   * Frees an IDC table, i.e. all the IDC bindings in the list.
   */
  static void
  xmlSchemaIDCFreeIDCTable(xmlSchemaPSVIIDCBindingPtr bind)
  {
      xmlSchemaPSVIIDCBindingPtr prev;
  
      while (bind != NULL) {
  	prev = bind;
  	bind = bind->next;
  	xmlSchemaIDCFreeBinding(prev);
      }
  }
  
  /**
   * xmlSchemaIDCFreeMatcherList:
   * @matcher: the first IDC matcher in the list
   *
   * Frees a list of IDC matchers.
   */
  static void
  xmlSchemaIDCFreeMatcherList(xmlSchemaIDCMatcherPtr matcher)
  {
      xmlSchemaIDCMatcherPtr next;
  
      while (matcher != NULL) {
  	next = matcher->next;
  	if (matcher->keySeqs != NULL) {
  	    int i;
  	    for (i = 0; i < matcher->sizeKeySeqs; i++)
  		if (matcher->keySeqs[i] != NULL)
  		    xmlFree(matcher->keySeqs[i]);
  	    xmlFree(matcher->keySeqs);
  	}
  	if (matcher->targets != NULL) {
  	    if (matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) {
  		int i;
  		xmlSchemaPSVIIDCNodePtr idcNode;
  		/*
  		* Node-table items for keyrefs are not stored globally
  		* to the validation context, since they are not bubbled.
  		* We need to free them here.
  		*/
  		for (i = 0; i < matcher->targets->nbItems; i++) {
  		    idcNode =
  			(xmlSchemaPSVIIDCNodePtr) matcher->targets->items[i];
  		    xmlFree(idcNode->keys);
  		    xmlFree(idcNode);
  		}
  	    }
  	    xmlSchemaItemListFree(matcher->targets);
  	}
  	xmlFree(matcher);
  	matcher = next;
      }
  }
  
  /**
   * xmlSchemaIDCReleaseMatcherList:
   * @vctxt: the WXS validation context
   * @matcher: the first IDC matcher in the list
   *
   * Caches a list of IDC matchers for reuse.
   */
  static void
  xmlSchemaIDCReleaseMatcherList(xmlSchemaValidCtxtPtr vctxt,
  			       xmlSchemaIDCMatcherPtr matcher)
  {
      xmlSchemaIDCMatcherPtr next;
  
      while (matcher != NULL) {
  	next = matcher->next;
  	if (matcher->keySeqs != NULL) {
  	    int i;
  	    /*
  	    * Don't free the array, but only the content.
  	    */
  	    for (i = 0; i < matcher->sizeKeySeqs; i++)
  		if (matcher->keySeqs[i] != NULL) {
  		    xmlFree(matcher->keySeqs[i]);
  		    matcher->keySeqs[i] = NULL;
  		}
  	}
  	if (matcher->targets) {
  	    if (matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) {
  		int i;
  		xmlSchemaPSVIIDCNodePtr idcNode;
  		/*
  		* Node-table items for keyrefs are not stored globally
  		* to the validation context, since they are not bubbled.
  		* We need to free them here.
  		*/
  		for (i = 0; i < matcher->targets->nbItems; i++) {
  		    idcNode =
  			(xmlSchemaPSVIIDCNodePtr) matcher->targets->items[i];
  		    xmlFree(idcNode->keys);
  		    xmlFree(idcNode);
  		}
  	    }
  	    xmlSchemaItemListFree(matcher->targets);
  	    matcher->targets = NULL;
  	}
  	matcher->next = NULL;
  	/*
  	* Cache the matcher.
  	*/
  	if (vctxt->idcMatcherCache != NULL)
  	    matcher->nextCached = vctxt->idcMatcherCache;
  	vctxt->idcMatcherCache = matcher;
  
  	matcher = next;
      }
  }
  
  /**
   * xmlSchemaIDCAddStateObject:
   * @vctxt: the WXS validation context
   * @matcher: the IDC matcher
   * @sel: the XPath information
   * @parent: the parent "selector" state object if any
   * @type: "selector" or "field"
   *
   * Creates/reuses and activates state objects for the given
   * XPath information; if the XPath expression consists of unions,
   * multiple state objects are created for every unioned expression.
   *
   * Returns 0 on success and -1 on internal errors.
   */
  static int
  xmlSchemaIDCAddStateObject(xmlSchemaValidCtxtPtr vctxt,
  			xmlSchemaIDCMatcherPtr matcher,
  			xmlSchemaIDCSelectPtr sel,
  			int type)
  {
      xmlSchemaIDCStateObjPtr sto;
  
      /*
      * Reuse the state objects from the pool.
      */
      if (vctxt->xpathStatePool != NULL) {
  	sto = vctxt->xpathStatePool;
  	vctxt->xpathStatePool = sto->next;
  	sto->next = NULL;
      } else {
  	/*
  	* Create a new state object.
  	*/
  	sto = (xmlSchemaIDCStateObjPtr) xmlMalloc(sizeof(xmlSchemaIDCStateObj));
  	if (sto == NULL) {
  	    xmlSchemaVErrMemory(NULL,
  		"allocating an IDC state object", NULL);
  	    return (-1);
  	}
  	memset(sto, 0, sizeof(xmlSchemaIDCStateObj));
      }
      /*
      * Add to global list.
      */
      if (vctxt->xpathStates != NULL)
  	sto->next = vctxt->xpathStates;
      vctxt->xpathStates = sto;
  
      /*
      * Free the old xpath validation context.
      */
      if (sto->xpathCtxt != NULL)
  	xmlFreeStreamCtxt((xmlStreamCtxtPtr) sto->xpathCtxt);
  
      /*
      * Create a new XPath (pattern) validation context.
      */
      sto->xpathCtxt = (void *) xmlPatternGetStreamCtxt(
  	(xmlPatternPtr) sel->xpathComp);
      if (sto->xpathCtxt == NULL) {
  	VERROR_INT("xmlSchemaIDCAddStateObject",
  	    "failed to create an XPath validation context");
  	return (-1);
      }
      sto->type = type;
      sto->depth = vctxt->depth;
      sto->matcher = matcher;
      sto->sel = sel;
      sto->nbHistory = 0;
  
  #ifdef DEBUG_IDC
      xmlGenericError(xmlGenericErrorContext, "IDC:   STO push '%s'\n",
  	sto->sel->xpath);
  #endif
      return (0);
  }
  
  /**
   * xmlSchemaXPathEvaluate:
   * @vctxt: the WXS validation context
   * @nodeType: the nodeType of the current node
   *
   * Evaluates all active XPath state objects.
   *
   * Returns the number of IC "field" state objects which resolved to
   * this node, 0 if none resolved and -1 on internal errors.
   */
  static int
  xmlSchemaXPathEvaluate(xmlSchemaValidCtxtPtr vctxt,
  		       xmlElementType nodeType)
  {
      xmlSchemaIDCStateObjPtr sto, head = NULL, first;
      int res, resolved = 0, depth = vctxt->depth;
  
      if (vctxt->xpathStates == NULL)
  	return (0);
  
      if (nodeType == XML_ATTRIBUTE_NODE)
  	depth++;
  #ifdef DEBUG_IDC
      {
  	xmlChar *str = NULL;
  	xmlGenericError(xmlGenericErrorContext,
  	    "IDC: EVAL on %s, depth %d, type %d\n",
  	    xmlSchemaFormatQName(&str, vctxt->inode->nsName,
  		vctxt->inode->localName), depth, nodeType);
  	FREE_AND_NULL(str)
      }
  #endif
      /*
      * Process all active XPath state objects.
      */
      first = vctxt->xpathStates;
      sto = first;
      while (sto != head) {
  #ifdef DEBUG_IDC
  	if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR)
  	    xmlGenericError(xmlGenericErrorContext, "IDC:   ['%s'] selector '%s'\n",
  		sto->matcher->aidc->def->name, sto->sel->xpath);
  	else
  	    xmlGenericError(xmlGenericErrorContext, "IDC:   ['%s'] field '%s'\n",
  		sto->matcher->aidc->def->name, sto->sel->xpath);
  #endif
  	if (nodeType == XML_ELEMENT_NODE)
  	    res = xmlStreamPush((xmlStreamCtxtPtr) sto->xpathCtxt,
  		vctxt->inode->localName, vctxt->inode->nsName);
  	else
  	    res = xmlStreamPushAttr((xmlStreamCtxtPtr) sto->xpathCtxt,
  		vctxt->inode->localName, vctxt->inode->nsName);
  
  	if (res == -1) {
  	    VERROR_INT("xmlSchemaXPathEvaluate",
  		"calling xmlStreamPush()");
  	    return (-1);
  	}
  	if (res == 0)
  	    goto next_sto;
  	/*
  	* Full match.
  	*/
  #ifdef DEBUG_IDC
  	xmlGenericError(xmlGenericErrorContext, "IDC:     "
  	    "MATCH\n");
  #endif
  	/*
  	* Register a match in the state object history.
  	*/
  	if (sto->history == NULL) {
  	    sto->history = (int *) xmlMalloc(5 * sizeof(int));
  	    if (sto->history == NULL) {
  		xmlSchemaVErrMemory(NULL,
  		    "allocating the state object history", NULL);
  		return(-1);
  	    }
  	    sto->sizeHistory = 5;
  	} else if (sto->sizeHistory <= sto->nbHistory) {
  	    sto->sizeHistory *= 2;
  	    sto->history = (int *) xmlRealloc(sto->history,
  		sto->sizeHistory * sizeof(int));
  	    if (sto->history == NULL) {
  		xmlSchemaVErrMemory(NULL,
  		    "re-allocating the state object history", NULL);
  		return(-1);
  	    }
  	}
  	sto->history[sto->nbHistory++] = depth;
  
  #ifdef DEBUG_IDC
  	xmlGenericError(xmlGenericErrorContext, "IDC:       push match '%d'\n",
  	    vctxt->depth);
  #endif
  
  	if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) {
  	    xmlSchemaIDCSelectPtr sel;
  	    /*
  	    * Activate state objects for the IDC fields of
  	    * the IDC selector.
  	    */
  #ifdef DEBUG_IDC
  	    xmlGenericError(xmlGenericErrorContext, "IDC:     "
  		"activating field states\n");
  #endif
  	    sel = sto->matcher->aidc->def->fields;
  	    while (sel != NULL) {
  		if (xmlSchemaIDCAddStateObject(vctxt, sto->matcher,
  		    sel, XPATH_STATE_OBJ_TYPE_IDC_FIELD) == -1)
  		    return (-1);
  		sel = sel->next;
  	    }
  	} else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) {
  	    /*
  	    * An IDC key node was found by the IDC field.
  	    */
  #ifdef DEBUG_IDC
  	    xmlGenericError(xmlGenericErrorContext,
  		"IDC:     key found\n");
  #endif
  	    /*
  	    * Notify that the character value of this node is
  	    * needed.
  	    */
  	    if (resolved == 0) {
  		if ((vctxt->inode->flags &
  		    XML_SCHEMA_NODE_INFO_VALUE_NEEDED) == 0)
  		vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_VALUE_NEEDED;
  	    }
  	    resolved++;
  	}
  next_sto:
  	if (sto->next == NULL) {
  	    /*
  	    * Evaluate field state objects created on this node as well.
  	    */
  	    head = first;
  	    sto = vctxt->xpathStates;
  	} else
  	    sto = sto->next;
      }
      return (resolved);
  }
  
  static const xmlChar *
  xmlSchemaFormatIDCKeySequence(xmlSchemaValidCtxtPtr vctxt,
  			      xmlChar **buf,
  			      xmlSchemaPSVIIDCKeyPtr *seq,
  			      int count)
  {
      int i, res;
      xmlChar *value = NULL;
  
      *buf = xmlStrdup(BAD_CAST "[");
      for (i = 0; i < count; i++) {
  	*buf = xmlStrcat(*buf, BAD_CAST "'");
  	res = xmlSchemaGetCanonValueWhtspExt(seq[i]->val,
  	    xmlSchemaGetWhiteSpaceFacetValue(seq[i]->type),
  	    &value);
  	if (res == 0)
  	    *buf = xmlStrcat(*buf, BAD_CAST value);
  	else {
  	    VERROR_INT("xmlSchemaFormatIDCKeySequence",
  		"failed to compute a canonical value");
  	    *buf = xmlStrcat(*buf, BAD_CAST "???");
  	}
  	if (i < count -1)
  	    *buf = xmlStrcat(*buf, BAD_CAST "', ");
  	else
  	    *buf = xmlStrcat(*buf, BAD_CAST "'");
  	if (value != NULL) {
  	    xmlFree(value);
  	    value = NULL;
  	}
      }
      *buf = xmlStrcat(*buf, BAD_CAST "]");
  
      return (BAD_CAST *buf);
  }
  
  /**
   * xmlSchemaXPathPop:
   * @vctxt: the WXS validation context
   *
   * Pops all XPath states.
   *
   * Returns 0 on success and -1 on internal errors.
   */
  static int
  xmlSchemaXPathPop(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaIDCStateObjPtr sto;
      int res;
  
      if (vctxt->xpathStates == NULL)
  	return(0);
      sto = vctxt->xpathStates;
      do {
  	res = xmlStreamPop((xmlStreamCtxtPtr) sto->xpathCtxt);
  	if (res == -1)
  	    return (-1);
  	sto = sto->next;
      } while (sto != NULL);
      return(0);
  }
  
  /**
   * xmlSchemaXPathProcessHistory:
   * @vctxt: the WXS validation context
   * @type: the simple/complex type of the current node if any at all
   * @val: the precompiled value
   *
   * Processes and pops the history items of the IDC state objects.
   * IDC key-sequences are validated/created on IDC bindings.
   *
   * Returns 0 on success and -1 on internal errors.
   */
  static int
  xmlSchemaXPathProcessHistory(xmlSchemaValidCtxtPtr vctxt,
  			     int depth)
  {
      xmlSchemaIDCStateObjPtr sto, nextsto;
      int res, matchDepth;
      xmlSchemaPSVIIDCKeyPtr key = NULL;
      xmlSchemaTypePtr type = vctxt->inode->typeDef, simpleType = NULL;
  
      if (vctxt->xpathStates == NULL)
  	return (0);
      sto = vctxt->xpathStates;
  
  #ifdef DEBUG_IDC
      {
  	xmlChar *str = NULL;
  	xmlGenericError(xmlGenericErrorContext,
  	    "IDC: BACK on %s, depth %d\n",
  	    xmlSchemaFormatQName(&str, vctxt->inode->nsName,
  		vctxt->inode->localName), vctxt->depth);
  	FREE_AND_NULL(str)
      }
  #endif
      /*
      * Evaluate the state objects.
      */
      while (sto != NULL) {
  	res = xmlStreamPop((xmlStreamCtxtPtr) sto->xpathCtxt);
  	if (res == -1) {
  	    VERROR_INT("xmlSchemaXPathProcessHistory",
  		"calling xmlStreamPop()");
  	    return (-1);
  	}
  #ifdef DEBUG_IDC
  	xmlGenericError(xmlGenericErrorContext, "IDC:   stream pop '%s'\n",
  	    sto->sel->xpath);
  #endif
  	if (sto->nbHistory == 0)
  	    goto deregister_check;
  
  	matchDepth = sto->history[sto->nbHistory -1];
  
  	/*
  	* Only matches at the current depth are of interest.
  	*/
  	if (matchDepth != depth) {
  	    sto = sto->next;
  	    continue;
  	}
  	if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_FIELD) {
  	    /*
  	    * NOTE: According to
  	    *   http://www.w3.org/Bugs/Public/show_bug.cgi?id=2198
  	    *   ... the simple-content of complex types is also allowed.
  	    */
  
  	    if (WXS_IS_COMPLEX(type)) {
  		if (WXS_HAS_SIMPLE_CONTENT(type)) {
  		    /*
  		    * Sanity check for complex types with simple content.
  		    */
  		    simpleType = type->contentTypeDef;
  		    if (simpleType == NULL) {
  			VERROR_INT("xmlSchemaXPathProcessHistory",
  			    "field resolves to a CT with simple content "
  			    "but the CT is missing the ST definition");
  			return (-1);
  		    }
  		} else
  		    simpleType = NULL;
  	    } else
  		simpleType = type;
  	    if (simpleType == NULL) {
  		xmlChar *str = NULL;
  
  		/*
  		* Not qualified if the field resolves to a node of non
  		* simple type.
  		*/
  		xmlSchemaCustomErr(ACTXT_CAST vctxt,
  		    XML_SCHEMAV_CVC_IDC, NULL,
  		    WXS_BASIC_CAST sto->matcher->aidc->def,
  		    "The XPath '%s' of a field of %s does evaluate to a node of "
  		    "non-simple type",
  		    sto->sel->xpath,
  		    xmlSchemaGetIDCDesignation(&str, sto->matcher->aidc->def));
  		FREE_AND_NULL(str);
  		sto->nbHistory--;
  		goto deregister_check;
  	    }
  
  	    if ((key == NULL) && (vctxt->inode->val == NULL)) {
  		/*
  		* Failed to provide the normalized value; maybe
  		* the value was invalid.
  		*/
  		VERROR(XML_SCHEMAV_CVC_IDC,
  		    WXS_BASIC_CAST sto->matcher->aidc->def,
  		    "Warning: No precomputed value available, the value "
  		    "was either invalid or something strange happened");
  		sto->nbHistory--;
  		goto deregister_check;
  	    } else {
  		xmlSchemaIDCMatcherPtr matcher = sto->matcher;
  		xmlSchemaPSVIIDCKeyPtr *keySeq;
  		int pos, idx;
  
  		/*
  		* The key will be anchored on the matcher's list of
  		* key-sequences. The position in this list is determined
  		* by the target node's depth relative to the matcher's
  		* depth of creation (i.e. the depth of the scope element).
  		*
  		* Element        Depth    Pos   List-entries
  		* <scope>          0              NULL
  		*   <bar>          1              NULL
  		*     <target/>    2       2      target
  		*   <bar>
                  * </scope>
  		*
  		* The size of the list is only dependent on the depth of
  		* the tree.
  		* An entry will be NULLed in selector_leave, i.e. when
  		* we hit the target's
  		*/
  		pos = sto->depth - matcher->depth;
  		idx = sto->sel->index;
  
  		/*
  		* Create/grow the array of key-sequences.
  		*/
  		if (matcher->keySeqs == NULL) {
  		    if (pos > 9)
  			matcher->sizeKeySeqs = pos * 2;
  		    else
  			matcher->sizeKeySeqs = 10;
  		    matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **)
  			xmlMalloc(matcher->sizeKeySeqs *
  			sizeof(xmlSchemaPSVIIDCKeyPtr *));
  		    if (matcher->keySeqs == NULL) {
  			xmlSchemaVErrMemory(NULL,
  			    "allocating an array of key-sequences",
  			    NULL);
  			return(-1);
  		    }
  		    memset(matcher->keySeqs, 0,
  			matcher->sizeKeySeqs *
  			sizeof(xmlSchemaPSVIIDCKeyPtr *));
  		} else if (pos >= matcher->sizeKeySeqs) {
  		    int i = matcher->sizeKeySeqs;
  
  		    matcher->sizeKeySeqs *= 2;
  		    matcher->keySeqs = (xmlSchemaPSVIIDCKeyPtr **)
  			xmlRealloc(matcher->keySeqs,
  			matcher->sizeKeySeqs *
  			sizeof(xmlSchemaPSVIIDCKeyPtr *));
  		    if (matcher->keySeqs == NULL) {
  			xmlSchemaVErrMemory(NULL,
  			    "reallocating an array of key-sequences",
  			    NULL);
  			return (-1);
  		    }
  		    /*
  		    * The array needs to be NULLed.
  		    * TODO: Use memset?
  		    */
  		    for (; i < matcher->sizeKeySeqs; i++)
  			matcher->keySeqs[i] = NULL;
  		}
  
  		/*
  		* Get/create the key-sequence.
  		*/
  		keySeq = matcher->keySeqs[pos];
  		if (keySeq == NULL) {
  		    goto create_sequence;
  		} else if (keySeq[idx] != NULL) {
  		    xmlChar *str = NULL;
  		    /*
  		    * cvc-identity-constraint:
  		    * 3 For each node in the `target node set` all
  		    * of the {fields}, with that node as the context
  		    * node, evaluate to either an empty node-set or
  		    * a node-set with exactly one member, which must
  		    * have a simple type.
  		    *
  		    * The key was already set; report an error.
  		    */
  		    xmlSchemaCustomErr(ACTXT_CAST vctxt,
  			XML_SCHEMAV_CVC_IDC, NULL,
  			WXS_BASIC_CAST matcher->aidc->def,
  			"The XPath '%s' of a field of %s evaluates to a "
  			"node-set with more than one member",
  			sto->sel->xpath,
  			xmlSchemaGetIDCDesignation(&str, matcher->aidc->def));
  		    FREE_AND_NULL(str);
  		    sto->nbHistory--;
  		    goto deregister_check;
  		} else
  		    goto create_key;
  
  create_sequence:
  		/*
  		* Create a key-sequence.
  		*/
  		keySeq = (xmlSchemaPSVIIDCKeyPtr *) xmlMalloc(
  		    matcher->aidc->def->nbFields *
  		    sizeof(xmlSchemaPSVIIDCKeyPtr));
  		if (keySeq == NULL) {
  		    xmlSchemaVErrMemory(NULL,
  			"allocating an IDC key-sequence", NULL);
  		    return(-1);
  		}
  		memset(keySeq, 0, matcher->aidc->def->nbFields *
  		    sizeof(xmlSchemaPSVIIDCKeyPtr));
  		matcher->keySeqs[pos] = keySeq;
  create_key:
  		/*
  		* Create a key once per node only.
  		*/
  		if (key == NULL) {
  		    key = (xmlSchemaPSVIIDCKeyPtr) xmlMalloc(
  			sizeof(xmlSchemaPSVIIDCKey));
  		    if (key == NULL) {
  			xmlSchemaVErrMemory(NULL,
  			    "allocating a IDC key", NULL);
  			xmlFree(keySeq);
  			matcher->keySeqs[pos] = NULL;
  			return(-1);
  		    }
  		    /*
  		    * Consume the compiled value.
  		    */
  		    key->type = simpleType;
  		    key->val = vctxt->inode->val;
  		    vctxt->inode->val = NULL;
  		    /*
  		    * Store the key in a global list.
  		    */
  		    if (xmlSchemaIDCStoreKey(vctxt, key) == -1) {
  			xmlSchemaIDCFreeKey(key);
  			return (-1);
  		    }
  		}
  		keySeq[idx] = key;
  	    }
  	} else if (sto->type == XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) {
  
  	    xmlSchemaPSVIIDCKeyPtr **keySeq = NULL;
  	    /* xmlSchemaPSVIIDCBindingPtr bind; */
  	    xmlSchemaPSVIIDCNodePtr ntItem;
  	    xmlSchemaIDCMatcherPtr matcher;
  	    xmlSchemaIDCPtr idc;
  	    xmlSchemaItemListPtr targets;
  	    int pos, i, j, nbKeys;
  	    /*
  	    * Here we have the following scenario:
  	    * An IDC 'selector' state object resolved to a target node,
  	    * during the time this target node was in the
  	    * ancestor-or-self axis, the 'field' state object(s) looked
  	    * out for matching nodes to create a key-sequence for this
  	    * target node. Now we are back to this target node and need
  	    * to put the key-sequence, together with the target node
  	    * itself, into the node-table of the corresponding IDC
  	    * binding.
  	    */
  	    matcher = sto->matcher;
  	    idc = matcher->aidc->def;
  	    nbKeys = idc->nbFields;
  	    pos = depth - matcher->depth;
  	    /*
  	    * Check if the matcher has any key-sequences at all, plus
  	    * if it has a key-sequence for the current target node.
  	    */
  	    if ((matcher->keySeqs == NULL) ||
  		(matcher->sizeKeySeqs <= pos)) {
  		if (idc->type == XML_SCHEMA_TYPE_IDC_KEY)
  		    goto selector_key_error;
  		else
  		    goto selector_leave;
  	    }
  
  	    keySeq = &(matcher->keySeqs[pos]);
  	    if (*keySeq == NULL) {
  		if (idc->type == XML_SCHEMA_TYPE_IDC_KEY)
  		    goto selector_key_error;
  		else
  		    goto selector_leave;
  	    }
  
  	    for (i = 0; i < nbKeys; i++) {
  		if ((*keySeq)[i] == NULL) {
  		    /*
  		    * Not qualified, if not all fields did resolve.
  		    */
  		    if (idc->type == XML_SCHEMA_TYPE_IDC_KEY) {
  			/*
  			* All fields of a "key" IDC must resolve.
  			*/
  			goto selector_key_error;
  		    }
  		    goto selector_leave;
  		}
  	    }
  	    /*
  	    * All fields did resolve.
  	    */
  
  	    /*
  	    * 4.1 If the {identity-constraint category} is unique(/key),
  	    * then no two members of the `qualified node set` have
  	    * `key-sequences` whose members are pairwise equal, as
  	    * defined by Equal in [XML Schemas: Datatypes].
  	    *
  	    * Get the IDC binding from the matcher and check for
  	    * duplicate key-sequences.
  	    */
  #if 0
  	    bind = xmlSchemaIDCAcquireBinding(vctxt, matcher);
  #endif
  	    targets = xmlSchemaIDCAcquireTargetList(vctxt, matcher);
  	    if ((idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) &&
  		(targets->nbItems != 0)) {
  		xmlSchemaPSVIIDCKeyPtr ckey, bkey, *bkeySeq;
  
  		i = 0;
  		res = 0;
  		/*
  		* Compare the key-sequences, key by key.
  		*/
  		do {
  		    bkeySeq =
  			((xmlSchemaPSVIIDCNodePtr) targets->items[i])->keys;
  		    for (j = 0; j < nbKeys; j++) {
  			ckey = (*keySeq)[j];
  			bkey = bkeySeq[j];
  			res = xmlSchemaAreValuesEqual(ckey->val, bkey->val);
  			if (res == -1) {
  			    return (-1);
  			} else if (res == 0) {
  			    /*
  			    * One of the keys differs, so the key-sequence
  			    * won't be equal; get out.
  			    */
  			    break;
  			}
  		    }
  		    if (res == 1) {
  			/*
  			* Duplicate key-sequence found.
  			*/
  			break;
  		    }
  		    i++;
  		} while (i < targets->nbItems);
  		if (i != targets->nbItems) {
  		    xmlChar *str = NULL, *strB = NULL;
  		    /*
  		    * TODO: Try to report the key-sequence.
  		    */
  		    xmlSchemaCustomErr(ACTXT_CAST vctxt,
  			XML_SCHEMAV_CVC_IDC, NULL,
  			WXS_BASIC_CAST idc,
  			"Duplicate key-sequence %s in %s",
  			xmlSchemaFormatIDCKeySequence(vctxt, &str,
  			    (*keySeq), nbKeys),
  			xmlSchemaGetIDCDesignation(&strB, idc));
  		    FREE_AND_NULL(str);
  		    FREE_AND_NULL(strB);
  		    goto selector_leave;
  		}
  	    }
  	    /*
  	    * Add a node-table item to the IDC binding.
  	    */
  	    ntItem = (xmlSchemaPSVIIDCNodePtr) xmlMalloc(
  		sizeof(xmlSchemaPSVIIDCNode));
  	    if (ntItem == NULL) {
  		xmlSchemaVErrMemory(NULL,
  		    "allocating an IDC node-table item", NULL);
  		xmlFree(*keySeq);
  		*keySeq = NULL;
  		return(-1);
  	    }
  	    memset(ntItem, 0, sizeof(xmlSchemaPSVIIDCNode));
  
  	    /*
  	    * Store the node-table item in a global list.
  	    */
  	    if (idc->type != XML_SCHEMA_TYPE_IDC_KEYREF) {
  		if (xmlSchemaIDCStoreNodeTableItem(vctxt, ntItem) == -1) {
  		    xmlFree(ntItem);
  		    xmlFree(*keySeq);
  		    *keySeq = NULL;
  		    return (-1);
  		}
  		ntItem->nodeQNameID = -1;
  	    } else {
  		/*
  		* Save a cached QName for this node on the IDC node, to be
  		* able to report it, even if the node is not saved.
  		*/
  		ntItem->nodeQNameID = xmlSchemaVAddNodeQName(vctxt,
  		    vctxt->inode->localName, vctxt->inode->nsName);
  		if (ntItem->nodeQNameID == -1) {
  		    xmlFree(ntItem);
  		    xmlFree(*keySeq);
  		    *keySeq = NULL;
  		    return (-1);
  		}
  	    }
  	    /*
  	    * Init the node-table item: Save the node, position and
  	    * consume the key-sequence.
  	    */
  	    ntItem->node = vctxt->node;
  	    ntItem->nodeLine = vctxt->inode->nodeLine;
  	    ntItem->keys = *keySeq;
  	    *keySeq = NULL;
  #if 0
  	    if (xmlSchemaIDCAppendNodeTableItem(bind, ntItem) == -1)
  #endif
  	    if (xmlSchemaItemListAdd(targets, ntItem) == -1) {
  		if (idc->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
  		    /*
  		    * Free the item, since keyref items won't be
  		    * put on a global list.
  		    */
  		    xmlFree(ntItem->keys);
  		    xmlFree(ntItem);
  		}
  		return (-1);
  	    }
  
  	    goto selector_leave;
  selector_key_error:
  	    {
  		xmlChar *str = NULL;
  		/*
  		* 4.2.1 (KEY) The `target node set` and the
  		* `qualified node set` are equal, that is, every
  		* member of the `target node set` is also a member
  		* of the `qualified node set` and vice versa.
  		*/
  		xmlSchemaCustomErr(ACTXT_CAST vctxt,
  		    XML_SCHEMAV_CVC_IDC, NULL,
  		    WXS_BASIC_CAST idc,
  		    "Not all fields of %s evaluate to a node",
  		    xmlSchemaGetIDCDesignation(&str, idc), NULL);
  		FREE_AND_NULL(str);
  	    }
  selector_leave:
  	    /*
  	    * Free the key-sequence if not added to the IDC table.
  	    */
  	    if ((keySeq != NULL) && (*keySeq != NULL)) {
  		xmlFree(*keySeq);
  		*keySeq = NULL;
  	    }
  	} /* if selector */
  
  	sto->nbHistory--;
  
  deregister_check:
  	/*
  	* Deregister state objects if they reach the depth of creation.
  	*/
  	if ((sto->nbHistory == 0) && (sto->depth == depth)) {
  #ifdef DEBUG_IDC
  	    xmlGenericError(xmlGenericErrorContext, "IDC:   STO pop '%s'\n",
  		sto->sel->xpath);
  #endif
  	    if (vctxt->xpathStates != sto) {
  		VERROR_INT("xmlSchemaXPathProcessHistory",
  		    "The state object to be removed is not the first "
  		    "in the list");
  	    }
  	    nextsto = sto->next;
  	    /*
  	    * Unlink from the list of active XPath state objects.
  	    */
  	    vctxt->xpathStates = sto->next;
  	    sto->next = vctxt->xpathStatePool;
  	    /*
  	    * Link it to the pool of reusable state objects.
  	    */
  	    vctxt->xpathStatePool = sto;
  	    sto = nextsto;
  	} else
  	    sto = sto->next;
      } /* while (sto != NULL) */
      return (0);
  }
  
  /**
   * xmlSchemaIDCRegisterMatchers:
   * @vctxt: the WXS validation context
   * @elemDecl: the element declaration
   *
   * Creates helper objects to evaluate IDC selectors/fields
   * successively.
   *
   * Returns 0 if OK and -1 on internal errors.
   */
  static int
  xmlSchemaIDCRegisterMatchers(xmlSchemaValidCtxtPtr vctxt,
  			     xmlSchemaElementPtr elemDecl)
  {
      xmlSchemaIDCMatcherPtr matcher, last = NULL;
      xmlSchemaIDCPtr idc, refIdc;
      xmlSchemaIDCAugPtr aidc;
  
      idc = (xmlSchemaIDCPtr) elemDecl->idcs;
      if (idc == NULL)
  	return (0);
  
  #ifdef DEBUG_IDC
      {
  	xmlChar *str = NULL;
  	xmlGenericError(xmlGenericErrorContext,
  	    "IDC: REGISTER on %s, depth %d\n",
  	    (char *) xmlSchemaFormatQName(&str, vctxt->inode->nsName,
  		vctxt->inode->localName), vctxt->depth);
  	FREE_AND_NULL(str)
      }
  #endif
      if (vctxt->inode->idcMatchers != NULL) {
  	VERROR_INT("xmlSchemaIDCRegisterMatchers",
  	    "The chain of IDC matchers is expected to be empty");
  	return (-1);
      }
      do {
  	if (idc->type == XML_SCHEMA_TYPE_IDC_KEYREF) {
  	    /*
  	    * Since IDCs bubbles are expensive we need to know the
  	    * depth at which the bubbles should stop; this will be
  	    * the depth of the top-most keyref IDC. If no keyref
  	    * references a key/unique IDC, the keyrefDepth will
  	    * be -1, indicating that no bubbles are needed.
  	    */
  	    refIdc = (xmlSchemaIDCPtr) idc->ref->item;
  	    if (refIdc != NULL) {
  		/*
  		* Remember that we have keyrefs on this node.
  		*/
  		vctxt->inode->hasKeyrefs = 1;
  		/*
  		* Lookup the referenced augmented IDC info.
  		*/
  		aidc = vctxt->aidcs;
  		while (aidc != NULL) {
  		    if (aidc->def == refIdc)
  			break;
  		    aidc = aidc->next;
  		}
  		if (aidc == NULL) {
  		    VERROR_INT("xmlSchemaIDCRegisterMatchers",
  			"Could not find an augmented IDC item for an IDC "
  			"definition");
  		    return (-1);
  		}
  		if ((aidc->keyrefDepth == -1) ||
  		    (vctxt->depth < aidc->keyrefDepth))
  		    aidc->keyrefDepth = vctxt->depth;
  	    }
  	}
  	/*
  	* Lookup the augmented IDC item for the IDC definition.
  	*/
  	aidc = vctxt->aidcs;
  	while (aidc != NULL) {
  	    if (aidc->def == idc)
  		break;
  	    aidc = aidc->next;
  	}
  	if (aidc == NULL) {
  	    VERROR_INT("xmlSchemaIDCRegisterMatchers",
  		"Could not find an augmented IDC item for an IDC definition");
  	    return (-1);
  	}
  	/*
  	* Create an IDC matcher for every IDC definition.
  	*/
  	if (vctxt->idcMatcherCache != NULL) {
  	    /*
  	    * Reuse a cached matcher.
  	    */
  	    matcher = vctxt->idcMatcherCache;
  	    vctxt->idcMatcherCache = matcher->nextCached;
  	    matcher->nextCached = NULL;
  	} else {
  	    matcher = (xmlSchemaIDCMatcherPtr)
  		xmlMalloc(sizeof(xmlSchemaIDCMatcher));
  	    if (matcher == NULL) {
  		xmlSchemaVErrMemory(vctxt,
  		    "allocating an IDC matcher", NULL);
  		return (-1);
  	    }
  	    memset(matcher, 0, sizeof(xmlSchemaIDCMatcher));
  	}
  	if (last == NULL)
  	    vctxt->inode->idcMatchers = matcher;
  	else
  	    last->next = matcher;
  	last = matcher;
  
  	matcher->type = IDC_MATCHER;
  	matcher->depth = vctxt->depth;
  	matcher->aidc = aidc;
  	matcher->idcType = aidc->def->type;
  #ifdef DEBUG_IDC
  	xmlGenericError(xmlGenericErrorContext, "IDC:   register matcher\n");
  #endif
  	/*
  	* Init the automaton state object.
  	*/
  	if (xmlSchemaIDCAddStateObject(vctxt, matcher,
  	    idc->selector, XPATH_STATE_OBJ_TYPE_IDC_SELECTOR) == -1)
  	    return (-1);
  
  	idc = idc->next;
      } while (idc != NULL);
      return (0);
  }
  
  static int
  xmlSchemaIDCFillNodeTables(xmlSchemaValidCtxtPtr vctxt,
  			   xmlSchemaNodeInfoPtr ielem)
  {
      xmlSchemaPSVIIDCBindingPtr bind;
      int res, i, j, k, nbTargets, nbFields, nbDupls, nbNodeTable;
      xmlSchemaPSVIIDCKeyPtr *keys, *ntkeys;
      xmlSchemaPSVIIDCNodePtr *targets, *dupls;
  
      xmlSchemaIDCMatcherPtr matcher = ielem->idcMatchers;
      /* vctxt->createIDCNodeTables */
      while (matcher != NULL) {
  	/*
  	* Skip keyref IDCs and empty IDC target-lists.
  	*/
  	if ((matcher->aidc->def->type == XML_SCHEMA_TYPE_IDC_KEYREF) ||
  	    WXS_ILIST_IS_EMPTY(matcher->targets))
  	{
  	    matcher = matcher->next;
  	    continue;
  	}
  	/*
  	* If we _want_ the IDC node-table to be created in any case
  	* then do so. Otherwise create them only if keyrefs need them.
  	*/
  	if ((! vctxt->createIDCNodeTables) &&
  	    ((matcher->aidc->keyrefDepth == -1) ||
  	     (matcher->aidc->keyrefDepth > vctxt->depth)))
  	{
  	    matcher = matcher->next;
  	    continue;
  	}
  	/*
  	* Get/create the IDC binding on this element for the IDC definition.
  	*/
  	bind = xmlSchemaIDCAcquireBinding(vctxt, matcher);
  	if (bind == NULL)
  	   goto internal_error;
  
  	if (! WXS_ILIST_IS_EMPTY(bind->dupls)) {
  	    dupls = (xmlSchemaPSVIIDCNodePtr *) bind->dupls->items;
  	    nbDupls = bind->dupls->nbItems;
  	} else {
  	    dupls = NULL;
  	    nbDupls = 0;
  	}
  	if (bind->nodeTable != NULL) {
  	    nbNodeTable = bind->nbNodes;
  	} else {
  	    nbNodeTable = 0;
  	}
  
  	if ((nbNodeTable == 0) && (nbDupls == 0)) {
  	    /*
  	    * Transfer all IDC target-nodes to the IDC node-table.
  	    */
  	    bind->nodeTable =
  		(xmlSchemaPSVIIDCNodePtr *) matcher->targets->items;
  	    bind->sizeNodes = matcher->targets->sizeItems;
  	    bind->nbNodes = matcher->targets->nbItems;
  
  	    matcher->targets->items = NULL;
  	    matcher->targets->sizeItems = 0;
  	    matcher->targets->nbItems = 0;
  	} else {
  	    /*
  	    * Compare the key-sequences and add to the IDC node-table.
  	    */
  	    nbTargets = matcher->targets->nbItems;
  	    targets = (xmlSchemaPSVIIDCNodePtr *) matcher->targets->items;
  	    nbFields = matcher->aidc->def->nbFields;
  	    i = 0;
  	    do {
  		keys = targets[i]->keys;
  		if (nbDupls) {
  		    /*
  		    * Search in already found duplicates first.
  		    */
  		    j = 0;
  		    do {
  			if (nbFields == 1) {
  			    res = xmlSchemaAreValuesEqual(keys[0]->val,
  				dupls[j]->keys[0]->val);
  			    if (res == -1)
  				goto internal_error;
  			    if (res == 1) {
  				/*
  				* Equal key-sequence.
  				*/
  				goto next_target;
  			    }
  			} else {
  			    res = 0;
  			    ntkeys = dupls[j]->keys;
  			    for (k = 0; k < nbFields; k++) {
  				res = xmlSchemaAreValuesEqual(keys[k]->val,
  				    ntkeys[k]->val);
  				if (res == -1)
  				    goto internal_error;
  				if (res == 0) {
  				    /*
  				    * One of the keys differs.
  				    */
  				    break;
  				}
  			    }
  			    if (res == 1) {
  				/*
  				* Equal key-sequence found.
  				*/
  				goto next_target;
  			    }
  			}
  			j++;
  		    } while (j < nbDupls);
  		}
  		if (nbNodeTable) {
  		    j = 0;
  		    do {
  			if (nbFields == 1) {
  			    res = xmlSchemaAreValuesEqual(keys[0]->val,
  				bind->nodeTable[j]->keys[0]->val);
  			    if (res == -1)
  				goto internal_error;
  			    if (res == 0) {
  				/*
  				* The key-sequence differs.
  				*/
  				goto next_node_table_entry;
  			    }
  			} else {
  			    res = 0;
  			    ntkeys = bind->nodeTable[j]->keys;
  			    for (k = 0; k < nbFields; k++) {
  				res = xmlSchemaAreValuesEqual(keys[k]->val,
  				    ntkeys[k]->val);
  				if (res == -1)
  				    goto internal_error;
  				if (res == 0) {
  				    /*
  				    * One of the keys differs.
  				    */
  				    goto next_node_table_entry;
  				}
  			    }
  			}
  			/*
  			* Add the duplicate to the list of duplicates.
  			*/
  			if (bind->dupls == NULL) {
  			    bind->dupls = xmlSchemaItemListCreate();
  			    if (bind->dupls == NULL)
  				goto internal_error;
  			}
  			if (xmlSchemaItemListAdd(bind->dupls, bind->nodeTable[j]) == -1)
  			    goto internal_error;
  			/*
  			* Remove the duplicate entry from the IDC node-table.
  			*/
  			bind->nodeTable[j] = bind->nodeTable[bind->nbNodes -1];
  			bind->nbNodes--;
  
  			goto next_target;
  
  next_node_table_entry:
  			j++;
  		    } while (j < nbNodeTable);
  		}
  		/*
  		* If everything is fine, then add the IDC target-node to
  		* the IDC node-table.
  		*/
  		if (xmlSchemaIDCAppendNodeTableItem(bind, targets[i]) == -1)
  		    goto internal_error;
  
  next_target:
  		i++;
  	    } while (i < nbTargets);
  	}
  	matcher = matcher->next;
      }
      return(0);
  
  internal_error:
      return(-1);
  }
  
  /**
   * xmlSchemaBubbleIDCNodeTables:
   * @depth: the current tree depth
   *
   * Merges IDC bindings of an element at @depth into the corresponding IDC
   * bindings of its parent element. If a duplicate note-table entry is found,
   * both, the parent node-table entry and child entry are discarded from the
   * node-table of the parent.
   *
   * Returns 0 if OK and -1 on internal errors.
   */
  static int
  xmlSchemaBubbleIDCNodeTables(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaPSVIIDCBindingPtr bind; /* IDC bindings of the current node. */
      xmlSchemaPSVIIDCBindingPtr *parTable, parBind = NULL; /* parent IDC bindings. */
      xmlSchemaPSVIIDCNodePtr node, parNode = NULL, *dupls, *parNodes; /* node-table entries. */
      xmlSchemaIDCAugPtr aidc;
      int i, j, k, ret = 0, nbFields, oldNum, oldDupls;
  
      bind = vctxt->inode->idcTable;
      if (bind == NULL) {
  	/* Fine, no table, no bubbles. */
  	return (0);
      }
  
      parTable = &(vctxt->elemInfos[vctxt->depth -1]->idcTable);
      /*
      * Walk all bindings; create new or add to existing bindings.
      * Remove duplicate key-sequences.
      */
      while (bind != NULL) {
  
  	if ((bind->nbNodes == 0) && WXS_ILIST_IS_EMPTY(bind->dupls))
  	    goto next_binding;
  	/*
  	* Check if the key/unique IDC table needs to be bubbled.
  	*/
  	if (! vctxt->createIDCNodeTables) {
  	    aidc = vctxt->aidcs;
  	    do {
  		if (aidc->def == bind->definition) {
  		    if ((aidc->keyrefDepth == -1) ||
  			(aidc->keyrefDepth >= vctxt->depth)) {
  			goto next_binding;
  		    }
  		    break;
  		}
  		aidc = aidc->next;
  	    } while (aidc != NULL);
  	}
  
  	if (parTable != NULL)
  	    parBind = *parTable;
  	/*
  	* Search a matching parent binding for the
  	* IDC definition.
  	*/
  	while (parBind != NULL) {
  	    if (parBind->definition == bind->definition)
  		break;
  	    parBind = parBind->next;
  	}
  
  	if (parBind != NULL) {
  	    /*
  	    * Compare every node-table entry of the child node,
  	    * i.e. the key-sequence within, ...
  	    */
  	    oldNum = parBind->nbNodes; /* Skip newly added items. */
  
  	    if (! WXS_ILIST_IS_EMPTY(parBind->dupls)) {
  		oldDupls = parBind->dupls->nbItems;
  		dupls = (xmlSchemaPSVIIDCNodePtr *) parBind->dupls->items;
  	    } else {
  		dupls = NULL;
  		oldDupls = 0;
  	    }
  
  	    parNodes = parBind->nodeTable;
  	    nbFields = bind->definition->nbFields;
  
  	    for (i = 0; i < bind->nbNodes; i++) {
  		node = bind->nodeTable[i];
  		if (node == NULL)
  		    continue;
  		/*
  		* ...with every key-sequence of the parent node, already
  		* evaluated to be a duplicate key-sequence.
  		*/
  		if (oldDupls) {
  		    j = 0;
  		    while (j < oldDupls) {
  			if (nbFields == 1) {
  			    ret = xmlSchemaAreValuesEqual(
  				node->keys[0]->val,
  				dupls[j]->keys[0]->val);
  			    if (ret == -1)
  				goto internal_error;
  			    if (ret == 0) {
  				j++;
  				continue;
  			    }
  			} else {
  			    parNode = dupls[j];
  			    for (k = 0; k < nbFields; k++) {
  				ret = xmlSchemaAreValuesEqual(
  				    node->keys[k]->val,
  				    parNode->keys[k]->val);
  				if (ret == -1)
  				    goto internal_error;
  				if (ret == 0)
  				    break;
  			    }
  			}
  			if (ret == 1)
  			    /* Duplicate found. */
  			    break;
  			j++;
  		    }
  		    if (j != oldDupls) {
  			/* Duplicate found. Skip this entry. */
  			continue;
  		    }
  		}
  		/*
  		* ... and with every key-sequence of the parent node.
  		*/
  		if (oldNum) {
  		    j = 0;
  		    while (j < oldNum) {
  			parNode = parNodes[j];
  			if (nbFields == 1) {
  			    ret = xmlSchemaAreValuesEqual(
  				node->keys[0]->val,
  				parNode->keys[0]->val);
  			    if (ret == -1)
  				goto internal_error;
  			    if (ret == 0) {
  				j++;
  				continue;
  			    }
  			} else {
  			    for (k = 0; k < nbFields; k++) {
  				ret = xmlSchemaAreValuesEqual(
  				    node->keys[k]->val,
  				    parNode->keys[k]->val);
  				if (ret == -1)
  				    goto internal_error;
  				if (ret == 0)
  				    break;
  			    }
  			}
  			if (ret == 1)
  			    /* Duplicate found. */
  			    break;
  			j++;
  		    }
  		    if (j != oldNum) {
  			/*
  			* Handle duplicates. Move the duplicate in
  			* the parent's node-table to the list of
  			* duplicates.
  			*/
  			oldNum--;
  			parBind->nbNodes--;
  			/*
  			* Move last old item to pos of duplicate.
  			*/
  			parNodes[j] = parNodes[oldNum];
  
  			if (parBind->nbNodes != oldNum) {
  			    /*
  			    * If new items exist, move last new item to
  			    * last of old items.
  			    */
  			    parNodes[oldNum] =
  				parNodes[parBind->nbNodes];
  			}
  			if (parBind->dupls == NULL) {
  			    parBind->dupls = xmlSchemaItemListCreate();
  			    if (parBind->dupls == NULL)
  				goto internal_error;
  			}
  			xmlSchemaItemListAdd(parBind->dupls, parNode);
  		    } else {
  			/*
  			* Add the node-table entry (node and key-sequence) of
  			* the child node to the node table of the parent node.
  			*/
  			if (parBind->nodeTable == NULL) {
  			    parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *)
  				xmlMalloc(10 * sizeof(xmlSchemaPSVIIDCNodePtr));
  			    if (parBind->nodeTable == NULL) {
  				xmlSchemaVErrMemory(NULL,
  				    "allocating IDC list of node-table items", NULL);
  				goto internal_error;
  			    }
  			    parBind->sizeNodes = 1;
  			} else if (parBind->nbNodes >= parBind->sizeNodes) {
  			    parBind->sizeNodes *= 2;
  			    parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *)
  				xmlRealloc(parBind->nodeTable, parBind->sizeNodes *
  				sizeof(xmlSchemaPSVIIDCNodePtr));
  			    if (parBind->nodeTable == NULL) {
  				xmlSchemaVErrMemory(NULL,
  				    "re-allocating IDC list of node-table items", NULL);
  				goto internal_error;
  			    }
  			}
  			parNodes = parBind->nodeTable;
  			/*
  			* Append the new node-table entry to the 'new node-table
  			* entries' section.
  			*/
  			parNodes[parBind->nbNodes++] = node;
  		    }
  
  		}
  
  	    }
  	} else {
  	    /*
  	    * No binding for the IDC was found: create a new one and
  	    * copy all node-tables.
  	    */
  	    parBind = xmlSchemaIDCNewBinding(bind->definition);
  	    if (parBind == NULL)
  		goto internal_error;
  
  	    /*
  	    * TODO: Hmm, how to optimize the initial number of
  	    * allocated entries?
  	    */
  	    if (bind->nbNodes != 0) {
  		/*
  		* Add all IDC node-table entries.
  		*/
  		if (! vctxt->psviExposeIDCNodeTables) {
  		    /*
  		    * Just move the entries.
  		    * NOTE: this is quite save here, since
  		    * all the keyref lookups have already been
  		    * performed.
  		    */
  		    parBind->nodeTable = bind->nodeTable;
  		    bind->nodeTable = NULL;
  		    parBind->sizeNodes = bind->sizeNodes;
  		    bind->sizeNodes = 0;
  		    parBind->nbNodes = bind->nbNodes;
  		    bind->nbNodes = 0;
  		} else {
  		    /*
  		    * Copy the entries.
  		    */
  		    parBind->nodeTable = (xmlSchemaPSVIIDCNodePtr *)
  			xmlMalloc(bind->nbNodes *
  			sizeof(xmlSchemaPSVIIDCNodePtr));
  		    if (parBind->nodeTable == NULL) {
  			xmlSchemaVErrMemory(NULL,
  			    "allocating an array of IDC node-table "
  			    "items", NULL);
  			xmlSchemaIDCFreeBinding(parBind);
  			goto internal_error;
  		    }
  		    parBind->sizeNodes = bind->nbNodes;
  		    parBind->nbNodes = bind->nbNodes;
  		    memcpy(parBind->nodeTable, bind->nodeTable,
  			bind->nbNodes * sizeof(xmlSchemaPSVIIDCNodePtr));
  		}
  	    }
  	    if (bind->dupls) {
  		/*
  		* Move the duplicates.
  		*/
  		if (parBind->dupls != NULL)
  		    xmlSchemaItemListFree(parBind->dupls);
  		parBind->dupls = bind->dupls;
  		bind->dupls = NULL;
  	    }
              if (parTable != NULL) {
                  if (*parTable == NULL)
                      *parTable = parBind;
                  else {
                      parBind->next = *parTable;
                      *parTable = parBind;
                  }
              }
  	}
  
  next_binding:
  	bind = bind->next;
      }
      return (0);
  
  internal_error:
      return(-1);
  }
  
  /**
   * xmlSchemaCheckCVCIDCKeyRef:
   * @vctxt: the WXS validation context
   * @elemDecl: the element declaration
   *
   * Check the cvc-idc-keyref constraints.
   */
  static int
  xmlSchemaCheckCVCIDCKeyRef(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaIDCMatcherPtr matcher;
      xmlSchemaPSVIIDCBindingPtr bind;
  
      matcher = vctxt->inode->idcMatchers;
      /*
      * Find a keyref.
      */
      while (matcher != NULL) {
  	if ((matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) &&
  	    matcher->targets &&
  	    matcher->targets->nbItems)
  	{
  	    int i, j, k, res, nbFields, hasDupls;
  	    xmlSchemaPSVIIDCKeyPtr *refKeys, *keys;
  	    xmlSchemaPSVIIDCNodePtr refNode = NULL;
  
  	    nbFields = matcher->aidc->def->nbFields;
  
  	    /*
  	    * Find the IDC node-table for the referenced IDC key/unique.
  	    */
  	    bind = vctxt->inode->idcTable;
  	    while (bind != NULL) {
  		if ((xmlSchemaIDCPtr) matcher->aidc->def->ref->item ==
  		    bind->definition)
  		    break;
  		bind = bind->next;
  	    }
  	    hasDupls = (bind && bind->dupls && bind->dupls->nbItems) ? 1 : 0;
  	    /*
  	    * Search for a matching key-sequences.
  	    */
  	    for (i = 0; i < matcher->targets->nbItems; i++) {
  		res = 0;
  		refNode = matcher->targets->items[i];
  		if (bind != NULL) {
  		    refKeys = refNode->keys;
  		    for (j = 0; j < bind->nbNodes; j++) {
  			keys = bind->nodeTable[j]->keys;
  			for (k = 0; k < nbFields; k++) {
  			    res = xmlSchemaAreValuesEqual(keys[k]->val,
  				refKeys[k]->val);
  			    if (res == 0)
  				break;
  			    else if (res == -1) {
  				return (-1);
  			    }
  			}
  			if (res == 1) {
  			    /*
  			    * Match found.
  			    */
  			    break;
  			}
  		    }
  		    if ((res == 0) && hasDupls) {
  			/*
  			* Search in duplicates
  			*/
  			for (j = 0; j < bind->dupls->nbItems; j++) {
  			    keys = ((xmlSchemaPSVIIDCNodePtr)
  				bind->dupls->items[j])->keys;
  			    for (k = 0; k < nbFields; k++) {
  				res = xmlSchemaAreValuesEqual(keys[k]->val,
  				    refKeys[k]->val);
  				if (res == 0)
  				    break;
  				else if (res == -1) {
  				    return (-1);
  				}
  			    }
  			    if (res == 1) {
  				/*
  				* Match in duplicates found.
  				*/
  				xmlChar *str = NULL, *strB = NULL;
  				xmlSchemaKeyrefErr(vctxt,
  				    XML_SCHEMAV_CVC_IDC, refNode,
  				    (xmlSchemaTypePtr) matcher->aidc->def,
  				    "More than one match found for "
  				    "key-sequence %s of keyref '%s'",
  				    xmlSchemaFormatIDCKeySequence(vctxt, &str,
  					refNode->keys, nbFields),
  				    xmlSchemaGetComponentQName(&strB,
  					matcher->aidc->def));
  				FREE_AND_NULL(str);
  				FREE_AND_NULL(strB);
  				break;
  			    }
  			}
  		    }
  		}
  
  		if (res == 0) {
  		    xmlChar *str = NULL, *strB = NULL;
  		    xmlSchemaKeyrefErr(vctxt,
  			XML_SCHEMAV_CVC_IDC, refNode,
  			(xmlSchemaTypePtr) matcher->aidc->def,
  			"No match found for key-sequence %s of keyref '%s'",
  			xmlSchemaFormatIDCKeySequence(vctxt, &str,
  			    refNode->keys, nbFields),
  			xmlSchemaGetComponentQName(&strB, matcher->aidc->def));
  		    FREE_AND_NULL(str);
  		    FREE_AND_NULL(strB);
  		}
  	    }
  	}
  	matcher = matcher->next;
      }
      /* TODO: Return an error if any error encountered. */
      return (0);
  }
  
  /************************************************************************
   *									*
   *			XML Reader validation code                      *
   *									*
   ************************************************************************/
  
  static xmlSchemaAttrInfoPtr
  xmlSchemaGetFreshAttrInfo(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaAttrInfoPtr iattr;
      /*
      * Grow/create list of attribute infos.
      */
      if (vctxt->attrInfos == NULL) {
  	vctxt->attrInfos = (xmlSchemaAttrInfoPtr *)
  	    xmlMalloc(sizeof(xmlSchemaAttrInfoPtr));
  	vctxt->sizeAttrInfos = 1;
  	if (vctxt->attrInfos == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"allocating attribute info list", NULL);
  	    return (NULL);
  	}
      } else if (vctxt->sizeAttrInfos <= vctxt->nbAttrInfos) {
  	vctxt->sizeAttrInfos++;
  	vctxt->attrInfos = (xmlSchemaAttrInfoPtr *)
  	    xmlRealloc(vctxt->attrInfos,
  		vctxt->sizeAttrInfos * sizeof(xmlSchemaAttrInfoPtr));
  	if (vctxt->attrInfos == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"re-allocating attribute info list", NULL);
  	    return (NULL);
  	}
      } else {
  	iattr = vctxt->attrInfos[vctxt->nbAttrInfos++];
  	if (iattr->localName != NULL) {
  	    VERROR_INT("xmlSchemaGetFreshAttrInfo",
  		"attr info not cleared");
  	    return (NULL);
  	}
  	iattr->nodeType = XML_ATTRIBUTE_NODE;
  	return (iattr);
      }
      /*
      * Create an attribute info.
      */
      iattr = (xmlSchemaAttrInfoPtr)
  	xmlMalloc(sizeof(xmlSchemaAttrInfo));
      if (iattr == NULL) {
  	xmlSchemaVErrMemory(vctxt, "creating new attribute info", NULL);
  	return (NULL);
      }
      memset(iattr, 0, sizeof(xmlSchemaAttrInfo));
      iattr->nodeType = XML_ATTRIBUTE_NODE;
      vctxt->attrInfos[vctxt->nbAttrInfos++] = iattr;
  
      return (iattr);
  }
  
  static int
  xmlSchemaValidatorPushAttribute(xmlSchemaValidCtxtPtr vctxt,
  			xmlNodePtr attrNode,
  			int nodeLine,
  			const xmlChar *localName,
  			const xmlChar *nsName,
  			int ownedNames,
  			xmlChar *value,
  			int ownedValue)
  {
      xmlSchemaAttrInfoPtr attr;
  
      attr = xmlSchemaGetFreshAttrInfo(vctxt);
      if (attr == NULL) {
  	VERROR_INT("xmlSchemaPushAttribute",
  	    "calling xmlSchemaGetFreshAttrInfo()");
  	return (-1);
      }
      attr->node = attrNode;
      attr->nodeLine = nodeLine;
      attr->state = XML_SCHEMAS_ATTR_UNKNOWN;
      attr->localName = localName;
      attr->nsName = nsName;
      if (ownedNames)
  	attr->flags |= XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES;
      /*
      * Evaluate if it's an XSI attribute.
      */
      if (nsName != NULL) {
  	if (xmlStrEqual(localName, BAD_CAST "nil")) {
  	    if (xmlStrEqual(attr->nsName, xmlSchemaInstanceNs)) {
  		attr->metaType = XML_SCHEMA_ATTR_INFO_META_XSI_NIL;
  	    }
  	} else if (xmlStrEqual(localName, BAD_CAST "type")) {
  	    if (xmlStrEqual(attr->nsName, xmlSchemaInstanceNs)) {
  		attr->metaType = XML_SCHEMA_ATTR_INFO_META_XSI_TYPE;
  	    }
  	} else if (xmlStrEqual(localName, BAD_CAST "schemaLocation")) {
  	    if (xmlStrEqual(attr->nsName, xmlSchemaInstanceNs)) {
  		attr->metaType = XML_SCHEMA_ATTR_INFO_META_XSI_SCHEMA_LOC;
  	    }
  	} else if (xmlStrEqual(localName, BAD_CAST "noNamespaceSchemaLocation")) {
  	    if (xmlStrEqual(attr->nsName, xmlSchemaInstanceNs)) {
  		attr->metaType = XML_SCHEMA_ATTR_INFO_META_XSI_NO_NS_SCHEMA_LOC;
  	    }
  	} else if (xmlStrEqual(attr->nsName, xmlNamespaceNs)) {
  	    attr->metaType = XML_SCHEMA_ATTR_INFO_META_XMLNS;
  	}
      }
      attr->value = value;
      if (ownedValue)
  	attr->flags |= XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES;
      if (attr->metaType != 0)
  	attr->state = XML_SCHEMAS_ATTR_META;
      return (0);
  }
  
  /**
   * xmlSchemaClearElemInfo:
   * @vctxt: the WXS validation context
   * @ielem: the element information item
   */
  static void
  xmlSchemaClearElemInfo(xmlSchemaValidCtxtPtr vctxt,
  		       xmlSchemaNodeInfoPtr ielem)
  {
      ielem->hasKeyrefs = 0;
      ielem->appliedXPath = 0;
      if (ielem->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES) {
  	FREE_AND_NULL(ielem->localName);
  	FREE_AND_NULL(ielem->nsName);
      } else {
  	ielem->localName = NULL;
  	ielem->nsName = NULL;
      }
      if (ielem->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES) {
  	FREE_AND_NULL(ielem->value);
      } else {
  	ielem->value = NULL;
      }
      if (ielem->val != NULL) {
  	/*
  	* PSVI TODO: Be careful not to free it when the value is
  	* exposed via PSVI.
  	*/
  	xmlSchemaFreeValue(ielem->val);
  	ielem->val = NULL;
      }
      if (ielem->idcMatchers != NULL) {
  	/*
  	* REVISIT OPTIMIZE TODO: Use a pool of IDC matchers.
  	*   Does it work?
  	*/
  	xmlSchemaIDCReleaseMatcherList(vctxt, ielem->idcMatchers);
  #if 0
  	xmlSchemaIDCFreeMatcherList(ielem->idcMatchers);
  #endif
  	ielem->idcMatchers = NULL;
      }
      if (ielem->idcTable != NULL) {
  	/*
  	* OPTIMIZE TODO: Use a pool of IDC tables??.
  	*/
  	xmlSchemaIDCFreeIDCTable(ielem->idcTable);
  	ielem->idcTable = NULL;
      }
      if (ielem->regexCtxt != NULL) {
  	xmlRegFreeExecCtxt(ielem->regexCtxt);
  	ielem->regexCtxt = NULL;
      }
      if (ielem->nsBindings != NULL) {
  	xmlFree((xmlChar **)ielem->nsBindings);
  	ielem->nsBindings = NULL;
  	ielem->nbNsBindings = 0;
  	ielem->sizeNsBindings = 0;
      }
  }
  
  /**
   * xmlSchemaGetFreshElemInfo:
   * @vctxt: the schema validation context
   *
   * Creates/reuses and initializes the element info item for
   * the current tree depth.
   *
   * Returns the element info item or NULL on API or internal errors.
   */
  static xmlSchemaNodeInfoPtr
  xmlSchemaGetFreshElemInfo(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaNodeInfoPtr info = NULL;
  
      if (vctxt->depth > vctxt->sizeElemInfos) {
  	VERROR_INT("xmlSchemaGetFreshElemInfo",
  	    "inconsistent depth encountered");
  	return (NULL);
      }
      if (vctxt->elemInfos == NULL) {
  	vctxt->elemInfos = (xmlSchemaNodeInfoPtr *)
  	    xmlMalloc(10 * sizeof(xmlSchemaNodeInfoPtr));
  	if (vctxt->elemInfos == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"allocating the element info array", NULL);
  	    return (NULL);
  	}
  	memset(vctxt->elemInfos, 0, 10 * sizeof(xmlSchemaNodeInfoPtr));
  	vctxt->sizeElemInfos = 10;
      } else if (vctxt->sizeElemInfos <= vctxt->depth) {
  	int i = vctxt->sizeElemInfos;
  
  	vctxt->sizeElemInfos *= 2;
  	vctxt->elemInfos = (xmlSchemaNodeInfoPtr *)
  	    xmlRealloc(vctxt->elemInfos, vctxt->sizeElemInfos *
  	    sizeof(xmlSchemaNodeInfoPtr));
  	if (vctxt->elemInfos == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"re-allocating the element info array", NULL);
  	    return (NULL);
  	}
  	/*
  	* We need the new memory to be NULLed.
  	* TODO: Use memset instead?
  	*/
  	for (; i < vctxt->sizeElemInfos; i++)
  	    vctxt->elemInfos[i] = NULL;
      } else
  	info = vctxt->elemInfos[vctxt->depth];
  
      if (info == NULL) {
  	info = (xmlSchemaNodeInfoPtr)
  	    xmlMalloc(sizeof(xmlSchemaNodeInfo));
  	if (info == NULL) {
  	    xmlSchemaVErrMemory(vctxt,
  		"allocating an element info", NULL);
  	    return (NULL);
  	}
  	vctxt->elemInfos[vctxt->depth] = info;
      } else {
  	if (info->localName != NULL) {
  	    VERROR_INT("xmlSchemaGetFreshElemInfo",
  		"elem info has not been cleared");
  	    return (NULL);
  	}
      }
      memset(info, 0, sizeof(xmlSchemaNodeInfo));
      info->nodeType = XML_ELEMENT_NODE;
      info->depth = vctxt->depth;
  
      return (info);
  }
  
  #define ACTIVATE_ATTRIBUTE(item) vctxt->inode = (xmlSchemaNodeInfoPtr) item;
  #define ACTIVATE_ELEM vctxt->inode = vctxt->elemInfos[vctxt->depth];
  #define ACTIVATE_PARENT_ELEM vctxt->inode = vctxt->elemInfos[vctxt->depth -1];
  
  static int
  xmlSchemaValidateFacets(xmlSchemaAbstractCtxtPtr actxt,
  			xmlNodePtr node,
  			xmlSchemaTypePtr type,
  			xmlSchemaValType valType,
  			const xmlChar * value,
  			xmlSchemaValPtr val,
  			unsigned long length,
  			int fireErrors)
  {
      int ret, error = 0;
  
      xmlSchemaTypePtr tmpType;
      xmlSchemaFacetLinkPtr facetLink;
      xmlSchemaFacetPtr facet;
      unsigned long len = 0;
      xmlSchemaWhitespaceValueType ws;
  
      /*
      * In Libxml2, derived built-in types have currently no explicit facets.
      */
      if (type->type == XML_SCHEMA_TYPE_BASIC)
  	return (0);
  
      /*
      * NOTE: Do not jump away, if the facetSet of the given type is
      * empty: until now, "pattern" and "enumeration" facets of the
      * *base types* need to be checked as well.
      */
      if (type->facetSet == NULL)
  	goto pattern_and_enum;
  
      if (! WXS_IS_ATOMIC(type)) {
  	if (WXS_IS_LIST(type))
  	    goto WXS_IS_LIST;
  	else
  	    goto pattern_and_enum;
      }
  
      /*
      * Whitespace handling is only of importance for string-based
      * types.
      */
      tmpType = xmlSchemaGetPrimitiveType(type);
      if ((tmpType->builtInType == XML_SCHEMAS_STRING) ||
  	WXS_IS_ANY_SIMPLE_TYPE(tmpType)) {
  	ws = xmlSchemaGetWhiteSpaceFacetValue(type);
      } else
  	ws = XML_SCHEMA_WHITESPACE_COLLAPSE;
  
      /*
      * If the value was not computed (for string or
      * anySimpleType based types), then use the provided
      * type.
      */
      if (val != NULL)
  	valType = xmlSchemaGetValType(val);
  
      ret = 0;
      for (facetLink = type->facetSet; facetLink != NULL;
  	facetLink = facetLink->next) {
  	/*
  	* Skip the pattern "whiteSpace": it is used to
  	* format the character content beforehand.
  	*/
  	switch (facetLink->facet->type) {
  	    case XML_SCHEMA_FACET_WHITESPACE:
  	    case XML_SCHEMA_FACET_PATTERN:
  	    case XML_SCHEMA_FACET_ENUMERATION:
  		continue;
  	    case XML_SCHEMA_FACET_LENGTH:
  	    case XML_SCHEMA_FACET_MINLENGTH:
  	    case XML_SCHEMA_FACET_MAXLENGTH:
  		ret = xmlSchemaValidateLengthFacetWhtsp(facetLink->facet,
  		    valType, value, val, &len, ws);
  		break;
  	    default:
  		ret = xmlSchemaValidateFacetWhtsp(facetLink->facet, ws,
  		    valType, value, val, ws);
  		break;
  	}
  	if (ret < 0) {
  	    AERROR_INT("xmlSchemaValidateFacets",
  		"validating against a atomic type facet");
  	    return (-1);
  	} else if (ret > 0) {
  	    if (fireErrors)
  		xmlSchemaFacetErr(actxt, ret, node,
  		value, len, type, facetLink->facet, NULL, NULL, NULL);
  	    else
  		return (ret);
  	    if (error == 0)
  		error = ret;
  	}
  	ret = 0;
      }
  
  WXS_IS_LIST:
      if (! WXS_IS_LIST(type))
  	goto pattern_and_enum;
      /*
      * "length", "minLength" and "maxLength" of list types.
      */
      ret = 0;
      for (facetLink = type->facetSet; facetLink != NULL;
  	facetLink = facetLink->next) {
  
  	switch (facetLink->facet->type) {
  	    case XML_SCHEMA_FACET_LENGTH:
  	    case XML_SCHEMA_FACET_MINLENGTH:
  	    case XML_SCHEMA_FACET_MAXLENGTH:
  		ret = xmlSchemaValidateListSimpleTypeFacet(facetLink->facet,
  		    value, length, NULL);
  		break;
  	    default:
  		continue;
  	}
  	if (ret < 0) {
  	    AERROR_INT("xmlSchemaValidateFacets",
  		"validating against a list type facet");
  	    return (-1);
  	} else if (ret > 0) {
  	    if (fireErrors)
  		xmlSchemaFacetErr(actxt, ret, node,
  		value, length, type, facetLink->facet, NULL, NULL, NULL);
  	    else
  		return (ret);
  	    if (error == 0)
  		error = ret;
  	}
  	ret = 0;
      }
  
  pattern_and_enum:
      if (error >= 0) {
  	int found = 0;
  	/*
  	* Process enumerations. Facet values are in the value space
  	* of the defining type's base type. This seems to be a bug in the
  	* XML Schema 1.0 spec. Use the whitespace type of the base type.
  	* Only the first set of enumerations in the ancestor-or-self axis
  	* is used for validation.
  	*/
  	ret = 0;
  	tmpType = type;
  	do {
  	    for (facet = tmpType->facets; facet != NULL; facet = facet->next) {
  		if (facet->type != XML_SCHEMA_FACET_ENUMERATION)
  		    continue;
  		found = 1;
  		ret = xmlSchemaAreValuesEqual(facet->val, val);
  		if (ret == 1)
  		    break;
  		else if (ret < 0) {
  		    AERROR_INT("xmlSchemaValidateFacets",
  			"validating against an enumeration facet");
  		    return (-1);
  		}
  	    }
  	    if (ret != 0)
  		break;
  	    /*
  	    * Break on the first set of enumerations. Any additional
  	    *  enumerations which might be existent on the ancestors
  	    *  of the current type are restricted by this set; thus
  	    *  *must* *not* be taken into account.
  	    */
  	    if (found)
  		break;
  	    tmpType = tmpType->baseType;
  	} while ((tmpType != NULL) &&
  	    (tmpType->type != XML_SCHEMA_TYPE_BASIC));
  	if (found && (ret == 0)) {
  	    ret = XML_SCHEMAV_CVC_ENUMERATION_VALID;
  	    if (fireErrors) {
  		xmlSchemaFacetErr(actxt, ret, node,
  		    value, 0, type, NULL, NULL, NULL, NULL);
  	    } else
  		return (ret);
  	    if (error == 0)
  		error = ret;
  	}
      }
  
      if (error >= 0) {
  	int found;
  	/*
  	* Process patters. Pattern facets are ORed at type level
  	* and ANDed if derived. Walk the base type axis.
  	*/
  	tmpType = type;
  	facet = NULL;
  	do {
  	    found = 0;
  	    for (facetLink = tmpType->facetSet; facetLink != NULL;
  		facetLink = facetLink->next) {
  		if (facetLink->facet->type != XML_SCHEMA_FACET_PATTERN)
  		    continue;
  		found = 1;
  		/*
  		* NOTE that for patterns, @value needs to be the
  		* normalized value.
  		*/
  		ret = xmlRegexpExec(facetLink->facet->regexp, value);
  		if (ret == 1)
  		    break;
  		else if (ret < 0) {
  		    AERROR_INT("xmlSchemaValidateFacets",
  			"validating against a pattern facet");
  		    return (-1);
  		} else {
  		    /*
  		    * Save the last non-validating facet.
  		    */
  		    facet = facetLink->facet;
  		}
  	    }
  	    if (found && (ret != 1)) {
  		ret = XML_SCHEMAV_CVC_PATTERN_VALID;
  		if (fireErrors) {
  		    xmlSchemaFacetErr(actxt, ret, node,
  			value, 0, type, facet, NULL, NULL, NULL);
  		} else
  		    return (ret);
  		if (error == 0)
  		    error = ret;
  		break;
  	    }
  	    tmpType = tmpType->baseType;
  	} while ((tmpType != NULL) && (tmpType->type != XML_SCHEMA_TYPE_BASIC));
      }
  
      return (error);
  }
  
  static xmlChar *
  xmlSchemaNormalizeValue(xmlSchemaTypePtr type,
  			const xmlChar *value)
  {
      switch (xmlSchemaGetWhiteSpaceFacetValue(type)) {
  	case XML_SCHEMA_WHITESPACE_COLLAPSE:
  	    return (xmlSchemaCollapseString(value));
  	case XML_SCHEMA_WHITESPACE_REPLACE:
  	    return (xmlSchemaWhiteSpaceReplace(value));
  	default:
  	    return (NULL);
      }
  }
  
  static int
  xmlSchemaValidateQName(xmlSchemaValidCtxtPtr vctxt,
  		       const xmlChar *value,
  		       xmlSchemaValPtr *val,
  		       int valNeeded)
  {
      int ret;
      const xmlChar *nsName;
      xmlChar *local, *prefix = NULL;
  
      ret = xmlValidateQName(value, 1);
      if (ret != 0) {
  	if (ret == -1) {
  	    VERROR_INT("xmlSchemaValidateQName",
  		"calling xmlValidateQName()");
  	    return (-1);
  	}
  	return( XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1);
      }
      /*
      * NOTE: xmlSplitQName2 will always return a duplicated
      * strings.
      */
      local = xmlSplitQName2(value, &prefix);
      if (local == NULL)
  	local = xmlStrdup(value);
      /*
      * OPTIMIZE TODO: Use flags for:
      *  - is there any namespace binding?
      *  - is there a default namespace?
      */
      nsName = xmlSchemaLookupNamespace(vctxt, prefix);
  
      if (prefix != NULL) {
  	xmlFree(prefix);
  	/*
  	* A namespace must be found if the prefix is
  	* NOT NULL.
  	*/
  	if (nsName == NULL) {
  	    ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1;
  	    xmlSchemaCustomErr(ACTXT_CAST vctxt, ret, NULL,
  		WXS_BASIC_CAST xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME),
  		"The QName value '%s' has no "
  		"corresponding namespace declaration in "
  		"scope", value, NULL);
  	    if (local != NULL)
  		xmlFree(local);
  	    return (ret);
  	}
      }
      if (valNeeded && val) {
  	if (nsName != NULL)
  	    *val = xmlSchemaNewQNameValue(
  		BAD_CAST xmlStrdup(nsName), BAD_CAST local);
  	else
  	    *val = xmlSchemaNewQNameValue(NULL,
  		BAD_CAST local);
      } else
  	xmlFree(local);
      return (0);
  }
  
  /*
  * cvc-simple-type
  */
  static int
  xmlSchemaVCheckCVCSimpleType(xmlSchemaAbstractCtxtPtr actxt,
  			     xmlNodePtr node,
  			     xmlSchemaTypePtr type,
  			     const xmlChar *value,
  			     xmlSchemaValPtr *retVal,
  			     int fireErrors,
  			     int normalize,
  			     int isNormalized)
  {
      int ret = 0, valNeeded = (retVal) ? 1 : 0;
      xmlSchemaValPtr val = NULL;
      /* xmlSchemaWhitespaceValueType ws; */
      xmlChar *normValue = NULL;
  
  #define NORMALIZE(atype) \
      if ((! isNormalized) && \
      (normalize || (type->flags & XML_SCHEMAS_TYPE_NORMVALUENEEDED))) { \
  	normValue = xmlSchemaNormalizeValue(atype, value); \
  	if (normValue != NULL) \
  	    value = normValue; \
  	isNormalized = 1; \
      }
  
      if ((retVal != NULL) && (*retVal != NULL)) {
  	xmlSchemaFreeValue(*retVal);
  	*retVal = NULL;
      }
      /*
      * 3.14.4 Simple Type Definition Validation Rules
      * Validation Rule: String Valid
      */
      /*
      * 1 It is schema-valid with respect to that definition as defined
      * by Datatype Valid in [XML Schemas: Datatypes].
      */
      /*
      * 2.1 If The definition is ENTITY or is validly derived from ENTITY given
      * the empty set, as defined in Type Derivation OK (Simple) ($3.14.6), then
      * the string must be a `declared entity name`.
      */
      /*
      * 2.2 If The definition is ENTITIES or is validly derived from ENTITIES
      * given the empty set, as defined in Type Derivation OK (Simple) ($3.14.6),
      * then every whitespace-delimited substring of the string must be a `declared
      * entity name`.
      */
      /*
      * 2.3 otherwise no further condition applies.
      */
      if ((! valNeeded) && (type->flags & XML_SCHEMAS_TYPE_FACETSNEEDVALUE))
  	valNeeded = 1;
      if (value == NULL)
  	value = BAD_CAST "";
      if (WXS_IS_ANY_SIMPLE_TYPE(type) || WXS_IS_ATOMIC(type)) {
  	xmlSchemaTypePtr biType; /* The built-in type. */
  	/*
  	* SPEC (1.2.1) "if {variety} is `atomic` then the string must `match`
  	* a literal in the `lexical space` of {base type definition}"
  	*/
  	/*
  	* Whitespace-normalize.
  	*/
  	NORMALIZE(type);
  	if (type->type != XML_SCHEMA_TYPE_BASIC) {
  	    /*
  	    * Get the built-in type.
  	    */
  	    biType = type->baseType;
  	    while ((biType != NULL) &&
  		(biType->type != XML_SCHEMA_TYPE_BASIC))
  		biType = biType->baseType;
  
  	    if (biType == NULL) {
  		AERROR_INT("xmlSchemaVCheckCVCSimpleType",
  		    "could not get the built-in type");
  		goto internal_error;
  	    }
  	} else
  	    biType = type;
  	/*
  	* NOTATIONs need to be processed here, since they need
  	* to lookup in the hashtable of NOTATION declarations of the schema.
  	*/
  	if (actxt->type == XML_SCHEMA_CTXT_VALIDATOR) {
  	    switch (biType->builtInType) {
  		case XML_SCHEMAS_NOTATION:
  		    ret = xmlSchemaValidateNotation(
  			(xmlSchemaValidCtxtPtr) actxt,
  			((xmlSchemaValidCtxtPtr) actxt)->schema,
  			NULL, value, &val, valNeeded);
  		    break;
  		case XML_SCHEMAS_QNAME:
  		    ret = xmlSchemaValidateQName((xmlSchemaValidCtxtPtr) actxt,
  			value, &val, valNeeded);
  		    break;
  		default:
  		    /* ws = xmlSchemaGetWhiteSpaceFacetValue(type); */
  		    if (valNeeded)
  			ret = xmlSchemaValPredefTypeNodeNoNorm(biType,
  			    value, &val, node);
  		    else
  			ret = xmlSchemaValPredefTypeNodeNoNorm(biType,
  			    value, NULL, node);
  		    break;
  	    }
  	} else if (actxt->type == XML_SCHEMA_CTXT_PARSER) {
  	    switch (biType->builtInType) {
  		case XML_SCHEMAS_NOTATION:
  		    ret = xmlSchemaValidateNotation(NULL,
  			((xmlSchemaParserCtxtPtr) actxt)->schema, node,
  			value, &val, valNeeded);
  		    break;
  		default:
  		    /* ws = xmlSchemaGetWhiteSpaceFacetValue(type); */
  		    if (valNeeded)
  			ret = xmlSchemaValPredefTypeNodeNoNorm(biType,
  			    value, &val, node);
  		    else
  			ret = xmlSchemaValPredefTypeNodeNoNorm(biType,
  			    value, NULL, node);
  		    break;
  	    }
  	} else {
  	    /*
  	    * Validation via a public API is not implemented yet.
  	    */
  	    TODO
  	    goto internal_error;
  	}
  	if (ret != 0) {
  	    if (ret < 0) {
  		AERROR_INT("xmlSchemaVCheckCVCSimpleType",
  		    "validating against a built-in type");
  		goto internal_error;
  	    }
  	    if (WXS_IS_LIST(type))
  		ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2;
  	    else
  		ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1;
  	}
  	if ((ret == 0) && (type->flags & XML_SCHEMAS_TYPE_HAS_FACETS)) {
  	    /*
  	    * Check facets.
  	    */
  	    ret = xmlSchemaValidateFacets(actxt, node, type,
  		(xmlSchemaValType) biType->builtInType, value, val,
  		0, fireErrors);
  	    if (ret != 0) {
  		if (ret < 0) {
  		    AERROR_INT("xmlSchemaVCheckCVCSimpleType",
  			"validating facets of atomic simple type");
  		    goto internal_error;
  		}
  		if (WXS_IS_LIST(type))
  		    ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2;
  		else
  		    ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1;
  	    }
  	}
  	else if (fireErrors && (ret > 0))
  	    xmlSchemaSimpleTypeErr(actxt, ret, node, value, type, 1);
      } else if (WXS_IS_LIST(type)) {
  
  	xmlSchemaTypePtr itemType;
  	const xmlChar *cur, *end;
  	xmlChar *tmpValue = NULL;
  	unsigned long len = 0;
  	xmlSchemaValPtr prevVal = NULL, curVal = NULL;
  	/* 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}
  	*/
  	/*
  	* Note that XML_SCHEMAS_TYPE_NORMVALUENEEDED will be set if
  	* the list type has an enum or pattern facet.
  	*/
  	NORMALIZE(type);
  	/*
  	* VAL TODO: Optimize validation of empty values.
  	* VAL TODO: We do not have computed values for lists.
  	*/
  	itemType = WXS_LIST_ITEMTYPE(type);
  	cur = value;
  	do {
  	    while (IS_BLANK_CH(*cur))
  		cur++;
  	    end = cur;
  	    while ((*end != 0) && (!(IS_BLANK_CH(*end))))
  		end++;
  	    if (end == cur)
  		break;
  	    tmpValue = xmlStrndup(cur, end - cur);
  	    len++;
  
  	    if (valNeeded)
  		ret = xmlSchemaVCheckCVCSimpleType(actxt, node, itemType,
  		    tmpValue, &curVal, fireErrors, 0, 1);
  	    else
  		ret = xmlSchemaVCheckCVCSimpleType(actxt, node, itemType,
  		    tmpValue, NULL, fireErrors, 0, 1);
  	    FREE_AND_NULL(tmpValue);
  	    if (curVal != NULL) {
  		/*
  		* Add to list of computed values.
  		*/
  		if (val == NULL)
  		    val = curVal;
  		else
  		    xmlSchemaValueAppend(prevVal, curVal);
  		prevVal = curVal;
  		curVal = NULL;
  	    }
  	    if (ret != 0) {
  		if (ret < 0) {
  		    AERROR_INT("xmlSchemaVCheckCVCSimpleType",
  			"validating an item of list simple type");
  		    goto internal_error;
  		}
  		ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2;
  		break;
  	    }
  	    cur = end;
  	} while (*cur != 0);
  	FREE_AND_NULL(tmpValue);
  	if ((ret == 0) && (type->flags & XML_SCHEMAS_TYPE_HAS_FACETS)) {
  	    /*
  	    * Apply facets (pattern, enumeration).
  	    */
  	    ret = xmlSchemaValidateFacets(actxt, node, type,
  		XML_SCHEMAS_UNKNOWN, value, val,
  		len, fireErrors);
  	    if (ret != 0) {
  		if (ret < 0) {
  		    AERROR_INT("xmlSchemaVCheckCVCSimpleType",
  			"validating facets of list simple type");
  		    goto internal_error;
  		}
  		ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_2;
  	    }
  	}
  	if (fireErrors && (ret > 0)) {
  	    /*
  	    * Report the normalized value.
  	    */
  	    normalize = 1;
  	    NORMALIZE(type);
  	    xmlSchemaSimpleTypeErr(actxt, ret, node, value, type, 1);
  	}
      } else if (WXS_IS_UNION(type)) {
  	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) {
  	    AERROR_INT("xmlSchemaVCheckCVCSimpleType",
  		"union simple type has no member types");
  	    goto internal_error;
  	}
  	/*
  	* Always normalize union type values, since we currently
  	* cannot store the whitespace information with the value
  	* itself; otherwise a later value-comparison would be
  	* not possible.
  	*/
  	while (memberLink != NULL) {
  	    if (valNeeded)
  		ret = xmlSchemaVCheckCVCSimpleType(actxt, node,
  		    memberLink->type, value, &val, 0, 1, 0);
  	    else
  		ret = xmlSchemaVCheckCVCSimpleType(actxt, node,
  		    memberLink->type, value, NULL, 0, 1, 0);
  	    if (ret <= 0)
  		break;
  	    memberLink = memberLink->next;
  	}
  	if (ret != 0) {
  	    if (ret < 0) {
  		AERROR_INT("xmlSchemaVCheckCVCSimpleType",
  		    "validating members of union simple type");
  		goto internal_error;
  	    }
  	    ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3;
  	}
  	/*
  	* Apply facets (pattern, enumeration).
  	*/
  	if ((ret == 0) && (type->flags & XML_SCHEMAS_TYPE_HAS_FACETS)) {
  	    /*
  	    * 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.
  	    */
  	    NORMALIZE(memberLink->type);
  	    ret = xmlSchemaValidateFacets(actxt, node, type,
  		XML_SCHEMAS_UNKNOWN, value, val,
  		0, fireErrors);
  	    if (ret != 0) {
  		if (ret < 0) {
  		    AERROR_INT("xmlSchemaVCheckCVCSimpleType",
  			"validating facets of union simple type");
  		    goto internal_error;
  		}
  		ret = XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_3;
  	    }
  	}
  	if (fireErrors && (ret > 0))
  	    xmlSchemaSimpleTypeErr(actxt, ret, node, value, type, 1);
      }
  
      if (normValue != NULL)
  	xmlFree(normValue);
      if (ret == 0) {
  	if (retVal != NULL)
  	    *retVal = val;
  	else if (val != NULL)
  	    xmlSchemaFreeValue(val);
      } else if (val != NULL)
  	xmlSchemaFreeValue(val);
      return (ret);
  internal_error:
      if (normValue != NULL)
  	xmlFree(normValue);
      if (val != NULL)
  	xmlSchemaFreeValue(val);
      return (-1);
  }
  
  static int
  xmlSchemaVExpandQName(xmlSchemaValidCtxtPtr vctxt,
  			   const xmlChar *value,
  			   const xmlChar **nsName,
  			   const xmlChar **localName)
  {
      int ret = 0;
  
      if ((nsName == NULL) || (localName == NULL))
  	return (-1);
      *nsName = NULL;
      *localName = NULL;
  
      ret = xmlValidateQName(value, 1);
      if (ret == -1)
  	return (-1);
      if (ret > 0) {
  	xmlSchemaSimpleTypeErr(ACTXT_CAST vctxt,
  	    XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, NULL,
  	    value, xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME), 1);
  	return (1);
      }
      {
  	xmlChar *local = NULL;
  	xmlChar *prefix;
  
  	/*
  	* NOTE: xmlSplitQName2 will return a duplicated
  	* string.
  	*/
  	local = xmlSplitQName2(value, &prefix);
  	if (local == NULL)
  	    *localName = xmlDictLookup(vctxt->dict, value, -1);
  	else {
  	    *localName = xmlDictLookup(vctxt->dict, local, -1);
  	    xmlFree(local);
  	}
  
  	*nsName = xmlSchemaLookupNamespace(vctxt, prefix);
  
  	if (prefix != NULL) {
  	    xmlFree(prefix);
  	    /*
  	    * A namespace must be found if the prefix is NOT NULL.
  	    */
  	    if (*nsName == NULL) {
  		xmlSchemaCustomErr(ACTXT_CAST vctxt,
  		    XML_SCHEMAV_CVC_DATATYPE_VALID_1_2_1, NULL,
  		    WXS_BASIC_CAST xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME),
  		    "The QName value '%s' has no "
  		    "corresponding namespace declaration in scope",
  		    value, NULL);
  		return (2);
  	    }
  	}
      }
      return (0);
  }
  
  static int
  xmlSchemaProcessXSIType(xmlSchemaValidCtxtPtr vctxt,
  			xmlSchemaAttrInfoPtr iattr,
  			xmlSchemaTypePtr *localType,
  			xmlSchemaElementPtr elemDecl)
  {
      int ret = 0;
      /*
      * cvc-elt (3.3.4) : (4)
      * AND
      * Schema-Validity Assessment (Element) (cvc-assess-elt)
      *   (1.2.1.2.1) - (1.2.1.2.4)
      * Handle 'xsi:type'.
      */
      if (localType == NULL)
  	return (-1);
      *localType = NULL;
      if (iattr == NULL)
  	return (0);
      else {
  	const xmlChar *nsName = NULL, *local = NULL;
  	/*
  	* TODO: We should report a *warning* that the type was overridden
  	* by the instance.
  	*/
  	ACTIVATE_ATTRIBUTE(iattr);
  	/*
  	* (cvc-elt) (3.3.4) : (4.1)
  	* (cvc-assess-elt) (1.2.1.2.2)
  	*/
  	ret = xmlSchemaVExpandQName(vctxt, iattr->value,
  	    &nsName, &local);
  	if (ret != 0) {
  	    if (ret < 0) {
  		VERROR_INT("xmlSchemaValidateElementByDeclaration",
  		    "calling xmlSchemaQNameExpand() to validate the "
  		    "attribute 'xsi:type'");
  		goto internal_error;
  	    }
  	    goto exit;
  	}
  	/*
  	* (cvc-elt) (3.3.4) : (4.2)
  	* (cvc-assess-elt) (1.2.1.2.3)
  	*/
  	*localType = xmlSchemaGetType(vctxt->schema, local, nsName);
  	if (*localType == NULL) {
  	    xmlChar *str = NULL;
  
  	    xmlSchemaCustomErr(ACTXT_CAST vctxt,
  		XML_SCHEMAV_CVC_ELT_4_2, NULL,
  		WXS_BASIC_CAST xmlSchemaGetBuiltInType(XML_SCHEMAS_QNAME),
  		"The QName value '%s' of the xsi:type attribute does not "
  		"resolve to a type definition",
  		xmlSchemaFormatQName(&str, nsName, local), NULL);
  	    FREE_AND_NULL(str);
  	    ret = vctxt->err;
  	    goto exit;
  	}
  	if (elemDecl != NULL) {
  	    int set = 0;
  
  	    /*
  	    * SPEC cvc-elt (3.3.4) : (4.3) (Type Derivation OK)
  	    * "The `local type definition` must be validly
  	    * derived from the {type definition} given the union of
  	    * the {disallowed substitutions} and the {type definition}'s
  	    * {prohibited substitutions}, as defined in
  	    * Type Derivation OK (Complex) ($3.4.6)
  	    * (if it is a complex type definition),
  	    * or given {disallowed substitutions} as defined in Type
  	    * Derivation OK (Simple) ($3.14.6) (if it is a simple type
  	    * definition)."
  	    *
  	    * {disallowed substitutions}: the "block" on the element decl.
  	    * {prohibited substitutions}: the "block" on the type def.
  	    */
  	    /*
  	    * OPTIMIZE TODO: We could map types already evaluated
  	    * to be validly derived from other types to avoid checking
  	    * this over and over for the same types.
  	    */
  	    if ((elemDecl->flags & XML_SCHEMAS_ELEM_BLOCK_EXTENSION) ||
  		(elemDecl->subtypes->flags &
  		    XML_SCHEMAS_TYPE_BLOCK_EXTENSION))
  		set |= SUBSET_EXTENSION;
  
  	    if ((elemDecl->flags & XML_SCHEMAS_ELEM_BLOCK_RESTRICTION) ||
  		(elemDecl->subtypes->flags &
  		    XML_SCHEMAS_TYPE_BLOCK_RESTRICTION))
  		set |= SUBSET_RESTRICTION;
  
  	    /*
  	    * REMOVED and CHANGED since this produced a parser context
  	    * which adds to the string dict of the schema. So this would
  	    * change the schema and we don't want this. We don't need
  	    * the parser context anymore.
  	    *
  	    * if ((vctxt->pctxt == NULL) &&
  	    *	(xmlSchemaCreatePCtxtOnVCtxt(vctxt) == -1))
  	    *	    return (-1);
  	    */
  
  	    if (xmlSchemaCheckCOSDerivedOK(ACTXT_CAST vctxt, *localType,
  		elemDecl->subtypes, set) != 0) {
  		xmlChar *str = NULL;
  
  		xmlSchemaCustomErr(ACTXT_CAST vctxt,
  		    XML_SCHEMAV_CVC_ELT_4_3, NULL, NULL,
  		    "The type definition '%s', specified by xsi:type, is "
  		    "blocked or not validly derived from the type definition "
  		    "of the element declaration",
  		    xmlSchemaFormatQName(&str,
  			(*localType)->targetNamespace,
  			(*localType)->name),
  		    NULL);
  		FREE_AND_NULL(str);
  		ret = vctxt->err;
  		*localType = NULL;
  	    }
  	}
      }
  exit:
      ACTIVATE_ELEM;
      return (ret);
  internal_error:
      ACTIVATE_ELEM;
      return (-1);
  }
  
  static int
  xmlSchemaValidateElemDecl(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaElementPtr elemDecl = vctxt->inode->decl;
      xmlSchemaTypePtr actualType;
  
      /*
      * cvc-elt (3.3.4) : 1
      */
      if (elemDecl == NULL) {
  	VERROR(XML_SCHEMAV_CVC_ELT_1, NULL,
  	    "No matching declaration available");
          return (vctxt->err);
      }
      actualType = WXS_ELEM_TYPEDEF(elemDecl);
      /*
      * cvc-elt (3.3.4) : 2
      */
      if (elemDecl->flags & XML_SCHEMAS_ELEM_ABSTRACT) {
  	VERROR(XML_SCHEMAV_CVC_ELT_2, NULL,
  	    "The element declaration is abstract");
          return (vctxt->err);
      }
      if (actualType == NULL) {
  	VERROR(XML_SCHEMAV_CVC_TYPE_1, NULL,
  	    "The type definition is absent");
  	return (XML_SCHEMAV_CVC_TYPE_1);
      }
      if (vctxt->nbAttrInfos != 0) {
  	int ret;
  	xmlSchemaAttrInfoPtr iattr;
  	/*
  	* cvc-elt (3.3.4) : 3
  	* Handle 'xsi:nil'.
  	*/
  	iattr = xmlSchemaGetMetaAttrInfo(vctxt,
  	    XML_SCHEMA_ATTR_INFO_META_XSI_NIL);
  	if (iattr) {
  	    ACTIVATE_ATTRIBUTE(iattr);
  	    /*
  	    * Validate the value.
  	    */
  	    ret = xmlSchemaVCheckCVCSimpleType(
  		ACTXT_CAST vctxt, NULL,
  		xmlSchemaGetBuiltInType(XML_SCHEMAS_BOOLEAN),
  		iattr->value, &(iattr->val), 1, 0, 0);
  	    ACTIVATE_ELEM;
  	    if (ret < 0) {
  		VERROR_INT("xmlSchemaValidateElemDecl",
  		    "calling xmlSchemaVCheckCVCSimpleType() to "
  		    "validate the attribute 'xsi:nil'");
  		return (-1);
  	    }
  	    if (ret == 0) {
  		if ((elemDecl->flags & XML_SCHEMAS_ELEM_NILLABLE) == 0) {
  		    /*
  		    * cvc-elt (3.3.4) : 3.1
  		    */
  		    VERROR(XML_SCHEMAV_CVC_ELT_3_1, NULL,
  			"The element is not 'nillable'");
  		    /* Does not return an error on purpose. */
  		} else {
  		    if (xmlSchemaValueGetAsBoolean(iattr->val)) {
  			/*
  			* cvc-elt (3.3.4) : 3.2.2
  			*/
  			if ((elemDecl->flags & XML_SCHEMAS_ELEM_FIXED) &&
  			    (elemDecl->value != NULL)) {
  			    VERROR(XML_SCHEMAV_CVC_ELT_3_2_2, NULL,
  				"The element cannot be 'nilled' because "
  				"there is a fixed value constraint defined "
  				"for it");
  			     /* Does not return an error on purpose. */
  			} else
  			    vctxt->inode->flags |=
  				XML_SCHEMA_ELEM_INFO_NILLED;
  		    }
  		}
  	    }
  	}
  	/*
  	* cvc-elt (3.3.4) : 4
  	* Handle 'xsi:type'.
  	*/
  	iattr = xmlSchemaGetMetaAttrInfo(vctxt,
  	    XML_SCHEMA_ATTR_INFO_META_XSI_TYPE);
  	if (iattr) {
  	    xmlSchemaTypePtr localType = NULL;
  
  	    ret = xmlSchemaProcessXSIType(vctxt, iattr, &localType,
  		elemDecl);
  	    if (ret != 0) {
  		if (ret == -1) {
  		    VERROR_INT("xmlSchemaValidateElemDecl",
  			"calling xmlSchemaProcessXSIType() to "
  			"process the attribute 'xsi:type'");
  		    return (-1);
  		}
  		/* Does not return an error on purpose. */
  	    }
  	    if (localType != NULL) {
  		vctxt->inode->flags |= XML_SCHEMA_ELEM_INFO_LOCAL_TYPE;
  		actualType = localType;
  	    }
  	}
      }
      /*
      * IDC: Register identity-constraint XPath matchers.
      */
      if ((elemDecl->idcs != NULL) &&
  	(xmlSchemaIDCRegisterMatchers(vctxt, elemDecl) == -1))
  	    return (-1);
      /*
      * No actual type definition.
      */
      if (actualType == NULL) {
  	VERROR(XML_SCHEMAV_CVC_TYPE_1, NULL,
  	    "The type definition is absent");
  	return (XML_SCHEMAV_CVC_TYPE_1);
      }
      /*
      * Remember the actual type definition.
      */
      vctxt->inode->typeDef = actualType;
  
      return (0);
  }
  
  static int
  xmlSchemaVAttributesSimple(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaAttrInfoPtr iattr;
      int ret = 0, i;
  
      /*
      * SPEC cvc-type (3.1.1)
      * "The attributes of 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."
      */
      if (vctxt->nbAttrInfos == 0)
  	return (0);
      for (i = 0; i < vctxt->nbAttrInfos; i++) {
  	iattr = vctxt->attrInfos[i];
  	if (! iattr->metaType) {
  	    ACTIVATE_ATTRIBUTE(iattr)
  	    xmlSchemaIllegalAttrErr(ACTXT_CAST vctxt,
  		XML_SCHEMAV_CVC_TYPE_3_1_1, iattr, NULL);
  	    ret = XML_SCHEMAV_CVC_TYPE_3_1_1;
          }
      }
      ACTIVATE_ELEM
      return (ret);
  }
  
  /*
  * Cleanup currently used attribute infos.
  */
  static void
  xmlSchemaClearAttrInfos(xmlSchemaValidCtxtPtr vctxt)
  {
      int i;
      xmlSchemaAttrInfoPtr attr;
  
      if (vctxt->nbAttrInfos == 0)
  	return;
      for (i = 0; i < vctxt->nbAttrInfos; i++) {
  	attr = vctxt->attrInfos[i];
  	if (attr->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES) {
  	    if (attr->localName != NULL)
  		xmlFree((xmlChar *) attr->localName);
  	    if (attr->nsName != NULL)
  		xmlFree((xmlChar *) attr->nsName);
  	}
  	if (attr->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES) {
  	    if (attr->value != NULL)
  		xmlFree((xmlChar *) attr->value);
  	}
  	if (attr->val != NULL) {
  	    xmlSchemaFreeValue(attr->val);
  	    attr->val = NULL;
  	}
  	memset(attr, 0, sizeof(xmlSchemaAttrInfo));
      }
      vctxt->nbAttrInfos = 0;
  }
  
  /*
  * 3.4.4 Complex Type Definition Validation Rules
  *   Element Locally Valid (Complex Type) (cvc-complex-type)
  * 3.2.4 Attribute Declaration Validation Rules
  *   Validation Rule: Attribute Locally Valid (cvc-attribute)
  *   Attribute Locally Valid (Use) (cvc-au)
  *
  * Only "assessed" attribute information items will be visible to
  * IDCs. I.e. not "lax" (without declaration) and "skip" wild attributes.
  */
  static int
  xmlSchemaVAttributesComplex(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaTypePtr type = vctxt->inode->typeDef;
      xmlSchemaItemListPtr attrUseList;
      xmlSchemaAttributeUsePtr attrUse = NULL;
      xmlSchemaAttributePtr attrDecl = NULL;
      xmlSchemaAttrInfoPtr iattr, tmpiattr;
      int i, j, found, nbAttrs, nbUses;
      int xpathRes = 0, res, wildIDs = 0, fixed;
      xmlNodePtr defAttrOwnerElem = NULL;
  
      /*
      * SPEC (cvc-attribute)
      * (1) "The declaration must not be `absent` (see Missing
      * Sub-components ($5.3) for how this can fail to be
      * the case)."
      * (2) "Its {type definition} must not be absent."
      *
      * NOTE (1) + (2): This is not handled here, since we currently do not
      * allow validation against schemas which have missing sub-components.
      *
      * SPEC (cvc-complex-type)
      * (3) "For each attribute information item in the element information
      * item's [attributes] 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, the appropriate case among the following
      * must be true:
      *
      */
      attrUseList = (xmlSchemaItemListPtr) type->attrUses;
      /*
      * @nbAttrs is the number of attributes present in the instance.
      */
      nbAttrs = vctxt->nbAttrInfos;
      if (attrUseList != NULL)
  	nbUses = attrUseList->nbItems;
      else
  	nbUses = 0;
      for (i = 0; i < nbUses; i++) {
          found = 0;
  	attrUse = attrUseList->items[i];
  	attrDecl = WXS_ATTRUSE_DECL(attrUse);
          for (j = 0; j < nbAttrs; j++) {
  	    iattr = vctxt->attrInfos[j];
  	    /*
  	    * SPEC (cvc-complex-type) (3)
  	    * Skip meta attributes.
  	    */
  	    if (iattr->metaType)
  		continue;
  	    if (iattr->localName[0] != attrDecl->name[0])
  		continue;
  	    if (!xmlStrEqual(iattr->localName, attrDecl->name))
  		continue;
  	    if (!xmlStrEqual(iattr->nsName, attrDecl->targetNamespace))
  		continue;
  	    found = 1;
  	    /*
  	    * SPEC (cvc-complex-type)
  	    * (3.1) "If there is among the {attribute uses} an attribute
  	    * use with an {attribute declaration} whose {name} matches
  	    * the attribute information item's [local name] and whose
  	    * {target namespace} is identical to the attribute information
  	    * item's [namespace name] (where an `absent` {target namespace}
  	    * is taken to be identical to a [namespace name] with no value),
  	    * then the attribute information must be `valid` with respect
  	    * to that attribute use as per Attribute Locally Valid (Use)
  	    * ($3.5.4). In this case the {attribute declaration} of that
  	    * attribute use is the `context-determined declaration` for the
  	    * attribute information item with respect to Schema-Validity
  	    * Assessment (Attribute) ($3.2.4) and
  	    * Assessment Outcome (Attribute) ($3.2.5).
  	    */
  	    iattr->state = XML_SCHEMAS_ATTR_ASSESSED;
  	    iattr->use = attrUse;
  	    /*
  	    * Context-determined declaration.
  	    */
  	    iattr->decl = attrDecl;
  	    iattr->typeDef = attrDecl->subtypes;
  	    break;
  	}
  
  	if (found)
  	    continue;
  
  	if (attrUse->occurs == XML_SCHEMAS_ATTR_USE_REQUIRED) {
  	    /*
  	    * Handle non-existent, required attributes.
  	    *
  	    * SPEC (cvc-complex-type)
  	    * (4) "The {attribute declaration} of each attribute use in
  	    * the {attribute uses} whose {required} is true matches one
  	    * of the attribute information items in the element information
  	    * item's [attributes] as per clause 3.1 above."
  	    */
  	    tmpiattr = xmlSchemaGetFreshAttrInfo(vctxt);
  	    if (tmpiattr == NULL) {
  		VERROR_INT(
  		    "xmlSchemaVAttributesComplex",
  		    "calling xmlSchemaGetFreshAttrInfo()");
  		return (-1);
  	    }
  	    tmpiattr->state = XML_SCHEMAS_ATTR_ERR_MISSING;
  	    tmpiattr->use = attrUse;
  	    tmpiattr->decl = attrDecl;
  	} else if ((attrUse->occurs == XML_SCHEMAS_ATTR_USE_OPTIONAL) &&
  	    ((attrUse->defValue != NULL) ||
  	     (attrDecl->defValue != NULL))) {
  	    /*
  	    * Handle non-existent, optional, default/fixed attributes.
  	    */
  	    tmpiattr = xmlSchemaGetFreshAttrInfo(vctxt);
  	    if (tmpiattr == NULL) {
  		VERROR_INT(
  		    "xmlSchemaVAttributesComplex",
  		    "calling xmlSchemaGetFreshAttrInfo()");
  		return (-1);
  	    }
  	    tmpiattr->state = XML_SCHEMAS_ATTR_DEFAULT;
  	    tmpiattr->use = attrUse;
  	    tmpiattr->decl = attrDecl;
  	    tmpiattr->typeDef = attrDecl->subtypes;
  	    tmpiattr->localName = attrDecl->name;
  	    tmpiattr->nsName = attrDecl->targetNamespace;
  	}
      }
  
      if (vctxt->nbAttrInfos == 0)
  	return (0);
      /*
      * Validate against the wildcard.
      */
      if (type->attributeWildcard != NULL) {
  	/*
  	* SPEC (cvc-complex-type)
  	* (3.2.1) "There must be an {attribute wildcard}."
  	*/
  	for (i = 0; i < nbAttrs; i++) {
  	    iattr = vctxt->attrInfos[i];
  	    /*
  	    * SPEC (cvc-complex-type) (3)
  	    * Skip meta attributes.
  	    */
  	    if (iattr->state != XML_SCHEMAS_ATTR_UNKNOWN)
  		continue;
  	    /*
  	    * SPEC (cvc-complex-type)
  	    * (3.2.2) "The attribute information item must be `valid` with
  	    * respect to it as defined in Item Valid (Wildcard) ($3.10.4)."
  	    *
  	    * SPEC Item Valid (Wildcard) (cvc-wildcard)
  	    * "... its [namespace name] must be `valid` with respect to
  	    * the wildcard constraint, as defined in Wildcard allows
  	    * Namespace Name ($3.10.4)."
  	    */
  	    if (xmlSchemaCheckCVCWildcardNamespace(type->attributeWildcard,
  		    iattr->nsName) == 0) {
  		/*
  		* Handle processContents.
  		*
  		* SPEC (cvc-wildcard):
  		* processContents | context-determined declaration:
  		* "strict"          "mustFind"
  		* "lax"             "none"
  		* "skip"            "skip"
  		*/
  		if (type->attributeWildcard->processContents ==
  		    XML_SCHEMAS_ANY_SKIP) {
  		     /*
  		    * context-determined declaration = "skip"
  		    *
  		    * SPEC PSVI Assessment Outcome (Attribute)
  		    * [validity] = "notKnown"
  		    * [validation attempted] = "none"
  		    */
  		    iattr->state = XML_SCHEMAS_ATTR_WILD_SKIP;
  		    continue;
  		}
  		/*
  		* Find an attribute declaration.
  		*/
  		iattr->decl = xmlSchemaGetAttributeDecl(vctxt->schema,
  		    iattr->localName, iattr->nsName);
  		if (iattr->decl != NULL) {
  		    iattr->state = XML_SCHEMAS_ATTR_ASSESSED;
  		    /*
  		    * SPEC (cvc-complex-type)
  		    * (5) "Let [Definition:]  the wild IDs be the set of
  		    * all attribute information item to which clause 3.2
  		    * applied and whose `validation` resulted in a
  		    * `context-determined declaration` of mustFind or no
  		    * `context-determined declaration` at all, and whose
  		    * [local name] and [namespace name] resolve (as
  		    * defined by QName resolution (Instance) ($3.15.4)) to
  		    * an attribute declaration whose {type definition} is
  		    * or is derived from ID. Then all of the following
  		    * must be true:"
  		    */
  		    iattr->typeDef = WXS_ATTR_TYPEDEF(iattr->decl);
  		    if (xmlSchemaIsDerivedFromBuiltInType(
  			iattr->typeDef, XML_SCHEMAS_ID)) {
  			/*
  			* SPEC (5.1) "There must be no more than one
  			* item in `wild IDs`."
  			*/
  			if (wildIDs != 0) {
  			    /* VAL TODO */
  			    iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_DUPLICATE_ID;
  			    TODO
  			    continue;
  			}
  			wildIDs++;
  			/*
  			* SPEC (cvc-complex-type)
  			* (5.2) "If `wild IDs` is non-empty, there must not
  			* be any attribute uses among the {attribute uses}
  			* whose {attribute declaration}'s {type definition}
  			* is or is derived from ID."
  			*/
                          if (attrUseList != NULL) {
                              for (j = 0; j < attrUseList->nbItems; j++) {
                                  if (xmlSchemaIsDerivedFromBuiltInType(
                                      WXS_ATTRUSE_TYPEDEF(attrUseList->items[j]),
                                      XML_SCHEMAS_ID)) {
                                      /* URGENT VAL TODO: implement */
                              iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_AND_USE_ID;
                                      TODO
                                      break;
                                  }
                              }
                          }
  		    }
  		} else if (type->attributeWildcard->processContents ==
  		    XML_SCHEMAS_ANY_LAX) {
  		    iattr->state = XML_SCHEMAS_ATTR_WILD_LAX_NO_DECL;
  		    /*
  		    * SPEC PSVI Assessment Outcome (Attribute)
  		    * [validity] = "notKnown"
  		    * [validation attempted] = "none"
  		    */
  		} else {
  		    iattr->state = XML_SCHEMAS_ATTR_ERR_WILD_STRICT_NO_DECL;
  		}
  	    }
  	}
      }
  
      if (vctxt->nbAttrInfos == 0)
  	return (0);
  
      /*
      * Get the owner element; needed for creation of default attributes.
      * This fixes bug #341337, reported by David Grohmann.
      */
      if (vctxt->options & XML_SCHEMA_VAL_VC_I_CREATE) {
  	xmlSchemaNodeInfoPtr ielem = vctxt->elemInfos[vctxt->depth];
  	if (ielem && ielem->node && ielem->node->doc)
  	    defAttrOwnerElem = ielem->node;
      }
      /*
      * Validate values, create default attributes, evaluate IDCs.
      */
      for (i = 0; i < vctxt->nbAttrInfos; i++) {
  	iattr = vctxt->attrInfos[i];
  	/*
  	* VAL TODO: Note that we won't try to resolve IDCs to
  	* "lax" and "skip" validated attributes. Check what to
  	* do in this case.
  	*/
  	if ((iattr->state != XML_SCHEMAS_ATTR_ASSESSED) &&
  	    (iattr->state != XML_SCHEMAS_ATTR_DEFAULT))
  	    continue;
  	/*
  	* VAL TODO: What to do if the type definition is missing?
  	*/
  	if (iattr->typeDef == NULL) {
  	    iattr->state = XML_SCHEMAS_ATTR_ERR_NO_TYPE;
  	    continue;
  	}
  
  	ACTIVATE_ATTRIBUTE(iattr);
  	fixed = 0;
  	xpathRes = 0;
  
  	if (vctxt->xpathStates != NULL) {
  	    /*
  	    * Evaluate IDCs.
  	    */
  	    xpathRes = xmlSchemaXPathEvaluate(vctxt,
  		XML_ATTRIBUTE_NODE);
  	    if (xpathRes == -1) {
  		VERROR_INT("xmlSchemaVAttributesComplex",
  		    "calling xmlSchemaXPathEvaluate()");
  		goto internal_error;
  	    }
  	}
  
  	if (iattr->state == XML_SCHEMAS_ATTR_DEFAULT) {
  	    /*
  	    * Default/fixed attributes.
  	    * We need the value only if we need to resolve IDCs or
  	    * will create default attributes.
  	    */
  	    if ((xpathRes) || (defAttrOwnerElem)) {
  		if (iattr->use->defValue != NULL) {
  		    iattr->value = (xmlChar *) iattr->use->defValue;
  		    iattr->val = iattr->use->defVal;
  		} else {
  		    iattr->value = (xmlChar *) iattr->decl->defValue;
  		    iattr->val = iattr->decl->defVal;
  		}
  		/*
  		* IDCs will consume the precomputed default value,
  		* so we need to clone it.
  		*/
  		if (iattr->val == NULL) {
  		    VERROR_INT("xmlSchemaVAttributesComplex",
  			"default/fixed value on an attribute use was "
  			"not precomputed");
  		    goto internal_error;
  		}
  		iattr->val = xmlSchemaCopyValue(iattr->val);
  		if (iattr->val == NULL) {
  		    VERROR_INT("xmlSchemaVAttributesComplex",
  			"calling xmlSchemaCopyValue()");
  		    goto internal_error;
  		}
  	    }
  	    /*
  	    * PSVI: Add the default attribute to the current element.
  	    * VAL TODO: Should we use the *normalized* value? This currently
  	    *   uses the *initial* value.
  	    */
  
  	    if (defAttrOwnerElem) {
  		xmlChar *normValue;
  		const xmlChar *value;
  
  		value = iattr->value;
  		/*
  		* Normalize the value.
  		*/
  		normValue = xmlSchemaNormalizeValue(iattr->typeDef,
  		    iattr->value);
  		if (normValue != NULL)
  		    value = BAD_CAST normValue;
  
  		if (iattr->nsName == NULL) {
  		    if (xmlNewProp(defAttrOwnerElem,
  			iattr->localName, value) == NULL) {
  			VERROR_INT("xmlSchemaVAttributesComplex",
  			    "calling xmlNewProp()");
  			if (normValue != NULL)
  			    xmlFree(normValue);
  			goto internal_error;
  		    }
  		} else {
  		    xmlNsPtr ns;
  
  		    ns = xmlSearchNsByHref(defAttrOwnerElem->doc,
  			defAttrOwnerElem, iattr->nsName);
  		    if (ns == NULL) {
  			xmlChar prefix[12];
  			int counter = 0;
  
  			/*
  			* Create a namespace declaration on the validation
  			* root node if no namespace declaration is in scope.
  			*/
  			do {
  			    snprintf((char *) prefix, 12, "p%d", counter++);
  			    ns = xmlSearchNs(defAttrOwnerElem->doc,
  				defAttrOwnerElem, BAD_CAST prefix);
  			    if (counter > 1000) {
  				VERROR_INT(
  				    "xmlSchemaVAttributesComplex",
  				    "could not compute a ns prefix for a "
  				    "default/fixed attribute");
  				if (normValue != NULL)
  				    xmlFree(normValue);
  				goto internal_error;
  			    }
  			} while (ns != NULL);
  			ns = xmlNewNs(vctxt->validationRoot,
  			    iattr->nsName, BAD_CAST prefix);
  		    }
  		    /*
  		    * TODO:
  		    * http://lists.w3.org/Archives/Public/www-xml-schema-comments/2005JulSep/0406.html
  		    * If we have QNames: do we need to ensure there's a
  		    * prefix defined for the QName?
  		    */
  		    xmlNewNsProp(defAttrOwnerElem, ns, iattr->localName, value);
  		}
  		if (normValue != NULL)
  		    xmlFree(normValue);
  	    }
  	    /*
  	    * Go directly to IDC evaluation.
  	    */
  	    goto eval_idcs;
  	}
  	/*
  	* Validate the value.
  	*/
  	if (vctxt->value != NULL) {
  	    /*
  	    * Free last computed value; just for safety reasons.
  	    */
  	    xmlSchemaFreeValue(vctxt->value);
  	    vctxt->value = NULL;
  	}
  	/*
  	* Note that the attribute *use* can be unavailable, if
  	* the attribute was a wild attribute.
  	*/
  	if ((iattr->decl->flags & XML_SCHEMAS_ATTR_FIXED) ||
  	    ((iattr->use != NULL) &&
  	     (iattr->use->flags & XML_SCHEMAS_ATTR_FIXED)))
  	    fixed = 1;
  	else
  	    fixed = 0;
  	/*
  	* SPEC (cvc-attribute)
  	* (3) "The item's `normalized value` must be locally `valid`
  	* with respect to that {type definition} as per
  	* String Valid ($3.14.4)."
  	*
  	* VAL TODO: Do we already have the
  	* "normalized attribute value" here?
  	*/
  	if (xpathRes || fixed) {
  	    iattr->flags |= XML_SCHEMA_NODE_INFO_VALUE_NEEDED;
  	    /*
  	    * Request a computed value.
  	    */
  	    res = xmlSchemaVCheckCVCSimpleType(
  		ACTXT_CAST vctxt,
  		iattr->node, iattr->typeDef, iattr->value, &(iattr->val),
  		1, 1, 0);
  	} else {
  	    res = xmlSchemaVCheckCVCSimpleType(
  		ACTXT_CAST vctxt,
  		iattr->node, iattr->typeDef, iattr->value, NULL,
  		1, 0, 0);
  	}
  
  	if (res != 0) {
  	    if (res == -1) {
  		VERROR_INT("xmlSchemaVAttributesComplex",
  		    "calling xmlSchemaStreamValidateSimpleTypeValue()");
  		goto internal_error;
  	    }
  	    iattr->state = XML_SCHEMAS_ATTR_INVALID_VALUE;
  	    /*
  	    * SPEC PSVI Assessment Outcome (Attribute)
  	    * [validity] = "invalid"
  	    */
  	    goto eval_idcs;
  	}
  
  	if (fixed) {
  	    /*
  	    * SPEC Attribute Locally Valid (Use) (cvc-au)
  	    * "For an attribute information item to be `valid`
  	    * with respect to an attribute use its *normalized*
  	    * value must match the *canonical* lexical
  	    * representation of the attribute use's {value
  	    * constraint}value, if it is present and fixed."
  	    *
  	    * VAL TODO: The requirement for the *canonical* value
  	    * will be removed in XML Schema 1.1.
  	    */
  	    /*
  	    * SPEC Attribute Locally Valid (cvc-attribute)
  	    * (4) "The item's *actual* value must match the *value* of
  	    * the {value constraint}, if it is present and fixed."
  	    */
  	    if (iattr->val == NULL) {
  		/* VAL TODO: A value was not precomputed. */
  		TODO
  		goto eval_idcs;
  	    }
  	    if ((iattr->use != NULL) &&
  		(iattr->use->defValue != NULL)) {
  		if (iattr->use->defVal == NULL) {
  		    /* VAL TODO: A default value was not precomputed. */
  		    TODO
  		    goto eval_idcs;
  		}
  		iattr->vcValue = iattr->use->defValue;
  		/*
  		if (xmlSchemaCompareValuesWhtsp(attr->val,
  		    (xmlSchemaWhitespaceValueType) ws,
  		    attr->use->defVal,
  		    (xmlSchemaWhitespaceValueType) ws) != 0) {
  		*/
  		if (! xmlSchemaAreValuesEqual(iattr->val, iattr->use->defVal))
  		    iattr->state = XML_SCHEMAS_ATTR_ERR_FIXED_VALUE;
  	    } else {
  		if (iattr->decl->defVal == NULL) {
  		    /* VAL TODO: A default value was not precomputed. */
  		    TODO
  		    goto eval_idcs;
  		}
  		iattr->vcValue = iattr->decl->defValue;
  		/*
  		if (xmlSchemaCompareValuesWhtsp(attr->val,
  		    (xmlSchemaWhitespaceValueType) ws,
  		    attrDecl->defVal,
  		    (xmlSchemaWhitespaceValueType) ws) != 0) {
  		*/
  		if (! xmlSchemaAreValuesEqual(iattr->val, iattr->decl->defVal))
  		    iattr->state = XML_SCHEMAS_ATTR_ERR_FIXED_VALUE;
  	    }
  	    /*
  	    * [validity] = "valid"
  	    */
  	}
  eval_idcs:
  	/*
  	* Evaluate IDCs.
  	*/
  	if (xpathRes) {
  	    if (xmlSchemaXPathProcessHistory(vctxt,
  		vctxt->depth +1) == -1) {
  		VERROR_INT("xmlSchemaVAttributesComplex",
  		    "calling xmlSchemaXPathEvaluate()");
  		goto internal_error;
  	    }
  	} else if (vctxt->xpathStates != NULL)
  	    xmlSchemaXPathPop(vctxt);
      }
  
      /*
      * Report errors.
      */
      for (i = 0; i < vctxt->nbAttrInfos; i++) {
  	iattr = vctxt->attrInfos[i];
  	if ((iattr->state == XML_SCHEMAS_ATTR_META) ||
  	    (iattr->state == XML_SCHEMAS_ATTR_ASSESSED) ||
  	    (iattr->state == XML_SCHEMAS_ATTR_WILD_SKIP) ||
  	    (iattr->state == XML_SCHEMAS_ATTR_WILD_LAX_NO_DECL))
  	    continue;
  	ACTIVATE_ATTRIBUTE(iattr);
  	switch (iattr->state) {
  	    case XML_SCHEMAS_ATTR_ERR_MISSING: {
  		    xmlChar *str = NULL;
  		    ACTIVATE_ELEM;
  		    xmlSchemaCustomErr(ACTXT_CAST vctxt,
  			XML_SCHEMAV_CVC_COMPLEX_TYPE_4, NULL, NULL,
  			"The attribute '%s' is required but missing",
  			xmlSchemaFormatQName(&str,
  			    iattr->decl->targetNamespace,
  			    iattr->decl->name),
  			NULL);
  		    FREE_AND_NULL(str)
  		    break;
  		}
  	    case XML_SCHEMAS_ATTR_ERR_NO_TYPE:
  		VERROR(XML_SCHEMAV_CVC_ATTRIBUTE_2, NULL,
  		    "The type definition is absent");
  		break;
  	    case XML_SCHEMAS_ATTR_ERR_FIXED_VALUE:
  		xmlSchemaCustomErr(ACTXT_CAST vctxt,
  		    XML_SCHEMAV_CVC_AU, NULL, NULL,
  		    "The value '%s' does not match the fixed "
  		    "value constraint '%s'",
  		    iattr->value, iattr->vcValue);
  		break;
  	    case XML_SCHEMAS_ATTR_ERR_WILD_STRICT_NO_DECL:
  		VERROR(XML_SCHEMAV_CVC_WILDCARD, NULL,
  		    "No matching global attribute declaration available, but "
  		    "demanded by the strict wildcard");
  		break;
  	    case XML_SCHEMAS_ATTR_UNKNOWN:
  		if (iattr->metaType)
  		    break;
  		/*
  		* MAYBE VAL TODO: One might report different error messages
  		* for the following errors.
  		*/
  		if (type->attributeWildcard == NULL) {
  		    xmlSchemaIllegalAttrErr(ACTXT_CAST vctxt,
  			XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_1, iattr, NULL);
  		} else {
  		    xmlSchemaIllegalAttrErr(ACTXT_CAST vctxt,
  			XML_SCHEMAV_CVC_COMPLEX_TYPE_3_2_2, iattr, NULL);
  		}
  		break;
  	    default:
  		break;
  	}
      }
  
      ACTIVATE_ELEM;
      return (0);
  internal_error:
      ACTIVATE_ELEM;
      return (-1);
  }
  
  static int
  xmlSchemaValidateElemWildcard(xmlSchemaValidCtxtPtr vctxt,
  			      int *skip)
  {
      xmlSchemaWildcardPtr wild = (xmlSchemaWildcardPtr) vctxt->inode->decl;
      /*
      * The namespace of the element was already identified to be
      * matching the wildcard.
      */
      if ((skip == NULL) || (wild == NULL) ||
  	(wild->type != XML_SCHEMA_TYPE_ANY)) {
  	VERROR_INT("xmlSchemaValidateElemWildcard",
  	    "bad arguments");
  	return (-1);
      }
      *skip = 0;
      if (wild->processContents == XML_SCHEMAS_ANY_SKIP) {
  	/*
  	* URGENT VAL TODO: Either we need to position the stream to the
  	* next sibling, or walk the whole subtree.
  	*/
  	*skip = 1;
  	return (0);
      }
      {
  	xmlSchemaElementPtr decl = NULL;
  
  	decl = xmlSchemaGetElem(vctxt->schema,
  	    vctxt->inode->localName, vctxt->inode->nsName);
  	if (decl != NULL) {
  	    vctxt->inode->decl = decl;
  	    return (0);
  	}
      }
      if (wild->processContents == XML_SCHEMAS_ANY_STRICT) {
  	/* VAL TODO: Change to proper error code. */
  	VERROR(XML_SCHEMAV_CVC_ELT_1, NULL, /* WXS_BASIC_CAST wild */
  	    "No matching global element declaration available, but "
  	    "demanded by the strict wildcard");
  	return (vctxt->err);
      }
      if (vctxt->nbAttrInfos != 0) {
  	xmlSchemaAttrInfoPtr iattr;
  	/*
  	* SPEC Validation Rule: Schema-Validity Assessment (Element)
  	* (1.2.1.2.1) - (1.2.1.2.3 )
  	*
  	* Use the xsi:type attribute for the type definition.
  	*/
  	iattr = xmlSchemaGetMetaAttrInfo(vctxt,
  	    XML_SCHEMA_ATTR_INFO_META_XSI_TYPE);
  	if (iattr != NULL) {
  	    if (xmlSchemaProcessXSIType(vctxt, iattr,
  		&(vctxt->inode->typeDef), NULL) == -1) {
  		VERROR_INT("xmlSchemaValidateElemWildcard",
  		    "calling xmlSchemaProcessXSIType() to "
  		    "process the attribute 'xsi:nil'");
  		return (-1);
  	    }
  	    /*
  	    * Don't return an error on purpose.
  	    */
  	    return (0);
  	}
      }
      /*
      * SPEC Validation Rule: Schema-Validity Assessment (Element)
      *
      * Fallback to "anyType".
      */
      vctxt->inode->typeDef =
  	xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE);
      return (0);
  }
  
  /*
  * xmlSchemaCheckCOSValidDefault:
  *
  * This will be called if: not nilled, no content and a default/fixed
  * value is provided.
  */
  
  static int
  xmlSchemaCheckCOSValidDefault(xmlSchemaValidCtxtPtr vctxt,
  			      const xmlChar *value,
  			      xmlSchemaValPtr *val)
  {
      int ret = 0;
      xmlSchemaNodeInfoPtr inode = vctxt->inode;
  
      /*
      * cos-valid-default:
      * Schema Component Constraint: Element Default Valid (Immediate)
      * For a string to be a valid default with respect to a type
      * definition the appropriate case among the following must be true:
      */
      if WXS_IS_COMPLEX(inode->typeDef) {
  	/*
  	* Complex type.
  	*
  	* SPEC (2.1) "its {content type} must be a simple type definition
  	* or mixed."
  	* SPEC (2.2.2) "If the {content type} is mixed, then the {content
  	* type}'s particle must be `emptiable` as defined by
  	* Particle Emptiable ($3.9.6)."
  	*/
  	if ((! WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) &&
  	    ((! WXS_HAS_MIXED_CONTENT(inode->typeDef)) ||
  	     (! WXS_EMPTIABLE(inode->typeDef)))) {
  	    ret = XML_SCHEMAP_COS_VALID_DEFAULT_2_1;
  	    /* NOTE that this covers (2.2.2) as well. */
  	    VERROR(ret, NULL,
  		"For a string to be a valid default, the type definition "
  		"must be a simple type or a complex type with simple content "
  		"or mixed content and a particle emptiable");
  	    return(ret);
  	}
      }
      /*
      * 1 If the type definition is a simple type definition, then the string
      * must be `valid` with respect to that definition as defined by String
      * Valid ($3.14.4).
      *
      * AND
      *
      * 2.2.1 If the {content type} is a simple type definition, then the
      * string must be `valid` with respect to that simple type definition
      * as defined by String Valid ($3.14.4).
      */
      if (WXS_IS_SIMPLE(inode->typeDef)) {
  
  	ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST vctxt,
  	    NULL, inode->typeDef, value, val, 1, 1, 0);
  
      } else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) {
  
  	ret = xmlSchemaVCheckCVCSimpleType(ACTXT_CAST vctxt,
  	    NULL, inode->typeDef->contentTypeDef, value, val, 1, 1, 0);
      }
      if (ret < 0) {
  	VERROR_INT("xmlSchemaCheckCOSValidDefault",
  	    "calling xmlSchemaVCheckCVCSimpleType()");
      }
      return (ret);
  }
  
  static void
  xmlSchemaVContentModelCallback(xmlRegExecCtxtPtr exec ATTRIBUTE_UNUSED,
  			       const xmlChar * name ATTRIBUTE_UNUSED,
  			       void *transdata, void *inputdata)
  {
      xmlSchemaElementPtr item = (xmlSchemaElementPtr) transdata;
      xmlSchemaNodeInfoPtr inode = (xmlSchemaNodeInfoPtr) inputdata;
      inode->decl = item;
  #ifdef DEBUG_CONTENT
      {
  	xmlChar *str = NULL;
  
  	if (item->type == XML_SCHEMA_TYPE_ELEMENT) {
  	    xmlGenericError(xmlGenericErrorContext,
  		"AUTOMATON callback for '%s' [declaration]\n",
  		xmlSchemaFormatQName(&str,
  		inode->localName, inode->nsName));
  	} else {
  	    xmlGenericError(xmlGenericErrorContext,
  		    "AUTOMATON callback for '%s' [wildcard]\n",
  		    xmlSchemaFormatQName(&str,
  		    inode->localName, inode->nsName));
  
  	}
  	FREE_AND_NULL(str)
      }
  #endif
  }
  
  static int
  xmlSchemaValidatorPushElem(xmlSchemaValidCtxtPtr vctxt)
  {
      vctxt->inode = xmlSchemaGetFreshElemInfo(vctxt);
      if (vctxt->inode == NULL) {
  	VERROR_INT("xmlSchemaValidatorPushElem",
  	    "calling xmlSchemaGetFreshElemInfo()");
  	return (-1);
      }
      vctxt->nbAttrInfos = 0;
      return (0);
  }
  
  static int
  xmlSchemaVCheckINodeDataType(xmlSchemaValidCtxtPtr vctxt,
  			     xmlSchemaNodeInfoPtr inode,
  			     xmlSchemaTypePtr type,
  			     const xmlChar *value)
  {
      if (inode->flags & XML_SCHEMA_NODE_INFO_VALUE_NEEDED)
  	return (xmlSchemaVCheckCVCSimpleType(
  	    ACTXT_CAST vctxt, NULL,
  	    type, value, &(inode->val), 1, 1, 0));
      else
  	return (xmlSchemaVCheckCVCSimpleType(
  	    ACTXT_CAST vctxt, NULL,
  	    type, value, NULL, 1, 0, 0));
  }
  
  
  
  /*
  * Process END of element.
  */
  static int
  xmlSchemaValidatorPopElem(xmlSchemaValidCtxtPtr vctxt)
  {
      int ret = 0;
      xmlSchemaNodeInfoPtr inode = vctxt->inode;
  
      if (vctxt->nbAttrInfos != 0)
  	xmlSchemaClearAttrInfos(vctxt);
      if (inode->flags & XML_SCHEMA_NODE_INFO_ERR_NOT_EXPECTED) {
  	/*
  	* This element was not expected;
  	* we will not validate child elements of broken parents.
  	* Skip validation of all content of the parent.
  	*/
  	vctxt->skipDepth = vctxt->depth -1;
  	goto end_elem;
      }
      if ((inode->typeDef == NULL) ||
  	(inode->flags & XML_SCHEMA_NODE_INFO_ERR_BAD_TYPE)) {
  	/*
  	* 1. the type definition might be missing if the element was
  	*    error prone
  	* 2. it might be abstract.
  	*/
  	goto end_elem;
      }
      /*
      * Check the content model.
      */
      if ((inode->typeDef->contentType == XML_SCHEMA_CONTENT_MIXED) ||
  	(inode->typeDef->contentType == XML_SCHEMA_CONTENT_ELEMENTS)) {
  
  	/*
  	* Workaround for "anyType".
  	*/
  	if (inode->typeDef->builtInType == XML_SCHEMAS_ANYTYPE)
  	    goto character_content;
  
  	if ((inode->flags & XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT) == 0) {
  	    xmlChar *values[10];
  	    int terminal, nbval = 10, nbneg;
  
  	    if (inode->regexCtxt == NULL) {
  		/*
  		* Create the regex context.
  		*/
  		inode->regexCtxt =
  		    xmlRegNewExecCtxt(inode->typeDef->contModel,
  		    xmlSchemaVContentModelCallback, vctxt);
  		if (inode->regexCtxt == NULL) {
  		    VERROR_INT("xmlSchemaValidatorPopElem",
  			"failed to create a regex context");
  		    goto internal_error;
  		}
  #ifdef DEBUG_AUTOMATA
  		xmlGenericError(xmlGenericErrorContext,
  		    "AUTOMATON create on '%s'\n", inode->localName);
  #endif
  	    }
  
  	    /*
  	     * Do not check further content if the node has been nilled
  	     */
  	    if (INODE_NILLED(inode)) {
  		ret = 0;
  #ifdef DEBUG_AUTOMATA
  		xmlGenericError(xmlGenericErrorContext,
  		    "AUTOMATON succeeded on nilled '%s'\n",
  		    inode->localName);
  #endif
                  goto skip_nilled;
  	    }
  
  	    /*
  	    * Get hold of the still expected content, since a further
  	    * call to xmlRegExecPushString() will lose this information.
  	    */
  	    xmlRegExecNextValues(inode->regexCtxt,
  		&nbval, &nbneg, &values[0], &terminal);
  	    ret = xmlRegExecPushString(inode->regexCtxt, NULL, NULL);
  	    if ((ret<0) || ((ret==0) && (!INODE_NILLED(inode)))) {
  		/*
  		* Still missing something.
  		*/
  		ret = 1;
  		inode->flags |=
  		    XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT;
  		xmlSchemaComplexTypeErr(ACTXT_CAST vctxt,
  		    XML_SCHEMAV_ELEMENT_CONTENT, NULL, NULL,
  		    "Missing child element(s)",
  		    nbval, nbneg, values);
  #ifdef DEBUG_AUTOMATA
  		xmlGenericError(xmlGenericErrorContext,
  		    "AUTOMATON missing ERROR on '%s'\n",
  		    inode->localName);
  #endif
  	    } else {
  		/*
  		* Content model is satisfied.
  		*/
  		ret = 0;
  #ifdef DEBUG_AUTOMATA
  		xmlGenericError(xmlGenericErrorContext,
  		    "AUTOMATON succeeded on '%s'\n",
  		    inode->localName);
  #endif
  	    }
  
  	}
      }
  
  skip_nilled:
  
      if (inode->typeDef->contentType == XML_SCHEMA_CONTENT_ELEMENTS)
  	goto end_elem;
  
  character_content:
  
      if (vctxt->value != NULL) {
  	xmlSchemaFreeValue(vctxt->value);
  	vctxt->value = NULL;
      }
      /*
      * Check character content.
      */
      if (inode->decl == NULL) {
  	/*
  	* Speedup if no declaration exists.
  	*/
  	if (WXS_IS_SIMPLE(inode->typeDef)) {
  	    ret = xmlSchemaVCheckINodeDataType(vctxt,
  		inode, inode->typeDef, inode->value);
  	} else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) {
  	    ret = xmlSchemaVCheckINodeDataType(vctxt,
  		inode, inode->typeDef->contentTypeDef,
  		inode->value);
  	}
  	if (ret < 0) {
  	    VERROR_INT("xmlSchemaValidatorPopElem",
  		"calling xmlSchemaVCheckCVCSimpleType()");
  	    goto internal_error;
  	}
  	goto end_elem;
      }
      /*
      * cvc-elt (3.3.4) : 5
      * The appropriate case among the following must be true:
      */
      /*
      * cvc-elt (3.3.4) : 5.1
      * If the declaration has a {value constraint},
      * the item has neither element nor character [children] and
      * clause 3.2 has not applied, then all of the following must be true:
      */
      if ((inode->decl->value != NULL) &&
  	(inode->flags & XML_SCHEMA_ELEM_INFO_EMPTY) &&
  	(! INODE_NILLED(inode))) {
  	/*
  	* cvc-elt (3.3.4) : 5.1.1
  	* If the `actual type definition` is a `local type definition`
  	* then the canonical lexical representation of the {value constraint}
  	* value must be a valid default for the `actual type definition` as
  	* defined in Element Default Valid (Immediate) ($3.3.6).
  	*/
  	/*
  	* NOTE: 'local' above means types acquired by xsi:type.
  	* NOTE: Although the *canonical* value is stated, it is not
  	* relevant if canonical or not. Additionally XML Schema 1.1
  	* will removed this requirement as well.
  	*/
  	if (inode->flags & XML_SCHEMA_ELEM_INFO_LOCAL_TYPE) {
  
  	    ret = xmlSchemaCheckCOSValidDefault(vctxt,
  		inode->decl->value, &(inode->val));
  	    if (ret != 0) {
  		if (ret < 0) {
  		    VERROR_INT("xmlSchemaValidatorPopElem",
  			"calling xmlSchemaCheckCOSValidDefault()");
  		    goto internal_error;
  		}
  		goto end_elem;
  	    }
  	    /*
  	    * Stop here, to avoid redundant validation of the value
  	    * (see following).
  	    */
  	    goto default_psvi;
  	}
  	/*
  	* cvc-elt (3.3.4) : 5.1.2
  	* The element information item with the canonical lexical
  	* representation of the {value constraint} value used as its
  	* `normalized value` must be `valid` with respect to the
  	* `actual type definition` as defined by Element Locally Valid (Type)
  	* ($3.3.4).
  	*/
  	if (WXS_IS_SIMPLE(inode->typeDef)) {
  	    ret = xmlSchemaVCheckINodeDataType(vctxt,
  		inode, inode->typeDef, inode->decl->value);
  	} else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) {
  	    ret = xmlSchemaVCheckINodeDataType(vctxt,
  		inode, inode->typeDef->contentTypeDef,
  		inode->decl->value);
  	}
  	if (ret != 0) {
  	    if (ret < 0) {
  		VERROR_INT("xmlSchemaValidatorPopElem",
  		    "calling xmlSchemaVCheckCVCSimpleType()");
  		goto internal_error;
  	    }
  	    goto end_elem;
  	}
  
  default_psvi:
  	/*
  	* PSVI: Create a text node on the instance element.
  	*/
  	if ((vctxt->options & XML_SCHEMA_VAL_VC_I_CREATE) &&
  	    (inode->node != NULL)) {
  	    xmlNodePtr textChild;
  	    xmlChar *normValue;
  	    /*
  	    * VAL TODO: Normalize the value.
  	    */
  	    normValue = xmlSchemaNormalizeValue(inode->typeDef,
  		inode->decl->value);
  	    if (normValue != NULL) {
  		textChild = xmlNewText(BAD_CAST normValue);
  		xmlFree(normValue);
  	    } else
  		textChild = xmlNewText(inode->decl->value);
  	    if (textChild == NULL) {
  		VERROR_INT("xmlSchemaValidatorPopElem",
  		    "calling xmlNewText()");
  		goto internal_error;
  	    } else
  		xmlAddChild(inode->node, textChild);
  	}
  
      } else if (! INODE_NILLED(inode)) {
  	/*
  	* 5.2.1 The element information item must be `valid` with respect
  	* to the `actual type definition` as defined by Element Locally
  	* Valid (Type) ($3.3.4).
  	*/
  	if (WXS_IS_SIMPLE(inode->typeDef)) {
  	     /*
  	    * SPEC (cvc-type) (3.1)
  	    * "If the type definition is a simple type definition, ..."
  	    * (3.1.3) "If clause 3.2 of Element Locally Valid
  	    * (Element) ($3.3.4) did not apply, then the `normalized value`
  	    * must be `valid` with respect to the type definition as defined
  	    * by String Valid ($3.14.4).
  	    */
  	    ret = xmlSchemaVCheckINodeDataType(vctxt,
  		    inode, inode->typeDef, inode->value);
  	} else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) {
  	    /*
  	    * SPEC (cvc-type) (3.2) "If the type definition is a complex type
  	    * definition, then the element information item must be
  	    * `valid` with respect to the type definition as per
  	    * Element Locally Valid (Complex Type) ($3.4.4);"
  	    *
  	    * SPEC (cvc-complex-type) (2.2)
  	    * "If the {content type} is a simple type definition, ...
  	    * 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)."
  	    */
  	    ret = xmlSchemaVCheckINodeDataType(vctxt,
  		inode, inode->typeDef->contentTypeDef, inode->value);
  	}
  	if (ret != 0) {
  	    if (ret < 0) {
  		VERROR_INT("xmlSchemaValidatorPopElem",
  		    "calling xmlSchemaVCheckCVCSimpleType()");
  		goto internal_error;
  	    }
  	    goto end_elem;
  	}
  	/*
  	* 5.2.2 If there is a fixed {value constraint} and clause 3.2 has
  	* not applied, all of the following must be true:
  	*/
  	if ((inode->decl->value != NULL) &&
  	    (inode->decl->flags & XML_SCHEMAS_ELEM_FIXED)) {
  
  	    /*
  	    * TODO: We will need a computed value, when comparison is
  	    * done on computed values.
  	    */
  	    /*
  	    * 5.2.2.1 The element information item must have no element
  	    * information item [children].
  	    */
  	    if (inode->flags &
  		    XML_SCHEMA_ELEM_INFO_HAS_ELEM_CONTENT) {
  		ret = XML_SCHEMAV_CVC_ELT_5_2_2_1;
  		VERROR(ret, NULL,
  		    "The content must not contain element nodes since "
  		    "there is a fixed value constraint");
  		goto end_elem;
  	    } else {
  		/*
  		* 5.2.2.2 The appropriate case among the following must
  		* be true:
  		*/
  		if (WXS_HAS_MIXED_CONTENT(inode->typeDef)) {
  		    /*
  		    * 5.2.2.2.1 If the {content type} of the `actual type
  		    * definition` is mixed, then the *initial value* of the
  		    * item must match the canonical lexical representation
  		    * of the {value constraint} value.
  		    *
  		    * ... the *initial value* of an element information
  		    * item is the string composed of, in order, the
  		    * [character code] of each character information item in
  		    * the [children] of that element information item.
  		    */
  		    if (! xmlStrEqual(inode->value, inode->decl->value)){
  			/*
  			* VAL TODO: Report invalid & expected values as well.
  			* VAL TODO: Implement the canonical stuff.
  			*/
  			ret = XML_SCHEMAV_CVC_ELT_5_2_2_2_1;
  			xmlSchemaCustomErr(ACTXT_CAST vctxt,
  			    ret, NULL, NULL,
  			    "The initial value '%s' does not match the fixed "
  			    "value constraint '%s'",
  			    inode->value, inode->decl->value);
  			goto end_elem;
  		    }
  		} else if (WXS_HAS_SIMPLE_CONTENT(inode->typeDef)) {
  		    /*
  		    * 5.2.2.2.2 If the {content type} of the `actual type
  		    * definition` is a simple type definition, then the
  		    * *actual value* of the item must match the canonical
  		    * lexical representation of the {value constraint} value.
  		    */
  		    /*
  		    * VAL TODO: *actual value* is the normalized value, impl.
  		    *           this.
  		    * VAL TODO: Report invalid & expected values as well.
  		    * VAL TODO: Implement a comparison with the computed values.
  		    */
  		    if (! xmlStrEqual(inode->value,
  			    inode->decl->value)) {
  			ret = XML_SCHEMAV_CVC_ELT_5_2_2_2_2;
  			xmlSchemaCustomErr(ACTXT_CAST vctxt,
  			    ret, NULL, NULL,
  			    "The actual value '%s' does not match the fixed "
  			    "value constraint '%s'",
  			    inode->value,
  			    inode->decl->value);
  			goto end_elem;
  		    }
  		}
  	    }
  	}
      }
  
  end_elem:
      if (vctxt->depth < 0) {
  	/* TODO: raise error? */
  	return (0);
      }
      if (vctxt->depth == vctxt->skipDepth)
  	vctxt->skipDepth = -1;
      /*
      * Evaluate the history of XPath state objects.
      */
      if (inode->appliedXPath &&
  	(xmlSchemaXPathProcessHistory(vctxt, vctxt->depth) == -1))
  	goto internal_error;
      /*
      * MAYBE TODO:
      * SPEC (6) "The element information item must be `valid` with
      * respect to each of the {identity-constraint definitions} as per
      * Identity-constraint Satisfied ($3.11.4)."
      */
      /*
      * PSVI TODO: If we expose IDC node-tables via PSVI then the tables
      *   need to be built in any case.
      *   We will currently build IDC node-tables and bubble them only if
      *   keyrefs do exist.
      */
  
      /*
      * Add the current IDC target-nodes to the IDC node-tables.
      */
      if ((inode->idcMatchers != NULL) &&
  	(vctxt->hasKeyrefs || vctxt->createIDCNodeTables))
      {
  	if (xmlSchemaIDCFillNodeTables(vctxt, inode) == -1)
  	    goto internal_error;
      }
      /*
      * Validate IDC keyrefs.
      */
      if (vctxt->inode->hasKeyrefs)
  	if (xmlSchemaCheckCVCIDCKeyRef(vctxt) == -1)
  	    goto internal_error;
      /*
      * Merge/free the IDC table.
      */
      if (inode->idcTable != NULL) {
  #ifdef DEBUG_IDC_NODE_TABLE
  	xmlSchemaDebugDumpIDCTable(stdout,
  	    inode->nsName,
  	    inode->localName,
  	    inode->idcTable);
  #endif
  	if ((vctxt->depth > 0) &&
  	    (vctxt->hasKeyrefs || vctxt->createIDCNodeTables))
  	{
  	    /*
  	    * Merge the IDC node table with the table of the parent node.
  	    */
  	    if (xmlSchemaBubbleIDCNodeTables(vctxt) == -1)
  		goto internal_error;
  	}
      }
      /*
      * Clear the current ielem.
      * VAL TODO: Don't free the PSVI IDC tables if they are
      * requested for the PSVI.
      */
      xmlSchemaClearElemInfo(vctxt, inode);
      /*
      * Skip further processing if we are on the validation root.
      */
      if (vctxt->depth == 0) {
  	vctxt->depth--;
  	vctxt->inode = NULL;
  	return (0);
      }
      /*
      * Reset the keyrefDepth if needed.
      */
      if (vctxt->aidcs != NULL) {
  	xmlSchemaIDCAugPtr aidc = vctxt->aidcs;
  	do {
  	    if (aidc->keyrefDepth == vctxt->depth) {
  		/*
  		* A 'keyrefDepth' of a key/unique IDC matches the current
  		* depth, this means that we are leaving the scope of the
  		* top-most keyref IDC which refers to this IDC.
  		*/
  		aidc->keyrefDepth = -1;
  	    }
  	    aidc = aidc->next;
  	} while (aidc != NULL);
      }
      vctxt->depth--;
      vctxt->inode = vctxt->elemInfos[vctxt->depth];
      /*
      * VAL TODO: 7 If the element information item is the `validation root`, it must be
      * `valid` per Validation Root Valid (ID/IDREF) ($3.3.4).
      */
      return (ret);
  
  internal_error:
      vctxt->err = -1;
      return (-1);
  }
  
  /*
  * 3.4.4 Complex Type Definition Validation Rules
  * Validation Rule: Element Locally Valid (Complex Type) (cvc-complex-type)
  */
  static int
  xmlSchemaValidateChildElem(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlSchemaNodeInfoPtr pielem;
      xmlSchemaTypePtr ptype;
      int ret = 0;
  
      if (vctxt->depth <= 0) {
  	VERROR_INT("xmlSchemaValidateChildElem",
  	    "not intended for the validation root");
  	return (-1);
      }
      pielem = vctxt->elemInfos[vctxt->depth -1];
      if (pielem->flags & XML_SCHEMA_ELEM_INFO_EMPTY)
  	pielem->flags ^= XML_SCHEMA_ELEM_INFO_EMPTY;
      /*
      * Handle 'nilled' elements.
      */
      if (INODE_NILLED(pielem)) {
  	/*
  	* SPEC (cvc-elt) (3.3.4) : (3.2.1)
  	*/
  	ACTIVATE_PARENT_ELEM;
  	ret = XML_SCHEMAV_CVC_ELT_3_2_1;
  	VERROR(ret, NULL,
  	    "Neither character nor element content is allowed, "
  	    "because the element was 'nilled'");
  	ACTIVATE_ELEM;
  	goto unexpected_elem;
      }
  
      ptype = pielem->typeDef;
  
      if (ptype->builtInType == XML_SCHEMAS_ANYTYPE) {
  	/*
  	* Workaround for "anyType": we have currently no content model
  	* assigned for "anyType", so handle it explicitly.
  	* "anyType" has an unbounded, lax "any" wildcard.
  	*/
  	vctxt->inode->decl = xmlSchemaGetElem(vctxt->schema,
  	    vctxt->inode->localName,
  	    vctxt->inode->nsName);
  
  	if (vctxt->inode->decl == NULL) {
  	    xmlSchemaAttrInfoPtr iattr;
  	    /*
  	    * Process "xsi:type".
  	    * SPEC (cvc-assess-elt) (1.2.1.2.1) - (1.2.1.2.3)
  	    */
  	    iattr = xmlSchemaGetMetaAttrInfo(vctxt,
  		XML_SCHEMA_ATTR_INFO_META_XSI_TYPE);
  	    if (iattr != NULL) {
  		ret = xmlSchemaProcessXSIType(vctxt, iattr,
  		    &(vctxt->inode->typeDef), NULL);
  		if (ret != 0) {
  		    if (ret == -1) {
  			VERROR_INT("xmlSchemaValidateChildElem",
  			    "calling xmlSchemaProcessXSIType() to "
  			    "process the attribute 'xsi:nil'");
  			return (-1);
  		    }
  		    return (ret);
  		}
  	    } else {
  		 /*
  		 * Fallback to "anyType".
  		 *
  		 * SPEC (cvc-assess-elt)
  		 * "If the item cannot be `strictly assessed`, [...]
  		 * an element information item's schema validity may be laxly
  		 * assessed if its `context-determined declaration` is not
  		 * skip by `validating` with respect to the `ur-type
  		 * definition` as per Element Locally Valid (Type) ($3.3.4)."
  		*/
  		vctxt->inode->typeDef =
  		    xmlSchemaGetBuiltInType(XML_SCHEMAS_ANYTYPE);
  	    }
  	}
  	return (0);
      }
  
      switch (ptype->contentType) {
  	case XML_SCHEMA_CONTENT_EMPTY:
  	    /*
  	    * SPEC (2.1) "If the {content type} is empty, then the
  	    * element information item has no character or element
  	    * information item [children]."
  	    */
  	    ACTIVATE_PARENT_ELEM
  	    ret = XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1;
  	    VERROR(ret, NULL,
  		"Element content is not allowed, "
  		"because the content type is empty");
  	    ACTIVATE_ELEM
  	    goto unexpected_elem;
  	    break;
  
  	case XML_SCHEMA_CONTENT_MIXED:
          case XML_SCHEMA_CONTENT_ELEMENTS: {
  	    xmlRegExecCtxtPtr regexCtxt;
  	    xmlChar *values[10];
  	    int terminal, nbval = 10, nbneg;
  
  	    /* VAL TODO: Optimized "anyType" validation.*/
  
  	    if (ptype->contModel == NULL) {
  		VERROR_INT("xmlSchemaValidateChildElem",
  		    "type has elem content but no content model");
  		return (-1);
  	    }
  	    /*
  	    * Safety belt for evaluation if the cont. model was already
  	    * examined to be invalid.
  	    */
  	    if (pielem->flags & XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT) {
  		VERROR_INT("xmlSchemaValidateChildElem",
  		    "validating elem, but elem content is already invalid");
  		return (-1);
  	    }
  
  	    regexCtxt = pielem->regexCtxt;
  	    if (regexCtxt == NULL) {
  		/*
  		* Create the regex context.
  		*/
  		regexCtxt = xmlRegNewExecCtxt(ptype->contModel,
  		    xmlSchemaVContentModelCallback, vctxt);
  		if (regexCtxt == NULL) {
  		    VERROR_INT("xmlSchemaValidateChildElem",
  			"failed to create a regex context");
  		    return (-1);
  		}
  		pielem->regexCtxt = regexCtxt;
  #ifdef DEBUG_AUTOMATA
  		xmlGenericError(xmlGenericErrorContext, "AUTOMATA create on '%s'\n",
  		    pielem->localName);
  #endif
  	    }
  
  	    /*
  	    * SPEC (2.4) "If the {content type} is element-only or mixed,
  	    * then the sequence of the element information item's
  	    * element information item [children], if any, taken in
  	    * order, is `valid` with respect to the {content type}'s
  	    * particle, as defined in Element Sequence Locally Valid
  	    * (Particle) ($3.9.4)."
  	    */
  	    ret = xmlRegExecPushString2(regexCtxt,
  		vctxt->inode->localName,
  		vctxt->inode->nsName,
  		vctxt->inode);
  #ifdef DEBUG_AUTOMATA
  	    if (ret < 0)
  		xmlGenericError(xmlGenericErrorContext,
  		"AUTOMATON push ERROR for '%s' on '%s'\n",
  		vctxt->inode->localName, pielem->localName);
  	    else
  		xmlGenericError(xmlGenericErrorContext,
  		"AUTOMATON push OK for '%s' on '%s'\n",
  		vctxt->inode->localName, pielem->localName);
  #endif
  	    if (vctxt->err == XML_SCHEMAV_INTERNAL) {
  		VERROR_INT("xmlSchemaValidateChildElem",
  		    "calling xmlRegExecPushString2()");
  		return (-1);
  	    }
  	    if (ret < 0) {
  		xmlRegExecErrInfo(regexCtxt, NULL, &nbval, &nbneg,
  		    &values[0], &terminal);
  		xmlSchemaComplexTypeErr(ACTXT_CAST vctxt,
  		    XML_SCHEMAV_ELEMENT_CONTENT, NULL,NULL,
  		    "This element is not expected",
  		    nbval, nbneg, values);
  		ret = vctxt->err;
  		goto unexpected_elem;
  	    } else
  		ret = 0;
  	}
  	    break;
  	case XML_SCHEMA_CONTENT_SIMPLE:
  	case XML_SCHEMA_CONTENT_BASIC:
  	    ACTIVATE_PARENT_ELEM
  	    if (WXS_IS_COMPLEX(ptype)) {
  		/*
  		* SPEC (cvc-complex-type) (2.2)
  		* "If the {content type} is a simple type definition, then
  		* the element information item has no element information
  		* item [children], ..."
  		*/
  		ret = XML_SCHEMAV_CVC_COMPLEX_TYPE_2_2;
  		VERROR(ret, NULL, "Element content is not allowed, "
  		    "because the content type is a simple type definition");
  	    } else {
  		/*
  		* SPEC (cvc-type) (3.1.2) "The element information item must
  		* have no element information item [children]."
  		*/
  		ret = XML_SCHEMAV_CVC_TYPE_3_1_2;
  		VERROR(ret, NULL, "Element content is not allowed, "
  		    "because the type definition is simple");
  	    }
  	    ACTIVATE_ELEM
  	    ret = vctxt->err;
  	    goto unexpected_elem;
  	    break;
  
  	default:
  	    break;
      }
      return (ret);
  unexpected_elem:
      /*
      * Pop this element and set the skipDepth to skip
      * all further content of the parent element.
      */
      vctxt->skipDepth = vctxt->depth;
      vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_ERR_NOT_EXPECTED;
      pielem->flags |= XML_SCHEMA_ELEM_INFO_ERR_BAD_CONTENT;
      return (ret);
  }
  
  #define XML_SCHEMA_PUSH_TEXT_PERSIST 1
  #define XML_SCHEMA_PUSH_TEXT_CREATED 2
  #define XML_SCHEMA_PUSH_TEXT_VOLATILE 3
  
  static int
  xmlSchemaVPushText(xmlSchemaValidCtxtPtr vctxt,
  		  int nodeType, const xmlChar *value, int len,
  		  int mode, int *consumed)
  {
      /*
      * Unfortunately we have to duplicate the text sometimes.
      * OPTIMIZE: Maybe we could skip it, if:
      *   1. content type is simple
      *   2. whitespace is "collapse"
      *   3. it consists of whitespace only
      *
      * Process character content.
      */
      if (consumed != NULL)
  	*consumed = 0;
      if (INODE_NILLED(vctxt->inode)) {
  	/*
  	* SPEC cvc-elt (3.3.4 - 3.2.1)
  	* "The element information item must have no character or
  	* element information item [children]."
  	*/
  	VERROR(XML_SCHEMAV_CVC_ELT_3_2_1, NULL,
  	    "Neither character nor element content is allowed "
  	    "because the element is 'nilled'");
  	return (vctxt->err);
      }
      /*
      * SPEC (2.1) "If the {content type} is empty, then the
      * element information item has no character or element
      * information item [children]."
      */
      if (vctxt->inode->typeDef->contentType ==
  	    XML_SCHEMA_CONTENT_EMPTY) {
  	VERROR(XML_SCHEMAV_CVC_COMPLEX_TYPE_2_1, NULL,
  	    "Character content is not allowed, "
  	    "because the content type is empty");
  	return (vctxt->err);
      }
  
      if (vctxt->inode->typeDef->contentType ==
  	    XML_SCHEMA_CONTENT_ELEMENTS) {
  	if ((nodeType != XML_TEXT_NODE) ||
  	    (! xmlSchemaIsBlank((xmlChar *) value, len))) {
  	    /*
  	    * SPEC cvc-complex-type (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)]."
  	    */
  	    VERROR(XML_SCHEMAV_CVC_COMPLEX_TYPE_2_3, NULL,
  		"Character content other than whitespace is not allowed "
  		"because the content type is 'element-only'");
  	    return (vctxt->err);
  	}
  	return (0);
      }
  
      if ((value == NULL) || (value[0] == 0))
  	return (0);
      /*
      * Save the value.
      * NOTE that even if the content type is *mixed*, we need the
      * *initial value* for default/fixed value constraints.
      */
      if ((vctxt->inode->typeDef->contentType == XML_SCHEMA_CONTENT_MIXED) &&
  	((vctxt->inode->decl == NULL) ||
  	(vctxt->inode->decl->value == NULL)))
  	return (0);
  
      if (vctxt->inode->value == NULL) {
  	/*
  	* Set the value.
  	*/
  	switch (mode) {
  	    case XML_SCHEMA_PUSH_TEXT_PERSIST:
  		/*
  		* When working on a tree.
  		*/
  		vctxt->inode->value = value;
  		break;
  	    case XML_SCHEMA_PUSH_TEXT_CREATED:
  		/*
  		* When working with the reader.
  		* The value will be freed by the element info.
  		*/
  		vctxt->inode->value = value;
  		if (consumed != NULL)
  		    *consumed = 1;
  		vctxt->inode->flags |=
  		    XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES;
  		break;
  	    case XML_SCHEMA_PUSH_TEXT_VOLATILE:
  		/*
  		* When working with SAX.
  		* The value will be freed by the element info.
  		*/
  		if (len != -1)
  		    vctxt->inode->value = BAD_CAST xmlStrndup(value, len);
  		else
  		    vctxt->inode->value = BAD_CAST xmlStrdup(value);
  		vctxt->inode->flags |=
  		    XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES;
  		break;
  	    default:
  		break;
  	}
      } else {
  	if (len < 0)
  	    len = xmlStrlen(value);
  	/*
  	* Concat the value.
  	*/
  	if (vctxt->inode->flags & XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES) {
  	    vctxt->inode->value = BAD_CAST xmlStrncat(
  		(xmlChar *) vctxt->inode->value, value, len);
  	} else {
  	    vctxt->inode->value =
  		BAD_CAST xmlStrncatNew(vctxt->inode->value, value, len);
  	    vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_FLAG_OWNED_VALUES;
  	}
      }
  
      return (0);
  }
  
  static int
  xmlSchemaValidateElem(xmlSchemaValidCtxtPtr vctxt)
  {
      int ret = 0;
  
      if ((vctxt->skipDepth != -1) &&
  	(vctxt->depth >= vctxt->skipDepth)) {
  	VERROR_INT("xmlSchemaValidateElem",
  	    "in skip-state");
  	goto internal_error;
      }
      if (vctxt->xsiAssemble) {
  	/*
  	* We will stop validation if there was an error during
  	* dynamic schema construction.
  	* Note that we simply set @skipDepth to 0, this could
  	* mean that a streaming document via SAX would be
  	* still read to the end but it won't be validated any more.
  	* TODO: If we are sure how to stop the validation at once
  	*   for all input scenarios, then this should be changed to
  	*   instantly stop the validation.
  	*/
  	ret = xmlSchemaAssembleByXSI(vctxt);
  	if (ret != 0) {
  	    if (ret == -1)
  		goto internal_error;
  	    vctxt->skipDepth = 0;
  	    return(ret);
  	}
          /*
           * Augment the IDC definitions for the main schema and all imported ones
           * NOTE: main schema is the first in the imported list
           */
          xmlHashScan(vctxt->schema->schemasImports, xmlSchemaAugmentImportedIDC,
                      vctxt);
      }
      if (vctxt->depth > 0) {
  	/*
  	* Validate this element against the content model
  	* of the parent.
  	*/
  	ret = xmlSchemaValidateChildElem(vctxt);
  	if (ret != 0) {
  	    if (ret < 0) {
  		VERROR_INT("xmlSchemaValidateElem",
  		    "calling xmlSchemaStreamValidateChildElement()");
  		goto internal_error;
  	    }
  	    goto exit;
  	}
  	if (vctxt->depth == vctxt->skipDepth)
  	    goto exit;
  	if ((vctxt->inode->decl == NULL) &&
  	    (vctxt->inode->typeDef == NULL)) {
  	    VERROR_INT("xmlSchemaValidateElem",
  		"the child element was valid but neither the "
  		"declaration nor the type was set");
  	    goto internal_error;
  	}
      } else {
  	/*
  	* Get the declaration of the validation root.
  	*/
  	vctxt->inode->decl = xmlSchemaGetElem(vctxt->schema,
  	    vctxt->inode->localName,
  	    vctxt->inode->nsName);
  	if (vctxt->inode->decl == NULL) {
  	    ret = XML_SCHEMAV_CVC_ELT_1;
  	    VERROR(ret, NULL,
  		"No matching global declaration available "
  		"for the validation root");
  	    goto exit;
  	}
      }
  
      if (vctxt->inode->decl == NULL)
  	goto type_validation;
  
      if (vctxt->inode->decl->type == XML_SCHEMA_TYPE_ANY) {
  	int skip;
  	/*
  	* Wildcards.
  	*/
  	ret = xmlSchemaValidateElemWildcard(vctxt, &skip);
  	if (ret != 0) {
  	    if (ret < 0) {
  		VERROR_INT("xmlSchemaValidateElem",
  		    "calling xmlSchemaValidateElemWildcard()");
  		goto internal_error;
  	    }
  	    goto exit;
  	}
  	if (skip) {
  	    vctxt->skipDepth = vctxt->depth;
  	    goto exit;
  	}
  	/*
  	* The declaration might be set by the wildcard validation,
  	* when the processContents is "lax" or "strict".
  	*/
  	if (vctxt->inode->decl->type != XML_SCHEMA_TYPE_ELEMENT) {
  	    /*
  	    * Clear the "decl" field to not confuse further processing.
  	    */
  	    vctxt->inode->decl = NULL;
  	    goto type_validation;
  	}
      }
      /*
      * Validate against the declaration.
      */
      ret = xmlSchemaValidateElemDecl(vctxt);
      if (ret != 0) {
  	if (ret < 0) {
  	    VERROR_INT("xmlSchemaValidateElem",
  		"calling xmlSchemaValidateElemDecl()");
  	    goto internal_error;
  	}
  	goto exit;
      }
      /*
      * Validate against the type definition.
      */
  type_validation:
  
      if (vctxt->inode->typeDef == NULL) {
  	vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_ERR_BAD_TYPE;
  	ret = XML_SCHEMAV_CVC_TYPE_1;
  	VERROR(ret, NULL,
  	    "The type definition is absent");
  	goto exit;
      }
      if (vctxt->inode->typeDef->flags & XML_SCHEMAS_TYPE_ABSTRACT) {
  	vctxt->inode->flags |= XML_SCHEMA_NODE_INFO_ERR_BAD_TYPE;
  	ret = XML_SCHEMAV_CVC_TYPE_2;
  	    VERROR(ret, NULL,
  	    "The type definition is abstract");
  	goto exit;
      }
      /*
      * Evaluate IDCs. Do it here, since new IDC matchers are registered
      * during validation against the declaration. This must be done
      * _before_ attribute validation.
      */
      if (vctxt->xpathStates != NULL) {
  	ret = xmlSchemaXPathEvaluate(vctxt, XML_ELEMENT_NODE);
  	vctxt->inode->appliedXPath = 1;
  	if (ret == -1) {
  	    VERROR_INT("xmlSchemaValidateElem",
  		"calling xmlSchemaXPathEvaluate()");
  	    goto internal_error;
  	}
      }
      /*
      * Validate attributes.
      */
      if (WXS_IS_COMPLEX(vctxt->inode->typeDef)) {
  	if ((vctxt->nbAttrInfos != 0) ||
  	    (vctxt->inode->typeDef->attrUses != NULL)) {
  
  	    ret = xmlSchemaVAttributesComplex(vctxt);
  	}
      } else if (vctxt->nbAttrInfos != 0) {
  
  	ret = xmlSchemaVAttributesSimple(vctxt);
      }
      /*
      * Clear registered attributes.
      */
      if (vctxt->nbAttrInfos != 0)
  	xmlSchemaClearAttrInfos(vctxt);
      if (ret == -1) {
  	VERROR_INT("xmlSchemaValidateElem",
  	    "calling attributes validation");
  	goto internal_error;
      }
      /*
      * Don't return an error if attributes are invalid on purpose.
      */
      ret = 0;
  
  exit:
      if (ret != 0)
  	vctxt->skipDepth = vctxt->depth;
      return (ret);
  internal_error:
      return (-1);
  }
  
  #ifdef XML_SCHEMA_READER_ENABLED
  static int
  xmlSchemaVReaderWalk(xmlSchemaValidCtxtPtr vctxt)
  {
      const int WHTSP = 13, SIGN_WHTSP = 14, END_ELEM = 15;
      int depth, nodeType, ret = 0, consumed;
      xmlSchemaNodeInfoPtr ielem;
  
      vctxt->depth = -1;
      ret = xmlTextReaderRead(vctxt->reader);
      /*
      * Move to the document element.
      */
      while (ret == 1) {
  	nodeType = xmlTextReaderNodeType(vctxt->reader);
  	if (nodeType == XML_ELEMENT_NODE)
  	    goto root_found;
  	ret = xmlTextReaderRead(vctxt->reader);
      }
      goto exit;
  
  root_found:
  
      do {
  	depth = xmlTextReaderDepth(vctxt->reader);
  	nodeType = xmlTextReaderNodeType(vctxt->reader);
  
  	if (nodeType == XML_ELEMENT_NODE) {
  
  	    vctxt->depth++;
  	    if (xmlSchemaValidatorPushElem(vctxt) == -1) {
  		VERROR_INT("xmlSchemaVReaderWalk",
  		    "calling xmlSchemaValidatorPushElem()");
  		goto internal_error;
  	    }
  	    ielem = vctxt->inode;
  	    ielem->localName = xmlTextReaderLocalName(vctxt->reader);
  	    ielem->nsName = xmlTextReaderNamespaceUri(vctxt->reader);
  	    ielem->flags |= XML_SCHEMA_NODE_INFO_FLAG_OWNED_NAMES;
  	    /*
  	    * Is the element empty?
  	    */
  	    ret = xmlTextReaderIsEmptyElement(vctxt->reader);
  	    if (ret == -1) {
  		VERROR_INT("xmlSchemaVReaderWalk",
  		    "calling xmlTextReaderIsEmptyElement()");
  		goto internal_error;
  	    }
  	    if (ret) {
  		ielem->flags |= XML_SCHEMA_ELEM_INFO_EMPTY;
  	    }
  	    /*
  	    * Register attributes.
  	    */
  	    vctxt->nbAttrInfos = 0;
  	    ret = xmlTextReaderMoveToFirstAttribute(vctxt->reader);
  	    if (ret == -1) {
  		VERROR_INT("xmlSchemaVReaderWalk",
  		    "calling xmlTextReaderMoveToFirstAttribute()");
  		goto internal_error;
  	    }
  	    if (ret == 1) {
  		do {
  		    /*
  		    * VAL TODO: How do we know that the reader works on a
  		    * node tree, to be able to pass a node here?
  		    */
  		    if (xmlSchemaValidatorPushAttribute(vctxt, NULL,
  			(const xmlChar *) xmlTextReaderLocalName(vctxt->reader),
  			xmlTextReaderNamespaceUri(vctxt->reader), 1,
  			xmlTextReaderValue(vctxt->reader), 1) == -1) {
  
  			VERROR_INT("xmlSchemaVReaderWalk",
  			    "calling xmlSchemaValidatorPushAttribute()");
  			goto internal_error;
  		    }
  		    ret = xmlTextReaderMoveToNextAttribute(vctxt->reader);
  		    if (ret == -1) {
  			VERROR_INT("xmlSchemaVReaderWalk",
  			    "calling xmlTextReaderMoveToFirstAttribute()");
  			goto internal_error;
  		    }
  		} while (ret == 1);
  		/*
  		* Back to element position.
  		*/
  		ret = xmlTextReaderMoveToElement(vctxt->reader);
  		if (ret == -1) {
  		    VERROR_INT("xmlSchemaVReaderWalk",
  			"calling xmlTextReaderMoveToElement()");
  		    goto internal_error;
  		}
  	    }
  	    /*
  	    * Validate the element.
  	    */
  	    ret= xmlSchemaValidateElem(vctxt);
  	    if (ret != 0) {
  		if (ret == -1) {
  		    VERROR_INT("xmlSchemaVReaderWalk",
  			"calling xmlSchemaValidateElem()");
  		    goto internal_error;
  		}
  		goto exit;
  	    }
  	    if (vctxt->depth == vctxt->skipDepth) {
  		int curDepth;
  		/*
  		* Skip all content.
  		*/
  		if ((ielem->flags & XML_SCHEMA_ELEM_INFO_EMPTY) == 0) {
  		    ret = xmlTextReaderRead(vctxt->reader);
  		    curDepth = xmlTextReaderDepth(vctxt->reader);
  		    while ((ret == 1) && (curDepth != depth)) {
  			ret = xmlTextReaderRead(vctxt->reader);
  			curDepth = xmlTextReaderDepth(vctxt->reader);
  		    }
  		    if (ret < 0) {
  			/*
  			* VAL TODO: A reader error occurred; what to do here?
  			*/
  			ret = 1;
  			goto exit;
  		    }
  		}
  		goto leave_elem;
  	    }
  	    /*
  	    * READER VAL TODO: Is an END_ELEM really never called
  	    * if the elem is empty?
  	    */
  	    if (ielem->flags & XML_SCHEMA_ELEM_INFO_EMPTY)
  		goto leave_elem;
  	} else if (nodeType == END_ELEM) {
  	    /*
  	    * Process END of element.
  	    */
  leave_elem:
  	    ret = xmlSchemaValidatorPopElem(vctxt);
  	    if (ret != 0) {
  		if (ret < 0) {
  		    VERROR_INT("xmlSchemaVReaderWalk",
  			"calling xmlSchemaValidatorPopElem()");
  		    goto internal_error;
  		}
  		goto exit;
  	    }
  	    if (vctxt->depth >= 0)
  		ielem = vctxt->inode;
  	    else
  		ielem = NULL;
  	} else if ((nodeType == XML_TEXT_NODE) ||
  	    (nodeType == XML_CDATA_SECTION_NODE) ||
  	    (nodeType == WHTSP) ||
  	    (nodeType == SIGN_WHTSP)) {
  	    /*
  	    * Process character content.
  	    */
  	    xmlChar *value;
  
  	    if ((nodeType == WHTSP) || (nodeType == SIGN_WHTSP))
  		nodeType = XML_TEXT_NODE;
  
  	    value = xmlTextReaderValue(vctxt->reader);
  	    ret = xmlSchemaVPushText(vctxt, nodeType, BAD_CAST value,
  		-1, XML_SCHEMA_PUSH_TEXT_CREATED, &consumed);
  	    if (! consumed)
  		xmlFree(value);
  	    if (ret == -1) {
  		VERROR_INT("xmlSchemaVReaderWalk",
  		    "calling xmlSchemaVPushText()");
  		goto internal_error;
  	    }
  	} else if ((nodeType == XML_ENTITY_NODE) ||
  	    (nodeType == XML_ENTITY_REF_NODE)) {
  	    /*
  	    * VAL TODO: What to do with entities?
  	    */
  	    TODO
  	}
  	/*
  	* Read next node.
  	*/
  	ret = xmlTextReaderRead(vctxt->reader);
      } while (ret == 1);
  
  exit:
      return (ret);
  internal_error:
      return (-1);
  }
  #endif
  
  /************************************************************************
   *									*
   *			SAX validation handlers				*
   *									*
   ************************************************************************/
  
  /*
  * Process text content.
  */
  static void
  xmlSchemaSAXHandleText(void *ctx,
  		       const xmlChar * ch,
  		       int len)
  {
      xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx;
  
      if (vctxt->depth < 0)
  	return;
      if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth))
  	return;
      if (vctxt->inode->flags & XML_SCHEMA_ELEM_INFO_EMPTY)
  	vctxt->inode->flags ^= XML_SCHEMA_ELEM_INFO_EMPTY;
      if (xmlSchemaVPushText(vctxt, XML_TEXT_NODE, ch, len,
  	XML_SCHEMA_PUSH_TEXT_VOLATILE, NULL) == -1) {
  	VERROR_INT("xmlSchemaSAXHandleCDataSection",
  	    "calling xmlSchemaVPushText()");
  	vctxt->err = -1;
  	xmlStopParser(vctxt->parserCtxt);
      }
  }
  
  /*
  * Process CDATA content.
  */
  static void
  xmlSchemaSAXHandleCDataSection(void *ctx,
  			     const xmlChar * ch,
  			     int len)
  {
      xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx;
  
      if (vctxt->depth < 0)
  	return;
      if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth))
  	return;
      if (vctxt->inode->flags & XML_SCHEMA_ELEM_INFO_EMPTY)
  	vctxt->inode->flags ^= XML_SCHEMA_ELEM_INFO_EMPTY;
      if (xmlSchemaVPushText(vctxt, XML_CDATA_SECTION_NODE, ch, len,
  	XML_SCHEMA_PUSH_TEXT_VOLATILE, NULL) == -1) {
  	VERROR_INT("xmlSchemaSAXHandleCDataSection",
  	    "calling xmlSchemaVPushText()");
  	vctxt->err = -1;
  	xmlStopParser(vctxt->parserCtxt);
      }
  }
  
  static void
  xmlSchemaSAXHandleReference(void *ctx ATTRIBUTE_UNUSED,
  			    const xmlChar * name ATTRIBUTE_UNUSED)
  {
      xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx;
  
      if (vctxt->depth < 0)
  	return;
      if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth))
  	return;
      /* SAX VAL TODO: What to do here? */
      TODO
  }
  
  static void
  xmlSchemaSAXHandleStartElementNs(void *ctx,
  				 const xmlChar * localname,
  				 const xmlChar * prefix ATTRIBUTE_UNUSED,
  				 const xmlChar * URI,
  				 int nb_namespaces,
  				 const xmlChar ** namespaces,
  				 int nb_attributes,
  				 int nb_defaulted ATTRIBUTE_UNUSED,
  				 const xmlChar ** attributes)
  {
      xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx;
      int ret;
      xmlSchemaNodeInfoPtr ielem;
      int i, j;
  
      /*
      * SAX VAL TODO: What to do with nb_defaulted?
      */
      /*
      * Skip elements if inside a "skip" wildcard or invalid.
      */
      vctxt->depth++;
      if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth))
  	return;
      /*
      * Push the element.
      */
      if (xmlSchemaValidatorPushElem(vctxt) == -1) {
  	VERROR_INT("xmlSchemaSAXHandleStartElementNs",
  	    "calling xmlSchemaValidatorPushElem()");
  	goto internal_error;
      }
      ielem = vctxt->inode;
      /*
      * TODO: Is this OK?
      */
      ielem->nodeLine = xmlSAX2GetLineNumber(vctxt->parserCtxt);
      ielem->localName = localname;
      ielem->nsName = URI;
      ielem->flags |= XML_SCHEMA_ELEM_INFO_EMPTY;
      /*
      * Register namespaces on the elem info.
      */
      if (nb_namespaces != 0) {
  	/*
  	* Although the parser builds its own namespace list,
  	* we have no access to it, so we'll use an own one.
  	*/
          for (i = 0, j = 0; i < nb_namespaces; i++, j += 2) {
  	    /*
  	    * Store prefix and namespace name.
  	    */
  	    if (ielem->nsBindings == NULL) {
  		ielem->nsBindings =
  		    (const xmlChar **) xmlMalloc(10 *
  			sizeof(const xmlChar *));
  		if (ielem->nsBindings == NULL) {
  		    xmlSchemaVErrMemory(vctxt,
  			"allocating namespace bindings for SAX validation",
  			NULL);
  		    goto internal_error;
  		}
  		ielem->nbNsBindings = 0;
  		ielem->sizeNsBindings = 5;
  	    } else if (ielem->sizeNsBindings <= ielem->nbNsBindings) {
  		ielem->sizeNsBindings *= 2;
  		ielem->nsBindings =
  		    (const xmlChar **) xmlRealloc(
  			(void *) ielem->nsBindings,
  			ielem->sizeNsBindings * 2 * sizeof(const xmlChar *));
  		if (ielem->nsBindings == NULL) {
  		    xmlSchemaVErrMemory(vctxt,
  			"re-allocating namespace bindings for SAX validation",
  			NULL);
  		    goto internal_error;
  		}
  	    }
  
  	    ielem->nsBindings[ielem->nbNsBindings * 2] = namespaces[j];
  	    if (namespaces[j+1][0] == 0) {
  		/*
  		* Handle xmlns="".
  		*/
  		ielem->nsBindings[ielem->nbNsBindings * 2 + 1] = NULL;
  	    } else
  		ielem->nsBindings[ielem->nbNsBindings * 2 + 1] =
  		    namespaces[j+1];
  	    ielem->nbNsBindings++;
  	}
      }
      /*
      * Register attributes.
      * SAX VAL TODO: We are not adding namespace declaration
      * attributes yet.
      */
      if (nb_attributes != 0) {
  	int valueLen, k, l;
  	xmlChar *value;
  
          for (j = 0, i = 0; i < nb_attributes; i++, j += 5) {
  	    /*
  	    * Duplicate the value, changing any &#38; to a literal ampersand.
  	    *
  	    * libxml2 differs from normal SAX here in that it escapes all ampersands
  	    * as &#38; instead of delivering the raw converted string. Changing the
  	    * behavior at this point would break applications that use this API, so
  	    * we are forced to work around it.
  	    */
  	    valueLen = attributes[j+4] - attributes[j+3];
  	    value = xmlMallocAtomic(valueLen + 1);
  	    if (value == NULL) {
  		xmlSchemaVErrMemory(vctxt,
  		    "allocating string for decoded attribute",
  		    NULL);
  		goto internal_error;
  	    }
  	    for (k = 0, l = 0; k < valueLen; l++) {
  		if (k < valueLen - 4 &&
  		    attributes[j+3][k+0] == '&' &&
  		    attributes[j+3][k+1] == '#' &&
  		    attributes[j+3][k+2] == '3' &&
  		    attributes[j+3][k+3] == '8' &&
  		    attributes[j+3][k+4] == ';') {
  		    value[l] = '&';
  		    k += 5;
  		} else {
  		    value[l] = attributes[j+3][k];
  		    k++;
  		}
  	    }
  	    value[l] = '\0';
  	    /*
  	    * TODO: Set the node line.
  	    */
  	    ret = xmlSchemaValidatorPushAttribute(vctxt,
  		NULL, ielem->nodeLine, attributes[j], attributes[j+2], 0,
  		value, 1);
  	    if (ret == -1) {
  		VERROR_INT("xmlSchemaSAXHandleStartElementNs",
  		    "calling xmlSchemaValidatorPushAttribute()");
  		goto internal_error;
  	    }
  	}
      }
      /*
      * Validate the element.
      */
      ret = xmlSchemaValidateElem(vctxt);
      if (ret != 0) {
  	if (ret == -1) {
  	    VERROR_INT("xmlSchemaSAXHandleStartElementNs",
  		"calling xmlSchemaValidateElem()");
  	    goto internal_error;
  	}
  	goto exit;
      }
  
  exit:
      return;
  internal_error:
      vctxt->err = -1;
      xmlStopParser(vctxt->parserCtxt);
      return;
  }
  
  static void
  xmlSchemaSAXHandleEndElementNs(void *ctx,
  			       const xmlChar * localname ATTRIBUTE_UNUSED,
  			       const xmlChar * prefix ATTRIBUTE_UNUSED,
  			       const xmlChar * URI ATTRIBUTE_UNUSED)
  {
      xmlSchemaValidCtxtPtr vctxt = (xmlSchemaValidCtxtPtr) ctx;
      int res;
  
      /*
      * Skip elements if inside a "skip" wildcard or if invalid.
      */
      if (vctxt->skipDepth != -1) {
  	if (vctxt->depth > vctxt->skipDepth) {
  	    vctxt->depth--;
  	    return;
  	} else
  	    vctxt->skipDepth = -1;
      }
      /*
      * SAX VAL TODO: Just a temporary check.
      */
      if ((!xmlStrEqual(vctxt->inode->localName, localname)) ||
  	(!xmlStrEqual(vctxt->inode->nsName, URI))) {
  	VERROR_INT("xmlSchemaSAXHandleEndElementNs",
  	    "elem pop mismatch");
      }
      res = xmlSchemaValidatorPopElem(vctxt);
      if (res != 0) {
  	if (res < 0) {
  	    VERROR_INT("xmlSchemaSAXHandleEndElementNs",
  		"calling xmlSchemaValidatorPopElem()");
  	    goto internal_error;
  	}
  	goto exit;
      }
  exit:
      return;
  internal_error:
      vctxt->err = -1;
      xmlStopParser(vctxt->parserCtxt);
      return;
  }
  
  /************************************************************************
   *									*
   *			Validation interfaces				*
   *									*
   ************************************************************************/
  
  /**
   * xmlSchemaNewValidCtxt:
   * @schema:  a precompiled XML Schemas
   *
   * Create an XML Schemas validation context based on the given schema.
   *
   * Returns the validation context or NULL in case of error
   */
  xmlSchemaValidCtxtPtr
  xmlSchemaNewValidCtxt(xmlSchemaPtr schema)
  {
      xmlSchemaValidCtxtPtr ret;
  
      ret = (xmlSchemaValidCtxtPtr) xmlMalloc(sizeof(xmlSchemaValidCtxt));
      if (ret == NULL) {
          xmlSchemaVErrMemory(NULL, "allocating validation context", NULL);
          return (NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaValidCtxt));
      ret->type = XML_SCHEMA_CTXT_VALIDATOR;
      ret->dict = xmlDictCreate();
      ret->nodeQNames = xmlSchemaItemListCreate();
      ret->schema = schema;
      return (ret);
  }
  
  /**
   * xmlSchemaValidateSetFilename:
   * @vctxt: the schema validation context
   * @filename: the file name
   *
   * Workaround to provide file error reporting information when this is
   * not provided by current APIs
   */
  void
  xmlSchemaValidateSetFilename(xmlSchemaValidCtxtPtr vctxt, const char *filename) {
      if (vctxt == NULL)
          return;
      if (vctxt->filename != NULL)
          xmlFree(vctxt->filename);
      if (filename != NULL)
          vctxt->filename = (char *) xmlStrdup((const xmlChar *) filename);
      else
          vctxt->filename = NULL;
  }
  
  /**
   * xmlSchemaClearValidCtxt:
   * @vctxt: the schema validation context
   *
   * Free the resources associated to the schema validation context;
   * leaves some fields alive intended for reuse of the context.
   */
  static void
  xmlSchemaClearValidCtxt(xmlSchemaValidCtxtPtr vctxt)
  {
      if (vctxt == NULL)
          return;
  
      /*
      * TODO: Should we clear the flags?
      *   Might be problematic if one reuses the context
      *   and assumes that the options remain the same.
      */
      vctxt->flags = 0;
      vctxt->validationRoot = NULL;
      vctxt->doc = NULL;
  #ifdef LIBXML_READER_ENABLED
      vctxt->reader = NULL;
  #endif
      vctxt->hasKeyrefs = 0;
  
      if (vctxt->value != NULL) {
          xmlSchemaFreeValue(vctxt->value);
  	vctxt->value = NULL;
      }
      /*
      * Augmented IDC information.
      */
      if (vctxt->aidcs != NULL) {
  	xmlSchemaIDCAugPtr cur = vctxt->aidcs, next;
  	do {
  	    next = cur->next;
  	    xmlFree(cur);
  	    cur = next;
  	} while (cur != NULL);
  	vctxt->aidcs = NULL;
      }
      if (vctxt->idcMatcherCache != NULL) {
  	xmlSchemaIDCMatcherPtr matcher = vctxt->idcMatcherCache, tmp;
  
  	while (matcher) {
  	    tmp = matcher;
  	    matcher = matcher->nextCached;
  	    xmlSchemaIDCFreeMatcherList(tmp);
  	}
  	vctxt->idcMatcherCache = NULL;
      }
  
  
      if (vctxt->idcNodes != NULL) {
  	int i;
  	xmlSchemaPSVIIDCNodePtr item;
  
  	for (i = 0; i < vctxt->nbIdcNodes; i++) {
  	    item = vctxt->idcNodes[i];
  	    xmlFree(item->keys);
  	    xmlFree(item);
  	}
  	xmlFree(vctxt->idcNodes);
  	vctxt->idcNodes = NULL;
  	vctxt->nbIdcNodes = 0;
  	vctxt->sizeIdcNodes = 0;
      }
  
      if (vctxt->idcKeys != NULL) {
  	int i;
  	for (i = 0; i < vctxt->nbIdcKeys; i++)
  	    xmlSchemaIDCFreeKey(vctxt->idcKeys[i]);
  	xmlFree(vctxt->idcKeys);
  	vctxt->idcKeys = NULL;
  	vctxt->nbIdcKeys = 0;
  	vctxt->sizeIdcKeys = 0;
      }
  
      /*
      * Note that we won't delete the XPath state pool here.
      */
      if (vctxt->xpathStates != NULL) {
  	xmlSchemaFreeIDCStateObjList(vctxt->xpathStates);
  	vctxt->xpathStates = NULL;
      }
      /*
      * Attribute info.
      */
      if (vctxt->nbAttrInfos != 0) {
  	xmlSchemaClearAttrInfos(vctxt);
      }
      /*
      * Element info.
      */
      if (vctxt->elemInfos != NULL) {
  	int i;
  	xmlSchemaNodeInfoPtr ei;
  
  	for (i = 0; i < vctxt->sizeElemInfos; i++) {
  	    ei = vctxt->elemInfos[i];
  	    if (ei == NULL)
  		break;
  	    xmlSchemaClearElemInfo(vctxt, ei);
  	}
      }
      xmlSchemaItemListClear(vctxt->nodeQNames);
      /* Recreate the dict. */
      xmlDictFree(vctxt->dict);
      /*
      * TODO: Is is save to recreate it? Do we have a scenario
      * where the user provides the dict?
      */
      vctxt->dict = xmlDictCreate();
  
      if (vctxt->filename != NULL) {
          xmlFree(vctxt->filename);
  	vctxt->filename = NULL;
      }
  }
  
  /**
   * xmlSchemaFreeValidCtxt:
   * @ctxt:  the schema validation context
   *
   * Free the resources associated to the schema validation context
   */
  void
  xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt)
  {
      if (ctxt == NULL)
          return;
      if (ctxt->value != NULL)
          xmlSchemaFreeValue(ctxt->value);
      if (ctxt->pctxt != NULL)
  	xmlSchemaFreeParserCtxt(ctxt->pctxt);
      if (ctxt->idcNodes != NULL) {
  	int i;
  	xmlSchemaPSVIIDCNodePtr item;
  
  	for (i = 0; i < ctxt->nbIdcNodes; i++) {
  	    item = ctxt->idcNodes[i];
  	    xmlFree(item->keys);
  	    xmlFree(item);
  	}
  	xmlFree(ctxt->idcNodes);
      }
      if (ctxt->idcKeys != NULL) {
  	int i;
  	for (i = 0; i < ctxt->nbIdcKeys; i++)
  	    xmlSchemaIDCFreeKey(ctxt->idcKeys[i]);
  	xmlFree(ctxt->idcKeys);
      }
  
      if (ctxt->xpathStates != NULL) {
  	xmlSchemaFreeIDCStateObjList(ctxt->xpathStates);
  	ctxt->xpathStates = NULL;
      }
      if (ctxt->xpathStatePool != NULL) {
  	xmlSchemaFreeIDCStateObjList(ctxt->xpathStatePool);
  	ctxt->xpathStatePool = NULL;
      }
  
      /*
      * Augmented IDC information.
      */
      if (ctxt->aidcs != NULL) {
  	xmlSchemaIDCAugPtr cur = ctxt->aidcs, next;
  	do {
  	    next = cur->next;
  	    xmlFree(cur);
  	    cur = next;
  	} while (cur != NULL);
      }
      if (ctxt->attrInfos != NULL) {
  	int i;
  	xmlSchemaAttrInfoPtr attr;
  
  	/* Just a paranoid call to the cleanup. */
  	if (ctxt->nbAttrInfos != 0)
  	    xmlSchemaClearAttrInfos(ctxt);
  	for (i = 0; i < ctxt->sizeAttrInfos; i++) {
  	    attr = ctxt->attrInfos[i];
  	    xmlFree(attr);
  	}
  	xmlFree(ctxt->attrInfos);
      }
      if (ctxt->elemInfos != NULL) {
  	int i;
  	xmlSchemaNodeInfoPtr ei;
  
  	for (i = 0; i < ctxt->sizeElemInfos; i++) {
  	    ei = ctxt->elemInfos[i];
  	    if (ei == NULL)
  		break;
  	    xmlSchemaClearElemInfo(ctxt, ei);
  	    xmlFree(ei);
  	}
  	xmlFree(ctxt->elemInfos);
      }
      if (ctxt->nodeQNames != NULL)
  	xmlSchemaItemListFree(ctxt->nodeQNames);
      if (ctxt->dict != NULL)
  	xmlDictFree(ctxt->dict);
      if (ctxt->filename != NULL)
  	xmlFree(ctxt->filename);
      xmlFree(ctxt);
  }
  
  /**
   * xmlSchemaIsValid:
   * @ctxt: the schema validation context
   *
   * Check if any error was detected during validation.
   *
   * Returns 1 if valid so far, 0 if errors were detected, and -1 in case
   *         of internal error.
   */
  int
  xmlSchemaIsValid(xmlSchemaValidCtxtPtr ctxt)
  {
      if (ctxt == NULL)
          return(-1);
      return(ctxt->err == 0);
  }
  
  /**
   * xmlSchemaSetValidErrors:
   * @ctxt:  a schema validation context
   * @err:  the error function
   * @warn: the warning function
   * @ctx: the functions context
   *
   * Set the error and warning callback informations
   */
  void
  xmlSchemaSetValidErrors(xmlSchemaValidCtxtPtr ctxt,
                          xmlSchemaValidityErrorFunc err,
                          xmlSchemaValidityWarningFunc warn, void *ctx)
  {
      if (ctxt == NULL)
          return;
      ctxt->error = err;
      ctxt->warning = warn;
      ctxt->errCtxt = ctx;
      if (ctxt->pctxt != NULL)
  	xmlSchemaSetParserErrors(ctxt->pctxt, err, warn, ctx);
  }
  
  /**
   * xmlSchemaSetValidStructuredErrors:
   * @ctxt:  a schema validation context
   * @serror:  the structured error function
   * @ctx: the functions context
   *
   * Set the structured error callback
   */
  void
  xmlSchemaSetValidStructuredErrors(xmlSchemaValidCtxtPtr ctxt,
  				  xmlStructuredErrorFunc serror, void *ctx)
  {
      if (ctxt == NULL)
          return;
      ctxt->serror = serror;
      ctxt->error = NULL;
      ctxt->warning = NULL;
      ctxt->errCtxt = ctx;
      if (ctxt->pctxt != NULL)
  	xmlSchemaSetParserStructuredErrors(ctxt->pctxt, serror, ctx);
  }
  
  /**
   * xmlSchemaGetValidErrors:
   * @ctxt: a XML-Schema validation context
   * @err: the error function result
   * @warn: the warning function result
   * @ctx: the functions context result
   *
   * Get the error and warning callback informations
   *
   * Returns -1 in case of error and 0 otherwise
   */
  int
  xmlSchemaGetValidErrors(xmlSchemaValidCtxtPtr ctxt,
  			xmlSchemaValidityErrorFunc * err,
  			xmlSchemaValidityWarningFunc * warn, void **ctx)
  {
  	if (ctxt == NULL)
  		return (-1);
  	if (err != NULL)
  		*err = ctxt->error;
  	if (warn != NULL)
  		*warn = ctxt->warning;
  	if (ctx != NULL)
  		*ctx = ctxt->errCtxt;
  	return (0);
  }
  
  
  /**
   * xmlSchemaSetValidOptions:
   * @ctxt:	a schema validation context
   * @options: a combination of xmlSchemaValidOption
   *
   * Sets the options to be used during the validation.
   *
   * Returns 0 in case of success, -1 in case of an
   * API error.
   */
  int
  xmlSchemaSetValidOptions(xmlSchemaValidCtxtPtr ctxt,
  			 int options)
  
  {
      int i;
  
      if (ctxt == NULL)
  	return (-1);
      /*
      * WARNING: Change the start value if adding to the
      * xmlSchemaValidOption.
      * TODO: Is there an other, more easy to maintain,
      * way?
      */
      for (i = 1; i < (int) sizeof(int) * 8; i++) {
          if (options & 1<<i)
  	    return (-1);
      }
      ctxt->options = options;
      return (0);
  }
  
  /**
   * xmlSchemaValidCtxtGetOptions:
   * @ctxt: a schema validation context
   *
   * Get the validation context options.
   *
   * Returns the option combination or -1 on error.
   */
  int
  xmlSchemaValidCtxtGetOptions(xmlSchemaValidCtxtPtr ctxt)
  
  {
      if (ctxt == NULL)
  	return (-1);
      else
  	return (ctxt->options);
  }
  
  static int
  xmlSchemaVDocWalk(xmlSchemaValidCtxtPtr vctxt)
  {
      xmlAttrPtr attr;
      int ret = 0;
      xmlSchemaNodeInfoPtr ielem = NULL;
      xmlNodePtr node, valRoot;
      const xmlChar *nsName;
  
      /* DOC VAL TODO: Move this to the start function. */
      if (vctxt->validationRoot != NULL)
          valRoot = vctxt->validationRoot;
      else
  	valRoot = xmlDocGetRootElement(vctxt->doc);
      if (valRoot == NULL) {
  	/* VAL TODO: Error code? */
  	VERROR(1, NULL, "The document has no document element");
  	return (1);
      }
      vctxt->depth = -1;
      vctxt->validationRoot = valRoot;
      node = valRoot;
      while (node != NULL) {
  	if ((vctxt->skipDepth != -1) && (vctxt->depth >= vctxt->skipDepth))
  	    goto next_sibling;
  	if (node->type == XML_ELEMENT_NODE) {
  
  	    /*
  	    * Init the node-info.
  	    */
  	    vctxt->depth++;
  	    if (xmlSchemaValidatorPushElem(vctxt) == -1)
  		goto internal_error;
  	    ielem = vctxt->inode;
  	    ielem->node = node;
  	    ielem->nodeLine = node->line;
  	    ielem->localName = node->name;
  	    if (node->ns != NULL)
  		ielem->nsName = node->ns->href;
  	    ielem->flags |= XML_SCHEMA_ELEM_INFO_EMPTY;
  	    /*
  	    * Register attributes.
  	    * DOC VAL TODO: We do not register namespace declaration
  	    * attributes yet.
  	    */
  	    vctxt->nbAttrInfos = 0;
  	    if (node->properties != NULL) {
  		attr = node->properties;
  		do {
  		    if (attr->ns != NULL)
  			nsName = attr->ns->href;
  		    else
  			nsName = NULL;
  		    ret = xmlSchemaValidatorPushAttribute(vctxt,
  			(xmlNodePtr) attr,
  			/*
  			* Note that we give it the line number of the
  			* parent element.
  			*/
  			ielem->nodeLine,
  			attr->name, nsName, 0,
  			xmlNodeListGetString(attr->doc, attr->children, 1), 1);
  		    if (ret == -1) {
  			VERROR_INT("xmlSchemaDocWalk",
  			    "calling xmlSchemaValidatorPushAttribute()");
  			goto internal_error;
  		    }
  		    attr = attr->next;
  		} while (attr);
  	    }
  	    /*
  	    * Validate the element.
  	    */
  	    ret = xmlSchemaValidateElem(vctxt);
  	    if (ret != 0) {
  		if (ret == -1) {
  		    VERROR_INT("xmlSchemaDocWalk",
  			"calling xmlSchemaValidateElem()");
  		    goto internal_error;
  		}
  		/*
  		* Don't stop validation; just skip the content
  		* of this element.
  		*/
  		goto leave_node;
  	    }
  	    if ((vctxt->skipDepth != -1) &&
  		(vctxt->depth >= vctxt->skipDepth))
  		goto leave_node;
  	} else if ((node->type == XML_TEXT_NODE) ||
  	    (node->type == XML_CDATA_SECTION_NODE)) {
  	    /*
  	    * Process character content.
  	    */
  	    if ((ielem != NULL) && (ielem->flags & XML_SCHEMA_ELEM_INFO_EMPTY))
  		ielem->flags ^= XML_SCHEMA_ELEM_INFO_EMPTY;
  	    ret = xmlSchemaVPushText(vctxt, node->type, node->content,
  		-1, XML_SCHEMA_PUSH_TEXT_PERSIST, NULL);
  	    if (ret < 0) {
  		VERROR_INT("xmlSchemaVDocWalk",
  		    "calling xmlSchemaVPushText()");
  		goto internal_error;
  	    }
  	    /*
  	    * DOC VAL TODO: Should we skip further validation of the
  	    * element content here?
  	    */
  	} else if ((node->type == XML_ENTITY_NODE) ||
  	    (node->type == XML_ENTITY_REF_NODE)) {
  	    /*
  	    * DOC VAL TODO: What to do with entities?
  	    */
  	    VERROR_INT("xmlSchemaVDocWalk",
  		"there is at least one entity reference in the node-tree "
  		"currently being validated. Processing of entities with "
  		"this XML Schema processor is not supported (yet). Please "
  		"substitute entities before validation.");
  	    goto internal_error;
  	} else {
  	    goto leave_node;
  	    /*
  	    * DOC VAL TODO: XInclude nodes, etc.
  	    */
  	}
  	/*
  	* Walk the doc.
  	*/
  	if (node->children != NULL) {
  	    node = node->children;
  	    continue;
  	}
  leave_node:
  	if (node->type == XML_ELEMENT_NODE) {
  	    /*
  	    * Leaving the scope of an element.
  	    */
  	    if (node != vctxt->inode->node) {
  		VERROR_INT("xmlSchemaVDocWalk",
  		    "element position mismatch");
  		goto internal_error;
  	    }
  	    ret = xmlSchemaValidatorPopElem(vctxt);
  	    if (ret != 0) {
  		if (ret < 0) {
  		    VERROR_INT("xmlSchemaVDocWalk",
  			"calling xmlSchemaValidatorPopElem()");
  		    goto internal_error;
  		}
  	    }
  	    if (node == valRoot)
  		goto exit;
  	}
  next_sibling:
  	if (node->next != NULL)
  	    node = node->next;
  	else {
  	    node = node->parent;
  	    goto leave_node;
  	}
      }
  
  exit:
      return (ret);
  internal_error:
      return (-1);
  }
  
  static int
  xmlSchemaPreRun(xmlSchemaValidCtxtPtr vctxt) {
      /*
      * Some initialization.
      */
      vctxt->err = 0;
      vctxt->nberrors = 0;
      vctxt->depth = -1;
      vctxt->skipDepth = -1;
      vctxt->xsiAssemble = 0;
      vctxt->hasKeyrefs = 0;
  #ifdef ENABLE_IDC_NODE_TABLES_TEST
      vctxt->createIDCNodeTables = 1;
  #else
      vctxt->createIDCNodeTables = 0;
  #endif
      /*
      * Create a schema + parser if necessary.
      */
      if (vctxt->schema == NULL) {
  	xmlSchemaParserCtxtPtr pctxt;
  
  	vctxt->xsiAssemble = 1;
  	/*
  	* If not schema was given then we will create a schema
  	* dynamically using XSI schema locations.
  	*
  	* Create the schema parser context.
  	*/
  	if ((vctxt->pctxt == NULL) &&
  	   (xmlSchemaCreatePCtxtOnVCtxt(vctxt) == -1))
  	   return (-1);
  	pctxt = vctxt->pctxt;
  	pctxt->xsiAssemble = 1;
  	/*
  	* Create the schema.
  	*/
  	vctxt->schema = xmlSchemaNewSchema(pctxt);
  	if (vctxt->schema == NULL)
  	    return (-1);
  	/*
  	* Create the schema construction context.
  	*/
  	pctxt->constructor = xmlSchemaConstructionCtxtCreate(pctxt->dict);
  	if (pctxt->constructor == NULL)
  	    return(-1);
  	pctxt->constructor->mainSchema = vctxt->schema;
  	/*
  	* Take ownership of the constructor to be able to free it.
  	*/
  	pctxt->ownsConstructor = 1;
      }
      /*
      * Augment the IDC definitions for the main schema and all imported ones
      * NOTE: main schema if the first in the imported list
      */
      xmlHashScan(vctxt->schema->schemasImports, xmlSchemaAugmentImportedIDC,
                  vctxt);
  
      return(0);
  }
  
  static void
  xmlSchemaPostRun(xmlSchemaValidCtxtPtr vctxt) {
      if (vctxt->xsiAssemble) {
  	if (vctxt->schema != NULL) {
  	    xmlSchemaFree(vctxt->schema);
  	    vctxt->schema = NULL;
  	}
      }
      xmlSchemaClearValidCtxt(vctxt);
  }
  
  static int
  xmlSchemaVStart(xmlSchemaValidCtxtPtr vctxt)
  {
      int ret = 0;
  
      if (xmlSchemaPreRun(vctxt) < 0)
          return(-1);
  
      if (vctxt->doc != NULL) {
  	/*
  	 * Tree validation.
  	 */
  	ret = xmlSchemaVDocWalk(vctxt);
  #ifdef LIBXML_READER_ENABLED
      } else if (vctxt->reader != NULL) {
  	/*
  	 * XML Reader validation.
  	 */
  #ifdef XML_SCHEMA_READER_ENABLED
  	ret = xmlSchemaVReaderWalk(vctxt);
  #endif
  #endif
      } else if ((vctxt->sax != NULL) && (vctxt->parserCtxt != NULL)) {
  	/*
  	 * SAX validation.
  	 */
  	ret = xmlParseDocument(vctxt->parserCtxt);
      } else {
  	VERROR_INT("xmlSchemaVStart",
  	    "no instance to validate");
  	ret = -1;
      }
  
      xmlSchemaPostRun(vctxt);
      if (ret == 0)
  	ret = vctxt->err;
      return (ret);
  }
  
  /**
   * xmlSchemaValidateOneElement:
   * @ctxt:  a schema validation context
   * @elem:  an element node
   *
   * Validate a branch of a tree, starting with the given @elem.
   *
   * Returns 0 if the element and its subtree is valid, a positive error
   * code number otherwise and -1 in case of an internal or API error.
   */
  int
  xmlSchemaValidateOneElement(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr elem)
  {
      if ((ctxt == NULL) || (elem == NULL) || (elem->type != XML_ELEMENT_NODE))
  	return (-1);
  
      if (ctxt->schema == NULL)
  	return (-1);
  
      ctxt->doc = elem->doc;
      ctxt->node = elem;
      ctxt->validationRoot = elem;
      return(xmlSchemaVStart(ctxt));
  }
  
  /**
   * xmlSchemaValidateDoc:
   * @ctxt:  a schema validation context
   * @doc:  a parsed document tree
   *
   * Validate a document tree in memory.
   *
   * Returns 0 if the document is schemas valid, a positive error code
   *     number otherwise and -1 in case of internal or API error.
   */
  int
  xmlSchemaValidateDoc(xmlSchemaValidCtxtPtr ctxt, xmlDocPtr doc)
  {
      if ((ctxt == NULL) || (doc == NULL))
          return (-1);
  
      ctxt->doc = doc;
      ctxt->node = xmlDocGetRootElement(doc);
      if (ctxt->node == NULL) {
          xmlSchemaCustomErr(ACTXT_CAST ctxt,
  	    XML_SCHEMAV_DOCUMENT_ELEMENT_MISSING,
  	    (xmlNodePtr) doc, NULL,
  	    "The document has no document element", NULL, NULL);
          return (ctxt->err);
      }
      ctxt->validationRoot = ctxt->node;
      return (xmlSchemaVStart(ctxt));
  }
  
  
  /************************************************************************
   *									*
   *		Function and data for SAX streaming API			*
   *									*
   ************************************************************************/
  typedef struct _xmlSchemaSplitSAXData xmlSchemaSplitSAXData;
  typedef xmlSchemaSplitSAXData *xmlSchemaSplitSAXDataPtr;
  
  struct _xmlSchemaSplitSAXData {
      xmlSAXHandlerPtr      user_sax;
      void                 *user_data;
      xmlSchemaValidCtxtPtr ctxt;
      xmlSAXHandlerPtr      schemas_sax;
  };
  
  #define XML_SAX_PLUG_MAGIC 0xdc43ba21
  
  struct _xmlSchemaSAXPlug {
      unsigned int magic;
  
      /* the original callbacks informations */
      xmlSAXHandlerPtr     *user_sax_ptr;
      xmlSAXHandlerPtr      user_sax;
      void                **user_data_ptr;
      void                 *user_data;
  
      /* the block plugged back and validation informations */
      xmlSAXHandler         schemas_sax;
      xmlSchemaValidCtxtPtr ctxt;
  };
  
  /* All those functions just bounces to the user provided SAX handlers */
  static void
  internalSubsetSplit(void *ctx, const xmlChar *name,
  	       const xmlChar *ExternalID, const xmlChar *SystemID)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->internalSubset != NULL))
  	ctxt->user_sax->internalSubset(ctxt->user_data, name, ExternalID,
  	                               SystemID);
  }
  
  static int
  isStandaloneSplit(void *ctx)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->isStandalone != NULL))
  	return(ctxt->user_sax->isStandalone(ctxt->user_data));
      return(0);
  }
  
  static int
  hasInternalSubsetSplit(void *ctx)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->hasInternalSubset != NULL))
  	return(ctxt->user_sax->hasInternalSubset(ctxt->user_data));
      return(0);
  }
  
  static int
  hasExternalSubsetSplit(void *ctx)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->hasExternalSubset != NULL))
  	return(ctxt->user_sax->hasExternalSubset(ctxt->user_data));
      return(0);
  }
  
  static void
  externalSubsetSplit(void *ctx, const xmlChar *name,
  	       const xmlChar *ExternalID, const xmlChar *SystemID)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->externalSubset != NULL))
  	ctxt->user_sax->externalSubset(ctxt->user_data, name, ExternalID,
  	                               SystemID);
  }
  
  static xmlParserInputPtr
  resolveEntitySplit(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->resolveEntity != NULL))
  	return(ctxt->user_sax->resolveEntity(ctxt->user_data, publicId,
  	                                     systemId));
      return(NULL);
  }
  
  static xmlEntityPtr
  getEntitySplit(void *ctx, const xmlChar *name)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->getEntity != NULL))
  	return(ctxt->user_sax->getEntity(ctxt->user_data, name));
      return(NULL);
  }
  
  static xmlEntityPtr
  getParameterEntitySplit(void *ctx, const xmlChar *name)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->getParameterEntity != NULL))
  	return(ctxt->user_sax->getParameterEntity(ctxt->user_data, name));
      return(NULL);
  }
  
  
  static void
  entityDeclSplit(void *ctx, const xmlChar *name, int type,
            const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->entityDecl != NULL))
  	ctxt->user_sax->entityDecl(ctxt->user_data, name, type, publicId,
  	                           systemId, content);
  }
  
  static void
  attributeDeclSplit(void *ctx, const xmlChar * elem,
                     const xmlChar * name, int type, int def,
                     const xmlChar * defaultValue, xmlEnumerationPtr tree)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->attributeDecl != NULL)) {
  	ctxt->user_sax->attributeDecl(ctxt->user_data, elem, name, type,
  	                              def, defaultValue, tree);
      } else {
  	xmlFreeEnumeration(tree);
      }
  }
  
  static void
  elementDeclSplit(void *ctx, const xmlChar *name, int type,
  	    xmlElementContentPtr content)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->elementDecl != NULL))
  	ctxt->user_sax->elementDecl(ctxt->user_data, name, type, content);
  }
  
  static void
  notationDeclSplit(void *ctx, const xmlChar *name,
  	     const xmlChar *publicId, const xmlChar *systemId)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->notationDecl != NULL))
  	ctxt->user_sax->notationDecl(ctxt->user_data, name, publicId,
  	                             systemId);
  }
  
  static void
  unparsedEntityDeclSplit(void *ctx, const xmlChar *name,
  		   const xmlChar *publicId, const xmlChar *systemId,
  		   const xmlChar *notationName)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->unparsedEntityDecl != NULL))
  	ctxt->user_sax->unparsedEntityDecl(ctxt->user_data, name, publicId,
  	                                   systemId, notationName);
  }
  
  static void
  setDocumentLocatorSplit(void *ctx, xmlSAXLocatorPtr loc)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->setDocumentLocator != NULL))
  	ctxt->user_sax->setDocumentLocator(ctxt->user_data, loc);
  }
  
  static void
  startDocumentSplit(void *ctx)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->startDocument != NULL))
  	ctxt->user_sax->startDocument(ctxt->user_data);
  }
  
  static void
  endDocumentSplit(void *ctx)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->endDocument != NULL))
  	ctxt->user_sax->endDocument(ctxt->user_data);
  }
  
  static void
  processingInstructionSplit(void *ctx, const xmlChar *target,
                        const xmlChar *data)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->processingInstruction != NULL))
  	ctxt->user_sax->processingInstruction(ctxt->user_data, target, data);
  }
  
  static void
  commentSplit(void *ctx, const xmlChar *value)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->comment != NULL))
  	ctxt->user_sax->comment(ctxt->user_data, value);
  }
  
  /*
   * Varargs error callbacks to the user application, harder ...
   */
  
  static void XMLCDECL
  warningSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->warning != NULL)) {
  	TODO
      }
  }
  static void XMLCDECL
  errorSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->error != NULL)) {
  	TODO
      }
  }
  static void XMLCDECL
  fatalErrorSplit(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->fatalError != NULL)) {
  	TODO
      }
  }
  
  /*
   * Those are function where both the user handler and the schemas handler
   * need to be called.
   */
  static void
  charactersSplit(void *ctx, const xmlChar *ch, int len)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if (ctxt == NULL)
          return;
      if ((ctxt->user_sax != NULL) && (ctxt->user_sax->characters != NULL))
  	ctxt->user_sax->characters(ctxt->user_data, ch, len);
      if (ctxt->ctxt != NULL)
  	xmlSchemaSAXHandleText(ctxt->ctxt, ch, len);
  }
  
  static void
  ignorableWhitespaceSplit(void *ctx, const xmlChar *ch, int len)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if (ctxt == NULL)
          return;
      if ((ctxt->user_sax != NULL) &&
          (ctxt->user_sax->ignorableWhitespace != NULL))
  	ctxt->user_sax->ignorableWhitespace(ctxt->user_data, ch, len);
      if (ctxt->ctxt != NULL)
  	xmlSchemaSAXHandleText(ctxt->ctxt, ch, len);
  }
  
  static void
  cdataBlockSplit(void *ctx, const xmlChar *value, int len)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if (ctxt == NULL)
          return;
      if ((ctxt->user_sax != NULL) &&
          (ctxt->user_sax->cdataBlock != NULL))
  	ctxt->user_sax->cdataBlock(ctxt->user_data, value, len);
      if (ctxt->ctxt != NULL)
  	xmlSchemaSAXHandleCDataSection(ctxt->ctxt, value, len);
  }
  
  static void
  referenceSplit(void *ctx, const xmlChar *name)
  {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if (ctxt == NULL)
          return;
      if ((ctxt != NULL) && (ctxt->user_sax != NULL) &&
          (ctxt->user_sax->reference != NULL))
  	ctxt->user_sax->reference(ctxt->user_data, name);
      if (ctxt->ctxt != NULL)
          xmlSchemaSAXHandleReference(ctxt->user_data, name);
  }
  
  static void
  startElementNsSplit(void *ctx, const xmlChar * localname,
  		    const xmlChar * prefix, const xmlChar * URI,
  		    int nb_namespaces, const xmlChar ** namespaces,
  		    int nb_attributes, int nb_defaulted,
  		    const xmlChar ** attributes) {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if (ctxt == NULL)
          return;
      if ((ctxt->user_sax != NULL) &&
          (ctxt->user_sax->startElementNs != NULL))
  	ctxt->user_sax->startElementNs(ctxt->user_data, localname, prefix,
  	                               URI, nb_namespaces, namespaces,
  				       nb_attributes, nb_defaulted,
  				       attributes);
      if (ctxt->ctxt != NULL)
  	xmlSchemaSAXHandleStartElementNs(ctxt->ctxt, localname, prefix,
  	                                 URI, nb_namespaces, namespaces,
  					 nb_attributes, nb_defaulted,
  					 attributes);
  }
  
  static void
  endElementNsSplit(void *ctx, const xmlChar * localname,
  		    const xmlChar * prefix, const xmlChar * URI) {
      xmlSchemaSAXPlugPtr ctxt = (xmlSchemaSAXPlugPtr) ctx;
      if (ctxt == NULL)
          return;
      if ((ctxt->user_sax != NULL) &&
          (ctxt->user_sax->endElementNs != NULL))
  	ctxt->user_sax->endElementNs(ctxt->user_data, localname, prefix, URI);
      if (ctxt->ctxt != NULL)
  	xmlSchemaSAXHandleEndElementNs(ctxt->ctxt, localname, prefix, URI);
  }
  
  /**
   * xmlSchemaSAXPlug:
   * @ctxt:  a schema validation context
   * @sax:  a pointer to the original xmlSAXHandlerPtr
   * @user_data:  a pointer to the original SAX user data pointer
   *
   * Plug a SAX based validation layer in a SAX parsing event flow.
   * The original @saxptr and @dataptr data are replaced by new pointers
   * but the calls to the original will be maintained.
   *
   * Returns a pointer to a data structure needed to unplug the validation layer
   *         or NULL in case of errors.
   */
  xmlSchemaSAXPlugPtr
  xmlSchemaSAXPlug(xmlSchemaValidCtxtPtr ctxt,
  		 xmlSAXHandlerPtr *sax, void **user_data)
  {
      xmlSchemaSAXPlugPtr ret;
      xmlSAXHandlerPtr old_sax;
  
      if ((ctxt == NULL) || (sax == NULL) || (user_data == NULL))
          return(NULL);
  
      /*
       * We only allow to plug into SAX2 event streams
       */
      old_sax = *sax;
      if ((old_sax != NULL) && (old_sax->initialized != XML_SAX2_MAGIC))
          return(NULL);
      if ((old_sax != NULL) &&
          (old_sax->startElementNs == NULL) && (old_sax->endElementNs == NULL) &&
          ((old_sax->startElement != NULL) || (old_sax->endElement != NULL)))
          return(NULL);
  
      /*
       * everything seems right allocate the local data needed for that layer
       */
      ret = (xmlSchemaSAXPlugPtr) xmlMalloc(sizeof(xmlSchemaSAXPlugStruct));
      if (ret == NULL) {
          return(NULL);
      }
      memset(ret, 0, sizeof(xmlSchemaSAXPlugStruct));
      ret->magic = XML_SAX_PLUG_MAGIC;
      ret->schemas_sax.initialized = XML_SAX2_MAGIC;
      ret->ctxt = ctxt;
      ret->user_sax_ptr = sax;
      ret->user_sax = old_sax;
      if (old_sax == NULL) {
          /*
  	 * go direct, no need for the split block and functions.
  	 */
  	ret->schemas_sax.startElementNs = xmlSchemaSAXHandleStartElementNs;
  	ret->schemas_sax.endElementNs = xmlSchemaSAXHandleEndElementNs;
  	/*
  	 * Note that we use the same text-function for both, to prevent
  	 * the parser from testing for ignorable whitespace.
  	 */
  	ret->schemas_sax.ignorableWhitespace = xmlSchemaSAXHandleText;
  	ret->schemas_sax.characters = xmlSchemaSAXHandleText;
  
  	ret->schemas_sax.cdataBlock = xmlSchemaSAXHandleCDataSection;
  	ret->schemas_sax.reference = xmlSchemaSAXHandleReference;
  
  	ret->user_data = ctxt;
  	*user_data = ctxt;
      } else {
         /*
          * for each callback unused by Schemas initialize it to the Split
  	* routine only if non NULL in the user block, this can speed up
  	* things at the SAX level.
  	*/
          if (old_sax->internalSubset != NULL)
              ret->schemas_sax.internalSubset = internalSubsetSplit;
          if (old_sax->isStandalone != NULL)
              ret->schemas_sax.isStandalone = isStandaloneSplit;
          if (old_sax->hasInternalSubset != NULL)
              ret->schemas_sax.hasInternalSubset = hasInternalSubsetSplit;
          if (old_sax->hasExternalSubset != NULL)
              ret->schemas_sax.hasExternalSubset = hasExternalSubsetSplit;
          if (old_sax->resolveEntity != NULL)
              ret->schemas_sax.resolveEntity = resolveEntitySplit;
          if (old_sax->getEntity != NULL)
              ret->schemas_sax.getEntity = getEntitySplit;
          if (old_sax->entityDecl != NULL)
              ret->schemas_sax.entityDecl = entityDeclSplit;
          if (old_sax->notationDecl != NULL)
              ret->schemas_sax.notationDecl = notationDeclSplit;
          if (old_sax->attributeDecl != NULL)
              ret->schemas_sax.attributeDecl = attributeDeclSplit;
          if (old_sax->elementDecl != NULL)
              ret->schemas_sax.elementDecl = elementDeclSplit;
          if (old_sax->unparsedEntityDecl != NULL)
              ret->schemas_sax.unparsedEntityDecl = unparsedEntityDeclSplit;
          if (old_sax->setDocumentLocator != NULL)
              ret->schemas_sax.setDocumentLocator = setDocumentLocatorSplit;
          if (old_sax->startDocument != NULL)
              ret->schemas_sax.startDocument = startDocumentSplit;
          if (old_sax->endDocument != NULL)
              ret->schemas_sax.endDocument = endDocumentSplit;
          if (old_sax->processingInstruction != NULL)
              ret->schemas_sax.processingInstruction = processingInstructionSplit;
          if (old_sax->comment != NULL)
              ret->schemas_sax.comment = commentSplit;
          if (old_sax->warning != NULL)
              ret->schemas_sax.warning = warningSplit;
          if (old_sax->error != NULL)
              ret->schemas_sax.error = errorSplit;
          if (old_sax->fatalError != NULL)
              ret->schemas_sax.fatalError = fatalErrorSplit;
          if (old_sax->getParameterEntity != NULL)
              ret->schemas_sax.getParameterEntity = getParameterEntitySplit;
          if (old_sax->externalSubset != NULL)
              ret->schemas_sax.externalSubset = externalSubsetSplit;
  
  	/*
  	 * the 6 schemas callback have to go to the splitter functions
  	 * Note that we use the same text-function for ignorableWhitespace
  	 * if possible, to prevent the parser from testing for ignorable
  	 * whitespace.
  	 */
          ret->schemas_sax.characters = charactersSplit;
  	if ((old_sax->ignorableWhitespace != NULL) &&
  	    (old_sax->ignorableWhitespace != old_sax->characters))
  	    ret->schemas_sax.ignorableWhitespace = ignorableWhitespaceSplit;
  	else
  	    ret->schemas_sax.ignorableWhitespace = charactersSplit;
          ret->schemas_sax.cdataBlock = cdataBlockSplit;
          ret->schemas_sax.reference = referenceSplit;
          ret->schemas_sax.startElementNs = startElementNsSplit;
          ret->schemas_sax.endElementNs = endElementNsSplit;
  
  	ret->user_data_ptr = user_data;
  	ret->user_data = *user_data;
  	*user_data = ret;
      }
  
      /*
       * plug the pointers back.
       */
      *sax = &(ret->schemas_sax);
      ctxt->sax = *sax;
      ctxt->flags |= XML_SCHEMA_VALID_CTXT_FLAG_STREAM;
      xmlSchemaPreRun(ctxt);
      return(ret);
  }
  
  /**
   * xmlSchemaSAXUnplug:
   * @plug:  a data structure returned by xmlSchemaSAXPlug
   *
   * Unplug a SAX based validation layer in a SAX parsing event flow.
   * The original pointers used in the call are restored.
   *
   * Returns 0 in case of success and -1 in case of failure.
   */
  int
  xmlSchemaSAXUnplug(xmlSchemaSAXPlugPtr plug)
  {
      xmlSAXHandlerPtr *sax;
      void **user_data;
  
      if ((plug == NULL) || (plug->magic != XML_SAX_PLUG_MAGIC))
          return(-1);
      plug->magic = 0;
  
      xmlSchemaPostRun(plug->ctxt);
      /* restore the data */
      sax = plug->user_sax_ptr;
      *sax = plug->user_sax;
      if (plug->user_sax != NULL) {
  	user_data = plug->user_data_ptr;
  	*user_data = plug->user_data;
      }
  
      /* free and return */
      xmlFree(plug);
      return(0);
  }
  
  /**
   * xmlSchemaValidateSetLocator:
   * @vctxt: a schema validation context
   * @f: the locator function pointer
   * @ctxt: the locator context
   *
   * Allows to set a locator function to the validation context,
   * which will be used to provide file and line information since
   * those are not provided as part of the SAX validation flow
   * Setting @f to NULL disable the locator.
   */
  
  void
  xmlSchemaValidateSetLocator(xmlSchemaValidCtxtPtr vctxt,
                              xmlSchemaValidityLocatorFunc f,
  			    void *ctxt)
  {
      if (vctxt == NULL) return;
      vctxt->locFunc = f;
      vctxt->locCtxt = ctxt;
  }
  
  /**
   * xmlSchemaValidateStreamLocator:
   * @ctx: the xmlTextReaderPtr used
   * @file: returned file information
   * @line: returned line information
   *
   * Internal locator function for the readers
   *
   * Returns 0 in case the Schema validation could be (de)activated and
   *         -1 in case of error.
   */
  static int
  xmlSchemaValidateStreamLocator(void *ctx, const char **file,
                                 unsigned long *line) {
      xmlParserCtxtPtr ctxt;
  
      if ((ctx == NULL) || ((file == NULL) && (line == NULL)))
          return(-1);
  
      if (file != NULL)
          *file = NULL;
      if (line != NULL)
          *line = 0;
  
      ctxt = (xmlParserCtxtPtr) ctx;
      if (ctxt->input != NULL) {
         if (file != NULL)
             *file = ctxt->input->filename;
         if (line != NULL)
             *line = ctxt->input->line;
         return(0);
      }
      return(-1);
  }
  
  /**
   * xmlSchemaValidateStream:
   * @ctxt:  a schema validation context
   * @input:  the input to use for reading the data
   * @enc:  an optional encoding information
   * @sax:  a SAX handler for the resulting events
   * @user_data:  the context to provide to the SAX handler.
   *
   * Validate an input based on a flow of SAX event from the parser
   * and forward the events to the @sax handler with the provided @user_data
   * the user provided @sax handler must be a SAX2 one.
   *
   * Returns 0 if the document is schemas valid, a positive error code
   *     number otherwise and -1 in case of internal or API error.
   */
  int
  xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
                          xmlParserInputBufferPtr input, xmlCharEncoding enc,
                          xmlSAXHandlerPtr sax, void *user_data)
  {
      xmlSchemaSAXPlugPtr plug = NULL;
      xmlSAXHandlerPtr old_sax = NULL;
      xmlParserCtxtPtr pctxt = NULL;
      xmlParserInputPtr inputStream = NULL;
      int ret;
  
      if ((ctxt == NULL) || (input == NULL))
          return (-1);
  
      /*
       * prepare the parser
       */
      pctxt = xmlNewParserCtxt();
      if (pctxt == NULL)
          return (-1);
      old_sax = pctxt->sax;
      pctxt->sax = sax;
      pctxt->userData = user_data;
  #if 0
      if (options)
          xmlCtxtUseOptions(pctxt, options);
  #endif
      pctxt->linenumbers = 1;
      xmlSchemaValidateSetLocator(ctxt, xmlSchemaValidateStreamLocator, pctxt);
  
      inputStream = xmlNewIOInputStream(pctxt, input, enc);;
      if (inputStream == NULL) {
          ret = -1;
  	goto done;
      }
      inputPush(pctxt, inputStream);
      ctxt->parserCtxt = pctxt;
      ctxt->input = input;
  
      /*
       * Plug the validation and launch the parsing
       */
      plug = xmlSchemaSAXPlug(ctxt, &(pctxt->sax), &(pctxt->userData));
      if (plug == NULL) {
          ret = -1;
  	goto done;
      }
      ctxt->input = input;
      ctxt->enc = enc;
      ctxt->sax = pctxt->sax;
      ctxt->flags |= XML_SCHEMA_VALID_CTXT_FLAG_STREAM;
      ret = xmlSchemaVStart(ctxt);
  
      if ((ret == 0) && (! ctxt->parserCtxt->wellFormed)) {
  	ret = ctxt->parserCtxt->errNo;
  	if (ret == 0)
  	    ret = 1;
      }
  
  done:
      ctxt->parserCtxt = NULL;
      ctxt->sax = NULL;
      ctxt->input = NULL;
      if (plug != NULL) {
          xmlSchemaSAXUnplug(plug);
      }
      /* cleanup */
      if (pctxt != NULL) {
  	pctxt->sax = old_sax;
  	xmlFreeParserCtxt(pctxt);
      }
      return (ret);
  }
  
  /**
   * xmlSchemaValidateFile:
   * @ctxt: a schema validation context
   * @filename: the URI of the instance
   * @options: a future set of options, currently unused
   *
   * Do a schemas validation of the given resource, it will use the
   * SAX streamable validation internally.
   *
   * Returns 0 if the document is valid, a positive error code
   *     number otherwise and -1 in case of an internal or API error.
   */
  int
  xmlSchemaValidateFile(xmlSchemaValidCtxtPtr ctxt,
                        const char * filename,
  		      int options ATTRIBUTE_UNUSED)
  {
      int ret;
      xmlParserInputBufferPtr input;
  
      if ((ctxt == NULL) || (filename == NULL))
          return (-1);
  
      input = xmlParserInputBufferCreateFilename(filename,
  	XML_CHAR_ENCODING_NONE);
      if (input == NULL)
  	return (-1);
      ret = xmlSchemaValidateStream(ctxt, input, XML_CHAR_ENCODING_NONE,
  	NULL, NULL);
      return (ret);
  }
  
  /**
   * xmlSchemaValidCtxtGetParserCtxt:
   * @ctxt: a schema validation context
   *
   * allow access to the parser context of the schema validation context
   *
   * Returns the parser context of the schema validation context or NULL
   *         in case of error.
   */
  xmlParserCtxtPtr
  xmlSchemaValidCtxtGetParserCtxt(xmlSchemaValidCtxtPtr ctxt)
  {
      if (ctxt == NULL)
          return(NULL);
      return (ctxt->parserCtxt);
  }
  
  #define bottom_xmlschemas
  #include "elfgcchack.h"
  #endif /* LIBXML_SCHEMAS_ENABLED */
  