views:

346

answers:

1

Hi,

Im trying to parse XML (which seems ok) and populate a Table View on Iphone. I'm working from apples siesmec examples. My XML looks something like this and has about 10 entries going from artist1 to artist10

<promo> <id> 42 </id> <artistname> artist1 </artistname> <img> http://address.com/avatar_42.jpg </img> </promo>

If I put in breakpoints I can see all of the correct names but when the parsing is finished all 10 cells in my table say "artist10:

The Code for the xml is in the file as the table view controller. Can you see anything thats glaring a stupid mistake?

#pragma mark Parser constants
    // Limit the number of parsed earthquakes to 50.

static const const NSUInteger kMaximumNumberOfEarthquakesToParse = 50;

static NSUInteger const kSizeOfEarthquakeBatch = 10;

// Reduce potential parsing errors by using string constants declared in a single place.
static NSString * const kArtistName = @"artistname";
static NSString * const kEntryElementName = @"promo";
static NSString *const kEntryElementID =@"id";
static NSString *const kEntryElementImg=@"img";


- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    if (parsedPromoListCounter >= kMaximumNumberOfEarthquakesToParse) {
        // Use the flag 
  didAbortParsing = YES;
        [parser abortParsing];
    }
    if ([elementName isEqualToString:kEntryElementName]) {
        PromoListItem *promoitem = [[PromoListItem alloc] init];
        self.currentPromoListObject = promoitem;
        [promoitem release];

} else if ([elementName isEqualToString:kEntryElementImg]) {
  //nothing for now
    } else if ([elementName isEqualToString:kArtistName] || [elementName isEqualToString:kEntryElementImg] || [elementName isEqualToString:kEntryElementID]) {
  accumulatingParsedCharacterData = YES;

        // The mutable string needs to be reset to empty.
        [currentParsedCharacterData setString:@""];
    }
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {     
 if ([elementName isEqualToString:kEntryElementName]) {
  [self.currentParseBatch addObject:self.currentPromoListObject];
  parsedPromoListCounter++;
  if (parsedPromoListCounter % kSizeOfEarthquakeBatch == 0) {
   [self performSelectorOnMainThread:@selector(addPromosToList:) withObject:self.currentParseBatch waitUntilDone:NO];
   self.currentParseBatch = [NSMutableArray array];
  }
 } else if ([elementName isEqualToString:kArtistName]) {
  self.currentPromoListObject.artistName=self.currentParsedCharacterData;
 } else if ([elementName isEqualToString: kEntryElementID]) {
  self.currentPromoListObject.artistID = self.currentParsedCharacterData;
 } else if ([elementName isEqualToString:kEntryElementImg]) {

  self.currentPromoListObject.imgLink=self.currentParsedCharacterData;
 }
 // Stop accumulating parsed character data. We won't start again until specific elements begin.
 accumulatingParsedCharacterData = NO;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
   if (accumulatingParsedCharacterData) {
    // If the current element is one whose content we care about, append 'string'
    // to the property that holds the content of the current element.
    [self.currentParsedCharacterData appendString:string];
   }
  }`

And this is how I populate my table view

#pragma mark Table View Methods

// The number of rows is equal to the number of earthquakes in the array.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.promoList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

 // Each subview in the cell will be identified by a unique tag.
    static NSUInteger const kartistNameLabelTag = 2;

    // Declare references to the subviews which will display the earthquake data.
    UILabel *artistNameLabel = nil;


 static NSString *kpromoCellID = @"promoCellID";   

   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kpromoCellID];
 if (cell == nil) {
        // No reusable cell was available, so we create a new cell and configure its subviews.
  cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kpromoCellID] autorelease];

        artistNameLabel = [[[UILabel alloc] initWithFrame:CGRectMake(10, 3, 190, 20)] autorelease];
  artistNameLabel.tag = kartistNameLabelTag;
        artistNameLabel.font = [UIFont boldSystemFontOfSize:14];
        [cell.contentView addSubview: artistNameLabel];

 } else {
        // A reusable cell was available, so we just need to get a reference to the subviews using their tags.
        artistNameLabel = (UILabel *)[cell.contentView viewWithTag:kartistNameLabelTag];

    }

    // Get the specific promo for this row.
 PromoListItem *promo = [promoList objectAtIndex:indexPath.row];

    // Set the relevant data for each subview in the cell.
    artistNameLabel.text =promo.artistName;

 return cell;

} 
A: 

This was driving me mad so I went for a different approach. The example used was from this site

http://www.iphonesdkarticles.com/2008/11/parsing-xml-files.html

Here is the code implmentation I did incase its useful to anyone.... but probably not

I'm not sure which approach is better. Maybe somebody would have an opinion on this?

The first version that I couldnt get working seemed to give you more control over what character data gets parsed. Thats the only real benefit that I can see.

-

 (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {

    if([elementName isEqualToString:@"promolist"]) {
        //Initialize the array.
        promoList = [[NSMutableArray alloc] init];
    }
    else if([elementName isEqualToString:kEntryElementName]) {

        //Initialize the book.
        //aBook = [[Book alloc] init];
        //aBook =[[PromoListItem alloc] init];
        PromoListItem *promo = [[PromoListItem alloc] init];
        self.currentPromoListObject = promo;
        [promo release];

    }

    NSLog(@"Processing Element: %@", elementName);
}

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

    if(!currentParsedCharacterData)
        currentParsedCharacterData = [[NSMutableString alloc] initWithString:string];
    else
        [currentParsedCharacterData appendString:string];

NSLog(@"Processing Value: %@", currentParsedCharacterData);   }

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

    if([elementName isEqualToString:@"promolist"])
    {
        [self.tableView reloadData];
        return;
    }

    //There is nothing to do if we encounter the promo element here.
    //If we encounter the promo element howevere, we want to add the book object to the array
    // and release the object.
    else if([elementName isEqualToString:kEntryElementName]) {
        [promoList addObject:currentPromoListObject];

        [currentPromoListObject release];
        currentPromoListObject = nil;
    }
    else{
        [currentPromoListObject setValue:currentParsedCharacterData forKey:elementName];

        }
    [currentParsedCharacterData release];
    currentParsedCharacterData = nil;

}
dubbeat