| /* |
| * 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. |
| */ |
| #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> |
| |
| /* #define DEBUG 1 */ |
| |
| /* #define DEBUG_CONTENT 1 */ |
| |
| /* #define DEBUG_TYPE 1 */ |
| |
| /* #define DEBUG_CONTENT_REGEXP 1 */ |
| |
| /* #define DEBUG_AUTOMATA 1 */ |
| |
| #define UNBOUNDED (1 << 30) |
| #define TODO \ |
| xmlGenericError(xmlGenericErrorContext, \ |
| "Unimplemented block at %s:%d\n", \ |
| __FILE__, __LINE__); |
| |
| #define XML_SCHEMAS_DEFAULT_NAMESPACE (const xmlChar *)"the default namespace" |
| |
| /* |
| * 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"; |
| |
| #define IS_SCHEMA(node, type) \ |
| ((node != NULL) && (node->ns != NULL) && \ |
| (xmlStrEqual(node->name, (const xmlChar *) type)) && \ |
| (xmlStrEqual(node->ns->href, xmlSchemaNs))) |
| |
| #define XML_SCHEMAS_PARSE_ERROR 1 |
| |
| #define SCHEMAS_PARSE_OPTIONS XML_PARSE_NOENT |
| |
| struct _xmlSchemaParserCtxt { |
| void *userData; /* user specific data block */ |
| xmlSchemaValidityErrorFunc error; /* the callback in case of errors */ |
| xmlSchemaValidityWarningFunc warning; /* the callback in case of warning */ |
| xmlSchemaValidError err; |
| int nberrors; |
| xmlStructuredErrorFunc serror; |
| |
| xmlSchemaPtr topschema; /* The main schema */ |
| xmlHashTablePtr namespaces; /* Hash table of namespaces to schemas */ |
| |
| xmlSchemaPtr schema; /* The schema in use */ |
| const xmlChar *container; /* the current element, group, ... */ |
| int counter; |
| |
| const xmlChar *URL; |
| xmlDocPtr doc; |
| |
| const char *buffer; |
| int size; |
| |
| /* |
| * Used to build complex element content models |
| */ |
| xmlAutomataPtr am; |
| xmlAutomataStatePtr start; |
| xmlAutomataStatePtr end; |
| xmlAutomataStatePtr state; |
| |
| xmlDictPtr dict; /* dictionnary for interned string names */ |
| int includes; /* the inclusion level, 0 for root or imports */ |
| }; |
| |
| |
| #define XML_SCHEMAS_ATTR_UNKNOWN 1 |
| #define XML_SCHEMAS_ATTR_CHECKED 2 |
| |
| typedef struct _xmlSchemaAttrState xmlSchemaAttrState; |
| typedef xmlSchemaAttrState *xmlSchemaAttrStatePtr; |
| struct _xmlSchemaAttrState { |
| xmlAttrPtr attr; |
| int state; |
| }; |
| |
| /** |
| * xmlSchemaValidCtxt: |
| * |
| * A Schemas validation context |
| */ |
| |
| struct _xmlSchemaValidCtxt { |
| void *userData; /* 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; |
| void *user_data; |
| |
| xmlDocPtr myDoc; |
| int err; |
| int nberrors; |
| |
| xmlNodePtr node; |
| xmlNodePtr cur; |
| xmlSchemaTypePtr type; |
| |
| xmlRegExecCtxtPtr regexp; |
| xmlSchemaValPtr value; |
| |
| int attrNr; |
| int attrBase; |
| int attrMax; |
| xmlSchemaAttrStatePtr attr; |
| }; |
| |
| /* |
| * These are the entries in the schemas importSchemas hash table |
| */ |
| typedef struct _xmlSchemaImport xmlSchemaImport; |
| typedef xmlSchemaImport *xmlSchemaImportPtr; |
| struct _xmlSchemaImport { |
| const xmlChar *schemaLocation; |
| xmlSchemaPtr schema; |
| }; |
| |
| /* |
| * These are the entries associated to includes in a schemas |
| */ |
| typedef struct _xmlSchemaInclude xmlSchemaInclude; |
| typedef xmlSchemaInclude *xmlSchemaIncludePtr; |
| struct _xmlSchemaInclude { |
| xmlSchemaIncludePtr next; |
| |
| const xmlChar *schemaLocation; |
| xmlDocPtr doc; |
| }; |
| |
| /************************************************************************ |
| * * |
| * Some predeclarations * |
| * * |
| ************************************************************************/ |
| static int xmlSchemaValidateSimpleValue(xmlSchemaValidCtxtPtr ctxt, |
| xmlSchemaTypePtr type, |
| const xmlChar * value); |
| |
| static int xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, |
| xmlNodePtr node); |
| /************************************************************************ |
| * * |
| * Datatype error handlers * |
| * * |
| ************************************************************************/ |
| |
| /** |
| * 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 |
| 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++; |
| channel = ctxt->error; |
| data = ctxt->userData; |
| schannel = ctxt->serror; |
| } |
| __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASP, |
| error, XML_ERR_ERROR, NULL, 0, |
| (const char *) 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 |
| 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); |
| } |
| |
| /** |
| * 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_SCHEMAS_ERR_INTERNAL; |
| } |
| __xmlSimpleError(XML_FROM_SCHEMASV, XML_ERR_NO_MEMORY, node, NULL, |
| extra); |
| } |
| |
| /** |
| * xmlSchemaVErr3: |
| * @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 |
| xmlSchemaVErr3(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error, |
| const char *msg, const xmlChar *str1, const xmlChar *str2, |
| const xmlChar *str3) |
| { |
| xmlStructuredErrorFunc schannel = NULL; |
| xmlGenericErrorFunc channel = NULL; |
| void *data = NULL; |
| |
| if (ctxt != NULL) { |
| ctxt->nberrors++; |
| ctxt->err = error; |
| channel = ctxt->error; |
| schannel = ctxt->serror; |
| data = ctxt->userData; |
| } |
| /* reajust to global error numbers */ |
| error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT; |
| __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV, |
| error, XML_ERR_ERROR, NULL, 0, |
| (const char *) str1, (const char *) str2, |
| (const char *) str3, 0, 0, |
| msg, str1, str2, str3); |
| } |
| /** |
| * xmlSchemaVErr: |
| * @ctxt: the validation context |
| * @node: the context node |
| * @error: the error code |
| * @msg: the error message |
| * @str1: extra data |
| * @str2: extra data |
| * |
| * Handle a validation error |
| */ |
| static void |
| xmlSchemaVErr(xmlSchemaValidCtxtPtr ctxt, xmlNodePtr node, int error, |
| const char *msg, const xmlChar * str1, const xmlChar * str2) |
| { |
| xmlStructuredErrorFunc schannel = NULL; |
| xmlGenericErrorFunc channel = NULL; |
| void *data = NULL; |
| |
| if (ctxt != NULL) { |
| ctxt->nberrors++; |
| ctxt->err = error; |
| channel = ctxt->error; |
| data = ctxt->userData; |
| schannel = ctxt->serror; |
| } |
| /* reajust to global error numbers */ |
| error += XML_SCHEMAV_NOROOT - XML_SCHEMAS_ERR_NOROOT; |
| __xmlRaiseError(schannel, channel, data, ctxt, node, XML_FROM_SCHEMASV, |
| error, XML_ERR_ERROR, NULL, 0, |
| (const char *) str1, (const char *) str2, NULL, 0, 0, |
| msg, str1, str2); |
| } |
| |
| /************************************************************************ |
| * * |
| * Allocation functions * |
| * * |
| ************************************************************************/ |
| |
| /** |
| * xmlSchemaNewSchema: |
| * @ctxt: a schema validation context (optional) |
| * |
| * Allocate a new Schema structure. |
| * |
| * Returns the newly allocated structure or NULL in case or error |
| */ |
| 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)); |
| xmlDictReference(ctxt->dict); |
| ret->dict = ctxt->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 (optional) |
| * @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); |
| } |
| |
| /** |
| * xmlSchemaFreeAnnot: |
| * @annot: a schema type structure |
| * |
| * Deallocate a annotation structure |
| */ |
| static void |
| xmlSchemaFreeAnnot(xmlSchemaAnnotPtr annot) |
| { |
| if (annot == NULL) |
| return; |
| xmlFree(annot); |
| } |
| |
| /** |
| * xmlSchemaFreeImport: |
| * @import: a schema import structure |
| * |
| * Deallocate an import structure |
| */ |
| static void |
| xmlSchemaFreeImport(xmlSchemaImportPtr import) |
| { |
| if (import == NULL) |
| return; |
| |
| xmlSchemaFree(import->schema); |
| xmlFree(import); |
| } |
| |
| /** |
| * xmlSchemaFreeInclude: |
| * @include: a schema include structure |
| * |
| * Deallocate an include structure |
| */ |
| static void |
| xmlSchemaFreeInclude(xmlSchemaIncludePtr include) |
| { |
| if (include == NULL) |
| return; |
| |
| xmlFreeDoc(include->doc); |
| xmlFree(include); |
| } |
| |
| /** |
| * xmlSchemaFreeIncludeList: |
| * @includes: a schema include list |
| * |
| * Deallocate an include structure |
| */ |
| static void |
| xmlSchemaFreeIncludeList(xmlSchemaIncludePtr includes) |
| { |
| xmlSchemaIncludePtr next; |
| |
| while (includes != NULL) { |
| next = includes->next; |
| xmlSchemaFreeInclude(includes); |
| includes = next; |
| } |
| } |
| |
| /** |
| * xmlSchemaFreeNotation: |
| * @schema: a schema notation structure |
| * |
| * Deallocate a Schema Notation structure. |
| */ |
| static void |
| xmlSchemaFreeNotation(xmlSchemaNotationPtr nota) |
| { |
| if (nota == NULL) |
| return; |
| xmlFree(nota); |
| } |
| |
| /** |
| * xmlSchemaFreeAttribute: |
| * @schema: a schema attribute structure |
| * |
| * Deallocate a Schema Attribute structure. |
| */ |
| static void |
| xmlSchemaFreeAttribute(xmlSchemaAttributePtr attr) |
| { |
| if (attr == NULL) |
| return; |
| xmlFree(attr); |
| } |
| |
| /** |
| * xmlSchemaFreeAttributeGroup: |
| * @schema: a schema attribute group structure |
| * |
| * Deallocate a Schema Attribute Group structure. |
| */ |
| static void |
| xmlSchemaFreeAttributeGroup(xmlSchemaAttributeGroupPtr attr) |
| { |
| if (attr == NULL) |
| return; |
| xmlFree(attr); |
| } |
| |
| /** |
| * 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); |
| 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; |
| } |
| } |
| xmlFree(type); |
| } |
| |
| /** |
| * xmlSchemaFreeTypeList: |
| * @type: a schema type structure |
| * |
| * Deallocate a Schema Type structure. |
| */ |
| static void |
| xmlSchemaFreeTypeList(xmlSchemaTypePtr type) |
| { |
| xmlSchemaTypePtr next; |
| |
| while (type != NULL) { |
| next = type->redef; |
| xmlSchemaFreeType(type); |
| type = next; |
| } |
| } |
| |
| /** |
| * xmlSchemaFree: |
| * @schema: a schema structure |
| * |
| * Deallocate a Schema structure. |
| */ |
| void |
| xmlSchemaFree(xmlSchemaPtr schema) |
| { |
| if (schema == NULL) |
| return; |
| |
| if (schema->notaDecl != NULL) |
| xmlHashFree(schema->notaDecl, |
| (xmlHashDeallocator) xmlSchemaFreeNotation); |
| if (schema->attrDecl != NULL) |
| xmlHashFree(schema->attrDecl, |
| (xmlHashDeallocator) xmlSchemaFreeAttribute); |
| if (schema->attrgrpDecl != NULL) |
| xmlHashFree(schema->attrgrpDecl, |
| (xmlHashDeallocator) xmlSchemaFreeAttributeGroup); |
| if (schema->elemDecl != NULL) |
| xmlHashFree(schema->elemDecl, |
| (xmlHashDeallocator) xmlSchemaFreeElement); |
| if (schema->typeDecl != NULL) |
| xmlHashFree(schema->typeDecl, |
| (xmlHashDeallocator) xmlSchemaFreeTypeList); |
| if (schema->groupDecl != NULL) |
| xmlHashFree(schema->groupDecl, |
| (xmlHashDeallocator) xmlSchemaFreeType); |
| if (schema->schemasImports != NULL) |
| xmlHashFree(schema->schemasImports, |
| (xmlHashDeallocator) xmlSchemaFreeImport); |
| if (schema->includes != NULL) { |
| xmlSchemaFreeIncludeList((xmlSchemaIncludePtr) schema->includes); |
| } |
| if (schema->annot != NULL) |
| xmlSchemaFreeAnnot(schema->annot); |
| if (schema->doc != NULL) |
| xmlFreeDoc(schema->doc); |
| xmlDictFree(schema->dict); |
| |
| xmlFree(schema); |
| } |
| |
| /************************************************************************ |
| * * |
| * Debug functions * |
| * * |
| ************************************************************************/ |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| |
| /** |
| * xmlSchemaElementDump: |
| * @elem: an element |
| * @output: the file output |
| * |
| * Dump the element |
| */ |
| static void |
| xmlSchemaElementDump(xmlSchemaElementPtr elem, FILE * output, |
| const xmlChar * name ATTRIBUTE_UNUSED, |
| const xmlChar * context ATTRIBUTE_UNUSED, |
| const xmlChar * namespace ATTRIBUTE_UNUSED) |
| { |
| if (elem == NULL) |
| return; |
| |
| fprintf(output, "Element "); |
| if (elem->flags & XML_SCHEMAS_ELEM_TOPLEVEL) |
| fprintf(output, "toplevel "); |
| fprintf(output, ": %s ", elem->name); |
| if (namespace != NULL) |
| fprintf(output, "namespace '%s' ", namespace); |
| |
| if (elem->flags & XML_SCHEMAS_ELEM_NILLABLE) |
| fprintf(output, "nillable "); |
| if (elem->flags & XML_SCHEMAS_ELEM_GLOBAL) |
| fprintf(output, "global "); |
| if (elem->flags & XML_SCHEMAS_ELEM_DEFAULT) |
| fprintf(output, "default "); |
| if (elem->flags & XML_SCHEMAS_ELEM_FIXED) |
| fprintf(output, "fixed "); |
| if (elem->flags & XML_SCHEMAS_ELEM_ABSTRACT) |
| fprintf(output, "abstract "); |
| if (elem->flags & XML_SCHEMAS_ELEM_REF) |
| fprintf(output, "ref '%s' ", elem->ref); |
| if (elem->id != NULL) |
| fprintf(output, "id '%s' ", elem->id); |
| fprintf(output, "\n"); |
| if ((elem->minOccurs != 1) || (elem->maxOccurs != 1)) { |
| fprintf(output, " "); |
| if (elem->minOccurs != 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"); |
| } |
| 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"); |
| } |
| 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"); |
| } |
| if (elem->value != NULL) |
| fprintf(output, " default: %s", elem->value); |
| } |
| |
| /** |
| * 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"); |
| } |
| |
| /** |
| * 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"); |
| 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, "unknowntype%d ", type->type); |
| break; |
| } |
| if (type->base != NULL) { |
| fprintf(output, "base %s, ", type->base); |
| } |
| 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: |
| fprintf(output, "mixed_or_elems "); |
| 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->minOccurs != 1) || (type->maxOccurs != 1)) { |
| fprintf(output, " "); |
| if (type->minOccurs != 1) |
| fprintf(output, "min: %d ", type->minOccurs); |
| if (type->maxOccurs >= UNBOUNDED) |
| fprintf(output, "max: unbounded\n"); |
| else if (type->maxOccurs != 1) |
| fprintf(output, "max: %d\n", type->maxOccurs); |
| else |
| fprintf(output, "\n"); |
| } |
| if (type->annot != NULL) |
| xmlSchemaAnnotDump(output, type->annot); |
| if (type->subtypes != NULL) { |
| xmlSchemaTypePtr sub = type->subtypes; |
| |
| fprintf(output, " subtypes: "); |
| while (sub != NULL) { |
| fprintf(output, "%s ", sub->name); |
| sub = sub->next; |
| } |
| fprintf(output, "\n"); |
| } |
| |
| } |
| |
| /** |
| * xmlSchemaDump: |
| * @output: the file output |
| * @schema: a schema structure |
| * |
| * Dump a Schema structure. |
| */ |
| void |
| xmlSchemaDump(FILE * output, xmlSchemaPtr schema) |
| { |
| 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, (xmlHashScanner) xmlSchemaTypeDump, |
| output); |
| xmlHashScanFull(schema->elemDecl, |
| (xmlHashScannerFull) xmlSchemaElementDump, output); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /************************************************************************ |
| * * |
| * Utilities * |
| * * |
| ************************************************************************/ |
| /** |
| * numberedString: |
| * @prefix: the string prefix |
| * @number: the number |
| * |
| * Build a new numbered string |
| * |
| * Returns the new string |
| */ |
| |
| /** |
| * 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 = xmlGetProp(node, BAD_CAST name); |
| if (val == NULL) |
| return(NULL); |
| ret = xmlDictLookup(ctxt->dict, val, -1); |
| xmlFree(val); |
| return(ret); |
| } |
| |
| /** |
| * xmlSchemaGetNamespace: |
| * @ctxt: the parser context |
| * @schema: the schemas containing the declaration |
| * @node: the node |
| * @qname: the QName to analyze |
| * |
| * Find the namespace name for the given declaration. |
| * |
| * Returns the local name for that declaration, as well as the namespace name |
| */ |
| static const xmlChar * |
| xmlSchemaGetNamespace(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node, const xmlChar *qname, |
| const xmlChar **namespace) { |
| int len; |
| const xmlChar *name, *prefix, *def = NULL; |
| xmlNsPtr ns; |
| |
| *namespace = NULL; |
| |
| if (xmlStrEqual(node->name, BAD_CAST "element") || |
| xmlStrEqual(node->name, BAD_CAST "attribute") || |
| xmlStrEqual(node->name, BAD_CAST "simpleType") || |
| xmlStrEqual(node->name, BAD_CAST "complexType")) { |
| def = xmlSchemaGetProp(ctxt, node, "targetNamespace"); |
| } |
| |
| qname = xmlDictLookup(ctxt->dict, qname, -1); /* intern the string */ |
| name = xmlSplitQName3(qname, &len); |
| if (name == NULL) { |
| if (def == NULL) { |
| if (xmlStrEqual(node->name, BAD_CAST "element")) { |
| if (schema->flags & XML_SCHEMAS_QUALIF_ELEM) |
| *namespace = schema->targetNamespace; |
| } else if (xmlStrEqual(node->name, BAD_CAST "attribute")) { |
| if (schema->flags & XML_SCHEMAS_QUALIF_ATTR) |
| *namespace = schema->targetNamespace; |
| } else if ((xmlStrEqual(node->name, BAD_CAST "simpleType")) || |
| (xmlStrEqual(node->name, BAD_CAST "complexType"))) { |
| *namespace = schema->targetNamespace; |
| } |
| } else { |
| *namespace = def; |
| } |
| return(qname); |
| } |
| name = xmlDictLookup(ctxt->dict, name, -1); |
| prefix = xmlDictLookup(ctxt->dict, qname, len); |
| if (def != NULL) { |
| xmlSchemaPErr(ctxt, node, XML_SCHEMAP_DEF_AND_PREFIX, |
| "%s: presence of both prefix %s and targetNamespace\n", |
| node->name, prefix); |
| } |
| ns = xmlSearchNs(node->doc, node, prefix); |
| if (ns == NULL) { |
| xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED, |
| "%s: the QName prefix %s is undefined\n", |
| node->name, prefix); |
| return(name); |
| } |
| *namespace = xmlDictLookup(ctxt->dict, ns->href, -1); |
| return(name); |
| } |
| |
| /************************************************************************ |
| * * |
| * Parsing functions * |
| * * |
| ************************************************************************/ |
| |
| /** |
| * xmlSchemaGetElem: |
| * @schema: the schemas context |
| * @name: the element name |
| * @ns: the element namespace |
| * @level: how deep is the request |
| * |
| * Lookup a an element in the schemas or the accessible schemas |
| * |
| * Returns the element definition or NULL if not found. |
| */ |
| static xmlSchemaElementPtr |
| xmlSchemaGetElem(xmlSchemaPtr schema, const xmlChar * name, |
| const xmlChar * namespace, int level) |
| { |
| xmlSchemaElementPtr ret; |
| xmlSchemaImportPtr import = NULL; |
| |
| if ((name == NULL) || (schema == NULL)) |
| return (NULL); |
| |
| if (namespace == NULL) { |
| ret = xmlHashLookup2(schema->elemDecl, name, namespace); |
| if ((ret != NULL) && |
| ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) { |
| return (ret); |
| } |
| } else if ((schema->flags & XML_SCHEMAS_QUALIF_ELEM) == 0) { |
| if (xmlStrEqual(namespace, schema->targetNamespace)) |
| ret = xmlHashLookup2(schema->elemDecl, name, NULL); |
| else |
| ret = xmlHashLookup2(schema->elemDecl, name, namespace); |
| if ((ret != NULL) && |
| ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) { |
| return (ret); |
| } |
| } else { |
| ret = xmlHashLookup2(schema->elemDecl, name, namespace); |
| if ((ret != NULL) && |
| ((level == 0) || (ret->flags & XML_SCHEMAS_ELEM_TOPLEVEL))) { |
| return (ret); |
| } |
| } |
| if (level > 0) |
| import = xmlHashLookup(schema->schemasImports, namespace); |
| if (import != NULL) |
| ret = xmlSchemaGetElem(import->schema, name, namespace, level + 1); |
| #ifdef DEBUG |
| if (ret == NULL) { |
| if (namespace == NULL) |
| fprintf(stderr, "Unable to lookup type %s", name); |
| else |
| fprintf(stderr, "Unable to lookup type %s:%s", name, |
| namespace); |
| } |
| #endif |
| return (ret); |
| } |
| |
| /** |
| * xmlSchemaGetType: |
| * @schema: the schemas context |
| * @name: the type name |
| * @ns: the type 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 * namespace) |
| { |
| xmlSchemaTypePtr ret; |
| xmlSchemaImportPtr import; |
| |
| if (name == NULL) |
| return (NULL); |
| if (schema != NULL) { |
| ret = xmlHashLookup2(schema->typeDecl, name, namespace); |
| if (ret != NULL) |
| return (ret); |
| } |
| ret = xmlSchemaGetPredefinedType(name, namespace); |
| if (ret != NULL) |
| return (ret); |
| import = xmlHashLookup(schema->schemasImports, namespace); |
| if (import != NULL) |
| ret = xmlSchemaGetType(import->schema, name, namespace); |
| #ifdef DEBUG |
| if (ret == NULL) { |
| if (namespace == NULL) |
| fprintf(stderr, "Unable to lookup type %s", name); |
| else |
| fprintf(stderr, "Unable to lookup type %s:%s", name, |
| namespace); |
| } |
| #endif |
| return (ret); |
| } |
| |
| /************************************************************************ |
| * * |
| * Parsing functions * |
| * * |
| ************************************************************************/ |
| |
| #define IS_BLANK_NODE(n) \ |
| (((n)->type == XML_TEXT_NODE) && (xmlSchemaIsBlank((n)->content))) |
| |
| /** |
| * xmlSchemaIsBlank: |
| * @str: a string |
| * |
| * 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) |
| { |
| if (str == NULL) |
| return (1); |
| while (*str != 0) { |
| if (!(IS_BLANK_CH(*str))) |
| return (0); |
| str++; |
| } |
| return (1); |
| } |
| |
| /** |
| * xmlSchemaAddNotation: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @name: the item name |
| * |
| * Add an XML schema Attrribute declaration |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns the new struture or NULL in case of error |
| */ |
| static xmlSchemaNotationPtr |
| xmlSchemaAddNotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| const xmlChar * name) |
| { |
| xmlSchemaNotationPtr ret = NULL; |
| int val; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
| return (NULL); |
| |
| if (schema->notaDecl == NULL) |
| schema->notaDecl = xmlHashCreate(10); |
| if (schema->notaDecl == NULL) |
| return (NULL); |
| |
| ret = (xmlSchemaNotationPtr) xmlMalloc(sizeof(xmlSchemaNotation)); |
| if (ret == NULL) { |
| xmlSchemaPErrMemory(ctxt, "add annotation", NULL); |
| return (NULL); |
| } |
| memset(ret, 0, sizeof(xmlSchemaNotation)); |
| ret->name = xmlDictLookup(ctxt->dict, name, -1); |
| val = xmlHashAddEntry2(schema->notaDecl, name, schema->targetNamespace, |
| ret); |
| if (val != 0) { |
| xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
| XML_SCHEMAP_REDEFINED_NOTATION, |
| "Notation %s already defined\n", |
| name, NULL); |
| xmlFree(ret); |
| return (NULL); |
| } |
| return (ret); |
| } |
| |
| |
| /** |
| * xmlSchemaAddAttribute: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @name: the item name |
| * @namespace: the namespace |
| * |
| * Add an XML schema Attrribute declaration |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns the new struture or NULL in case of error |
| */ |
| static xmlSchemaAttributePtr |
| xmlSchemaAddAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| const xmlChar * name, const xmlChar * namespace) |
| { |
| xmlSchemaAttributePtr ret = NULL; |
| int val; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
| return (NULL); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "Adding attribute %s\n", name); |
| if (namespace != NULL) |
| fprintf(stderr, " target namespace %s\n", namespace); |
| #endif |
| |
| if (schema->attrDecl == NULL) |
| schema->attrDecl = xmlHashCreate(10); |
| if (schema->attrDecl == NULL) |
| return (NULL); |
| |
| ret = (xmlSchemaAttributePtr) xmlMalloc(sizeof(xmlSchemaAttribute)); |
| if (ret == NULL) { |
| xmlSchemaPErrMemory(ctxt, "allocating attribute", NULL); |
| return (NULL); |
| } |
| memset(ret, 0, sizeof(xmlSchemaAttribute)); |
| ret->name = xmlDictLookup(ctxt->dict, name, -1); |
| ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1); |
| val = xmlHashAddEntry3(schema->attrDecl, name, |
| schema->targetNamespace, ctxt->container, ret); |
| if (val != 0) { |
| xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
| XML_SCHEMAP_REDEFINED_ATTR, |
| "Attribute %s already defined\n", |
| name, NULL); |
| xmlFree(ret); |
| return (NULL); |
| } |
| return (ret); |
| } |
| |
| /** |
| * xmlSchemaAddAttributeGroup: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @name: the item name |
| * |
| * Add an XML schema Attrribute Group declaration |
| * |
| * Returns the new struture or NULL in case of error |
| */ |
| static xmlSchemaAttributeGroupPtr |
| xmlSchemaAddAttributeGroup(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, const xmlChar * name) |
| { |
| xmlSchemaAttributeGroupPtr ret = NULL; |
| int val; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
| return (NULL); |
| |
| if (schema->attrgrpDecl == NULL) |
| schema->attrgrpDecl = xmlHashCreate(10); |
| if (schema->attrgrpDecl == NULL) |
| return (NULL); |
| |
| ret = |
| (xmlSchemaAttributeGroupPtr) |
| xmlMalloc(sizeof(xmlSchemaAttributeGroup)); |
| if (ret == NULL) { |
| xmlSchemaPErrMemory(ctxt, "allocating attribute group", NULL); |
| return (NULL); |
| } |
| memset(ret, 0, sizeof(xmlSchemaAttributeGroup)); |
| ret->name = xmlDictLookup(ctxt->dict, name, -1); |
| val = xmlHashAddEntry3(schema->attrgrpDecl, name, |
| schema->targetNamespace, ctxt->container, ret); |
| if (val != 0) { |
| xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
| XML_SCHEMAP_REDEFINED_ATTRGROUP, |
| "Attribute group %s already defined\n", |
| name, NULL); |
| xmlFree(ret); |
| return (NULL); |
| } |
| return (ret); |
| } |
| |
| /** |
| * xmlSchemaAddElement: |
| * @ctxt: a schema validation 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 struture or NULL in case of error |
| */ |
| static xmlSchemaElementPtr |
| xmlSchemaAddElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| const xmlChar * name, const xmlChar * namespace) |
| { |
| xmlSchemaElementPtr ret = NULL; |
| int val; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
| return (NULL); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "Adding element %s\n", name); |
| if (namespace != NULL) |
| fprintf(stderr, " target namespace %s\n", namespace); |
| #endif |
| |
| if (schema->elemDecl == NULL) |
| schema->elemDecl = xmlHashCreate(10); |
| if (schema->elemDecl == NULL) |
| return (NULL); |
| |
| ret = (xmlSchemaElementPtr) xmlMalloc(sizeof(xmlSchemaElement)); |
| if (ret == NULL) { |
| xmlSchemaPErrMemory(ctxt, "allocating element", NULL); |
| return (NULL); |
| } |
| memset(ret, 0, sizeof(xmlSchemaElement)); |
| ret->name = xmlDictLookup(ctxt->dict, name, -1); |
| ret->targetNamespace = xmlDictLookup(ctxt->dict, namespace, -1); |
| val = xmlHashAddEntry3(schema->elemDecl, name, |
| namespace, ctxt->container, ret); |
| if (val != 0) { |
| char buf[100]; |
| |
| snprintf(buf, 99, "privatieelem %d", ctxt->counter++ + 1); |
| val = xmlHashAddEntry3(schema->elemDecl, name, (xmlChar *) buf, |
| namespace, ret); |
| if (val != 0) { |
| xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
| XML_SCHEMAP_REDEFINED_ELEMENT, |
| "Element %s already defined\n", |
| name, NULL); |
| xmlFree(ret); |
| return (NULL); |
| } |
| } |
| return (ret); |
| } |
| |
| /** |
| * xmlSchemaAddType: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @name: the item name |
| * @namespace: the namespace |
| * |
| * Add an XML schema Simple Type definition |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns the new struture or NULL in case of error |
| */ |
| static xmlSchemaTypePtr |
| xmlSchemaAddType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| const xmlChar * name, const xmlChar * namespace) |
| { |
| xmlSchemaTypePtr ret = NULL; |
| int val; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
| return (NULL); |
| |
| #ifdef DEBUG |
| fprintf(stderr, "Adding type %s\n", name); |
| if (namespace != NULL) |
| fprintf(stderr, " target namespace %s\n", namespace); |
| #endif |
| |
| if (schema->typeDecl == NULL) |
| schema->typeDecl = xmlHashCreate(10); |
| if (schema->typeDecl == NULL) |
| return (NULL); |
| |
| ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); |
| if (ret == NULL) { |
| xmlSchemaPErrMemory(ctxt, "allocating type", NULL); |
| return (NULL); |
| } |
| memset(ret, 0, sizeof(xmlSchemaType)); |
| ret->name = xmlDictLookup(ctxt->dict, name, -1); |
| ret->redef = NULL; |
| val = xmlHashAddEntry2(schema->typeDecl, name, namespace, ret); |
| if (val != 0) { |
| if (ctxt->includes == 0) { |
| xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
| XML_SCHEMAP_REDEFINED_TYPE, |
| "Type %s already defined\n", |
| name, NULL); |
| xmlFree(ret); |
| return (NULL); |
| } else { |
| xmlSchemaTypePtr prev; |
| |
| prev = xmlHashLookup2(schema->typeDecl, name, namespace); |
| if (prev == NULL) { |
| xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
| XML_ERR_INTERNAL_ERROR, |
| "Internal error on type %s definition\n", |
| name, NULL); |
| xmlFree(ret); |
| return (NULL); |
| } |
| ret->redef = prev->redef; |
| prev->redef = ret; |
| } |
| } |
| ret->minOccurs = 1; |
| ret->maxOccurs = 1; |
| |
| return (ret); |
| } |
| |
| /** |
| * xmlSchemaAddGroup: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @name: the group name |
| * |
| * Add an XML schema Group definition |
| * |
| * Returns the new struture or NULL in case of error |
| */ |
| static xmlSchemaTypePtr |
| xmlSchemaAddGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| const xmlChar * name) |
| { |
| xmlSchemaTypePtr ret = NULL; |
| int val; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (name == NULL)) |
| return (NULL); |
| |
| if (schema->groupDecl == NULL) |
| schema->groupDecl = xmlHashCreate(10); |
| if (schema->groupDecl == NULL) |
| return (NULL); |
| |
| ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); |
| if (ret == NULL) { |
| xmlSchemaPErrMemory(ctxt, "adding group", NULL); |
| return (NULL); |
| } |
| memset(ret, 0, sizeof(xmlSchemaType)); |
| ret->name = xmlDictLookup(ctxt->dict, name, -1); |
| val = |
| xmlHashAddEntry2(schema->groupDecl, name, schema->targetNamespace, |
| ret); |
| if (val != 0) { |
| xmlSchemaPErr(ctxt, (xmlNodePtr) ctxt->doc, |
| XML_SCHEMAP_REDEFINED_GROUP, |
| "Group %s already defined\n", |
| name, NULL); |
| xmlFree(ret); |
| return (NULL); |
| } |
| ret->minOccurs = 1; |
| ret->maxOccurs = 1; |
| |
| return (ret); |
| } |
| |
| /************************************************************************ |
| * * |
| * Utilities for parsing * |
| * * |
| ************************************************************************/ |
| |
| /** |
| * xmlGetQNameProp: |
| * @ctxt: a schema validation context |
| * @node: a subtree containing XML Schema informations |
| * @name: the attribute name |
| * @namespace: the result namespace if any |
| * |
| * Extract a QName Attribute value |
| * |
| * Returns the NCName or NULL if not found, and also update @namespace |
| * with the namespace URI |
| */ |
| static const xmlChar * |
| xmlGetQNameProp(xmlSchemaParserCtxtPtr ctxt, xmlNodePtr node, |
| const char *name, const xmlChar ** namespace) |
| { |
| const xmlChar *val; |
| xmlNsPtr ns; |
| const xmlChar *ret, *prefix; |
| int len; |
| |
| *namespace = NULL; |
| val = xmlSchemaGetProp(ctxt, node, name); |
| if (val == NULL) |
| return (NULL); |
| |
| ret = xmlSplitQName3(val, &len); |
| if (ret == NULL) { |
| return (val); |
| } |
| ret = xmlDictLookup(ctxt->dict, ret, -1); |
| prefix = xmlDictLookup(ctxt->dict, val, len); |
| |
| ns = xmlSearchNs(node->doc, node, prefix); |
| if (ns == NULL) { |
| xmlSchemaPErr(ctxt, node, XML_SCHEMAP_PREFIX_UNDEFINED, |
| "Attribute %s: the QName prefix %s is undefined\n", |
| (const xmlChar *) name, prefix); |
| } else { |
| *namespace = xmlDictLookup(ctxt->dict, ns->href, -1); |
| } |
| return (ret); |
| } |
| |
| /** |
| * 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) |
| { |
| const xmlChar *val, *cur; |
| int ret = 0; |
| |
| val = xmlSchemaGetProp(ctxt, node, "maxOccurs"); |
| if (val == NULL) |
| return (1); |
| |
| if (xmlStrEqual(val, (const xmlChar *) "unbounded")) { |
| return (UNBOUNDED); /* encoding it with -1 might be another option */ |
| } |
| |
| cur = val; |
| while (IS_BLANK_CH(*cur)) |
| cur++; |
| while ((*cur >= '0') && (*cur <= '9')) { |
| ret = ret * 10 + (*cur - '0'); |
| cur++; |
| } |
| while (IS_BLANK_CH(*cur)) |
| cur++; |
| if (*cur != 0) { |
| xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MAXOCCURS, |
| "invalid value for maxOccurs: %s\n", val, NULL); |
| return (1); |
| } |
| 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) |
| { |
| const xmlChar *val, *cur; |
| int ret = 0; |
| |
| val = xmlSchemaGetProp(ctxt, node, "minOccurs"); |
| if (val == NULL) |
| return (1); |
| |
| cur = val; |
| while (IS_BLANK_CH(*cur)) |
| cur++; |
| while ((*cur >= '0') && (*cur <= '9')) { |
| ret = ret * 10 + (*cur - '0'); |
| cur++; |
| } |
| while (IS_BLANK_CH(*cur)) |
| cur++; |
| if (*cur != 0) { |
| xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_MINOCCURS, |
| "invalid value for minOccurs: %s\n", val, NULL); |
| return (1); |
| } |
| return (ret); |
| } |
| |
| /** |
| * xmlGetBooleanProp: |
| * @ctxt: a schema validation context |
| * @node: a subtree containing XML Schema informations |
| * @name: the attribute name |
| * @def: the default value |
| * |
| * Get is a bolean 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); |
| |
| if (xmlStrEqual(val, BAD_CAST "true")) |
| def = 1; |
| else if (xmlStrEqual(val, BAD_CAST "false")) |
| def = 0; |
| else { |
| xmlSchemaPErr(ctxt, node, XML_SCHEMAP_INVALID_BOOLEAN, |
| "Attribute %s: the value %s is not boolean\n", |
| (const xmlChar *) name, val); |
| } |
| return (def); |
| } |
| |
| /************************************************************************ |
| * * |
| * Shema extraction from an Infoset * |
| * * |
| ************************************************************************/ |
| static xmlSchemaTypePtr xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr |
| ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node); |
| static xmlSchemaTypePtr xmlSchemaParseComplexType(xmlSchemaParserCtxtPtr |
| ctxt, |
| xmlSchemaPtr schema, |
| xmlNodePtr node); |
| static xmlSchemaTypePtr xmlSchemaParseRestriction(xmlSchemaParserCtxtPtr |
| ctxt, |
| xmlSchemaPtr schema, |
| xmlNodePtr node, |
| int simple); |
| static xmlSchemaTypePtr xmlSchemaParseSequence(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, |
| xmlNodePtr node); |
| static xmlSchemaTypePtr xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, |
| xmlNodePtr node); |
| static xmlSchemaAttributePtr xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr |
| ctxt, |
| xmlSchemaPtr schema, |
| xmlNodePtr node); |
| static xmlSchemaAttributeGroupPtr |
| xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, xmlNodePtr node); |
| static xmlSchemaTypePtr xmlSchemaParseChoice(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, |
| xmlNodePtr node); |
| static xmlSchemaTypePtr xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, |
| xmlNodePtr node); |
| static xmlSchemaAttributePtr |
| xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, xmlNodePtr node); |
| |
| /** |
| * xmlSchemaParseAttrDecls: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * @type: the hosting type |
| * |
| * parse a XML schema attrDecls declaration corresponding to |
| * <!ENTITY % attrDecls |
| * '((%attribute;| %attributeGroup;)*,(%anyAttribute;)?)'> |
| */ |
| static xmlNodePtr |
| xmlSchemaParseAttrDecls(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr child, xmlSchemaTypePtr type) |
| { |
| xmlSchemaAttributePtr lastattr, attr; |
| |
| lastattr = NULL; |
| while ((IS_SCHEMA(child, "attribute")) || |
| (IS_SCHEMA(child, "attributeGroup"))) { |
| attr = NULL; |
| if (IS_SCHEMA(child, "attribute")) { |
| attr = xmlSchemaParseAttribute(ctxt, schema, child); |
| } else if (IS_SCHEMA(child, "attributeGroup")) { |
| attr = (xmlSchemaAttributePtr) |
| xmlSchemaParseAttributeGroup(ctxt, schema, child); |
| } |
| if (attr != NULL) { |
| if (lastattr == NULL) { |
| type->attributes = attr; |
| lastattr = attr; |
| } else { |
| lastattr->next = attr; |
| lastattr = attr; |
| } |
| } |
| child = child->next; |
| } |
| if (IS_SCHEMA(child, "anyAttribute")) { |
| attr = xmlSchemaParseAnyAttribute(ctxt, schema, child); |
| if (attr != NULL) { |
| if (lastattr == NULL) { |
| type->attributes = attr; |
| lastattr = attr; |
| } else { |
| lastattr->next = attr; |
| lastattr = attr; |
| } |
| } |
| child = child->next; |
| } |
| return (child); |
| } |
| |
| /** |
| * xmlSchemaParseAnnotation: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema Attrribute declaration |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns -1 in case of error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static xmlSchemaAnnotPtr |
| xmlSchemaParseAnnotation(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlSchemaAnnotPtr ret; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| ret = xmlSchemaNewAnnot(ctxt, node); |
| |
| 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); |
| } |
| facet->id = xmlSchemaGetProp(ctxt, node, "id"); |
| facet->value = value; |
| child = node->children; |
| |
| if (IS_SCHEMA(child, "annotation")) { |
| facet->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| 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); |
| } |
| |
| /** |
| * xmlSchemaParseAny: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema Any declaration |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns the new type structure or NULL in case of error |
| */ |
| static xmlSchemaTypePtr |
| xmlSchemaParseAny(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlSchemaTypePtr type; |
| xmlNodePtr child = NULL; |
| xmlChar name[30]; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| snprintf((char *) name, 30, "any %d", ctxt->counter++ + 1); |
| type = xmlSchemaAddType(ctxt, schema, name, NULL); |
| if (type == NULL) |
| return (NULL); |
| type->node = node; |
| type->type = XML_SCHEMA_TYPE_ANY; |
| child = node->children; |
| type->minOccurs = xmlGetMinOccurs(ctxt, node); |
| type->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
| |
| if (IS_SCHEMA(child, "annotation")) { |
| type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_UNKNOWN_SEQUENCE_CHILD, |
| "Sequence %s has unexpected content\n", type->name, |
| NULL); |
| } |
| |
| return (type); |
| } |
| |
| /** |
| * 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); |
| if (ret == NULL) { |
| return (NULL); |
| } |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_UNKNOWN_NOTATION_CHILD, |
| "notation %s has unexpected content\n", name, NULL); |
| } |
| |
| return (ret); |
| } |
| |
| /** |
| * xmlSchemaParseAnyAttribute: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema AnyAttrribute declaration |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns an attribute def structure or NULL |
| */ |
| static xmlSchemaAttributePtr |
| xmlSchemaParseAnyAttribute(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, xmlNodePtr node) |
| { |
| const xmlChar *processContents; |
| xmlSchemaAttributePtr ret; |
| xmlNodePtr child = NULL; |
| char name[100]; |
| const xmlChar *local, *ns; |
| |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| |
| snprintf(name, 99, "anyattr %d", ctxt->counter++ + 1); |
| local = xmlSchemaGetNamespace(ctxt, schema, node, BAD_CAST "anyattr", &ns); |
| ret = xmlSchemaAddAttribute(ctxt, schema, BAD_CAST name, ns); |
| if (ret == NULL) { |
| return (NULL); |
| } |
| ret->id = xmlSchemaGetProp(ctxt, node, "id"); |
| processContents = xmlSchemaGetProp(ctxt, node, "processContents"); |
| if ((processContents == NULL) |
| || (xmlStrEqual(processContents, (const xmlChar *) "strict"))) { |
| ret->occurs = XML_SCHEMAS_ANYATTR_STRICT; |
| } else if (xmlStrEqual(processContents, (const xmlChar *) "skip")) { |
| ret->occurs = XML_SCHEMAS_ANYATTR_SKIP; |
| } else if (xmlStrEqual(processContents, (const xmlChar *) "lax")) { |
| ret->occurs = XML_SCHEMAS_ANYATTR_LAX; |
| } else { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_UNKNOWN_PROCESSCONTENT_CHILD, |
| "anyAttribute has unexpected content for processContents: %s\n", |
| processContents, NULL); |
| ret->occurs = XML_SCHEMAS_ANYATTR_STRICT; |
| } |
| |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_UNKNOWN_ANYATTRIBUTE_CHILD, |
| "anyAttribute %s has unexpected content\n", |
| (const xmlChar *) name, NULL); |
| } |
| |
| return (ret); |
| } |
| |
| |
| /** |
| * xmlSchemaParseAttribute: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema Attrribute declaration |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns -1 in case of error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static xmlSchemaAttributePtr |
| xmlSchemaParseAttribute(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| const xmlChar *name, *refNs = NULL, *ref = NULL; |
| xmlSchemaAttributePtr ret; |
| xmlNodePtr child = NULL; |
| char buf[100]; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| name = xmlSchemaGetProp(ctxt, node, "name"); |
| if (name == NULL) { |
| |
| ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); |
| if (ref == NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_ATTR_NONAME_NOREF, |
| "Attribute has no name nor ref\n", NULL, NULL); |
| return (NULL); |
| } |
| if (refNs == NULL) |
| refNs = schema->targetNamespace; |
| snprintf(buf, 99, "anonattr %d", ctxt->counter++ + 1); |
| name = (const xmlChar *) buf; |
| ret = xmlSchemaAddAttribute(ctxt, schema, name, NULL); |
| } else { |
| const xmlChar *local, *ns; |
| |
| local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); |
| ret = xmlSchemaAddAttribute(ctxt, schema, local, ns); |
| } |
| if (ret == NULL) { |
| return (NULL); |
| } |
| ret->ref = ref; |
| ret->refNs = refNs; |
| if ((ret->targetNamespace != NULL) && |
| ((schema->flags & XML_SCHEMAS_QUALIF_ATTR) == 0) && |
| (xmlStrEqual(ret->targetNamespace, schema->targetNamespace))) |
| ret->flags |= XML_SCHEMAS_ATTR_NSDEFAULT; |
| ret->typeName = xmlGetQNameProp(ctxt, node, "type", &(ret->typeNs)); |
| if ((ret->typeName != NULL) && (ret->typeNs == NULL)) |
| ret->typeNs = schema->targetNamespace; |
| ret->node = node; |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| if (IS_SCHEMA(child, "simpleType")) { |
| ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child); |
| child = child->next; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ATTR_CHILD, |
| "attribute %s has unexpected content\n", name, |
| NULL); |
| } |
| |
| return (ret); |
| } |
| |
| /** |
| * xmlSchemaParseAttributeGroup: |
| * @ctxt: 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 or NULL in case of error. |
| */ |
| static xmlSchemaAttributeGroupPtr |
| xmlSchemaParseAttributeGroup(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, xmlNodePtr node) |
| { |
| const xmlChar *name, *refNs = NULL, *ref = NULL; |
| xmlSchemaAttributeGroupPtr ret; |
| xmlSchemaAttributePtr last = NULL, attr; |
| xmlNodePtr child = NULL; |
| const xmlChar *oldcontainer; |
| char buf[100]; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| oldcontainer = ctxt->container; |
| name = xmlSchemaGetProp(ctxt, node, "name"); |
| if (name == NULL) { |
| |
| ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); |
| if (ref == NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_ATTRGRP_NONAME_NOREF, |
| "AttributeGroup has no name nor ref\n", NULL, |
| NULL); |
| return (NULL); |
| } |
| if (refNs == NULL) |
| refNs = schema->targetNamespace; |
| snprintf(buf, 99, "anonattrgroup %d", ctxt->counter++ + 1); |
| name = (const xmlChar *) buf; |
| if (name == NULL) { |
| xmlSchemaPErrMemory(ctxt, "creating attribute group", node); |
| return (NULL); |
| } |
| } |
| ret = xmlSchemaAddAttributeGroup(ctxt, schema, name); |
| if (ret == NULL) { |
| return (NULL); |
| } |
| ret->ref = ref; |
| ret->refNs = refNs; |
| ret->type = XML_SCHEMA_TYPE_ATTRIBUTEGROUP; |
| ret->node = node; |
| child = node->children; |
| ctxt->container = name; |
| if (IS_SCHEMA(child, "annotation")) { |
| ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| while ((IS_SCHEMA(child, "attribute")) || |
| (IS_SCHEMA(child, "attributeGroup"))) { |
| attr = NULL; |
| if (IS_SCHEMA(child, "attribute")) { |
| attr = xmlSchemaParseAttribute(ctxt, schema, child); |
| } else if (IS_SCHEMA(child, "attributeGroup")) { |
| attr = (xmlSchemaAttributePtr) |
| xmlSchemaParseAttributeGroup(ctxt, schema, child); |
| } |
| if (attr != NULL) { |
| if (last == NULL) { |
| ret->attributes = attr; |
| last = attr; |
| } else { |
| last->next = attr; |
| last = attr; |
| } |
| } |
| child = child->next; |
| } |
| if (IS_SCHEMA(child, "anyAttribute")) { |
| TODO |
| child = child->next; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_UNKNOWN_ATTRGRP_CHILD, |
| "attribute group %s has unexpected content\n", name, |
| NULL); |
| } |
| ctxt->container = oldcontainer; |
| return (ret); |
| } |
| |
| /** |
| * xmlSchemaParseElement: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema Element declaration |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns -1 in case of error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static xmlSchemaElementPtr |
| xmlSchemaParseElement(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node, int toplevel) |
| { |
| const xmlChar *name, *fixed; |
| const xmlChar *refNs = NULL, *ref = NULL; |
| xmlSchemaElementPtr ret; |
| xmlNodePtr child = NULL; |
| const xmlChar *oldcontainer; |
| char buf[100]; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| oldcontainer = ctxt->container; |
| name = xmlSchemaGetProp(ctxt, node, "name"); |
| if (name == NULL) { |
| |
| ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); |
| if (ref == NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_ELEM_NONAME_NOREF, |
| "Element has no name nor ref\n", NULL, NULL); |
| return (NULL); |
| } |
| if (refNs == NULL) |
| refNs = schema->targetNamespace; |
| snprintf(buf, 99, "anonelem %d", ctxt->counter++ + 1); |
| name = (const xmlChar *) buf; |
| ret = xmlSchemaAddElement(ctxt, schema, name, NULL); |
| } else { |
| const xmlChar *local, *ns; |
| |
| local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); |
| ret = xmlSchemaAddElement(ctxt, schema, local, ns); |
| } |
| if (ret != NULL) |
| ret->node = node; |
| if (ret == NULL) { |
| return (NULL); |
| } |
| ret->type = XML_SCHEMA_TYPE_ELEMENT; |
| ret->ref = ref; |
| ret->refNs = refNs; |
| if (ref != NULL) |
| ret->flags |= XML_SCHEMAS_ELEM_REF; |
| if (toplevel) |
| ret->flags |= XML_SCHEMAS_ELEM_TOPLEVEL; |
| if (xmlGetBooleanProp(ctxt, node, "nillable", 0)) |
| ret->flags |= XML_SCHEMAS_ELEM_NILLABLE; |
| if (xmlGetBooleanProp(ctxt, node, "abstract", 0)) |
| ret->flags |= XML_SCHEMAS_ELEM_NILLABLE; |
| ctxt->container = name; |
| |
| ret->id = xmlSchemaGetProp(ctxt, node, "id"); |
| ret->namedType = |
| xmlGetQNameProp(ctxt, node, "type", &(ret->namedTypeNs)); |
| if ((ret->namedType != NULL) && (ret->namedTypeNs == NULL)) |
| ret->namedTypeNs = schema->targetNamespace; |
| ret->substGroup = |
| xmlGetQNameProp(ctxt, node, "substitutionGroup", |
| &(ret->substGroupNs)); |
| fixed = xmlSchemaGetProp(ctxt, node, "fixed"); |
| ret->minOccurs = xmlGetMinOccurs(ctxt, node); |
| ret->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
| |
| ret->value = xmlSchemaGetProp(ctxt, node, "default"); |
| if ((ret->value != NULL) && (fixed != NULL)) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_ELEM_DEFAULT_FIXED, |
| "Element %s has both default and fixed\n", |
| ret->name, NULL); |
| } else if (fixed != NULL) { |
| ret->flags |= XML_SCHEMAS_ELEM_FIXED; |
| ret->value = fixed; |
| } |
| |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| ret->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| if (IS_SCHEMA(child, "complexType")) { |
| ret->subtypes = xmlSchemaParseComplexType(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "simpleType")) { |
| ret->subtypes = xmlSchemaParseSimpleType(ctxt, schema, child); |
| child = child->next; |
| } |
| while ((IS_SCHEMA(child, "unique")) || |
| (IS_SCHEMA(child, "key")) || (IS_SCHEMA(child, "keyref"))) { |
| TODO child = child->next; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ELEM_CHILD, |
| "element %s has unexpected content\n", name, NULL); |
| } |
| |
| ctxt->container = oldcontainer; |
| return (ret); |
| } |
| |
| /** |
| * 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 error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static xmlSchemaTypePtr |
| xmlSchemaParseUnion(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlSchemaTypePtr type, subtype, last = NULL; |
| xmlNodePtr child = NULL; |
| xmlChar name[30]; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| |
| |
| snprintf((char *) name, 30, "union %d", ctxt->counter++ + 1); |
| type = xmlSchemaAddType(ctxt, schema, name, NULL); |
| if (type == NULL) |
| return (NULL); |
| type->node = node; |
| type->type = XML_SCHEMA_TYPE_LIST; |
| type->id = xmlSchemaGetProp(ctxt, node, "id"); |
| type->ref = xmlSchemaGetProp(ctxt, node, "memberTypes"); |
| |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| while (IS_SCHEMA(child, "simpleType")) { |
| subtype = (xmlSchemaTypePtr) |
| xmlSchemaParseSimpleType(ctxt, schema, child); |
| 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) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_UNION_CHILD, |
| "Union %s has unexpected content\n", type->name, |
| NULL); |
| } |
| return (type); |
| } |
| |
| /** |
| * 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 inproper and |
| * 1 in case of success. |
| */ |
| static xmlSchemaTypePtr |
| xmlSchemaParseList(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlSchemaTypePtr type, subtype; |
| xmlNodePtr child = NULL; |
| xmlChar name[30]; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| |
| snprintf((char *) name, 30, "list %d", ctxt->counter++ + 1); |
| type = xmlSchemaAddType(ctxt, schema, name, NULL); |
| if (type == NULL) |
| return (NULL); |
| type->node = node; |
| type->type = XML_SCHEMA_TYPE_LIST; |
| type->id = xmlSchemaGetProp(ctxt, node, "id"); |
| type->ref = xmlGetQNameProp(ctxt, node, "ref", &(type->refNs)); |
| if ((type->ref != NULL) && (type->refNs == NULL)) |
| type->refNs = schema->targetNamespace; |
| |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| subtype = NULL; |
| if (IS_SCHEMA(child, "simpleType")) { |
| subtype = (xmlSchemaTypePtr) |
| xmlSchemaParseSimpleType(ctxt, schema, child); |
| child = child->next; |
| type->subtypes = subtype; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_LIST_CHILD, |
| "List %s has unexpected content\n", type->name, |
| NULL); |
| } |
| return (type); |
| } |
| |
| /** |
| * xmlSchemaParseSimpleType: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema Simple Type definition |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns -1 in case of error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static xmlSchemaTypePtr |
| xmlSchemaParseSimpleType(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlSchemaTypePtr type, subtype; |
| xmlNodePtr child = NULL; |
| const xmlChar *name; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| |
| |
| name = xmlSchemaGetProp(ctxt, node, "name"); |
| if (name == NULL) { |
| char buf[100]; |
| |
| snprintf(buf, 99, "simpletype %d", ctxt->counter++ + 1); |
| type = xmlSchemaAddType(ctxt, schema, (const xmlChar *)buf, NULL); |
| } else { |
| const xmlChar *local, *ns; |
| |
| local = xmlSchemaGetNamespace(ctxt, schema, node, name, &ns); |
| type = xmlSchemaAddType(ctxt, schema, local, ns); |
| } |
| if (type == NULL) |
| return (NULL); |
| type->node = node; |
| type->type = XML_SCHEMA_TYPE_SIMPLE; |
| type->id = xmlSchemaGetProp(ctxt, node, "id"); |
| |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| subtype = NULL; |
| if (IS_SCHEMA(child, "restriction")) { |
| subtype = (xmlSchemaTypePtr) |
| xmlSchemaParseRestriction(ctxt, schema, child, 1); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "list")) { |
| subtype = (xmlSchemaTypePtr) |
| xmlSchemaParseList(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "union")) { |
| subtype = (xmlSchemaTypePtr) |
| xmlSchemaParseUnion(ctxt, schema, child); |
| child = child->next; |
| } |
| type->subtypes = subtype; |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_UNKNOWN_SIMPLETYPE_CHILD, |
| "SimpleType %s has unexpected content\n", |
| type->name, NULL); |
| } |
| |
| return (type); |
| } |
| |
| |
| /** |
| * xmlSchemaParseGroup: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema Group definition |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns -1 in case of error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static xmlSchemaTypePtr |
| xmlSchemaParseGroup(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlSchemaTypePtr type, subtype; |
| xmlNodePtr child = NULL; |
| const xmlChar *name; |
| const xmlChar *ref = NULL, *refNs = NULL; |
| char buf[100]; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| |
| |
| name = xmlSchemaGetProp(ctxt, node, "name"); |
| if (name == NULL) { |
| |
| ref = xmlGetQNameProp(ctxt, node, "ref", &refNs); |
| if (ref == NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_GROUP_NONAME_NOREF, |
| "Group has no name nor ref\n", NULL, NULL); |
| return (NULL); |
| } |
| if (refNs == NULL) |
| refNs = schema->targetNamespace; |
| snprintf(buf, 99, "anongroup %d", ctxt->counter++ + 1); |
| name = (const xmlChar *) buf; |
| } |
| type = xmlSchemaAddGroup(ctxt, schema, name); |
| if (type == NULL) |
| return (NULL); |
| |
| type->node = node; |
| type->type = XML_SCHEMA_TYPE_GROUP; |
| type->id = xmlSchemaGetProp(ctxt, node, "id"); |
| type->ref = ref; |
| type->refNs = refNs; |
| type->minOccurs = xmlGetMinOccurs(ctxt, node); |
| type->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
| |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| subtype = NULL; |
| if (IS_SCHEMA(child, "all")) { |
| subtype = (xmlSchemaTypePtr) |
| xmlSchemaParseAll(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "choice")) { |
| subtype = xmlSchemaParseChoice(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "sequence")) { |
| subtype = (xmlSchemaTypePtr) |
| xmlSchemaParseSequence(ctxt, schema, child); |
| child = child->next; |
| } |
| if (subtype != NULL) |
| type->subtypes = subtype; |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_GROUP_CHILD, |
| "Group %s has unexpected content\n", type->name, |
| NULL); |
| } |
| |
| return (type); |
| } |
| |
| /** |
| * xmlSchemaParseAll: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema All definition |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns -1 in case of error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static xmlSchemaTypePtr |
| xmlSchemaParseAll(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlSchemaTypePtr type, subtype, last = NULL; |
| xmlNodePtr child = NULL; |
| xmlChar name[30]; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (NULL); |
| |
| |
| snprintf((char *) name, 30, "all%d", ctxt->counter++ + 1); |
| type = xmlSchemaAddType(ctxt, schema, name, NULL); |
| if (type == NULL) |
| return (NULL); |
| type->node = node; |
| type->type = XML_SCHEMA_TYPE_ALL; |
| type->id = xmlSchemaGetProp(ctxt, node, "id"); |
| type->minOccurs = xmlGetMinOccurs(ctxt, node); |
| type->maxOccurs = xmlGetMaxOccurs(ctxt, node); |
| |
| child = node->children; |
| if (IS_SCHEMA(child, "annotation")) { |
| type->annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| child = child->next; |
| } |
| while (IS_SCHEMA(child, "element")) { |
| subtype = (xmlSchemaTypePtr) |
| xmlSchemaParseElement(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) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_ALL_CHILD, |
| "All %s has unexpected content\n", type->name, |
| NULL); |
| } |
| |
| return (type); |
| } |
| |
| /** |
| * xmlSchemaImportSchema |
| * |
| * @ctxt: a schema validation context |
| * @schemaLocation: an URI defining where to find the imported schema |
| * |
| * import a XML schema |
| * *WARNING* this interface is highly subject to change |
| * |
| * Returns -1 in case of error and 1 in case of success. |
| */ |
| static xmlSchemaImportPtr |
| xmlSchemaImportSchema(xmlSchemaParserCtxtPtr ctxt, |
| const xmlChar *schemaLocation) |
| { |
| xmlSchemaImportPtr import; |
| xmlSchemaParserCtxtPtr newctxt; |
| |
| newctxt = (xmlSchemaParserCtxtPtr) xmlMalloc(sizeof(xmlSchemaParserCtxt)); |
| if (newctxt == NULL) { |
| xmlSchemaPErrMemory(ctxt, "allocating schama parser context", |
| NULL); |
| return (NULL); |
| } |
| memset(newctxt, 0, sizeof(xmlSchemaParserCtxt)); |
| /* Keep the same dictionnary for parsing, really */ |
| xmlDictReference(ctxt->dict); |
| newctxt->dict = ctxt->dict; |
| newctxt->includes = 0; |
| newctxt->URL = xmlDictLookup(newctxt->dict, schemaLocation, -1); |
| |
| xmlSchemaSetParserErrors(newctxt, ctxt->error, ctxt->warning, |
| ctxt->userData); |
| |
| import = (xmlSchemaImport*) xmlMalloc(sizeof(xmlSchemaImport)); |
| if (import == NULL) { |
| xmlSchemaPErrMemory(NULL, "allocating imported schema", |
| NULL); |
| xmlSchemaFreeParserCtxt(newctxt); |
| return (NULL); |
| } |
| |
| memset(import, 0, sizeof(xmlSchemaImport)); |
| import->schemaLocation = xmlDictLookup(ctxt->dict, schemaLocation, -1); |
| import->schema = xmlSchemaParse(newctxt); |
| |
| if (import->schema == NULL) { |
| /* FIXME use another error enum here ? */ |
| xmlSchemaPErr(ctxt, NULL, XML_SCHEMAS_ERR_INTERNAL, |
| "failed to import schema at location %s\n", |
| schemaLocation, NULL); |
| |
| xmlSchemaFreeParserCtxt(newctxt); |
| if (import->schemaLocation != NULL) |
| xmlFree((xmlChar *)import->schemaLocation); |
| xmlFree(import); |
| return NULL; |
| } |
| |
| xmlSchemaFreeParserCtxt(newctxt); |
| return import; |
| } |
| |
| |
| /** |
| * 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 -1 in case of error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static int |
| xmlSchemaParseImport(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlNodePtr child = NULL; |
| xmlSchemaImportPtr import = NULL; |
| const xmlChar *namespace; |
| const xmlChar *schemaLocation; |
| const xmlChar *previous; |
| xmlURIPtr check; |
| |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (-1); |
| |
| namespace = xmlSchemaGetProp(ctxt, node, "namespace"); |
| if (namespace != NULL) { |
| check = xmlParseURI((const char *) namespace); |
| if (check == NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_IMPORT_NAMESPACE_NOT_URI, |
| "Import namespace attribute is not an URI: %s\n", |
| namespace, NULL); |
| return (-1); |
| } else { |
| xmlFreeURI(check); |
| } |
| } |
| schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation"); |
| if (schemaLocation != NULL) { |
| xmlChar *base = NULL; |
| xmlChar *URI = NULL; |
| check = xmlParseURI((const char *) schemaLocation); |
| if (check == NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_IMPORT_SCHEMA_NOT_URI, |
| "Import schemaLocation attribute is not an URI: %s\n", |
| schemaLocation, NULL); |
| return (-1); |
| } else { |
| xmlFreeURI(check); |
| } |
| base = xmlNodeGetBase(node->doc, node); |
| if (base == NULL) { |
| URI = xmlBuildURI(schemaLocation, node->doc->URL); |
| } else { |
| URI = xmlBuildURI(schemaLocation, base); |
| xmlFree(base); |
| } |
| if (URI != NULL) { |
| schemaLocation = xmlDictLookup(ctxt->dict, URI, -1); |
| xmlFree(URI); |
| } |
| } |
| if (schema->schemasImports == NULL) { |
| schema->schemasImports = xmlHashCreate(10); |
| if (schema->schemasImports == NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_FAILED_BUILD_IMPORT, |
| "Internal: failed to build import table\n", |
| NULL, NULL); |
| return (-1); |
| } |
| } |
| if (namespace == NULL) { |
| import = xmlHashLookup(schema->schemasImports, |
| XML_SCHEMAS_DEFAULT_NAMESPACE); |
| if (import != NULL) |
| previous = import->schemaLocation; |
| else |
| previous = NULL; |
| |
| if (schemaLocation != NULL) { |
| if (previous != NULL) { |
| if (!xmlStrEqual(schemaLocation, previous)) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_IMPORT_REDEFINE_NSNAME, |
| "Redefining import for default namespace with a different URI: %s\n", |
| schemaLocation, NULL); |
| } |
| } else { |
| import = xmlSchemaImportSchema(ctxt, schemaLocation); |
| if (import == NULL) { |
| return (-1); |
| } |
| xmlHashAddEntry(schema->schemasImports, |
| XML_SCHEMAS_DEFAULT_NAMESPACE, |
| import); |
| } |
| } |
| } else { |
| import = xmlHashLookup(schema->schemasImports, namespace); |
| if (import != NULL) |
| previous = import->schemaLocation; |
| else |
| previous = NULL; |
| |
| if (schemaLocation != NULL) { |
| if (previous != NULL) { |
| if (!xmlStrEqual(schemaLocation, previous)) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_IMPORT_REDEFINE_NSNAME, |
| "Redefining import for namespace %s with a different URI: %s\n", |
| namespace, schemaLocation); |
| } |
| } else { |
| import = xmlSchemaImportSchema(ctxt, schemaLocation); |
| if (import == NULL) { |
| return (-1); |
| } |
| xmlHashAddEntry(schema->schemasImports, |
| namespace, import); |
| } |
| } |
| } |
| |
| child = node->children; |
| while (IS_SCHEMA(child, "annotation")) { |
| /* |
| * the annotations here are simply discarded ... |
| */ |
| child = child->next; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_IMPORT_CHILD, |
| "Import has unexpected content\n", NULL, NULL); |
| return (-1); |
| } |
| return (1); |
| } |
| |
| /** |
| * 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; |
| } |
| } |
| |
| /** |
| * 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 void |
| xmlSchemaParseSchemaTopLevel(xmlSchemaParserCtxtPtr ctxt, |
| xmlSchemaPtr schema, xmlNodePtr nodes) |
| { |
| xmlNodePtr child; |
| xmlSchemaAnnotPtr annot; |
| |
| if ((ctxt == NULL) || (schema == NULL) || (nodes == NULL)) |
| return; |
| |
| 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, schema, child); |
| if (schema->annot == NULL) |
| schema->annot = annot; |
| else |
| xmlSchemaFreeAnnot(annot); |
| } else if (IS_SCHEMA(child, "import")) { |
| xmlSchemaParseImport(ctxt, schema, child); |
| } else if (IS_SCHEMA(child, "include")) { |
| ctxt->includes++; |
| xmlSchemaParseInclude(ctxt, schema, child); |
| ctxt->includes--; |
| } else if (IS_SCHEMA(child, "redefine")) { |
| TODO |
| } |
| child = child->next; |
| } |
| while (child != NULL) { |
| if (IS_SCHEMA(child, "complexType")) { |
| xmlSchemaParseComplexType(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "simpleType")) { |
| xmlSchemaParseSimpleType(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "element")) { |
| xmlSchemaParseElement(ctxt, schema, child, 1); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "attribute")) { |
| xmlSchemaParseAttribute(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "attributeGroup")) { |
| xmlSchemaParseAttributeGroup(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "group")) { |
| xmlSchemaParseGroup(ctxt, schema, child); |
| child = child->next; |
| } else if (IS_SCHEMA(child, "notation")) { |
| xmlSchemaParseNotation(ctxt, schema, child); |
| child = child->next; |
| } else { |
| xmlSchemaPErr2(ctxt, NULL, child, |
| XML_SCHEMAP_UNKNOWN_SCHEMAS_CHILD, |
| "Schemas: unexpected element %s here \n", |
| child->name, NULL); |
| child = child->next; |
| } |
| while (IS_SCHEMA(child, "annotation")) { |
| annot = xmlSchemaParseAnnotation(ctxt, schema, child); |
| if (schema->annot == NULL) |
| schema->annot = annot; |
| else |
| xmlSchemaFreeAnnot(annot); |
| child = child->next; |
| } |
| } |
| } |
| |
| /** |
| * xmlSchemaParseInclude: |
| * @ctxt: a schema validation context |
| * @schema: the schema being built |
| * @node: a subtree containing XML Schema informations |
| * |
| * parse a XML schema Include definition |
| * |
| * Returns -1 in case of error, 0 if the declaration is inproper and |
| * 1 in case of success. |
| */ |
| static int |
| xmlSchemaParseInclude(xmlSchemaParserCtxtPtr ctxt, xmlSchemaPtr schema, |
| xmlNodePtr node) |
| { |
| xmlNodePtr child = NULL; |
| const xmlChar *schemaLocation; |
| xmlURIPtr check; |
| xmlDocPtr doc; |
| xmlNodePtr root; |
| xmlSchemaIncludePtr include; |
| |
| |
| if ((ctxt == NULL) || (schema == NULL) || (node == NULL)) |
| return (-1); |
| |
| /* |
| * Preliminary step, extract the URI-Reference for the include and |
| * make an URI from the base. |
| */ |
| schemaLocation = xmlSchemaGetProp(ctxt, node, "schemaLocation"); |
| if (schemaLocation != NULL) { |
| xmlChar *base = NULL; |
| xmlChar *URI = NULL; |
| check = xmlParseURI((const char *) schemaLocation); |
| if (check == NULL) { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_INCLUDE_SCHEMA_NOT_URI, |
| "Include schemaLocation attribute is not an URI: %s\n", |
| schemaLocation, NULL); |
| return (-1); |
| } else { |
| xmlFreeURI(check); |
| } |
| base = xmlNodeGetBase(node->doc, node); |
| if (base == NULL) { |
| URI = xmlBuildURI(schemaLocation, node->doc->URL); |
| } else { |
| URI = xmlBuildURI(schemaLocation, base); |
| xmlFree(base); |
| } |
| if (URI != NULL) { |
| schemaLocation = xmlDictLookup(ctxt->dict, URI, -1); |
| xmlFree(URI); |
| } |
| } else { |
| xmlSchemaPErr2(ctxt, node, child, |
| XML_SCHEMAP_INCLUDE_SCHEMA_NO_URI, |
| "Include schemaLocation attribute missing\n", |
| NULL, NULL); |
| return (-1); |
| } |
| |
| child = node->children; |
| while (IS_SCHEMA(child, "annotation")) { |
| /* |
| * the annotations here are simply discarded ... |
| */ |
| child = child->next; |
| } |
| if (child != NULL) { |
| xmlSchemaPErr2(ctxt, node, child, XML_SCHEMAP_UNKNOWN_INCLUDE_CHILD, |
| "Include has unexpected content\n", NULL, NULL); |
| return (-1); |
| } |
| |
| /* |
| * First step is to parse the input document into an DOM/Infoset |
| */ |
| doc = xmlReadFile((const char *) schemaLocation, NULL, |
| SCHEMAS_PARSE_OPTIONS); |
| if (doc == NULL) { |
| xmlSchemaPErr(ctxt, NULL, |
| XML_SCHEMAP_FAILED_LOAD, |
| "xmlSchemaParse: could not load %s\n", |
| ctxt->URL, NULL); |
| return(-1); |
| } |
| |
| /* |
| * Then extract the root of the schema |
| */ |
| root = xmlDocGetRootElement(doc); |
| if (root == NULL) { |
| xmlSchemaPErr(ctxt, (xmlNodePtr) doc, |
| XML_SCHEMAP_NOROOT, |
| "schemas %s has no root", schemaLocation, NULL); |
| xmlFreeDoc(doc); |
| return (-1); |
| } |
| |
| /* |
| * Remove all the blank text nodes |
| */ |
| xmlSchemaCleanupDoc(ctxt, root); |
| |
| /* |
| * Check the schemas top level element |
<
|