2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo 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 OGo 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 OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "SaxObjectDecoder.h"
24 #include "SaxObjectModel.h"
27 static BOOL debugOn = NO;
29 @interface _SaxObjTagInfo : NSObject
32 SaxObjectDecoder *decoder; /* non-retained */
33 _SaxObjTagInfo *parentInfo; /* non-retained */
43 int isMutableString:1;
46 NSMutableString *collectedCharData;
51 - (SaxTagModel *)mapping;
59 - (void)characters:(unichar *)_chars length:(int)_len;
63 @implementation SaxObjectDecoder
65 static NSNull *null = nil;
68 if (null == nil) null = [[NSNull null] retain];
71 - (id)initWithMappingModel:(SaxObjectModel *)_model {
72 if ((self = [super init])) {
73 self->mapping = [_model retain];
78 - (id)initWithMappingAtPath:(NSString *)_path {
79 SaxObjectModel *model;
81 model = [SaxObjectModel modelWithContentsOfFile:_path];
82 return [self initWithMappingModel:model];
84 - (id)initWithMappingNamed:(NSString *)_name {
85 SaxObjectModel *model;
87 model = [SaxObjectModel modelWithName:_name];
88 return [self initWithMappingModel:model];
92 return [self initWithMappingModel:nil];
97 [self->objectStack release];
98 [self->mappingStack release];
99 [self->infoStack release];
100 [self->locator release];
107 return self->rootObject;
113 NSAutoreleasePool *pool;
115 pool = [[NSAutoreleasePool alloc] init];
116 [self->infoStack removeAllObjects];
117 [self->mappingStack removeAllObjects];
118 [self->objectStack removeAllObjects];
124 [self->rootObject release];
125 self->rootObject = nil;
130 - (void)startDocument {
133 if (self->infoStack == nil)
134 self->infoStack = [[NSMutableArray alloc] initWithCapacity:16];
137 - (void)endDocument {
141 /* positioning info */
143 - (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
144 ASSIGN(self->locator, _locator);
149 - (void)pushInfo:(_SaxObjTagInfo *)_info {
150 [self->infoStack addObject:_info];
153 [self->infoStack removeObjectAtIndex:([self->infoStack count] - 1)];
156 return [self->infoStack lastObject];
161 - (NSException *)missingNamespaceMapping:(NSString *)_ns {
162 return [NSException exceptionWithName:@"MissingNamespaceMapping"
166 - (NSException *)missingElementMapping:(NSString *)_ns:(NSString *)_tag {
167 return [NSException exceptionWithName:@"MissingElementMapping"
171 - (NSException *)missingMappedClass:(NSString *)_className {
172 return [NSException exceptionWithName:@"MissingMappedClass"
177 - (SaxTagModel *)mappingForTag:(NSString *)_tag namespace:(NSString *)_ns {
178 return [self->mapping modelForTag:_tag namespace:_ns];
181 - (void)couldNotApplyAttribute:(NSString *)_attr asKey:(NSString *)_key
184 NSLog(@"SaxObjectDecoder: could not apply attribute '%@' (key=%@) "
186 _attr, _key, _object);
189 - (void)startElement:(NSString *)_localName
190 namespace:(NSString *)_ns
191 rawName:(NSString *)_rawName
192 attributes:(id<SaxAttributes>)_attributes
194 _SaxObjTagInfo *info;
196 info = [_SaxObjTagInfo alloc];
197 info->decoder = self;
198 info->flags.isRoot = [self->infoStack count] == 0 ? 1 : 0;
199 info->parentInfo = info->flags.isRoot ? nil : [self->infoStack lastObject];
200 info->tagName = [_localName copy];
201 info->namespace = [_ns copy];
203 [self->infoStack addObject:info];
205 /* determine mapping dictionary */
207 if ((info->mapping = [self mappingForTag:_localName namespace:_ns]) == nil) {
209 NSLog(@"found no mapping for element '%@' (namespace %@)",
212 info->error = [[self missingElementMapping:_ns:_localName] retain];
219 /* add attribute values */
224 e = [[info->mapping attributeKeys] objectEnumerator];
225 while ((a = [e nextObject])) {
228 if ((v = [_attributes valueForName:a uri:_ns])) {
229 key = [info->mapping propertyKeyForAttribute:a];
232 [info->object takeValue:v forKey:key];
234 [self couldNotApplyAttribute:a asKey:key onObject:info->object];
240 - (void)endElement:(NSString *)_localName
241 namespace:(NSString *)_ns
242 rawName:(NSString *)_rawName
244 _SaxObjTagInfo *info;
247 idx = [self->infoStack count] - 1;
248 info = [self->infoStack objectAtIndex:idx];
252 ASSIGN(self->rootObject, [info object]);
254 [self->infoStack removeObjectAtIndex:idx];
259 - (void)characters:(unichar *)_chars length:(int)_len {
260 _SaxObjTagInfo *info;
262 if (_len == 0) return;
263 info = [self->infoStack objectAtIndex:([self->infoStack count] - 1)];
264 [info characters:_chars length:_len];
267 - (BOOL)processIgnorableWhitespace {
271 - (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
272 if ([self processIgnorableWhitespace])
273 [self characters:_chars length:_len];
276 @end /* SaxObjectDecoder */
278 @implementation NSObject(SaxObjectCoding)
280 - (id)initWithSaxDecoder:(SaxObjectDecoder *)_decoder {
284 - (id)awakeAfterUsingSaxDecoder:(SaxObjectDecoder *)_decoder {
290 @implementation _SaxObjTagInfo
292 static Class MutableDictClass = Nil;
293 static Class MutableStringClass = Nil;
294 static Class StringClass = Nil;
297 MutableDictClass = [NSMutableDictionary class];
298 MutableStringClass = [NSMutableString class];
299 StringClass = [NSString class];
303 [self->tagName release];
304 [self->namespace release];
305 [self->error release];
306 [self->object release];
307 [self->collectedCharData release];
313 - (NSException *)missingMappedClass:(NSString *)_className {
314 return [NSException exceptionWithName:@"MissingMappedClass"
321 - (SaxTagModel *)mapping {
322 return self->mapping;
325 return (self->object == null) ? nil : self->object;
328 - (SaxTagModel *)parentMapping {
329 return [self->parentInfo mapping];
332 return [self->parentInfo object];
337 - (Class)defaultElementClass {
338 return [NSMutableDictionary class];
341 - (void)unableToSetValue:(id)_object forKey:(NSString *)_key
342 withTag:(NSString *)_tag toParent:(id)_parent
343 exception:(NSException *)_exc
345 NSLog(@"couldn't apply value %@ for key %@ with parent %@<%@>: %@",
346 _object, _key, _parent, NSStringFromClass([_parent class]), _exc);
349 - (void)addObject:(id)_object fromTag:(NSString *)_tag
350 withMapping:(SaxTagModel *)_elementMap
351 toParent:(id)_parent withMapping:(SaxTagModel *)_parentMap
355 if (_object == nil || _object == null) return;
356 if (_parent == nil || _parent == null) return;
357 if (_elementMap == nil || _elementMap == (id)null) return;
358 if (_parentMap == nil || _parentMap == (id)null) return;
360 if ((key = [_parentMap propertyKeyForChildTag:_tag]) == nil) {
361 if ((key = [_elementMap key]) == nil)
366 if ([_parentMap isToManyKey:key]) {
367 [_parentMap addValue:_object toPropertyWithKey:key ofObject:_parent];
370 [_parent takeValue:_object forKey:key];
374 [self unableToSetValue:_object forKey:key withTag:_tag toParent:_parent
375 exception:localException];
384 /* determine class */
386 if ((s = [self->mapping className])) {
387 mappedClazz = NSClassFromString(s);
388 if (mappedClazz == Nil) {
389 self->error = [[self missingMappedClass:s] retain];
394 mappedClazz = [self defaultElementClass];
396 /* do we need to check for subclasses? I guess not. */
397 self->flags.isMutableDict = (mappedClazz == MutableDictClass) ? 1 : 0;
398 self->flags.isMutableString = (mappedClazz == MutableStringClass) ? 1 : 0;
399 self->flags.isString = (mappedClazz == StringClass) ? 1 : 0;
400 self->flags.hasContentKey = [[self->mapping contentKey] length] > 0 ?1:0;
402 /* create an object for the element .. */
404 if ((self->object = [[mappedClazz alloc] initWithSaxDecoder:self->decoder])) {
405 NSDictionary *defaultValues;
408 if ((defaultValues = [self->mapping defaultValues]))
409 [self->object takeValuesFromDictionary:defaultValues];
411 if ((tmp = [self->mapping tagKey]))
412 [self->object takeValue:self->tagName forKey:tmp];
413 if ((tmp = [self->mapping namespaceKey]))
414 [self->object takeValue:self->namespace forKey:tmp];
421 /* awake from decoding (the decoded object can replace itself :-) */
423 if (self->flags.isString) {
426 if (self->flags.hasContentKey) {
429 s = [self->collectedCharData copy];
430 ASSIGN(self->collectedCharData, (id)nil);
432 [self->object takeValue:s forKey:[self->mapping contentKey]];
438 [[self->object awakeAfterUsingSaxDecoder:self->decoder] retain];
441 if (!self->flags.isRoot) {
445 parent = [self parentObject];
449 if ((t = [self->mapping parentKey]))
450 [self->object takeValue:parent forKey:t];
452 [self addObject:self->object
453 fromTag:self->tagName
454 withMapping:self->mapping
456 withMapping:[self parentMapping]];
460 - (void)characters:(unichar *)_chars length:(int)_len {
461 if (self->flags.isMutableString) {
464 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
465 [self->object appendString:tmp];
468 else if (self->flags.isString) {
473 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
474 self->object = [self->object stringByAppendingString:tmp];
478 else if (self->flags.hasContentKey) {
479 if (self->collectedCharData == nil) {
480 self->collectedCharData =
481 [[NSMutableString alloc] initWithCharacters:_chars length:_len];
486 tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
487 [self->collectedCharData appendString:tmp];
493 @end /* _SaxObjTagInfo */