// $Id$ #include "XmlSchema.h" #include "XmlSchemaGroup.h" #include "XmlSchemaAttributeGroup.h" #include "XmlSchemaAttribute.h" #include "XmlSchemaElement.h" #include "XmlSchemaType.h" #include "XmlSchemaSaxBuilder.h" #include "common.h" @interface XmlSchema(Resources) + (NSString *)schemesPath; + (void)loadSchemaResources; @end static NSMutableDictionary *namespace2schema = nil; static NSDictionary *namespace2file = nil; @implementation XmlSchema + (XmlSchema *)schemaForNamespace:(NSString *)_namespace { XmlSchema *result; if (_namespace == nil) return nil; result = [namespace2schema objectForKey:_namespace]; if (result == nil) { NSString *file; file = [namespace2file objectForKey:_namespace]; if (file == nil) { NSLog(@"Warning: Could not find schema file for namespace '%@'. " @"Try namespace instead!", _namespace); file = _namespace; } result = [[[XmlSchema alloc] initWithContentsOfFile:file] autorelease]; } return result; } + (BOOL)hasSchemaForNamespace:(NSString *)_namespace { return ([namespace2schema objectForKey:_namespace] != nil) ? YES : NO; } + (void)registerSchemaAtPath:(NSString *)_path { XmlSchema *result = nil; NSString *uri; if (_path == nil) return; result = [[[XmlSchema alloc] initWithContentsOfFile:_path] autorelease]; if (result == nil) return; uri = [result targetNamespace]; if ([namespace2schema objectForKey:uri] == nil) [namespace2schema setObject:result forKey:uri]; else { NSLog(@"Could not register schema at path '%@' ", @"(There is already a schema at targetNamespace='%@')", _path, uri); } } + (XmlSchemaElement *)elementWithQName:(NSString *)_qName { XmlSchema *mySchema; mySchema = [XmlSchema schemaForNamespace:[_qName uriFromQName]]; return [mySchema elementWithName:[_qName valueFromQName]]; } + (XmlSchemaType *)typeWithQName:(NSString *)_qName { XmlSchema *mySchema; XmlSchemaType *type; mySchema = [XmlSchema schemaForNamespace:[_qName uriFromQName]]; type = [mySchema typeWithName:[_qName valueFromQName]]; return type; } + (BOOL)isXmlSchemaNamespace:(NSString *)_namespace { return isXmlSchemaNamespace(_namespace); } - (void)registerSchemaForNamespace:(NSString *)_namespace { if (_namespace == nil) return; if ([namespace2schema objectForKey:_namespace] != nil) { NSLog(@"can not register schema for uri '%@'(schema already exists!)", _namespace); return; } [namespace2schema setObject:self forKey:_namespace]; } - (void)registerSchema { [self registerSchemaForNamespace:[self targetNamespace]]; } - (id)initWithContentsOfFile:(NSString *)_file prepare:(BOOL)_prepare { RELEASE(self); self = [XmlSchemaSaxBuilder parseSchemaFromContentsOfFile:_file]; [self setSchemaLocation:_file]; [self _prepareTags:self->includes withSchema:self]; [self _prepareTags:self->imports withSchema:self]; if (_prepare) [self prepareSchema]; RETAIN(self); return self; } - (id)initWithContentsOfFile:(NSString *)_file { return [self initWithContentsOfFile:_file prepare:YES]; } - (id)init { return [self initWithContentsOfFile:nil]; } #if !LIB_FOUNDATION_BOEHM_GC - (void)dealloc { /* attributes */ RELEASE(self->targetNamespace); RELEASE(self->attributes); RELEASE(self->elements); RELEASE(self->groups); RELEASE(self->attributeGroups); RELEASE(self->types); RELEASE(self->includes); RELEASE(self->imports); RELEASE(self->blockDefault); RELEASE(self->finalDefault); RELEASE(self->idValue); RELEASE(self->version); RELEASE(self->elementFormDefault); RELEASE(self->attributeFormDefault); // RELEASE(self->schemaLocation); [super dealloc]; } #endif /* attributes */ - (NSString *)targetNamespace { return self->targetNamespace; } - (NSString *)blockDefault { return self->blockDefault; } - (NSString *)finalDefault { return self->finalDefault; } - (NSString *)id { return self->idValue; } - (NSString *)version { return self->version; } - (NSString *)elementFormDefault { return self->elementFormDefault; } - (NSString *)attributeFormDefault { return self->attributeFormDefault; } /* elements */ - (NSArray *)elementNames { return [self->elements allKeys]; } - (XmlSchemaElement *)elementWithName:(NSString *)_key { id result; result = [self->elements objectForKey:_key]; if (result == nil) { NSLog(@"Warning: schema '%@' has no element '%@'", self->targetNamespace, _key); } return result; } /* attribute */ - (NSArray *)attributeNames { return [self->attributes allKeys]; } - (XmlSchemaAttribute *)attributeWithName:(NSString *)_key { return [self->attributes objectForKey:_key]; } /* groups */ - (NSArray *)groupNames { return [self->groups allKeys]; } - (XmlSchemaGroup *)groupWithName:(NSString *)_key { return [self->groups objectForKey:_key]; } /* attribute groups */ - (NSArray *)attributeGroupNames { return [self->attributeGroups allKeys]; } - (XmlSchemaAttributeGroup *)attributeGroupWithName:(NSString *)_key { return [self->attributeGroups objectForKey:_key]; } /* types */ - (NSArray *)typeNames { return [self->types allKeys]; } - (XmlSchemaType *)typeWithName:(NSString *)_key { id result; result = [self->types objectForKey:_key]; if (result == nil) { NSLog(@"Warning: schema '%@' has no type '%@'", self->targetNamespace, _key); } return result; } /***************************************************************/ - (NSString *)description { NSEnumerator *tagEnum; NSMutableString *str = [NSMutableString stringWithCapacity:128]; id tag; [str appendString:@"\ntargetNamespace) { [str appendString:@" targetNamespace=\""]; [str appendString:self->targetNamespace]; [str appendString:@"\""]; } if (self->blockDefault) { [str appendString:@" blockDefault=\""]; [str appendString:self->blockDefault]; [str appendString:@"\""]; } if (self->finalDefault) { [str appendString:@" finalDefault=\""]; [str appendString:self->finalDefault]; [str appendString:@"\""]; } if (self->idValue) { [str appendString:@" id=\""]; [str appendString:self->idValue]; [str appendString:@"\""]; } if (self->version) { [str appendString:@" version=\""]; [str appendString:self->version]; [str appendString:@"\""]; } if (self->elementFormDefault) { [str appendString:@" elementFormDefault=\""]; [str appendString:self->elementFormDefault]; [str appendString:@"\""]; } if (self->attributeFormDefault) { [str appendString:@" attributeFormDefault=\""]; [str appendString:self->attributeFormDefault]; [str appendString:@"\""]; } [str appendString:@">\n"]; tagEnum = [self->elements objectEnumerator]; while ((tag = [tagEnum nextObject])) { [str appendString:@" "]; [str appendString:[tag description]]; [str appendString:@"\n"]; } tagEnum = [self->attributes objectEnumerator]; while ((tag = [tagEnum nextObject])) { [str appendString:@" "]; [str appendString:[tag description]]; [str appendString:@"\n"]; } [str appendString:@""]; return str; } @end /* XmlSchema */ @implementation XmlSchema(XmlSchemaSaxBuilder) static NSSet *Valid_schema_ContentTags = nil; + (void)initialize { if (Valid_schema_ContentTags == nil) { Valid_schema_ContentTags = [[NSSet alloc] initWithObjects: @"include", @"import", //@"redefine", @"simpleType", @"complexType", @"group", @"attributeGroup", @"element", @"attribute", //@"notation", nil]; } if (namespace2schema == nil) [XmlSchema loadSchemaResources]; } /* designated initialzer */ - (id)initWithAttributes:(id)_attrs namespace:(NSString *)_namespace namespaces:(NSDictionary *)_ns { if ((self = [super initWithAttributes:_attrs namespace:_namespace namespaces:_ns])) { NSZone *z; z = [self zone]; self->attributes = [[NSMutableDictionary alloc] initWithCapacity:32]; self->elements = [[NSMutableDictionary alloc] initWithCapacity:32]; self->groups = [[NSMutableDictionary alloc] initWithCapacity:32]; self->attributeGroups = [[NSMutableDictionary alloc] initWithCapacity:32]; self->types = [[NSMutableDictionary alloc] initWithCapacity:32]; self->includes = [[NSMutableArray alloc] initWithCapacity:4]; self->imports = [[NSMutableArray alloc] initWithCapacity:4]; self->targetNamespace =[[_attrs valueForRawName:@"targetNamespace"] copy]; self->blockDefault =[[_attrs valueForRawName:@"blockDefault"] copy]; self->finalDefault =[[_attrs valueForRawName:@"finalDefault"] copy]; self->version =[[_attrs valueForRawName:@"version"] copy]; self->idValue =[[_attrs valueForRawName:@"id"] copy]; self->elementFormDefault = [[_attrs valueForRawName:@"elementFormDefault"] copy]; self->attributeFormDefault = [[_attrs valueForRawName:@"attributeFormDefault"] copy]; if (![self->attributeFormDefault isEqualToString:@"qualified"]) ASSIGN(self->attributeFormDefault, @"unqualified"); if (![self->elementFormDefault isEqualToString:@"qualified"]) ASSIGN(self->elementFormDefault, @"unqualified"); if (self->targetNamespace == nil) { ASSIGN(self->targetNamespace, @""); } } return self; } - (void)prepareSchema { [self _prepareTags:self->types withSchema:self]; [self _prepareTags:self->attributes withSchema:self]; [self _prepareTags:self->attributeGroups withSchema:self]; [self _prepareTags:self->groups withSchema:self]; [self _prepareTags:self->elements withSchema:self]; } - (void)prepareWithSchema:(XmlSchema *)_schema { // do nothing } - (NSString *)tagName { return @"schema"; } - (BOOL)isTagNameAccepted:(NSString *)_tagName { if ([super isTagNameAccepted:_tagName]) return YES; else return [Valid_schema_ContentTags containsObject:_tagName]; } - (BOOL)addTag:(XmlSchemaTag *)_tag { NSString *tagName; tagName = [_tag tagName]; if ([tagName isEqualToString:@"element"]) { return [self _insertTag:(XmlSchemaType *)_tag intoDict:self->elements]; } else if ([tagName isEqualToString:@"group"]) { return [self _insertTag:(XmlSchemaType *)_tag intoDict:self->groups]; } else if ([tagName isEqualToString:@"attribute"]) { return [self _insertTag:(XmlSchemaType *)_tag intoDict:self->attributes]; } else if ([tagName isEqualToString:@"attributeGroup"]) { return [self _insertTag:(XmlSchemaType *)_tag intoDict:self->attributeGroups]; } else if ([tagName isEqualToString:@"complexType"]) { return [self _insertTag:(XmlSchemaType *)_tag intoDict:self->types]; } else if ([tagName isEqualToString:@"simpleType"]) { return [self _insertTag:(XmlSchemaType *)_tag intoDict:self->types]; } else if ([tagName isEqualToString:@"include"]) { [self->includes addObject:_tag]; return YES; } else if ([tagName isEqualToString:@"import"]) { [self->imports addObject:_tag]; return YES; } else return [super addTag:_tag]; } @end /* XmlSchema(XmlSchemaSaxBuilder) */ @implementation XmlSchema(AdditionalApi) - (void)setSchemaLocation:(NSString *)_schemaLocation { ASSIGNCOPY(self->schemaLocation, _schemaLocation); } - (NSString *)schemaLocation { return self->schemaLocation; } @end @implementation XmlSchema(Resources) #if !COMPILE_AS_FRAMEWORK + (NSString *)schemesPath { NSString *apath; NSFileManager *fm = [NSFileManager defaultManager]; NSDictionary *env; NSString *relPath; env = [[NSProcessInfo processInfo] environment]; relPath = @"Libraries"; relPath = [relPath stringByAppendingPathComponent:@"Resources"]; relPath = [relPath stringByAppendingPathComponent:@"XmlSchema"]; relPath = [relPath stringByAppendingPathComponent:@"schemes"]; apath = [env objectForKey:@"GNUSTEP_USER_ROOT"]; apath = [apath stringByAppendingPathComponent:relPath]; if (![fm fileExistsAtPath:apath]) { apath = [env objectForKey:@"GNUSTEP_LOCAL_ROOT"]; apath = [apath stringByAppendingPathComponent:relPath]; } if (![fm fileExistsAtPath:apath]) { apath = [env objectForKey:@"GNUSTEP_SYSTEM_ROOT"]; apath = [apath stringByAppendingPathComponent:relPath]; } if (![fm fileExistsAtPath:apath]) { apath = relPath; } if (![fm fileExistsAtPath:apath]) { NSLog(@"ERROR: cannot find path for schema resources " @"of XmlSchema library !"); } return apath; } #endif + (void)loadSchemaResources { NSDictionary *tmp = nil; NSMutableDictionary *dict = nil; NSEnumerator *nsEnum = nil; NSString *ns = nil; NSString *path = nil; NSString *file = nil; ASSIGN(namespace2schema, (id)nil); ASSIGN(namespace2file, (id)nil); namespace2schema = [[NSMutableDictionary alloc] initWithCapacity:32]; #if COMPILE_AS_FRAMEWORK path = nil; file = [[NSBundle bundleForClass:self] pathForResource:@"namespaces" ofType:@"plist"]; #else path = [XmlSchema schemesPath]; file = [path stringByAppendingPathComponent:@"namespaces.plist"]; #endif tmp = [[NSDictionary alloc] initWithContentsOfFile:file]; nsEnum = [tmp keyEnumerator]; dict = [NSMutableDictionary dictionaryWithCapacity:64]; while ((ns = [nsEnum nextObject])) { file = [path stringByAppendingPathComponent:[tmp objectForKey:ns]]; [dict setObject:file forKey:ns]; } namespace2file = [[NSDictionary alloc] initWithDictionary:dict]; } @end /* XmlSchema(Resources) */