Question

I'm using NSXMLParser to parse XML data from a remote server. I followed a tutorial to get up and running and everything is ok for any (NSString *) members I have in my objects that I'm creating. I also have integers that I need to set from the XML data, such as:

<root>
    <child>
        <name> Hello </name>
        <number> 123 </number>
    </child>
    <child>
        <name> World</name>
        <number> 456 </number>
    </child>
</root>

In this case I would be creating two "child" objects. I'm using:

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
      namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    ...
    [aChild setValue:currentElementValue forKey:elementName];
    ...
}

Delegate to set the values. This is where I get to my problem. The "NSString *name" member is set fine everytime, however if I use an NSInteger, then whenever I try to set "number" I get an EXC_BAD_ACCESS. So I tried using an "int" instead. But now I can't use key-value programming and need to look for the node manually:

if([elementName isEqualToString:@"number"]) {
    aChild.number = [currentElementValue intValue]
}

This is okay, I can deal with that because I know what nodes I'll be getting, but it gets worse. When currentElementValue is an "NSMutableString *" as per the tutorial, it does not return the correct integer even though the string is correct. For instance:

    NSLog(@"NSMutableString Value: %@, and intValue %d\n", currentElementValue, [currentElementValue intValue]); 
// Value will be 123 but intValue will be 0

So I made currentElementValue an NSString instead of an NSMutableString and I can get the proper intValue. But I read online that the reason it is an NSMutableString is because the:

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string

Delegate used to set the value can occur more than once, but typically does not. So my question is does anybody know what I'm doing wrong? This seems like a pretty trivial case for NSXMLParser so I'm sure it's something I'm misunderstanding.

Was it helpful?

Solution

Couple things going on here.

First, you have obvious blanks in your XML character data, e.g.

        <number> 456 </number>

You should really strip out that whitespace. That is likely what is causing the return value of [NSString intValue] to be wrong. If you can remove it at the source, great. If not, you can strip it out on the receiving end by doing:

currentElementValue = [currentElementValue stringByTrimmingCharactersInSet:
    [NSCharacterSet whitespaceAndNewlineCharacterSet]];

The reason you couldn't use key/value is that you can't store an NSInteger value in an NSMutableDictionary. Both keys and values in the dictionary have to descend from NSObject, and NSInteger is (I'm surmising, here) just a platform-safe typedef of int. So you should use an NSNumber instead:

NSNumber *theInt = [NSNumber numberWithInt:[currentElementValue intValue]];
[aChild setObject:theInt forKey:elementName];

OTHER TIPS

I don't know where your code is failing, but here's the correct way to handle this:

NSMutableString *buffer = [[NSMutableString alloc] init];

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
    [buffer setString:@""];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if([elementName isEqualToString:@"number"]) {
        [aChild setNumber:[buffer intValue]];
        [buffer setString:@""];
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    [buffer appendString:string];
}
  1. intValue should work identically NSString and NSMutableString. Are you sure that Value was '123' and not '\n123' (\n means a new line character), if the string doesn't start with a decimal number then intValue will return 0.

  2. Are you clearing the mutable string correctly at parser:didStartElement:? If you're cleaning only at parser:didEndElement: then parser:foundCharacters: will collect characters from parent element too. Which will prefix your string with newlines in this case and intValue will return 0.

  3. You're correct in that parser:foundCharacters: can be called multiple times for a single element.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top