Need help parsing out my NSString!

Discussion in 'iOS Programming' started by ethana, Aug 9, 2008.

  1. ethana macrumors 6502a

    Joined:
    Jul 17, 2008
    Location:
    Seattle, WA
    #1
    I have a string coming in from the Internet in my app that looks like this:

    Last update on 09:25 am<br><b>Auction 1</b><br>ebay.com<br><br>

    I set that to an NSString *foobar. The problem is, when I write the text to a UITextView like this "txtInfo.text = foobar;" then the string comes out like this:

    Last update on 09:25 am

    The rest is completely cut off at the & symbol. I need it to display on the next line "Auction 1" and then another line that says "ebay.com". Anyone have any ideas how I can pull out what I need? I am at a loss right now. The & symbol is killing me.

    Ethan
     
  2. ayasin macrumors 6502

    Joined:
    Jun 26, 2008
    #2
    Post the actual code snippit so we can have a look.
     
  3. ethana thread starter macrumors 6502a

    Joined:
    Jul 17, 2008
    Location:
    Seattle, WA
    #3
    Code:
    items = [rss items];
    	
    // loop through all posts in the feed
    NSEnumerator *enumerator = [items objectEnumerator];
    NSDictionary *dict;
    int i = 0;
    NSString *foobar = @"";
    	
    while(dict = [enumerator nextObject]) {
    	foobar = [foobar stringByAppendingString:[[items objectAtIndex:i] objectForKey:@"title"]];
    	foobar = [foobar stringByAppendingString:@"\n"];
    	foobar = [foobar stringByAppendingString:[[items objectAtIndex:i] objectForKey:@"description"]];
    	foobar = [foobar stringByAppendingString:@"\n\n"];
    		
    	i = i + 1;
    }
    
    lblData.text = foobar;
    
    Is it because I'm using NSDictionary and objectForKey instead of valueForKey? valueForKey doesn't working because my data doesn't have a @ sign in front of it.

    Ethan
     
  4. ayasin macrumors 6502

    Joined:
    Jun 26, 2008
    #4
    Well first a couple of suggestions:

    try this bit of code instead...it's a lot more efficient:

    Code:
    
    NSMutableString* text = [[NSMutableString alloc] init];
    for (NSDictionary* dict in [rss items]) {
        [text appendFormat:@"%@\n%@\n\n",[dict objectForKey:@"title"], [dict objectForKey:@"description"]]; 
    }
    [lblData setText:text];
    
    
    Next, we need to see how you decompose the string coming from the internet...I suspect the problem is there. By the time it's in [rss items] I bet it's already bad.
     
  5. ethana thread starter macrumors 6502a

    Joined:
    Jul 17, 2008
    Location:
    Seattle, WA
    #5
    You're right. After doing some debugging it looks like it's already bad in "items". Here's the code that I'm using to parse the RSS XML feed:

    iPhoneRSS.m
    Code:
    #import "iPhoneRSS.h"
    
    #import <UIKit/UIKit.h>
    
    @implementation iPhoneRSS
    
    - (iPhoneRSS*) initWithURL:(NSURL*)url
    {
    	NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
    	[parser setDelegate:self];
    	
    	items = [[NSMutableArray alloc] init];
    	
    	currentProperty = nil;
    	curItem = nil;
    	
    	[parser parse];
    
    	return self;
    }
    
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    	
    	if([elementName isEqualToString:@"item"]) {
    		curItem = [[NSMutableDictionary alloc] init];
    	}
    	else if(curItem != nil) {
    		currentProperty = [[[NSString alloc] initWithString:elementName] retain];
    	}
    	
    }
    
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    	if(curItem != nil && [elementName isEqualToString:@"item"]) {
    		[items addObject:curItem];
    		[curItem release];
    		curItem = nil;
    	}
    }
    
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    	
    	if(curItem != nil && currentProperty != nil && string != nil) {
    		[curItem setObject:string forKey:currentProperty];
    		[currentProperty release];
    		currentProperty = nil;
    	}
    	
    }
    
    - (NSArray*)items {
    	return items;
    }
    
    @end
    
    iPhoneRSS.h
    Code:
    #import <UIKit/UIKit.h>
    
    @interface iPhoneRSS : NSObject {
    	NSMutableArray *items;
    	
    	NSString *currentProperty;
    	
    	NSMutableDictionary *curItem;
    }
    
    - (iPhoneRSS*) initWithURL:(NSURL*)url;
    - (NSArray*)items;
    
    @end
    
    Thanks for your help tonight. This is super critical for me right now.

    By the way, I got this from http://www.chrismoos.com/, so it's not my code but it is free to use.

    Ethan
     
  6. ayasin macrumors 6502

    Joined:
    Jun 26, 2008
    #6
    The problem with your program is the way that you are decoding the XML.

    What you intended was that there be 2 XML elements, one for the title and the other for the description. That's all your app is coded to handle, but that's not what you're getting. You're getting additional elements and it's screwing up your parsing. You get a second didStartElement as soon as the parser hits the <B> which I suspect is actually not escaped like that in the source string but actually <B>. When your app gets to the first embedded tag it starts decoding it...when it gets to the end tag it throws it away because it's not currently decoding an item tag. The only part you're actually saving is the part before it starts decoding embedded tags. To solve this you'll need to be smarter about how you parse. Hope that reply wasn't too convoluted and gets you thinking on the right track...it's pretty late here and I'm getting tired ;).
     
  7. xoclipse macrumors newbie

    Joined:
    Jul 17, 2008
    #7
    You can just decode the html entities....

     
  8. ethana thread starter macrumors 6502a

    Joined:
    Jul 17, 2008
    Location:
    Seattle, WA
    #8
    I just figured it out myself actually, and what you said is exactly what I found as well. Now I concatenate string after string until I know I've reached the end of the current element. Before it was just reporting after the first string came in.

    Apple even says in their documentation for parser:foundCharacters: the following:

    "The parser object may send the delegate several parser:foundCharacters: messages to report the characters of an element. Because string may be only part of the total character content for the current element, you should append it to the current accumulation of characters until the element changes."

    Here's how I changed the code (just needed to change two functions):

    Code:
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    	if(curItem != nil && [elementName isEqualToString:@"item"]) {
    		[items addObject:curItem];
    		[curItem release];
    		curItem = nil;
    	}
    	else if (curItem != nil && currentProperty != nil)
    	{
    		[curItem setObject:concatString forKey:currentProperty];
    		[currentProperty release];
    		currentProperty = nil;
    	}
    }
    
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    	if(curItem != nil && string != nil) {
    		concatString = [concatString stringByAppendingString:string];
    	}
    }
    
    It's probably not perfect but it works for me for now. I'll inform the original author.

    Thanks for your help!

    Ethan
     

Share This Page