2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with SOPE; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "SaxObjectModel.h"
25 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
26 APPLE_FOUNDATION_LIBRARY
27 bool _CFArrayIsMutable(CFArrayRef dict);
30 static NSDictionary *mapDictsToObjects(NSDictionary *_dict, Class clazz) {
31 NSMutableDictionary *md;
35 md = [NSMutableDictionary dictionaryWithCapacity:16];
37 e = [_dict keyEnumerator];
38 while ((key = [e nextObject])) {
41 obj = [[clazz alloc] initWithDictionary:[_dict objectForKey:key]];
42 [md setObject:obj forKey:key];
48 @implementation SaxObjectModel
50 static BOOL doDebug = NO;
51 static NSArray *searchPathes = nil;
53 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
54 APPLE_FOUNDATION_LIBRARY
55 static Class NSCFArrayClass = Nil;
58 static BOOL isInitialized = NO;
60 if (isInitialized) return;
62 NSCFArrayClass = NSClassFromString(@"NSCFArray");
66 + (NSArray *)saxMappingSearchPathes {
67 if (searchPathes == nil) {
72 env = [[NSProcessInfo processInfo] environment];
73 ma = [NSMutableArray arrayWithCapacity:6];
75 #if COCOA_Foundation_LIBRARY
76 tmp = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory,
79 if ([tmp count] > 0) {
82 e = [tmp objectEnumerator];
83 while ((tmp = [e nextObject])) {
84 tmp = [tmp stringByAppendingPathComponent:@"SaxMappings"];
85 if (![ma containsObject:tmp])
90 if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
91 tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
92 tmp = [tmp componentsSeparatedByString:@":"];
93 if ([tmp count] > 0) {
96 e = [tmp objectEnumerator];
97 while ((tmp = [e nextObject])) {
98 tmp = [tmp stringByAppendingPathComponent:@"Library/SaxMappings"];
99 if (![ma containsObject:tmp])
109 p = [NSString stringWithFormat:@"share/sope-%i.%i/saxmappings/",
110 SOPE_MAJOR_VERSION, SOPE_MINOR_VERSION];
111 #ifdef FHS_INSTALL_ROOT
112 [ma addObject:[FHS_INSTALL_ROOT stringByAppendingPathComponent:p]];
114 [ma addObject:[@"/usr/local/" stringByAppendingString:p]];
115 [ma addObject:[@"/usr/" stringByAppendingString:p]];
117 searchPathes = [ma copy];
119 if ([searchPathes count] == 0)
120 NSLog(@"%s: no search pathes were found!", __PRETTY_FUNCTION__);
125 + (id)modelWithName:(NSString *)_name {
126 NSFileManager *fileManager;
127 NSEnumerator *pathes;
130 /* first look in main bundle */
132 if ((path = [[NSBundle mainBundle] pathForResource:_name ofType:@"xmap"]))
133 return [self modelWithContentsOfFile:path];
135 /* then in Library */
137 fileManager = [NSFileManager defaultManager];
138 pathes = [[[self class] saxMappingSearchPathes] objectEnumerator];
139 _name = [_name stringByAppendingPathExtension:@"xmap"];
141 while ((path = [pathes nextObject])) {
144 path = [path stringByAppendingPathComponent:_name];
146 if (![fileManager fileExistsAtPath:path isDirectory:&isDir])
154 return [self modelWithContentsOfFile:path];
157 + (id)modelWithContentsOfFile:(NSString *)_path {
160 if ((dict = [NSDictionary dictionaryWithContentsOfFile:_path]) == nil)
163 return [[[self alloc] initWithDictionary:dict] autorelease];
166 - (id)initWithDictionary:(NSDictionary *)_dict {
168 [mapDictsToObjects(_dict, [SaxNamespaceModel class]) retain];
173 [self->nsToModel release];
179 - (SaxTagModel *)modelForTag:(NSString *)_localName namespace:(NSString *)_ns {
180 SaxNamespaceModel *nsmap;
182 if ((nsmap = [self->nsToModel objectForKey:_ns]) == nil) {
183 if ((nsmap = [self->nsToModel objectForKey:@"*"]) == nil)
186 return [nsmap modelForTag:_localName];
189 /* faking dictionary */
191 - (id)objectForKey:(id)_key {
192 return [self->nsToModel objectForKey:_key];
195 @end /* SaxMappingModel */
197 @implementation SaxNamespaceModel
199 - (id)initWithDictionary:(NSDictionary *)_dict {
200 self->tagToModel = [mapDictsToObjects(_dict, [SaxTagModel class]) retain];
205 [self->tagToModel release];
211 - (SaxTagModel *)modelForTag:(NSString *)_localName {
214 if ((map = [self->tagToModel objectForKey:_localName]))
216 if ((map = [self->tagToModel objectForKey:@"*"]))
221 /* faking dictionary */
223 - (id)objectForKey:(id)_key {
224 return [self->tagToModel objectForKey:_key];
227 @end /* SaxNamespaceModel */
229 @implementation SaxTagModel
231 - (NSDictionary *)_extractAttributeMapping:(NSDictionary *)as {
232 NSMutableDictionary *md;
235 NSDictionary *result;
237 md = [[NSMutableDictionary alloc] initWithCapacity:16];
239 keys = [as keyEnumerator];
240 while ((k = [keys nextObject])) {
243 val = [as objectForKey:k];
245 if ([val isKindOfClass:[NSString class]])
246 [md setObject:val forKey:k];
247 else if ([val count] == 0)
248 [md setObject:k forKey:k];
250 [md setObject:[(NSDictionary *)val objectForKey:@"key"] forKey:k];
258 - (id)initWithDictionary:(NSDictionary *)_dict {
259 if ((self = [super init])) {
263 self->className = [[_dict objectForKey:@"class"] copy];
264 self->key = [[_dict objectForKey:@"key"] copy];
265 self->tagKey = [[_dict objectForKey:@"tagKey"] copy];
266 self->namespaceKey = [[_dict objectForKey:@"namespaceKey"] copy];
267 self->parentKey = [[_dict objectForKey:@"parentKey"] copy];
268 self->contentKey = [[_dict objectForKey:@"contentKey"] copy];
269 self->defaultValues = [[_dict objectForKey:@"defaultValues"] copy];
271 if ((as = [_dict objectForKey:@"attributes"]))
272 self->attrToKey = [self _extractAttributeMapping:as];
274 if ((rels = [_dict objectForKey:@"ToManyRelationships"])) {
275 NSMutableDictionary *md;
279 self->toManyRelationshipKeys = [[rels allKeys] copy];
281 md = [[NSMutableDictionary alloc] initWithCapacity:16];
283 keys = [self->toManyRelationshipKeys objectEnumerator];
284 while ((k = [keys nextObject])) {
288 tags = [rels objectForKey:k];
289 if ([tags isKindOfClass:[NSString class]])
290 tags = [NSArray arrayWithObject:tags];
291 tags = [tags objectEnumerator];
293 while ((tag = [tags nextObject])) {
296 if ((t = [md objectForKey:tag])) {
297 NSLog(@"SaxObjectModel: cannot map tag '%@' to key '%@', "
298 @"it is already mapped to key '%@'.",
302 [md setObject:k forKey:tag];
306 self->tagToKey = [md copy];
315 [self->defaultValues release];
316 [self->toManyRelationshipKeys release];
317 [self->tagToKey release];
318 [self->className release];
319 [self->tagKey release];
320 [self->namespaceKey release];
321 [self->parentKey release];
322 [self->contentKey release];
324 [self->attrToKey release];
330 - (NSString *)className {
331 return self->className;
336 - (NSString *)tagKey {
339 - (NSString *)namespaceKey {
340 return self->namespaceKey;
342 - (NSString *)parentKey {
343 return self->parentKey;
345 - (NSString *)contentKey {
346 return self->contentKey;
349 - (NSDictionary *)defaultValues {
350 return self->defaultValues;
353 - (BOOL)isToManyKey:(NSString *)_key {
354 return [self->toManyRelationshipKeys containsObject:_key];
356 - (NSArray *)toManyRelationshipKeys {
357 return self->toManyRelationshipKeys;
360 - (BOOL)isToManyTag:(NSString *)_tag {
361 return ([self->tagToKey objectForKey:_tag] != nil) ? YES : NO;
364 - (NSString *)propertyKeyForChildTag:(NSString *)_tag {
365 return [self->tagToKey objectForKey:_tag];
368 - (NSArray *)attributeKeys {
369 return [self->attrToKey allKeys];
371 - (NSString *)propertyKeyForAttribute:(NSString *)_attr {
372 return [self->attrToKey objectForKey:_attr];
375 /* object operations */
377 - (void)addValue:(id)_value toPropertyWithKey:(NSString *)_key
383 selname = [[NSString alloc] initWithFormat:@"addTo%@:",
384 [_key capitalizedString]];
385 if ((sel = NSSelectorFromString(selname)) == NULL) {
387 NSLog(@"got no selector for key '%@', selname '%@' !",
391 [selname release]; selname = nil;
394 NSLog(@"%s: adding value %@ to %@ of %@", __PRETTY_FUNCTION__,
395 _value, _key, _object);
396 NSLog(@" selector: %@", NSStringFromSelector(sel));
399 if ((sel != NULL) && [_object respondsToSelector:sel]) {
400 [_object performSelector:sel withObject:_value];
405 v = [_object valueForKey:_key];
407 if ([self isToManyKey:_key]) {
408 /* to-many relationship */
411 [_object takeValue:[NSArray arrayWithObject:_value] forKey:_key];
414 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
415 APPLE_FOUNDATION_LIBRARY
416 if ([v isKindOfClass:NSCFArrayClass] &&
417 _CFArrayIsMutable((CFArrayRef)v))
419 if ([v respondsToSelector:@selector(addObject:)])
421 /* the value is mutable */
422 [v addObject:_value];
424 /* the value is immutable */
425 v = [v arrayByAddingObject:_value];
426 [_object takeValue:v forKey:_key];
431 NSLog(@" APPLIED ON TO-ONE (%@) !", _key);
432 /* to-one relationship */
434 [_object takeValue:v forKey:_key];
439 @end /* SaxTagModel */