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 [ma addObject:[@"/usr/local/" stringByAppendingString:p]];
112 [ma addObject:[@"/usr/" stringByAppendingString:p]];
114 searchPathes = [ma copy];
116 if ([searchPathes count] == 0)
117 NSLog(@"%s: no search pathes were found!", __PRETTY_FUNCTION__);
122 + (id)modelWithName:(NSString *)_name {
123 NSFileManager *fileManager;
124 NSEnumerator *pathes;
127 /* first look in main bundle */
129 if ((path = [[NSBundle mainBundle] pathForResource:_name ofType:@"xmap"]))
130 return [self modelWithContentsOfFile:path];
132 /* then in Library */
134 fileManager = [NSFileManager defaultManager];
135 pathes = [[[self class] saxMappingSearchPathes] objectEnumerator];
136 _name = [_name stringByAppendingPathExtension:@"xmap"];
138 while ((path = [pathes nextObject])) {
141 path = [path stringByAppendingPathComponent:_name];
143 if (![fileManager fileExistsAtPath:path isDirectory:&isDir])
151 return [self modelWithContentsOfFile:path];
154 + (id)modelWithContentsOfFile:(NSString *)_path {
157 if ((dict = [NSDictionary dictionaryWithContentsOfFile:_path]) == nil)
160 return [[[self alloc] initWithDictionary:dict] autorelease];
163 - (id)initWithDictionary:(NSDictionary *)_dict {
165 [mapDictsToObjects(_dict, [SaxNamespaceModel class]) retain];
170 [self->nsToModel release];
176 - (SaxTagModel *)modelForTag:(NSString *)_localName namespace:(NSString *)_ns {
177 SaxNamespaceModel *nsmap;
179 if ((nsmap = [self->nsToModel objectForKey:_ns]) == nil) {
180 if ((nsmap = [self->nsToModel objectForKey:@"*"]) == nil)
183 return [nsmap modelForTag:_localName];
186 /* faking dictionary */
188 - (id)objectForKey:(id)_key {
189 return [self->nsToModel objectForKey:_key];
192 @end /* SaxMappingModel */
194 @implementation SaxNamespaceModel
196 - (id)initWithDictionary:(NSDictionary *)_dict {
197 self->tagToModel = [mapDictsToObjects(_dict, [SaxTagModel class]) retain];
202 [self->tagToModel release];
208 - (SaxTagModel *)modelForTag:(NSString *)_localName {
211 if ((map = [self->tagToModel objectForKey:_localName]))
213 if ((map = [self->tagToModel objectForKey:@"*"]))
218 /* faking dictionary */
220 - (id)objectForKey:(id)_key {
221 return [self->tagToModel objectForKey:_key];
224 @end /* SaxNamespaceModel */
226 @implementation SaxTagModel
228 - (NSDictionary *)_extractAttributeMapping:(NSDictionary *)as {
229 NSMutableDictionary *md;
232 NSDictionary *result;
234 md = [[NSMutableDictionary alloc] initWithCapacity:16];
236 keys = [as keyEnumerator];
237 while ((k = [keys nextObject])) {
240 val = [as objectForKey:k];
242 if ([val isKindOfClass:[NSString class]])
243 [md setObject:val forKey:k];
244 else if ([val count] == 0)
245 [md setObject:k forKey:k];
247 [md setObject:[(NSDictionary *)val objectForKey:@"key"] forKey:k];
255 - (id)initWithDictionary:(NSDictionary *)_dict {
256 if ((self = [super init])) {
260 self->className = [[_dict objectForKey:@"class"] copy];
261 self->key = [[_dict objectForKey:@"key"] copy];
262 self->tagKey = [[_dict objectForKey:@"tagKey"] copy];
263 self->namespaceKey = [[_dict objectForKey:@"namespaceKey"] copy];
264 self->parentKey = [[_dict objectForKey:@"parentKey"] copy];
265 self->contentKey = [[_dict objectForKey:@"contentKey"] copy];
266 self->defaultValues = [[_dict objectForKey:@"defaultValues"] copy];
268 if ((as = [_dict objectForKey:@"attributes"]))
269 self->attrToKey = [self _extractAttributeMapping:as];
271 if ((rels = [_dict objectForKey:@"ToManyRelationships"])) {
272 NSMutableDictionary *md;
276 self->toManyRelationshipKeys = [[rels allKeys] copy];
278 md = [[NSMutableDictionary alloc] initWithCapacity:16];
280 keys = [self->toManyRelationshipKeys objectEnumerator];
281 while ((k = [keys nextObject])) {
285 tags = [rels objectForKey:k];
286 if ([tags isKindOfClass:[NSString class]])
287 tags = [NSArray arrayWithObject:tags];
288 tags = [tags objectEnumerator];
290 while ((tag = [tags nextObject])) {
293 if ((t = [md objectForKey:tag])) {
294 NSLog(@"SaxObjectModel: cannot map tag '%@' to key '%@', "
295 @"it is already mapped to key '%@'.",
299 [md setObject:k forKey:tag];
303 self->tagToKey = [md copy];
312 [self->defaultValues release];
313 [self->toManyRelationshipKeys release];
314 [self->tagToKey release];
315 [self->className release];
316 [self->tagKey release];
317 [self->namespaceKey release];
318 [self->parentKey release];
319 [self->contentKey release];
321 [self->attrToKey release];
327 - (NSString *)className {
328 return self->className;
333 - (NSString *)tagKey {
336 - (NSString *)namespaceKey {
337 return self->namespaceKey;
339 - (NSString *)parentKey {
340 return self->parentKey;
342 - (NSString *)contentKey {
343 return self->contentKey;
346 - (NSDictionary *)defaultValues {
347 return self->defaultValues;
350 - (BOOL)isToManyKey:(NSString *)_key {
351 return [self->toManyRelationshipKeys containsObject:_key];
353 - (NSArray *)toManyRelationshipKeys {
354 return self->toManyRelationshipKeys;
357 - (BOOL)isToManyTag:(NSString *)_tag {
358 return ([self->tagToKey objectForKey:_tag] != nil) ? YES : NO;
361 - (NSString *)propertyKeyForChildTag:(NSString *)_tag {
362 return [self->tagToKey objectForKey:_tag];
365 - (NSArray *)attributeKeys {
366 return [self->attrToKey allKeys];
368 - (NSString *)propertyKeyForAttribute:(NSString *)_attr {
369 return [self->attrToKey objectForKey:_attr];
372 /* object operations */
374 - (void)addValue:(id)_value toPropertyWithKey:(NSString *)_key
380 selname = [[NSString alloc] initWithFormat:@"addTo%@:",
381 [_key capitalizedString]];
382 if ((sel = NSSelectorFromString(selname)) == NULL) {
384 NSLog(@"got no selector for key '%@', selname '%@' !",
388 [selname release]; selname = nil;
391 NSLog(@"%s: adding value %@ to %@ of %@", __PRETTY_FUNCTION__,
392 _value, _key, _object);
393 NSLog(@" selector: %@", NSStringFromSelector(sel));
396 if ((sel != NULL) && [_object respondsToSelector:sel]) {
397 [_object performSelector:sel withObject:_value];
402 v = [_object valueForKey:_key];
404 if ([self isToManyKey:_key]) {
405 /* to-many relationship */
408 [_object takeValue:[NSArray arrayWithObject:_value] forKey:_key];
411 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
412 APPLE_FOUNDATION_LIBRARY
413 if ([v isKindOfClass:NSCFArrayClass] &&
414 _CFArrayIsMutable((CFArrayRef)v))
416 if ([v respondsToSelector:@selector(addObject:)])
418 /* the value is mutable */
419 [v addObject:_value];
421 /* the value is immutable */
422 v = [v arrayByAddingObject:_value];
423 [_object takeValue:v forKey:_key];
428 NSLog(@" APPLIED ON TO-ONE (%@) !", _key);
429 /* to-one relationship */
431 [_object takeValue:v forKey:_key];
436 @end /* SaxTagModel */