views:

483

answers:

2

Hello all, I'm newbie in iPhone Application Programming. I can't get value from XML file and display it in UITableView. I need to get the name value of animal. How is the simple way to parse XML without attribute? I've been read NSXMLParser Documentation but the data is not displayed in my UITableView. Here is my XML file :

<?xml version="1.0" encoding="UTF-8"?>
<animals>
  <animal>
    <id>1</id>
    <name>Elephant</name>
  </animal>
  <animal>
    <id>2</id>
    <name>Tiger</name>
  </animal>
  <animal>
    <id>3</id>
    <name>Bird</name>
  </animal>
</animals>

I follow some tutorial about Parsing XML with attribute, but in my XML file, I don't have attribute. And this is my code to parse XML:

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

     if([elementName isEqualToString:@"animals"]) {
      appDelegate.animals = [[NSMutableArray alloc] init];
     }

     else if([elementName isEqualToString:@"animal"]) {  
     }

        else if([elementName isEqualToString:@"id"]){
      aAnimal = [[Animal alloc] init];
      aAnimal.animalID = elementName;
     } 
    }

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

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

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

     if([elementName isEqualToString:@"animals"])
      return;
     else if([elementName isEqualToString:@"animal"]) {
     }
        else if([elementName isEqualToString:@"id"]) {
      [appDelegate.animals addObject:aAnimal];      
      [aAnimal release];
      aAnimal = nil;
     }
     else 
      [aAnimal setValue:currentElementValue forKey:elementName];

     [currentElementValue release];
     currentElementValue = nil;
    }
A: 

Quite a common problem; an example solution is the CocoaXMLParser in the Apple example XMLPerformance that answers the question. Essentially define a boolean to control character data collection and a string to hold it in, ensure you initialise the string somewhere.

Turn character collection on in: - (void)parser:(NSXMLParser *)parser didStartElement Instantiate your variable in:

  • (void)parser:(NSXMLParser *)parser didEndElement

Collect characters in:

  • (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { if (storingCharacters) [currentString appendString:string]; }
A: 

Like ReaddyEddy mentioned, you need to save a current string by setting parser foundCharacters delegate. So it should look something like this:

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (!currentStringValue) {
    // currentStringValue is an NSMutableString instance variable
    currentStringValue = [[NSMutableString alloc] initWithCapacity:50] ; // +1
}

NSString *tempString = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([tempString length] > 0) {
    [currentStringValue appendString:tempString] ;
}

}

then in your parser didEndElement, you need to check the element name to match your desired tag. then save the currentStringValue:

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

if ( [elementName isEqualToString:@"id"]) {
    self.id = currentStringValue ;
}

if ( [elementName isEqualToString:@"name"]) {
    self.name = currentStringValue ;
}

}

what I normall do is put the foundCharacters in a class called baseModel.m. Then I have all my other models inherit from it. And each of the inheritance simply implement their own parser didEndElement method. In your case with Animals and Animal, I would also have two models, one with Animals and one with Animal, and in the Animals.m I would look for the tag Animal, then create an Animal object (like what you did there), but Then I would simply set the delegate to the newly created Animal object and let the Animal model handle it's own parsing. However, if you do that, you need to check for the end tags for each and set the delegate back to the parent.

tul697