Trouble Parsing XML and fetching data

117 views Asked by At

I have need to parse the following xml from webservicex.net, for and iPhone App. I need to store the verse Verse and BibleWords into some NSArray/NSDictionary or something.

<string xmlns="http://www.webserviceX.NET">
<NewDataSet>
  <Table>
    <Book>1</Book>
    <BookTitle>Genesis</BookTitle>
    <Chapter>1</Chapter>
    <Verse>1</Verse>
    <BibleWords>In the beginning God created the heaven and the earth.</BibleWords>
  </Table>
  <Table>
    <Book>1</Book>
    <BookTitle>Genesis</BookTitle>
    <Chapter>1</Chapter>
    <Verse>2</Verse>
    <BibleWords>And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.</BibleWords>
  </Table>
  <Table>
    <Book>1</Book>
    <BookTitle>Genesis</BookTitle>
    <Chapter>1</Chapter>
    <Verse>3</Verse>
    <BibleWords>And God said, Let there be light: and there was light.</BibleWords>
  </Table>
  <Table>
    <Book>1</Book>
    <BookTitle>Genesis</BookTitle>
    <Chapter>1</Chapter>
    <Verse>4</Verse>
    <BibleWords>And God saw the light, that it was good: and God divided the light from the darkness.</BibleWords>
  </Table>
</NewDataSet>
</string>

I wrote the following code for parsing the data.

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    if ([elementName isEqualToString:@"string"]) {
        model = [[Model alloc]init];        
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if(!currentElementValue) {
        currentElementValue = [[NSMutableString alloc]initWithString:string];
    }

    else {
        [currentElementValue appendString:string];
    }

    NSLog(@"%@", currentElementValue);
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ([elementName isEqualToString:@"NewDataSet"]) {
        return;
    }

    if ([elementName isEqualToString:@"Table"]) {
        [verses addObject:model];
        model = nil;
    }
    else {
        [model setValue:currentElementValue forKey:elementName]; //The exception break point hits here
    }    

    currentElementValue = nil;
}

The currentElementValue is displayed correctly. model is and object of a class named Model, currentElementValue is a NSMutableString object verses is an NSMutableArray. I am a beginner in objective C and haven't done parsing before. The problem is that the method:

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

is not working as expected. The app got broken after hitting the exception break point that i have commented in the code. How can I get the value of Verse and BibleWords and store it to some NSArray/NSMutableArray/NSDictionary/NSMutableDictionary. Please ask if there is anything else I need to mention to see where the problem actually lies.

EDIT:

Tried with this:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    captureCharacters = NO;
    [currentElementValue setString : @""];
    if ([elementName isEqualToString:@"Table"]) { //set a break point here as well. The elementName is string and hence is not entering any of the conditions in this delegate method. Hence captureCharacters is always set to NO and nothing is working.
        model = [[Model alloc]init];        
    }
    else if ([elementName isEqualToString:@"Verse"]) {
       capturingCharacters = yes;
    }

    else if ([elementName isEqualToString:@"BibleWords"]) {
       capturingCharacters = yes;
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if(capturingCharacters) {
        [currentElementValue appendString:string];
    }
 }

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ([elementName isEqualToString:@"Table"]) {
        [array addObject : model];
        model = nil;        
    }
    else if ([elementName isEqualToString:@"Verse"]) { //set a break point here
       model.Verse = currentElementValue; //not entering this condition
    }

    else if ([elementName isEqualToString:@"BibleWords"]) {
       model.BibleWords = currentElementValue; //not entering this condition
    }          
}

It is not working and I am getting null values for model.Verse and model.BibleWords. How does these methods work?

EDIT-2
Model Interface:

//model.h
@protocol HttpRequestHandler <NSObject>

- (void)returnFromSiteParsedData:(NSMutableArray *)parsedData;

@end

@interface Model : NSObject <NSURLConnectionDelegate, NSXMLParserDelegate>
{
    NSString *urlToLoad;
    NSMutableURLRequest *requestSiteToSendData;
    NSURLConnection *connectionToSiteToSendData;

    NSString *verseText;
    int verseNumber;

}
@property(nonatomic, retain) NSString *verseText;
@property(nonatomic, assign) int verseNumber;

- (void)loadSiteToSendDataWithChapterNumber:(int)chapterNumber AndBookNumber:(int)bookNumber;

@property(nonatomic, retain)id<HttpRequestHandler>httpRequestHandlerDelegate;

@end

Model Implementation

//model.m
@implementation Model

@synthesize verseNumber;
@synthesize verseText;

- (void)loadSiteToSendDataWithChapterNumber:(int)chapterNumber AndBookNumber:(int)bookNumber {

    urlToLoad = [[NSString alloc]initWithFormat:@"http://www.webservicex.net/BibleWebservice.asmx/GetBibleWordsByBookTitleAndChapter?BookTitle=Genesis&chapter=1"];
    requestSiteToSendData = [NSMutableURLRequest requestWithURL:[[NSURL alloc]initWithString:urlToLoad] cachePolicy:NSURLRequestReloadIgnoringCacheData  timeoutInterval:30];
    connectionToSiteToSendData = [[NSURLConnection alloc]initWithRequest:requestSiteToSendData delegate:self];    

}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {

    // Parse the XML into a dictionary
    NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
    VBSParser *vbsParser = [[VBSParser alloc]initVBSParser];
    [parser setDelegate:vbsParser];
    BOOL success = [parser parse];

    if (success) {
        NSMutableArray *verses = [vbsParser verses];
        NSLog(@"%@", verses);
        NSLog(@"Number: %d\n Text: %@", verseNumber,verseText);
        [self.httpRequestHandlerDelegate returnFromSiteParsedData:verses];
    }
    // Print the dictionary

}

@end

A delegate is used to return parsed data to the view controller.

1

There are 1 answers

0
Samkit Jain On

Make a BOOL capturingCharacters;

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    captureCharacters = NO;
    [currentElementValue setString : @""];
    if ([elementName isEqualToString:@"Table"]) {
        model = [[Model alloc]init];        
    }
    else if ([elementName isEqualToString:@"Verse"]) {
       capturingCharacters = yes;
    }

    else if ([elementName isEqualToString:@"BibleWords"]) {
       capturingCharacters = yes;
    }
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if(capturingCharacters) {
        [currentElementValue appendString:string];
    }
 }

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    if ([elementName isEqualToString:@"Table"]) {
        [array addObject : model];
        model = nil;        
    }
    else if ([elementName isEqualToString:@"Verse"]) {
       model.Verse = currentElementValue;
    }

    else if ([elementName isEqualToString:@"BibleWords"]) {
       model.BibleWords = currentElementValue;
    }          
}