Parsing XML File in Objective-C - ios

I have xml file which I have to parse it. I'm following a youtube tutorials for it. I'm showing the parsed data from tags in a table view controller, But when i run the app no data is shown there, the table view controller is just empty. My code for parsing the file is this,
#import "QuestionParser.h"
#import "Question.h"
#interface QuestionParser()
#property NSXMLParser *parser;
#property NSString *element;
#property NSString *currentxref;
#property NSString *currenttext;
#property NSString *currentprompt;
#property NSString *currentexplanation;
#property NSString *currenttext1;
-(id)initWithArray:(NSMutableArray *)questionArray{
self = [super init];
if (self) {
self.questionArray = questionArray;
}
return self;
}
-(void)parseFile{
NSURL *url= [[NSBundle mainBundle]URLForResource:#"test" withExtension:#"xml"];
self.parser = [[NSXMLParser alloc]initWithContentsOfURL:url];
self.parser.delegate=self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
self.element = elementName;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([self.element isEqualToString:#"xref"]) {
self.currentxref = string;
}
else if ([self.element isEqualToString:#"text"]){
self.currenttext = string;
}
else if ([self.element isEqualToString:#"prompt"]){
self.currentprompt = string;
}
else if ([self.element isEqualToString:#"explanation"]){
self.currentexplanation = string;
}
else if ([self.element isEqualToString:#"text"]){
self.currenttext1 = string;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"question"]) {
Question *ques= [[Question alloc]initWithName:_currentxref text:_currenttext prompt:_currentprompt explanation:_currentexplanation text1:_currenttext1];
[self.questionArray addObject:ques];
}
self.element = nil;
}
This is how I'm loading data in datasource,
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.questionArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
Question *ques=self.questionArray[indexPath.row];
cell.textLabel.text=ques.xref;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",ques.prompt];
return cell;
}
My xml file is this,

This method will execute after complete XML parsing. In this method reload the table view data.
-(void)parserDidEndDocument:(NSXMLParser *)parser{
// When the parsing has been finished then simply reload the table view.
[self.tableView reloadData];
}
If you want anything please follow this tutorial: https://www.appcoda.com/parse-xml-and-json-web-service/

Related

UITableView not display contents

I am trying to populate a UITableView in my viewcontroller (it is a delegate of UITableView)
The code below is something I've found online. I've made some changes so that I didn't need a UITableViewController in order to use it. However since I changed it, I am unable to figure out how to get the text to print in the cells. Before changing the code to allow my ViewcController subclass to be a delegate of UITableView. Could anyone point me in the right direction?
I have checked and the XML is parsing correctly. When the code reaches the if (marrXMLData.count != 0) in the startParsing method, marrXMLData is greater than 0 (8 being specific, the correct and total number of items in my XML)
code is from: http://www.theappguruz.com/blog/xmlparsing-with-nsxmlparser-tutorial
.m is below
DisplayTableViewController
#synthesize marrXMLData;
#synthesize mstrXMLString;
#synthesize mdictXMLPart;
- (void)viewDidLoad{
[super viewDidLoad];
[self startParsing];
}
- (void)startParsing{
NSData *fileData = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"file.xml"]];
NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithData:fileData];
[xmlparser setDelegate:self];
[xmlparser parse];
if (marrXMLData.count != 0) {
[self.myUITableView reloadData];
}
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;{
if([elementName isEqualToString:#"Content"])
marrXMLData = [[NSMutableArray alloc] init];
if([elementName isEqualToString:#"item"])
mdictXMLPart = [[NSMutableDictionary alloc] init];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;{
if(!mstrXMLString)
mstrXMLString = [[NSMutableString alloc] initWithString:string];
else
[mstrXMLString appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;{
if([elementName isEqualToString:#"title"] || [elementName isEqualToString:#"url"]){
[mdictXMLPart setObject:mstrXMLString forKey:elementName];
}
if([elementName isEqualToString:#"item"])
[marrXMLData addObject:mdictXMLPart];
mstrXMLString = nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section{
return [marrXMLData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.textLabel.text = [[[marrXMLData objectAtIndex:indexPath.row] valueForKey:#"title"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cell.detailTextLabel.text = [[[marrXMLData objectAtIndex:indexPath.row] valueForKey:#"url"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return cell;
}
#end
EDIT:
After playing with it some more this method is not being called
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
In the example code it is being called, but I'm not sure where. (Sorry, I am very new to iOS)
It sounds like your table view's delegate and/or dataSource links are not connected. If you set up the table view scene in IB (Interface Builder) then you just control-drag from the table view onto the view controller.

How to store value in array with dictionary for soap web service ios

Here NsmutableString=textInProgress, count1 is counter managed.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(#"%d",count1);
// Build the text value
[textInProgress appendString:string];
NSLog(#"%#",textInProgress);
NSLog(#"%d",count1);
count1=count1+1;
}
Please, someone guide me how to store this string value in array?.
And here when i print textInProgress in log, It return null value.
Some portion Of Output:-
2016-02-26 03:29:50.047 Hello_SOAP[3684:118829] 0
2016-02-26 03:29:50.047 Hello_SOAP[3684:118829] (null)
2016-02-26 03:29:50.047 Hello_SOAP[3684:118829] 0
2016-02-26 03:29:50.047 Hello_SOAP[3684:118829] 2
2016-02-26 03:29:50.047 Hello_SOAP[3684:118829] (null)
2016-02-26 03:29:50.047 Hello_SOAP[3684:118829] 2
Instead of this method in any other method i have not make increments of count1 variable
u have create nsobject file of parser
parser.h
#import <Foundation/Foundation.h>
#import "BookDetail.h"
#import "AppDelegate.h"
#interface Parser : NSObject<NSXMLParserDelegate>
{
AppDelegate *app;
NSMutableString *character;
BookDetail *book;
NSString *tempAuthorName;
NSMutableArray *booksArray;
}
-(Parser *)initParser;
#property(strong,nonatomic)NSString *tempAuthorName;
#property (nonatomic,retain) NSMutableArray *booksArray;
#end
now parser.m
#import "Parser.h"
#import "ViewController.h"
#import "DisplayInfoViewController.h"
#implementation Parser
#synthesize booksArray,tempAuthorName;
-(Parser *)initParser
{
self = [super init];
return self;
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if([elementName isEqualToString:#"books"])
{
booksArray = [[NSMutableArray alloc]init];
}
else if ([elementName isEqualToString:#"book"])
{
book = [[BookDetail alloc]init];
}
}
-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (!character)
character=[[NSMutableString alloc] initWithString:string];
else
[character appendString:string];
}
-(void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"isbn"])
{
book.isbn = character;
}
else if ([elementName isEqualToString:#"title"])
{
book.title = character;
}
else if ([elementName isEqualToString:#"author"])
{
book.author = character;
}
else if ([elementName isEqualToString:#"publisher"])
{
book.publisher = character;
}
else if ([elementName isEqualToString:#"amazon_price"])
{
book.amazon_price = character;
}
else if ([elementName isEqualToString:#"book"])
{
[booksArray addObject:book];
}
character = nil;
}
#end
xml file
<?xml version="1.0"?>
<books>
<book>
<isbn>1594489501</isbn>
<title>A Thousand Splendid Suns</title>
<author>Romio</author>
<publisher>Riverhead Hardcover</publisher>
<amazon_price>14.27</amazon_price>
</book>
<book>
<isbn>1594489587</isbn>
<title>The Brief Wondrous Life of Oscar Wao</title>
<author>Junot Diaz</author>
<publisher>Riverhead Hardcover</publisher>
<amazon_price>14.97</amazon_price>
</book>
<book>
<isbn>0545010221</isbn>
<title>Harry Potter and the Deathly Hallows</title>
<author>J. K. Rowling</author>
<publisher>Arthur A. Levine Books</publisher>
<amazon_price>19.24</amazon_price>
</book>
</books>
BookDetail is another nsobject class which help to handling the data
BookDetail.h
#import <Foundation/Foundation.h>
#interface BookDetail : NSObject
#property(nonatomic,retain)NSString *isbn;
#property(nonatomic,retain)NSString *title;
#property(nonatomic,retain)NSString *author;
#property(nonatomic,retain)NSString *publisher;
#property(nonatomic,retain)NSString *amazon_price;
#end
.m
#import "BookDetail.h"
#implementation BookDetail
#synthesize isbn,title,author,publisher,amazon_price;
#end
For getting data on table cell click may it will help you..
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"simpleIdentifier";
TableViewCell *cell = [tableView1 dequeueReusableCellWithIdentifier:identifier];
if(cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
BookDetail *ss=[parse.booksArray objectAtIndex:indexPath.row];
cell.bookName.text=ss.author;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DisplayInfoViewController *displayinfoViewController=[[DisplayInfoViewController alloc] initWithNibName:#"DisplayInfoViewController" bundle:nil];
BookDetail *ss=[parse.booksArray objectAtIndex:indexPath.row];
displayinfoViewController.isbnValue=ss.isbn;
displayinfoViewController.titleValue=ss.title;
displayinfoViewController.amazonValue=ss.amazon_price;
displayinfoViewController.authorValue=ss.author;
displayinfoViewController.publisherValue=ss.publisher;
[self.navigationController pushViewController:displayinfoViewController animated:YES];
}

NSXMLParser foundCharacters Thread 1: EXC_BAD_ACCESS (code=2, address=0x0)

I am trying to implement an rss reader into a table inside a container. I have the code of the parser in an other project and in the specific project it works fine without any error. I copied every file, 4 files exactly as they are in the other project and i copied also the view controllers into my storyboard so they are exactly the same. But when i run the code i get an error!
here is a pic with my error.
I don't know why is this happening. In the other project which has only two view controllers with the table view and the web view it works fine. But when i try to copy every file as it is into my other project I get this error.
This is my .m file
#import "APPMasterViewController.h"
#import "APPDetailViewController.h"
#interface APPMasterViewController () {
NSXMLParser *parser;
NSMutableArray *feeds;
NSMutableDictionary *item;
NSMutableString *title;
NSMutableString *link;
NSString *element;
}
#end
#implementation APPMasterViewController
(void)awakeFromNib {
[super awakeFromNib];
}
- (void)viewDidLoad {
[super viewDidLoad];
feeds = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:#"http://radioevros.gr/feed/"];
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[parser setDelegate:self];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return feeds.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = [[feeds objectAtIndex:indexPath.row] objectForKey: #"title"];
return cell;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
element = elementName;
if ([element isEqualToString:#"item"]) {
item = [[NSMutableDictionary alloc] init];
title = [[NSMutableString alloc] init];
link = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"item"]) {
[item setObject:title forKey:#"title"];
[item setObject:link forKey:#"link"];
[feeds addObject:[item copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if ([element isEqualToString:#"title"]) {
[title appendString:string];
} else if ([element isEqualToString:#"link"]) {
[link appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[self.tableView reloadData];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSString *string = [feeds[indexPath.row] objectForKey: #"link"];
[[segue destinationViewController] setUrl:string];
}
}
-(void) viewDidUnload{
[element release];
element = nil;
[super viewDidUnload];
}
- (void)dealloc {
[element release];
[super dealloc];
}
#end
I can't say for certain since I haven't tried running your code, but you may want to try to store element using element = [elementName copy]; instead and see if that gets rid of the exception.
My guess is that elementName gets deallocated after you exit the method since it is only a local parameter variable.
As a side note, it appears that you are doing manual memory management. I highly suggest that you convert your project to use ARC since it not only streamlines memory management, it is also what Apple has been recommending to use for quite a while now.

Where is my mistake in my code for display on tableview?

I tried load an array from web service and display on table view.This my tableview.But there is a mistake.Branchnames are
MEHMET FUDAYLÖZCAN,
SELAHATTİN KOÇAK,
Mehmet Süner Eken Petrol
Hasan Katkıcı Petrol
etc
etc
but table view show me like that
How I fix this ?
Th
Array Codes :
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict
{
if ( [elementName isEqualToString:#"Branchname"] )
{
teveRetorno = YES;
}
else if ( [elementName isEqualToString:#"GetBranchNameResult"] )
{
myArray = [[NSMutableArray alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if (teveRetorno) {
//[retornoSOAP appendString:string];
[myArray addObject:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ( [elementName isEqualToString:#"Branchname"] ) {
NSLog(#"My Array %#",myArray);
[[self tableView]reloadData];
//retornoSOAP = nil;
teveRetorno = NO;
}
}
Table Codes
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
#warning Incomplete method implementation.
// Return the number of rows in the section.
return [self.myArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text =[myArray objectAtIndex:indexPath.row];
return cell;
}
There is nothing wrong with your table view or output. Your XMLParser is getting confused by certain characters (Ö) and calling didStartElement too early. Check out this - NSXMLParser divides strings containing foreign(unicode) characters
If your asking about the reason the text is getting cut off, set adjustsFontSizeToFitWidth for the textLabel of the cell. If that dosent fix it, then manually lower the font of the textLabel.

iOS XML Parsing, display results on table view and pushing to a new tableview

The goal of my application is to parse some XML, display one element of the xml in a tableview and then have the user click on the cell, and it pushes to a new table view where the rest of the data for that element is displayed. The first table view that displays only the list works fine, but for some reason I can't get the push to a new view controller to work. Below is the code I am using. The first view controller displays in a table view; currentCallType. I wan the user to be be able to click on that table cell, then push to a new table view where it displays the units, station and location. Any help would be AWESOME! thanks.
View controller for first tableview:
#import "ThirdViewController.h"
#import "UnitsXMLParser.h"
#import "DetailViewController"
#implementation ThirdViewController
#synthesize unitsTableView;
#synthesize currentCallType, station, location, units;
XMLParser1 *xmlParser;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[xmlParser units] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
Units *currentCall = [[xmlParser units] objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Set up the cell...
cell.textLabel.text = [currentCall currentCallType];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 55;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detail = [self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
[self.navigationController pushViewController:detail animated:YES];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
xmlParser = [[XMLParser1 alloc] loadXMLByURL:#"http://localhost:8888/units.xml"];
}
XML Parser:
#import <Foundation/Foundation.h>
#import "UnitsXMLParser.h"
#implementation XMLParser1
#synthesize units = _units;
NSMutableString *currentNodeContent;
NSXMLParser *parser;
Units *currentCall;
bool isStatus;
-(id) loadXMLByURL:(NSString *)urlString
{
_units = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByReplacingOccurrencesOfString:#"~" withString:#""];
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"station"])
{
currentCall = [Units alloc];
isStatus = YES;
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if (isStatus)
{
if ([elementname isEqualToString:#"units"])
{
currentCall.units = currentNodeContent;
}
if ([elementname isEqualToString:#"name"])
{
currentCall.currentCallType = currentNodeContent;
}
if ([elementname isEqualToString:#"stationid"])
{
currentCall.station = currentNodeContent;
}
if ([elementname isEqualToString:#"address"])
{
currentCall.location = currentNodeContent;
}
}
if ([elementname isEqualToString:#"station"])
{
[self.units addObject:currentCall];
currentCall = nil;
currentNodeContent = nil;
}
}
#end
A longshot; but do you have your project configured to use a UINavigationController ? Your view controllers will not be contained in / managed by a UINavigationController unless you start with the correct project template or manually add the UINavigationController . If the view controller containing your posted code is not backed by a navigation controller, [self.navigationController pushViewController:detail animated:YES] will do nothing.
Also, make sure that you have hooked up your UITableViewDelegate in addition to your UITableViewDataSource , so that your code will catch the row selection.
I only ask because you do not explicitly state that you have set up your project to use a UINavigationController or confirm that you have hooked up both the delegate and datasource in Interface Builder.

Resources