I'm trying to parse through an XML I'm getting from a webservice with an NSXMLParserDelegate
. The NSObject
I want to put the data into (I'll just call it MyObject
) has @property
s that are not NSString
s (there are some NSDate
s, some NSNumber
s, and maybe at some point in the future some primitives).
Since the XML is all a big string, I'm getting errors and crashes when I try to just directly put the values from the XML into my properties (I'm using [myObject setValue:currentElementValue forKey:elementName];
in my parser:didEndElement:...
, which normally works fine - when key
is a NSString
). I didn't really expect this to work, but I figured it was worth a shot.
The easiest thing to do is just hardcode all of it, so if I have an '@property (nonatomic, strong) NSNumber *age;' on my object, when I find the <age>25</age>
part of my XML, I do MyObject.age = [NSNumber numberWithInt:[currentElementValue intValue]];
. The problem with this is it is very rigid - I'd like this code to be more dynamic than that. I don't want to have to know what all the properties of my object are ahead of time.
I've also tried checking what the class
of the property is, then doing some conversion before entering a value (so something like [myObject setValue:[NSNumber numberWithInt:[currentElementValue intValue] forKey:elementName];
if the property isKindOfClass:[NSNumber class]]
. The problem with this is that this is the first time that property is used, so it is nil
, and therefore doesn't have a class. So this approach doesn't really work either.
Am I doing this completely wrong? It seems like it should be fairly typical to get data from an XML and put it into non-NSString
variables, but I can't seem to get it to work.
If anyone needs to see more code to get a better understanding of how I've this is set up or what I've already tried, let me know.
EDIT: I've come up with a quick example of what I'm trying to do. Suppose I have the following XML:
<Object>
<ITEM_NUMBER>4</ITEM_NUMBER>
<IS_AWESOME>YES</IS_AWESOME>
<AWESOMENESS>9000.1</AWESOMENESS>
</Object>
that I want to parse into an instance of MyObject
(an NSObject
subclass)
@interface MyObject: NSObject
@property (nonatomic, assign) int ITEM_NUMBER;
@property (nonatomic, assign) BOOL IS_AWESOME;
@property (nonatomic, assign) float AWESOMENESS;
@end
And a second XML
<OtherObject>
<PRICE>4.99</PRICE>
<QUANTITY>5</QUANTITY>
<FOR_RESALE>NO</FOR_RESALE>
</OtherObject>
that will go into an instance of OtherObject
(also NSObject
subclass)
@interface OtherObject: NSObject
@property (nonatomic, assign) int QUANTITY;
@property (nonatomic, assign) BOOL FOR_RESALE;
@property (nonatomic, assign) float PRICE;
@end
I want to create a "template" parser (which has @property (nonatomic, strong) NSObject *instance;
and then NSMutableString *currentElementValue
as an ivar)
...
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
[currentElementValue setString:string];
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([[self.instance valueForKey:elementName] isKindOfClass:int])
{
[self.instance setValue:[currentElementValue intValue] forKey:elementName];
}
else if ([[self.instance valueForKey:elementName] isKindOfClass:float])
{
[self.instance setValue:[currentElementValue floatValue] forKey:elementName];
}
else if ([[self.instance valueForKey:elementName] isKindOfClass:BOOL])
{
[self.instance setValue:[currentElementValue boolValue] forKey:elementName];
}
else if ...
}
...
Then, I just subclass that "template" parser for each of my different XMLs and overwrite the init
method so that
self.instance = [[MyObject alloc] init];
or
self.instance = [[OtherObject alloc] init];
as appropriate. I have a lot of webservices I'm calling that I will be getting similarly structured XML from, so only having to change 1 line in the parsers for each is something that is very desirable. Having all the rest of the parser code in a single "template" class will make maintaining, reading, and debugging the code so much easier.
Obviously, the problem I'm having is isKindOfClass
doesn't accept int
, float
, or BOOL
as inputs. Is there anything similar that I can use instead?