]> err.no Git - sope/blob - sope-xml/SaxObjC/SaxObjectDecoder.m
removed NGCString
[sope] / sope-xml / SaxObjC / SaxObjectDecoder.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "SaxObjectDecoder.h"
24 #include "SaxObjectModel.h"
25 #include "common.h"
26
27 static BOOL debugOn = NO;
28
29 @interface _SaxObjTagInfo : NSObject
30 {
31 @public
32   SaxObjectDecoder *decoder;    /* non-retained */
33   _SaxObjTagInfo   *parentInfo; /* non-retained */
34   SaxTagModel *mapping;
35   NSString    *tagName;
36   NSString    *namespace;
37   NSException *error;
38   id          object;
39   struct {
40     int isRoot:1;
41     int isMutableDict:1;
42     int isString:1;
43     int isMutableString:1;
44     int hasContentKey:1;
45   } flags;
46   NSMutableString *collectedCharData;
47 }
48
49 /* accessors */
50
51 - (SaxTagModel *)mapping;
52 - (id)object;
53
54 /* tag handling */
55
56 - (void)start;
57 - (void)stop;
58
59 - (void)characters:(unichar *)_chars length:(int)_len;
60
61 @end
62
63 @implementation SaxObjectDecoder
64
65 static NSNull *null = nil;
66
67 + (void)initialize {
68   if (null == nil) null = [[NSNull null] retain];
69 }
70
71 - (id)initWithMappingModel:(SaxObjectModel *)_model {
72   if ((self = [super init])) {
73     self->mapping = [_model retain];
74   }
75   return self;
76 }
77
78 - (id)initWithMappingAtPath:(NSString *)_path {
79   SaxObjectModel *model;
80
81   model = [SaxObjectModel modelWithContentsOfFile:_path];
82   return [self initWithMappingModel:model];
83 }
84 - (id)initWithMappingNamed:(NSString *)_name {
85   SaxObjectModel *model;
86   
87   model = [SaxObjectModel modelWithName:_name];
88   return [self initWithMappingModel:model];
89 }
90
91 - (id)init {
92   return [self initWithMappingModel:nil];
93 }
94
95 - (void)dealloc {
96   [self reset];
97   [self->objectStack  release];
98   [self->mappingStack release];
99   [self->infoStack    release];
100   [self->locator      release];
101   [super dealloc];
102 }
103
104 /* parse results */
105
106 - (id)rootObject {
107   return self->rootObject;
108 }
109
110 /* cleanup */
111
112 - (void)parseReset {
113   NSAutoreleasePool *pool;
114   
115   pool = [[NSAutoreleasePool alloc] init];
116   [self->infoStack    removeAllObjects];
117   [self->mappingStack removeAllObjects];
118   [self->objectStack  removeAllObjects];
119   [pool release];
120 }
121 - (void)reset {
122   [self parseReset];
123   
124   [self->rootObject release]; 
125   self->rootObject = nil;
126 }
127
128 /* parsing */
129
130 - (void)startDocument {
131   [self reset];
132   
133   if (self->infoStack == nil)
134     self->infoStack = [[NSMutableArray alloc] initWithCapacity:16];
135 }
136
137 - (void)endDocument {
138   [self parseReset];
139 }
140
141 /* positioning info */
142
143 - (void)setDocumentLocator:(id<NSObject,SaxLocator>)_locator {
144   ASSIGN(self->locator, _locator);
145 }
146
147 /* stacks */
148
149 - (void)pushInfo:(_SaxObjTagInfo *)_info {
150   [self->infoStack addObject:_info];
151 }
152 - (void)popInfo {
153   [self->infoStack removeObjectAtIndex:([self->infoStack count] - 1)];
154 }
155 - (id)currentInfo {
156   return [self->infoStack lastObject];
157 }
158
159 /* elements */
160
161 - (NSException *)missingNamespaceMapping:(NSString *)_ns {
162   return [NSException exceptionWithName:@"MissingNamespaceMapping"
163                       reason:_ns
164                       userInfo:nil];
165 }
166 - (NSException *)missingElementMapping:(NSString *)_ns:(NSString *)_tag {
167   return [NSException exceptionWithName:@"MissingElementMapping"
168                       reason:_tag
169                       userInfo:nil];
170 }
171 - (NSException *)missingMappedClass:(NSString *)_className {
172   return [NSException exceptionWithName:@"MissingMappedClass"
173                       reason:_className
174                       userInfo:nil];
175 }
176
177 - (SaxTagModel *)mappingForTag:(NSString *)_tag namespace:(NSString *)_ns {
178   return [self->mapping modelForTag:_tag namespace:_ns];
179 }
180
181 - (void)couldNotApplyAttribute:(NSString *)_attr asKey:(NSString *)_key
182   onObject:(id)_object
183 {
184   NSLog(@"SaxObjectDecoder: could not apply attribute '%@' (key=%@) "
185         @"on object %@",
186         _attr, _key, _object);
187 }
188
189 - (void)startElement:(NSString *)_localName
190   namespace:(NSString *)_ns
191   rawName:(NSString *)_rawName
192   attributes:(id<SaxAttributes>)_attributes
193 {
194   _SaxObjTagInfo *info;
195   
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];
202   
203   [self->infoStack addObject:info];
204   
205   /* determine mapping dictionary */
206   
207   if ((info->mapping = [self mappingForTag:_localName namespace:_ns]) == nil) {
208     if (debugOn) {
209       NSLog(@"found no mapping for element '%@' (namespace %@)", 
210             _localName, _ns);
211     }
212     info->error = [[self missingElementMapping:_ns:_localName] retain];
213     return;
214   }
215   
216   /* start object */
217   [info start];
218   
219   /* add attribute values */
220   {
221     NSEnumerator *e;
222     NSString     *a;
223     
224     e = [[info->mapping attributeKeys] objectEnumerator];
225     while ((a = [e nextObject])) {
226       NSString *v, *key;
227       
228       if ((v = [_attributes valueForName:a uri:_ns])) {
229         key = [info->mapping propertyKeyForAttribute:a];
230         
231         NS_DURING
232           [info->object takeValue:v forKey:key];
233         NS_HANDLER
234           [self couldNotApplyAttribute:a asKey:key onObject:info->object];
235         NS_ENDHANDLER;
236       }
237     }
238   }
239 }
240 - (void)endElement:(NSString *)_localName
241   namespace:(NSString *)_ns
242   rawName:(NSString *)_rawName
243 {
244   _SaxObjTagInfo *info;
245   unsigned idx;
246
247   idx = [self->infoStack count] - 1;
248   info = [self->infoStack objectAtIndex:idx];
249   [info stop];
250   
251   if (idx == 0)
252     ASSIGN(self->rootObject, [info object]);
253   
254   [self->infoStack removeObjectAtIndex:idx];
255 }
256
257 /* CDATA */
258
259 - (void)characters:(unichar *)_chars length:(int)_len {
260   _SaxObjTagInfo *info;
261   
262   if (_len == 0) return;
263   info = [self->infoStack objectAtIndex:([self->infoStack count] - 1)];
264   [info characters:_chars length:_len];
265 }
266
267 - (BOOL)processIgnorableWhitespace {
268   return NO;
269 }
270
271 - (void)ignorableWhitespace:(unichar *)_chars length:(int)_len {
272   if ([self processIgnorableWhitespace])
273     [self characters:_chars length:_len];
274 }
275
276 @end /* SaxObjectDecoder */
277
278 @implementation NSObject(SaxObjectCoding)
279
280 - (id)initWithSaxDecoder:(SaxObjectDecoder *)_decoder {
281   return [self init];
282 }
283
284 - (id)awakeAfterUsingSaxDecoder:(SaxObjectDecoder *)_decoder {
285   return self;
286 }
287
288 @end /* SaxCoding */
289
290 @implementation _SaxObjTagInfo
291
292 static Class  MutableDictClass   = Nil;
293 static Class  MutableStringClass = Nil;
294 static Class  StringClass        = Nil;
295
296 + (void)initialize {
297   MutableDictClass   = [NSMutableDictionary class];
298   MutableStringClass = [NSMutableString     class];
299   StringClass        = [NSString            class];
300 }
301
302 - (void)dealloc {
303   [self->tagName   release];
304   [self->namespace release];
305   [self->error     release];
306   [self->object    release];
307   [self->collectedCharData release];
308   [super dealloc];
309 }
310
311 /* errors */
312
313 - (NSException *)missingMappedClass:(NSString *)_className {
314   return [NSException exceptionWithName:@"MissingMappedClass"
315                       reason:_className
316                       userInfo:nil];
317 }
318
319 /* accessors */
320
321 - (SaxTagModel *)mapping {
322   return self->mapping;
323 }
324 - (id)object {
325   return (self->object == null) ? nil : self->object;
326 }
327
328 - (SaxTagModel *)parentMapping {
329   return [self->parentInfo mapping];
330 }
331 - (id)parentObject {
332   return [self->parentInfo object];
333 }
334
335 /* run */
336
337 - (Class)defaultElementClass {
338   return [NSMutableDictionary class];
339 }
340
341 - (void)unableToSetValue:(id)_object forKey:(NSString *)_key
342   withTag:(NSString *)_tag toParent:(id)_parent
343   exception:(NSException *)_exc
344 {
345   NSLog(@"couldn't apply value %@ for key %@ with parent %@<%@>: %@",
346         _object, _key, _parent, NSStringFromClass([_parent class]), _exc);
347 }
348
349 - (void)addObject:(id)_object fromTag:(NSString *)_tag
350   withMapping:(SaxTagModel *)_elementMap
351   toParent:(id)_parent withMapping:(SaxTagModel *)_parentMap
352 {
353   NSString *key;
354
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;
359   
360   if ((key = [_parentMap propertyKeyForChildTag:_tag]) == nil) {
361     if ((key = [_elementMap key]) == nil)
362       key = _tag;
363   }
364   
365   NS_DURING {
366     if ([_parentMap isToManyKey:key]) {
367       [_parentMap addValue:_object toPropertyWithKey:key ofObject:_parent];
368     }
369     else {
370       [_parent takeValue:_object forKey:key];
371     }
372   }
373   NS_HANDLER {
374     [self unableToSetValue:_object forKey:key withTag:_tag toParent:_parent
375           exception:localException];
376   }
377   NS_ENDHANDLER;
378 }
379
380 - (void)start {
381   NSString *s;
382   Class    mappedClazz;
383   
384   /* determine class */
385   
386   if ((s = [self->mapping className])) {
387     mappedClazz = NSClassFromString(s);
388     if (mappedClazz == Nil) {
389       self->error = [[self missingMappedClass:s] retain];
390       return;
391     }
392   }
393   else
394     mappedClazz = [self defaultElementClass];
395   
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;
401   
402   /* create an object for the element .. */
403   
404   if ((self->object = [[mappedClazz alloc] initWithSaxDecoder:self->decoder])) {
405     NSDictionary *defaultValues;
406     id tmp;
407     
408     if ((defaultValues = [self->mapping defaultValues]))
409       [self->object takeValuesFromDictionary:defaultValues];
410     
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];
415   }
416 }
417
418 - (void)stop {
419   id tmp;
420
421   /* awake from decoding (the decoded object can replace itself :-) */
422   
423   if (self->flags.isString) {
424   }
425   else {
426     if (self->flags.hasContentKey) {
427       NSString *s;
428
429       s = [self->collectedCharData copy];
430       ASSIGN(self->collectedCharData, (id)nil);
431       
432       [self->object takeValue:s forKey:[self->mapping contentKey]];
433       [s release];
434     }
435     
436     tmp = self->object;
437     self->object =
438       [[self->object awakeAfterUsingSaxDecoder:self->decoder] retain];
439     [tmp release];
440   }
441   if (!self->flags.isRoot) {
442     NSString *t;
443     id parent;
444
445     parent = [self parentObject];
446     
447     /* add to parent */
448
449     if ((t = [self->mapping parentKey]))
450       [self->object takeValue:parent forKey:t];
451     
452     [self addObject:self->object 
453           fromTag:self->tagName
454           withMapping:self->mapping
455           toParent:parent
456           withMapping:[self parentMapping]];
457   }
458 }
459
460 - (void)characters:(unichar *)_chars length:(int)_len {
461   if (self->flags.isMutableString) {
462     NSString *tmp;
463     
464     tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
465     [self->object appendString:tmp];
466     [tmp release];
467   }
468   else if (self->flags.isString) {
469     NSString *tmp, *old;
470
471     old = self->object;
472     
473     tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
474     self->object = [self->object stringByAppendingString:tmp];
475     [tmp release];
476     [old release];
477   }
478   else if (self->flags.hasContentKey) {
479     if (self->collectedCharData == nil) {
480       self->collectedCharData = 
481         [[NSMutableString alloc] initWithCharacters:_chars length:_len];
482     }
483     else {
484       NSString *tmp;
485       
486       tmp = [[NSString alloc] initWithCharacters:_chars length:_len];
487       [self->collectedCharData appendString:tmp];
488       [tmp release];
489     }
490   }
491 }
492
493 @end /* _SaxObjTagInfo */