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 if (null == nil) null = [[NSNull null] retain];
70 - (id)initWithMappingModel:(SaxObjectModel *)_model {
71 if ((self = [super init])) {
72 self->mapping = [_model retain];
77 - (id)initWithMappingAtPath:(NSString *)_path {
78 SaxObjectModel *model;
80 model = [SaxObjectModel modelWithContentsOfFile:_path];
81 return [self initWithMappingModel:model];
83 - (id)initWithMappingNamed:(NSString *)_name {
84 SaxObjectModel *model;
86 model = [SaxObjectModel modelWithName:_name];
87 return [self initWithMappingModel:model];
91 return [self initWithMappingModel:nil];
95 [self->locator release];
96 [self->rootObject release];
97 [self->mapping release];
99 [self->infoStack release];
100 [self->mappingStack release];
101 [self->objectStack release];
108 return self->rootObject;
114 NSAutoreleasePool *pool;
116 pool = [[NSAutoreleasePool alloc] init];
117 [self->infoStack removeAllObjects];
118 [self->mappingStack removeAllObjects];
119 [self->objectStack removeAllObjects];
125 [self->rootObject release];
126 self->rootObject = nil;
131 - (void)startDocument {
134 if (self->infoStack == nil)
135 self->infoStack = [[NSMutableArray alloc] initWithCapacity:16];
138 - (void)endDocument {
142 /* positioning info */
144 - (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
145 ASSIGN(self->locator, _locator);
150 - (void)pushInfo:(_SaxObjTagInfo *)_info {
151 [self->infoStack addObject:_info];
154 [self->infoStack removeObjectAtIndex:([self->infoStack count] - 1)];
157 return [self->infoStack lastObject];
162 - (NSException *)missingNamespaceMapping:(NSString *)_ns {
163 return [NSException exceptionWithName:@"MissingNamespaceMapping"
167 - (NSException *)missingElementMapping:(NSString *)_ns:(NSString *)_tag {
168 return [NSException exceptionWithName:@"MissingElementMapping"
172 - (NSException *)missingMappedClass:(NSString *)_className {
173 return [NSException exceptionWithName:@"MissingMappedClass"
178 - (SaxTagModel *)mappingForTag:(NSString *)_tag namespace:(NSString *)_ns {
179 return [self->mapping modelForTag:_tag namespace:_ns];
182 - (void)couldNotApplyAttribute:(NSString *)_attr asKey:(NSString *)_key
185 NSLog(@"SaxObjectDecoder: could not apply attribute '%@' (key=%@) "
187 _attr, _key, _object);
190 - (void)startElement:(NSString *)_localName
191 namespace:(NSString *)_ns
192 rawName:(NSString *)_rawName
193 attributes:(id<SaxAttributes>)_attributes
195 _SaxObjTagInfo *info;
197 info = [_SaxObjTagInfo alloc];
198 info->decoder = self;
199 info->flags.isRoot = [self->infoStack count] == 0 ? 1 : 0;
200 info->parentInfo = info->flags.isRoot ? nil : [self->infoStack lastObject];
201 info->tagName = [_localName copy];
202 info->namespace = [_ns copy];
204 [self->infoStack addObject:info];
207 /* determine mapping dictionary */
209 if ((info->mapping = [self mappingForTag:_localName namespace:_ns]) == nil) {
211 NSLog(@"found no mapping for element '%@' (namespace %@)",
214 info->error = [[self missingElementMapping:_ns:_localName] retain];
221 /* add attribute values */
226 e = [[info->mapping attributeKeys] objectEnumerator];
227 while ((a = [e nextObject])) {
230 if ((v = [_attributes valueForName:a uri:_ns])) {
231 key = [info->mapping propertyKeyForAttribute:a];
234 [info->object takeValue:v forKey:key];
236 [self couldNotApplyAttribute:a asKey:key onObject:info->object];
242 - (void)endElement:(NSString *)_localName
243 namespace:(NSString *)_ns
244 rawName:(NSString *)_rawName
246 _SaxObjTagInfo *info;
249 idx = [self->infoStack count] - 1;
250 info = [self->infoStack objectAtIndex:idx];
254 ASSIGN(self->rootObject, [info object]);
256 [self->infoStack removeObjectAtIndex:idx];
261 - (void)characters:(unichar *)_chars length:(int)_len {
262 _SaxObjTagInfo *info;
264 if (_len == 0) return;
265 info = [self->infoStack objectAtIndex:([self->infoStack count] - 1)];
266 [info characters:_chars length:_len];
269 - (BOOL)processIgnorableWhitespace {
273 - (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
274 if ([self processIgnorableWhitespace])
275 [self characters:_chars length:_len];
278 @end /* SaxObjectDecoder */
280 @implementation NSObject(SaxObjectCoding)
282 - (id)initWithSaxDecoder:(SaxObjectDecoder *)_decoder {
286 - (id)awakeAfterUsingSaxDecoder:(SaxObjectDecoder *)_decoder {
292 @implementation _SaxObjTagInfo
294 static Class MutableDictClass = Nil;
295 static Class MutableStringClass = Nil;
296 static Class StringClass = Nil;
299 MutableDictClass = [NSMutableDictionary class];
300 MutableStringClass = [NSMutableString class];
301 StringClass = [NSString class];
305 [self->tagName release];
306 [self->namespace release];
307 [self->error release];
308 [self->object release];
309 [self->collectedCharData release];
315 - (NSException *)missingMappedClass:(NSString *)_className {
316 return [NSException exceptionWithName:@"MissingMappedClass"
323 - (SaxTagModel *)mapping {
324 return self->mapping;
327 return (self->object == null) ? nil : self->object;
330 - (SaxTagModel *)parentMapping {
331 return [self->parentInfo mapping];
334 return [self->parentInfo object];
339 - (Class)defaultElementClass {
340 return [NSMutableDictionary class];
343 - (void)unableToSetValue:(id)_object forKey:(NSString *)_key
344 withTag:(NSString *)_tag toParent:(id)_parent
345 exception:(NSException *)_exc
347 NSLog(@"couldn't apply value %@ for key %@ with parent %@<%@>: %@",
348 _object, _key, _parent, NSStringFromClass([_parent class]), _exc);
351 - (void)addObject:(id)_object fromTag:(NSString *)_tag
352 withMapping:(SaxTagModel *)_elementMap
353 toParent:(id)_parent withMapping:(SaxTagModel *)_parentMap
357 if (_object == nil || _object == null) return;
358 if (_parent == nil || _parent == null) return;
359 if (_elementMap == nil || _elementMap == (id)null) return;
360 if (_parentMap == nil || _parentMap == (id)null) return;
362 if ((key = [_parentMap propertyKeyForChildTag:_tag]) == nil) {
363 if ((key = [_elementMap key]) == nil)
368 if ([_parentMap isToManyKey:key]) {
369 [_parentMap addValue:_object toPropertyWithKey:key ofObject:_parent];
372 [_parent takeValue:_object forKey:key];
376 [self unableToSetValue:_object forKey:key withTag:_tag toParent:_parent
377 exception:localException];
386 /* determine class */
388 if ((s = [self->mapping className])) {
389 mappedClazz = NSClassFromString(s);
390 if (mappedClazz == Nil) {
391 self->error = [[self missingMappedClass:s] retain];
396 mappedClazz = [self defaultElementClass];
398 /* do we need to check for subclasses? I guess not. */
399 self->flags.isMutableDict = (mappedClazz == MutableDictClass) ? 1 : 0;
400 self->flags.isMutableString = (mappedClazz == MutableStringClass) ? 1 : 0;
401 self->flags.isString = (mappedClazz == StringClass) ? 1 : 0;
402 self->flags.hasContentKey = [[self->mapping contentKey] length] > 0 ?1:0;
404 /* create an object for the element .. */
406 if ((self->object = [[mappedClazz alloc] initWithSaxDecoder:self->decoder])) {
407 NSDictionary *defaultValues;
410 if ((defaultValues = [self->mapping defaultValues]))
411 [self->object takeValuesFromDictionary:defaultValues];
413 if ((tmp = [self->mapping tagKey]))
414 [self->object takeValue:self->tagName forKey:tmp];
415 if ((tmp = [self->mapping namespaceKey]))
416 [self->object takeValue:self->namespace forKey:tmp];
423 /* awake from decoding (the decoded object can replace itself :-) */
425 if (self->flags.isString) {
428 if (self->flags.hasContentKey) {
431 s = [self->collectedCharData copy];
432 ASSIGN(self->collectedCharData, (id)nil);
434 [self->object takeValue:s forKey:[self->mapping contentKey]];
440 [[self->object awakeAfterUsingSaxDecoder:self->decoder] retain];
443 if (!self->flags.isRoot) {
447 parent = [self parentObject];
451 if ((t = [self->mapping parentKey]))
452 [self->object takeValue:parent forKey:t];
454 [self addObject:self->object
455 fromTag:self->tagName
456 withMapping:self->mapping
458 withMapping:[self parentMapping]];
462 - (void)characters:(unichar *)_chars length:(int)_len {
463 if (self->flags.isMutableString) {
466 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
467 [self->object appendString:tmp];
470 else if (self->flags.isString) {
475 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
476 self->object = [[self->object stringByAppendingString:tmp] retain];
480 else if (self->flags.hasContentKey) {
481 if (self->collectedCharData == nil) {
482 self->collectedCharData =
483 [[NSMutableString alloc] initWithCharacters:_chars length:_len];
488 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
489 [self->collectedCharData appendString:tmp];
495 @end /* _SaxObjTagInfo */