/*! @header ECXMLControl @abstract Module of Encore @availability OS X, GNUstep @copyright 2004, 2005, 2006 Oliver Langer Author: Oliver Langer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA <pre> ------------------------------------------------------------------------- Modification history 27.11.05 ola initial version 22.08.06 ola license changed ------------------------------------------------------------------------- </pre> */ #include <Encore/ECMemory.h> #include <Encore/ECXMLControl.h> #include <Encore/ECXMLControlEvent.h> #include <Encore/ECXMLControlContext.h> #include <Encore/ECXMLControlDefaultAllocatorRule.h> #include <Encore/ECXMLControlDefaultRule.h> #include <Encore/ECXMLControlState.h> #include <Encore/ECXMLControlRuleSelector.h> #include <Encore/ECXMLControlReferenceRule.h> @implementation ECXMLControl - internalInit { self->state = [[ECXMLControlState alloc] init]; self->ruleSelector = [[ECXMLControlRuleSelector alloc] init]; self->defaultRulesAdded = NO; self->defaultRulesEnabled = YES; self->errorHandler = nil; self->errorHandlerMethod = NULL; return self; } - initWithContentsOfURL: (NSURL *) anURL { self = [super init]; self->parser = [[NSXMLParser alloc] initWithContentsOfURL: anURL]; [self internalInit]; return self; } - initWithData: (NSData *) data { self = [super init]; self->parser = [[NSXMLParser alloc] initWithData: data]; [self internalInit]; return self; } - (void) dealloc { if( nil != self->parser ) { [self->parser release]; } if( nil != self->ruleSelector ) { [self->ruleSelector release]; } [self->errorHandler release]; [super dealloc]; } - (NSArray *) userObjects { NSArray *toReturn = nil; if( nil == self->state ) { toReturn = [[[NSMutableArray alloc] init] autorelease]; } else { if( nil == [self->state allUserObjects] ) { toReturn = [[[NSMutableArray alloc] init] autorelease]; } else { toReturn = [self->state allUserObjects]; } } return toReturn; } - addDefaultRules { /* add rule which is responsible for allocating objects */ [self->ruleSelector addRule: [[[ECXMLControlDefaultAllocatorRule alloc] init] autorelease] forEvent: [ECXMLControlEvent eventId_elementStarted]]; /* add a rule which allows the usage of id and id-ref like mechanism by * which objects can be references see ECControlReferenceRule for more details */ [self->ruleSelector addRule: [[[ECXMLControlReferenceRule alloc] init] autorelease] forEvent: [ECXMLControlEvent eventId_addAttribute]]; // add rule which is responsible to lookup and call appropriate setting // methods for given attributes [self->ruleSelector addRule: [[[ECXMLControlSetAttributeRule alloc] init] autorelease] forEvent: [ECXMLControlEvent eventId_addAttribute]]; // add a rule which links nested objects together [self->ruleSelector addRule: [[[ECXMLControlLinkObjectRule alloc] init] autorelease] forEvent: [ECXMLControlEvent eventId_elementEnded]]; self->defaultRulesAdded = YES; return self; } - enableDefaultRules: (BOOL) enable { self->defaultRulesEnabled = enable; return self; } - parseXML { NSAssert( nil != self->parser, @"ECXMLControl::parseXML: Controller"\ " not correctly installed!" ); EC_AUTORELEASEPOOL_BEGIN [self->parser setDelegate: self]; [self->parser setShouldResolveExternalEntities: NO]; [self->parser setShouldProcessNamespaces: NO]; if( (!self->defaultRulesAdded) && (self->defaultRulesEnabled)) { [self addDefaultRules]; self->defaultRulesAdded = YES; } [self->parser parse]; EC_AUTORELEASEPOOL_END return self; } - (void) parser: (NSXMLParser*)aParser didEndElement: (NSString*)anElementName namespaceURI: (NSString*)aNamespaceURI qualifiedName: (NSString*)aQualifierName { EC_AUTORELEASEPOOL_BEGIN ECXMLControlEvent *event = [[[ECXMLControlEvent alloc] initElementEndedEventWithName: anElementName] autorelease]; ECXMLControlContext *context; context = [[[ECXMLControlContext alloc] initWithState: self->state causedEvent: event] autorelease]; [self->ruleSelector performRulesForContext: context]; EC_AUTORELEASEPOOL_END return; } - (void) parser: (NSXMLParser*) aParser didStartElement: (NSString*) anElementName namespaceURI: (NSString*) aNamespaceURI qualifiedName: (NSString*) aQualifierName attributes: (NSDictionary*) anAttributeDict { EC_AUTORELEASEPOOL_BEGIN NSEnumerator *allAttributes; id attributeName; ECXMLControlEvent *event = [[[ECXMLControlEvent alloc] initElementStartedEventWithName: anElementName withAttributes: anAttributeDict ] autorelease]; ECXMLControlContext *context; context = [[[ECXMLControlContext alloc] initWithState: self->state causedEvent: event] autorelease]; [self->ruleSelector performRulesForContext: context]; // now fire events where each event specifies an attribute allAttributes = [anAttributeDict keyEnumerator]; while( (attributeName = [allAttributes nextObject]) ) { event = [[[ECXMLControlEvent alloc] initAddAttributeEventWithName: anElementName withAttributeName: attributeName withAttributeValue: [anAttributeDict objectForKey: attributeName]] autorelease]; context = [[[ECXMLControlContext alloc] initWithState: self->state causedEvent: event] autorelease]; [self->ruleSelector performRulesForContext: context]; } EC_AUTORELEASEPOOL_END } - (void)parser:(NSXMLParser *)aParser parseErrorOccurred:(NSError *)parseError { if( nil != self->errorHandler ) { if( NULL != self->errorHandlerMethod ) { [self->errorHandler performSelector: self->errorHandlerMethod withObject: parseError]; } } } - (id) rootUserObject { NSArray *userObjects = [self userObjects]; id toReturn = nil; if( 0 < [userObjects count] ) { toReturn = [userObjects objectAtIndex: 0]; } return toReturn; } - (ECXMLControlRuleSelector *) ruleSelector { return self->ruleSelector; } - delegateErrorsTo: (id) anErrorHandler usingMethod: (SEL) aMethod { id tmp = self->errorHandler; self->errorHandler = [anErrorHandler retain]; [tmp release]; self->errorHandlerMethod = aMethod; return self; } @end