How to load XML file data into a UITableView? - objective-c

I am retrieving an XML document from a server and would like to display it in a UITableView in my application. I have the following code so far:
#implementation textxmlViewController
#synthesize tableviews;
-(void)viewDidLoad{
[super viewDidLoad];
NSURL *url = [[NSURL alloc] initWithString:#"http://theserver.com/demo.xml"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[xmlParser setDelegate:self];
BOOL success = [xmlParser parse];
if(success)
NSLog(#"success");
else
NSLog(#"Error");
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSLog(string);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if (qName) {
elementName = qName;
}
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
if (qName) {
elementName = qName;
}
if ([elementName isEqualToString:#"text"]) {
}
}
I already have a UITableView in this view, my question is how can I display the XML's content in the table view?
My XML data looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Answers>
<Answer>
<Result>it's good</Result>
<Evaluate>can you tell me why?</Evaluate>
</Answer>
<Answer>
<Result>about 5 hours</Result>
<Evaluate>it's too long</Evaluate>
</Answer>
</Answers>
So how can I do it? Thanks

I would recommend to use another XML parser instead of using NSXMLParser.
Ray Wenderlich wrote a good article about the different XML parsing possibilities on the iPhone(iOS): http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project
I think it'd be easier for you using a DOM based XML parser. you could use the indexPath to get the data right out of the parsed xmlData.
For example: if your using GDataXML you just need to call the method
+ (GDataXMLElement *)elementsWithName:(NSString *)name;
with name = 'Answers' which returns the Node for all the answer.
on this GDataXMLElement call the method
- (NSArray *)elementsForName:(NSString *)name;
with name = 'Answer' which gives you all the answers as a NSArray.
You can use this array as datasource for you UITableView by returning numberOfRowsInSection with [answersArray count]. And in the cellForIndexPath method get the GDataXMLElement for the answer by calling
GDataXMLElement * answerElement = [answersArray objectAtIndex: indexPath.row];
Just parse the answerElement for the elements 'name' and 'value' to show the data in your UITableView.

It depends on how you want the info to be displayed. At least you should implement cellForRowAtIndexPath: to return the UITableViewCell to be displayed.
According to your XML structure, you can have cells for answers, each having two UITextFields to display the result and evaluate.
Please take a look at http://adeem.me/blog/2009/05/19/iphone-programming-tutorial-part-1-uitableview-using-nsarray/ for a tutorial.

Related

I Got the XML data ,Now how I can save the XML Data in Objective C?

As an New to the iOS Development in Xcode 7.
Below I have some questions please clarify my doubt.
I need to Store the XML Data from an URL
And Split the XML data each line and store it in the Objective C.
<?xml version="1.0" encoding="UTF-8"?>
<NewDataSet>
<tbl>
<Es_Id>8e268283-e87e-4abc-aab9-07cb611a8e60</Es_Id>
<EstablishmentType>40640054-2221-4086-92e4-4440497ccea2</EstablishmentType>
<EstablishmentName>La Parrilla Colombian Steakhouse & Bar</EstablishmentName>
<BusinessName>La Parrilla Colombian Steakhouse & Bar</BusinessName>
<OpenTime>PT8H31M</OpenTime>
<ClosingTime>PT18H50M</ClosingTime>
<Floor>12 th floor</Floor>
</tbl>
</NewDataSet>
When I start learning XML parsing it has basic steps.I implement all for you.
In ViewController.h
Step 1 : Add the Delegate classes
First you have to add <NSXMLParserDelegate>
Step 2 : Create necessary objects
NSXMLParser *parser;
NSMutableData *ReceviedData;
NSMutableString *currentStringValue;
NSMutableArray *arrayID;
Now it looks like
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<NSXMLParserDelegate>
{
NSXMLParser *parser;
NSMutableData *ReceviedData;
NSMutableString *currentStringValue;
NSMutableArray *arrayID;
}
#end
Then in ViewController.m
Step 3 - Allocate your Array in your viewDidLoad method
arrayID = [[NSMutableArray alloc]init];
Step 4 - Create Connection in your viewDidLoad Like
[self createConnection:#"http://www.google.com"]; //give your valid url.
Now the viewDidLoad method is
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
arrayID = [[NSMutableArray alloc]init];
[self createConnection:#"http://www.google.com"]; //give your valid url.
}
createConnection method is
-(void)createConnection:(NSString *)urlString
{
NSURL *url = [NSURL URLWithString:urlString];
// Step 5 - parser delegate methods are using NSURLConnectionDelegate class or not.
BOOL success;
if (!parser)
{
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
parser.delegate = self;
parser.shouldResolveExternalEntities = YES;
success = [parser parse];
NSLog(#"Success : %c",success);
}
}
STEP 6 - NSXMLParserDlegate Methods are below
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"Current Element Name : %#",elementName);
if ([elementName isEqualToString:#"ID"]) //according to your xml response your id is Es_Id.So you need to compare #"Es_Id"
{
NSLog(#"The Result is==%#",elementName);
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentStringValue = [[NSMutableString alloc] initWithString:string];
NSLog(#"Current String Value : %#",currentStringValue);
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"ID"]) //according to your xml response your id is Es_Id.So you need to compare #"Es_Id"
{
[arrayResult addObject:currentStringValue];
}
currentStringValue = nil;
}
From above code I check ID only.According to your response you need to compare other keys like EstablishmentType,EstablishmentName,BusinessName,OpenTime.......

iPhone app crashes when empty node is parsed

I'm trying to parse an xml and the app crashes if there is an empty node in the xml feed.
What may be the reason for this?
EDIT
my xml looks like this
<Sponsors>
<Sponsor>
<Name>name...</Name>
<About>blah...blah...blah</About>
<Website>http://test.com</Website>
<LogoImage>someImage.jpg</LogoImage>
<smallIcon>someImage.jpg</smallIcon>
<Area/>
<BannerImage/>//->>>this node is empty//
</Sponsor>
</Sponsors>
I'm using NSXML Parser like this.
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(nil != self.currentsponsorElement){
[self.currentsponsorElement appendString:string];
}
}
Try This:-
inside didStartElement use this code:-
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementName isEqualToString:#"Sponsor"])
{
if(!soapResults)
{
soapResults = [[NSMutableString alloc] init]; //declared in .h
}
recordResults = YES;
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSMutableString *)string {
if (string != nil) {
[results setString:#""];
[results appendString: string];
NSLog(#"foundResults: %#",results);
}
}
Without looking at your code, I can only give you a general answer - it sounds like your code is "expecting" a value in the "parser:foundCharacters:" method. Go over your code and see what happens when the characters found are in fact nil. Use try-catch blocks and handle all possible scenarios so your code doen't cause crashes as a result of other things you still haven't thought of.

How to strip the string to get the URL in the HTML <img>?

I am writing a RSS project on iPhone. I wonder how I can strip everything inside this tag just to get the image URL:
<description><![CDATA[ <img src="http://vnexpress.net/Files/Subject/3b/bd/67/91/Lat-xe-xang-2.jpg">Trưa 7/5, chiếc xe bồn chở 25.000 lít xăng từ Hà Tĩnh vào Quảng Bình bị lật nghiêng trên quốc lộ 1A khiến xăng chảy lênh láng ra đường. ]]></description>
I just want to get the string
http://vnexpress.net/Files/Subject/3b/bd/67/91/Lat-xe-xang-2.jpg
Please show me how to do it in this case?
I recommend NSXMLParser.
See here: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSXMLParser_Class/Reference/Reference.html
use this method...
- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
}
hoping this helps..
Edit:
Oh, #Ankit Srivastava answer is right. I didn't catch that is a CDATA block. Follow his answer, but I don't delete mine, couse this still can be useful to you.
You should implement NSXMLParser delegate. In your .h file <NSXMLParserDelegate>
And then you have to put 3 useful method in your m file.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (element == nil) // where element is a NSMutableString
element = [[NSMutableString alloc] init];
[element appendString:string];
}
That doesn't matte rif you have or it will always call didStart end didEnd.
Now we have ex: :
elementName //contains your tag name. In this case "mytag"
element // contains text beetween tags. In this case null. But in <mytag>something</mytag> element = something.
attributeDict //This is probably most important to you. That contains NSDictionary with all your parameters. In above example this is a dictionary with key: myparam and object: test

iOS: Parsing a xml from HTTP using NSXMLParser for

It's first time using NSXMLParser and wondering if you give me some direction of parsing the returned xml from an http request that looks like:
<?xml version="1.0" ?>
<theresponse>
<status>OK</status>
<pricing currency="USD" symbol="$">
<price class="items">24.00</price>
<price class="shipping">6.00</price>
<price class="tax">1.57</price>
</pricing>
</theresponse>
I know the basic of parsing delegate methods, I just want to know what the code would look like in didEndElement/foundCharacters/didStartElement for retreiving above items(currency/items/shipping/tax)? any help greatly appreciated.
This is a little more tricky than some standard NSXMLParser code; Because essentially when you are looking for the "shipping" you want "6.00" but those two pieces of data are returned to you in different delegate methods, which is normal. But usually the element would be named "shipping" so in parser:didEndElement:namespaceURI:qualifiedName: you would automatically have the element name as it was passed into the method.
The solution would seem simple, have a _currentAttributes ivar and in parser:didStartElement:namespaceURI:qualifiedName:attributes: do something like _currentAttributes = attributeDict; and then handle this in the didEndElement: method. However this style would easily break, even on this moderately simple XML.
My way of handling this would be to store the attributes dictionary passed into the didStartElement: and set it in a dictionary as the object for the key of the element name. Combining this style with the standard use of an NSMutableString as a characterBuffer of sorts allows you to put all of your logic into the didEndElement: method.
Side note: I am also quite fond of having my NSXMLParserDelegate classes be NSXMLParser subclasses, as this one is. However the delegate methods would be identical if it were not.
ItemParser.h
#import <Foundation/Foundation.h>
#interface ItemParser : NSXMLParser <NSXMLParserDelegate>
#property (readonly) NSDictionary *itemData;
#end
ItemParser.m
#import "ItemParser.h"
#implementation ItemParser {
NSMutableDictionary *_itemData;
NSMutableDictionary *_attributesByElement;
NSMutableString *_elementString;
}
-(NSDictionary *)itemData{
return [_itemData copy];
}
-(void)parserDidStartDocument:(NSXMLParser *)parser{
_itemData = [[NSMutableDictionary alloc] init];
_attributesByElement = [[NSMutableDictionary alloc] init];
_elementString = [[NSMutableString alloc] init];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
// Save the attributes for later.
if (attributeDict) [_attributesByElement setObject:attributeDict forKey:elementName];
// Make sure the elementString is blank and ready to find characters
[_elementString setString:#""];
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
// Save foundCharacters for later
[_elementString appendString:string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"status"]){
// Element status only contains a string i.e. "OK"
// Simply set a copy of the element value string in the itemData dictionary
[_itemData setObject:[_elementString copy] forKey:elementName];
} else if ([elementName isEqualToString:#"pricing"]) {
// Pricing has an interesting attributes dictionary
// So copy the entries to the item data
NSDictionary *attributes = [_attributesByElement objectForKey:#"pricing"];
[_itemData addEntriesFromDictionary:attributes];
} else if ([elementName isEqualToString:#"price"]) {
// The element price occurs multiple times.
// The meaningful designation occurs in the "class" attribute.
NSString *class = [[_attributesByElement objectForKey:elementName] objectForKey:#"class"];
if (class) [_itemData setObject:[_elementString copy] forKey:class];
}
[_attributesByElement removeObjectForKey:elementName];
[_elementString setString:#""];
}
-(void)parserDidEndDocument:(NSXMLParser *)parser{
_attributesByElement = nil;
_elementString = nil;
}
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSLog(#"%# with error %#",NSStringFromSelector(_cmd),parseError.localizedDescription);
}
-(BOOL)parse{
self.delegate = self;
return [super parse];
}
#end
And so to test I stored the XML you posted above into a file named "ItemXML.xml". And tested it using this code:
NSURL *url = [[NSBundle mainBundle] URLForResource:#"ItemXML" withExtension:#"xml"];
ItemParser *parser = [[ItemParser alloc] initWithContentsOfURL:url];
[parser parse];
NSLog(#"%#",parser.itemData);
The result I got was:
{
currency = USD;
items = "24.00";
shipping = "6.00";
status = OK;
symbol = "$";
tax = "1.57";
}

NSMutableString issue with NSXMLParser

I am having a heck of a time with this -- I am trying to parse an XML file and set the text in a NSMutableString variable in order to later fill in a label's text as you can see below.
In my .h I have the following (simplified);
NSMutableString *contentsOfCurrentXMLProperty;
#property (nonatomic,retain) NSMutableString *contentsOfCurrentXMLProperty;
In my .m:
-(void) parseData {
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:myData];
[parser setDelegate:self];
[parser parse];
[parser release];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:#"Title"]) {
NSLog(#"FOUND TITLE!");
contentsOfCurrentXMLProperty = [NSMutableString setString:#""];
}
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"TITLE"]) {
myLabel.text = [contentsOfCurrentXMLProperty stringByReplacingOccurrencesOfString:#"[br]" withString:#"\n"];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
[self.contentsOfCurrentXMLProperty appendString:string];
}
When I run my app, the data is downloaded and parsed correctly. I run into issues when my observer fires off the event again. The parseData method is called and I get an error that I have traced to the line that reads: "contentsOfCurrentXMLProperty = [NSMutableString setString:#""];
"
What is the proper way to create or init a NSMutableString variable for me to use over and over? When/Where is the best place to release it? How do I essentially clear the variable so that when the observer fires off the parseData method it will again be able to set "contentsOfCurrentXMLProperty"?
-setString: is an instance method, not a class method. If you already have a valid NSMutableString object assigned to contentsOfCurrentXMLProperty and simply want to clear it, then:
contentsOfCurrentXMLProperty = [NSMutableString setString:#""];
should be
[contentsOfCurrentXMLProperty setString:#""];
On the other hand, if you want to assign a new object to contentsOfCurrentXMLProperty, here's one valid way to do it:
self.contentsOfCurrentXMLProperty = [NSMutableString stringWithCapacity:0];