Trouble Parsing XML and fetching data - objective-c

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.

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;
}
}

Related

How to parse an XML file, grabbing data from specific elements

so I have an XML file with data from a lot of instances of an object. I'm parsing this file, but only want the data with the element tag "Content"
I am using NSXMLParser, so I have the methods parserDidStartDocument, didStartElement, foundCharacters, and didEndElement
So here is my current implementation
In Header:
#property (strong) NSMutableArray* AssetJSONObjects;
In Implementation:
boo
l grabContent = NO;
- (void) parserDidStartDocument:(NSXMLParser *)parser {
NSLog(#"parserDidStartDocument");
self.AssetJSONObjects = [NSMutableArray new];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
NSLog(#"didStartElement --> %#", elementName);
if([elementName isEqual:#"Content"])
{
grabContent = YES;
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSLog(#"foundCharacters --> %#", string);
if(grabContent)
{
[self.AssetJSONObjects addObject:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(#"didEndElement --> %#", elementName);
if(grabContent)
{
grabContent = NO;
}
}
- (void) parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"parserDidEndDocument");
}
So here is my question: is the way that I'm declaring/initializing my array, AssetJSONObjects legitimate? Is the way I'm initializing my bool grabContent legitimate? Is there a better way to grab data from specific tags?
Went the cheap route, just kept track of a global boolean and set it if the tag was found
relevant code:
BOOL grabContent = NO;
- (void) parserDidStartDocument:(NSXMLParser *)parser {
self.AssetJSONObjects = [NSMutableArray new];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if([elementName isEqual:#"Content"])
{
grabContent = YES;
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(grabContent)
{
NSDictionary *JSONObject =
[NSJSONSerialization JSONObjectWithData: [string dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: nil];
if (JSONObject)
{
[self.AssetJSONObjects addObject:JSONObject];
}
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if(grabContent)
{
grabContent = NO;
}
}
- (void) parserDidEndDocument:(NSXMLParser *)parser {
self.notifications = [self convertRawJSONToNotifications:self.AssetJSONObjects];
if(self.notifications != nil)
{
self.notificationCompletionHandler(self.notifications, self.numNewNotifications);
}
}

Parsing an xml response using NSXml

I trying to parse an xml that has one root element with 2 child elements with the same name. However they keep getting concatenated together. How can i fix this? here is my code so far
-
(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
element = elementName;
if([element isEqualToString:#"bustime-response"]){
self.item = [[NSMutableDictionary alloc]init];
self.direction =[[NSMutableString alloc]init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([element isEqualToString:#"dir"]){
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[self.direction appendString:string];
}
}
Try this it works for me:
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
element = elementName;
if ([element isEqualToString:#"bustime-response"])
{
elementFound = YES;
if (self.item)
self.item = nil;
self.item = [[NSMutableDictionary alloc]init];
if (self.direction)
self.direction = nil;
self.direction =[[NSMutableString alloc]init];
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (elementFound)
{
if ([element isEqualToString:#"dir"]){
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[self.direction appendString:string];
}
//Add another if with the tag you want to retrieve the data from here
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([element isEqualToString:#"bustime-response"])
{
elementFound = NO;
// self.receivedDataArray - main array to store all of your dictionary
[self.receivedDataArray addObject: self.direction];
[self.receivedDataArray addObject: self.item];
self.direction = nil;
self.item = nil;
}
}
As you see you have to add another BOOL variable elementFound and NSMutableArray receivedDataArray for storing all of the data. Give it a go and let me know is it work for you. Remember it's good to add NSLogs for debugging, it helps a lot.

NSXMLParser can not parse special characters (german & french)

I am working on an App, which makes a search on a private server and shows the results to the user. The problem is NSXLParser can not parse the special german and french characters. For example: it should be:(Geschäftsführer) -> what i get is: (äftsführer)
How can i fix this ?
here is my code:
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"results"])
{
currentJob = [SearchResult alloc];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"jobTitle"])
{
currentJob.jobTitle = currentNodeContent;
}
if ([elementname isEqualToString:#"location"])
{
currentJob.shortAddress = currentNodeContent;
}
if ([elementname isEqualToString:#"companyName"])
{
currentJob.employer = currentNodeContent;
}
if ([elementname isEqualToString:#"results"])
{
[self.jobs addObject:currentJob];
currentJob = nil;
currentNodeContent = nil;
}
}
Any help would be much appreciated...
Thanks in advance
Your foundCharacters method should append the string to a NSMutableString object, because it can be called multiple times for a single value. In didStartElement, initialize a NSMutableString object (let's call it elementContentString), then do this:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)chars
{
[self.elementContentString appendString:chars];
}
And in your didEndElement you can get the content as a string. Note that you should make a non-mutable copy of it (so you don't overwrite it with the next element), using [NSString stringWithString:self.elementContentString].

NSXMLParser can not get the content of elements correctly

i have the following XMLParser but when i try to run it, it doesn't work properly.
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"results"])
{
currentJob = [SearchResult alloc];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"jobTitle"])
{
currentJob.jobTitle = currentNodeContent;
}
if ([elementname isEqualToString:#"location"])
{
currentJob.shortAddress = currentNodeContent;
}
if ([elementname isEqualToString:#"companyName"])
{
currentJob.employer = currentNodeContent;
}
if ([elementname isEqualToString:#"results"])
{
[self.jobs addObject:currentJob];
currentJob = nil;
currentNodeContent = nil;
}
}
AND here is my foundCharakter Method:
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
The output doesn't start from the beginning, it starts from the middle of the String...
I just can not understand, why some results look nice where some others don't.
What am i doing wrong ? How can i parse an xml properly ?
Any help will be appreciated.
Thx in advance
I used the following code and works now:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if(!elementContentString)
elementContentString = [[NSMutableString alloc] initWithString:string];
else
[elementContentString appendString:string];
}
I don't think there any problem in your code, it is working fine at my end. I am using the twitter api for getting xml and it is giving me proper output.

How to read the content of an XML tag

How to read the content of this XML?
<Locations>
<Location>4</Location>
</Locations>
I can parse it, and it works, but I can't access the value of Location (4). I'm using:
ZoneCheck *azone;
NSString *url1 = [NSString stringWithFormat:#"%#", azone.location];
I have already posted the answer please follow the following link 'https://stackoverflow.com/questions/10877374/how-to-parse-the-attributes-like-in-this-xml-file-through-xml-parser/10877758#10877758'
First take a bool variable. and then write the following code. perhaps it will help you I have done the related work , a few days ago.
First .h file
#interface EventsViewController : UIViewController <NSXMLParserDelegate>
{
NSMutableArray *_locationArray;
BOOL isLocation;
}
Then in .m file you should write this.
//In ViewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
_locationArray = [[NSMutableArray alloc] init];
NSURL * fileURL = [NSURL fileURLWithPath:xmlString];
NSXMLParser * parser = [[NSXMLParser alloc] initWithContentsOfURL:fileURL];
[parser setDelegate:self];
[parser parse];
}
// Now In xml Parser Delegate Methods
pragma mark - NSXMLParser Delegate Method
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if ([elementName isEqualToString:#"Locations"]) {
isLocation = YES;
}
else if ([elementName isEqualToString:#"Location"] && isLocation){
NSLog(#"Location is: %# ",elementName);
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([elementName isEqualToString:#"Location"] && isLocation){
NSLog(#"Location is: %# ",string);
[locationArray addObject:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"Location"]) {
isLocation=NO;
}
}
Note: At the end _locationArray will be having all the location's id's.