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 "SaxObjectDecoder.h"
23 #include "SaxObjectModel.h"
26 static BOOL debugOn = NO;
28 @interface _SaxObjTagInfo : NSObject
31 SaxObjectDecoder *decoder; /* non-retained */
32 _SaxObjTagInfo *parentInfo; /* non-retained */
42 int isMutableString:1;
45 NSMutableString *collectedCharData;
50 - (SaxTagModel *)mapping;
58 - (void)characters:(unichar *)_chars length:(int)_len;
62 @implementation SaxObjectDecoder
64 static NSNull *null = nil;
67 static BOOL didInit = NO;
73 null = [[NSNull null] retain];
74 ud = [NSUserDefaults standardUserDefaults];
75 debugOn = [ud boolForKey:@"SaxObjectDecoderDebugEnabled"];
78 - (id)initWithMappingModel:(SaxObjectModel *)_model {
79 if ((self = [super init])) {
80 self->mapping = [_model retain];
85 - (id)initWithMappingAtPath:(NSString *)_path {
86 SaxObjectModel *model;
88 model = [SaxObjectModel modelWithContentsOfFile:_path];
89 return [self initWithMappingModel:model];
91 - (id)initWithMappingNamed:(NSString *)_name {
92 SaxObjectModel *model;
94 model = [SaxObjectModel modelWithName:_name];
95 return [self initWithMappingModel:model];
99 return [self initWithMappingModel:nil];
103 [self->locator release];
104 [self->rootObject release];
105 [self->mapping release];
107 [self->infoStack release];
108 [self->mappingStack release];
109 [self->objectStack release];
116 return self->rootObject;
122 NSAutoreleasePool *pool;
124 pool = [[NSAutoreleasePool alloc] init];
125 [self->infoStack removeAllObjects];
126 [self->mappingStack removeAllObjects];
127 [self->objectStack removeAllObjects];
133 [self->rootObject release];
134 self->rootObject = nil;
139 - (void)startDocument {
142 if (self->infoStack == nil)
143 self->infoStack = [[NSMutableArray alloc] initWithCapacity:16];
146 - (void)endDocument {
150 /* positioning info */
152 - (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
153 ASSIGN(self->locator, _locator);
158 - (void)pushInfo:(_SaxObjTagInfo *)_info {
159 [self->infoStack addObject:_info];
162 [self->infoStack removeObjectAtIndex:([self->infoStack count] - 1)];
165 return [self->infoStack lastObject];
170 - (NSException *)missingNamespaceMapping:(NSString *)_ns {
171 return [NSException exceptionWithName:@"MissingNamespaceMapping"
175 - (NSException *)missingElementMapping:(NSString *)_ns:(NSString *)_tag {
176 return [NSException exceptionWithName:@"MissingElementMapping"
180 - (NSException *)missingMappedClass:(NSString *)_className {
181 return [NSException exceptionWithName:@"MissingMappedClass"
186 - (SaxTagModel *)mappingForTag:(NSString *)_tag namespace:(NSString *)_ns {
187 return [self->mapping modelForTag:_tag namespace:_ns];
190 - (void)couldNotApplyAttribute:(NSString *)_attr asKey:(NSString *)_key
193 NSLog(@"SaxObjectDecoder: could not apply attribute '%@' (key=%@) "
195 _attr, _key, _object);
198 - (void)startElement:(NSString *)_localName
199 namespace:(NSString *)_ns
200 rawName:(NSString *)_rawName
201 attributes:(id<SaxAttributes>)_attributes
203 _SaxObjTagInfo *info;
205 info = [_SaxObjTagInfo alloc];
206 info->decoder = self;
207 info->flags.isRoot = [self->infoStack count] == 0 ? 1 : 0;
208 info->parentInfo = info->flags.isRoot ? nil : [self->infoStack lastObject];
209 info->tagName = [_localName copy];
210 info->namespace = [_ns copy];
212 [self->infoStack addObject:info];
215 /* determine mapping dictionary */
217 if ((info->mapping = [self mappingForTag:_localName namespace:_ns]) == nil) {
219 NSLog(@"found no mapping for element '%@' (namespace %@)",
222 info->error = [[self missingElementMapping:_ns:_localName] retain];
229 /* add attribute values */
234 e = [[info->mapping attributeKeys] objectEnumerator];
235 while ((a = [e nextObject])) {
238 if ((v = [_attributes valueForName:a uri:_ns])) {
239 key = [info->mapping propertyKeyForAttribute:a];
242 [info->object takeValue:v forKey:key];
244 [self couldNotApplyAttribute:a asKey:key onObject:info->object];
250 - (void)endElement:(NSString *)_localName
251 namespace:(NSString *)_ns
252 rawName:(NSString *)_rawName
254 _SaxObjTagInfo *info;
257 idx = [self->infoStack count] - 1;
258 info = [self->infoStack objectAtIndex:idx];
262 ASSIGN(self->rootObject, [info object]);
264 [self->infoStack removeObjectAtIndex:idx];
269 - (void)characters:(unichar *)_chars length:(int)_len {
270 _SaxObjTagInfo *info;
272 if (_len == 0) return;
273 info = [self->infoStack objectAtIndex:([self->infoStack count] - 1)];
274 [info characters:_chars length:_len];
277 - (BOOL)processIgnorableWhitespace {
281 - (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
282 if ([self processIgnorableWhitespace])
283 [self characters:_chars length:_len];
286 @end /* SaxObjectDecoder */
288 @implementation NSObject(SaxObjectCoding)
290 - (id)initWithSaxDecoder:(SaxObjectDecoder *)_decoder {
294 - (id)awakeAfterUsingSaxDecoder:(SaxObjectDecoder *)_decoder {
300 @implementation _SaxObjTagInfo
302 static Class MutableDictClass = Nil;
303 static Class MutableStringClass = Nil;
304 static Class StringClass = Nil;
307 MutableDictClass = [NSMutableDictionary class];
308 MutableStringClass = [NSMutableString class];
309 StringClass = [NSString class];
313 [self->tagName release];
314 [self->namespace release];
315 [self->error release];
316 [self->object release];
317 [self->collectedCharData release];
323 - (NSException *)missingMappedClass:(NSString *)_className {
324 return [NSException exceptionWithName:@"MissingMappedClass"
331 - (SaxTagModel *)mapping {
332 return self->mapping;
335 return (self->object == null) ? nil : self->object;
338 - (SaxTagModel *)parentMapping {
339 return [self->parentInfo mapping];
342 return [self->parentInfo object];
347 - (Class)defaultElementClass {
348 return [NSMutableDictionary class];
351 - (void)unableToSetValue:(id)_object forKey:(NSString *)_key
352 withTag:(NSString *)_tag toParent:(id)_parent
353 exception:(NSException *)_exc
355 NSLog(@"couldn't apply value %@ for key %@ with parent %@<%@>: %@",
356 _object, _key, _parent, NSStringFromClass([_parent class]), _exc);
359 - (void)addObject:(id)_object fromTag:(NSString *)_tag
360 withMapping:(SaxTagModel *)_elementMap
361 toParent:(id)_parent withMapping:(SaxTagModel *)_parentMap
365 if (_object == nil || _object == null) return;
366 if (_parent == nil || _parent == null) return;
367 if (_elementMap == nil || _elementMap == (id)null) return;
368 if (_parentMap == nil || _parentMap == (id)null) return;
370 if ((key = [_parentMap propertyKeyForChildTag:_tag]) == nil) {
371 if ((key = [_elementMap key]) == nil)
376 if ([_parentMap isToManyKey:key]) {
377 [_parentMap addValue:_object toPropertyWithKey:key ofObject:_parent];
380 [_parent takeValue:_object forKey:key];
384 [self unableToSetValue:_object forKey:key withTag:_tag toParent:_parent
385 exception:localException];
394 /* determine class */
396 if ((s = [self->mapping className])) {
397 mappedClazz = NSClassFromString(s);
398 if (mappedClazz == Nil) {
399 self->error = [[self missingMappedClass:s] retain];
404 mappedClazz = [self defaultElementClass];
406 /* do we need to check for subclasses? I guess not. */
407 self->flags.isMutableDict = (mappedClazz == MutableDictClass) ? 1 : 0;
408 self->flags.isMutableString = (mappedClazz == MutableStringClass) ? 1 : 0;
409 self->flags.isString = (mappedClazz == StringClass) ? 1 : 0;
410 self->flags.hasContentKey = [[self->mapping contentKey] length] > 0 ?1:0;
412 /* create an object for the element .. */
414 if ((self->object = [[mappedClazz alloc] initWithSaxDecoder:self->decoder])) {
415 NSDictionary *defaultValues;
418 if ((defaultValues = [self->mapping defaultValues]))
419 [self->object takeValuesFromDictionary:defaultValues];
421 if ((tmp = [self->mapping tagKey]))
422 [self->object takeValue:self->tagName forKey:tmp];
423 if ((tmp = [self->mapping namespaceKey]))
424 [self->object takeValue:self->namespace forKey:tmp];
431 /* awake from decoding (the decoded object can replace itself :-) */
433 if (self->flags.isString) {
436 if (self->flags.hasContentKey) {
439 s = [self->collectedCharData copy];
440 ASSIGN(self->collectedCharData, (id)nil);
442 [self->object takeValue:s forKey:[self->mapping contentKey]];
448 [[self->object awakeAfterUsingSaxDecoder:self->decoder] retain];
451 if (!self->flags.isRoot) {
455 parent = [self parentObject];
459 if ((t = [self->mapping parentKey]))
460 [self->object takeValue:parent forKey:t];
462 [self addObject:self->object
463 fromTag:self->tagName
464 withMapping:self->mapping
466 withMapping:[self parentMapping]];
470 - (void)characters:(unichar *)_chars length:(int)_len {
471 if (self->flags.isMutableString) {
474 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
475 [self->object appendString:tmp];
478 else if (self->flags.isString) {
483 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
484 self->object = [[self->object stringByAppendingString:tmp] retain];
488 else if (self->flags.hasContentKey) {
489 if (self->collectedCharData == nil) {
490 self->collectedCharData =
491 [[NSMutableString alloc] initWithCharacters:_chars length:_len];
496 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
497 [self->collectedCharData appendString:tmp];
503 @end /* _SaxObjTagInfo */