XML Parsing in Cocoa Touch/iPhone - iphone

Okay i have seen TouchXML, parseXML, NSXMLDocument, NSXMLParser but i am really confused with what to to do.
I have an iphone app which connects to a servers, requests data and gets XML response. Sample xml response to different set of queries is give at http://pastebin.com/f681c4b04
I have another classes which acts as Controller (As in MVC, to do the logic of fetch the data). This class gets the input from the View classes and processes it e.g. send a request to the webserver, gets xml, parses xml, populates its variables (its a singleton/shared Classes), and then responses as true or false to the caller. Caller, based on response given by the controller class, checks controller's variables and shows appropriate contents to the user.
I have the following Controller Class variables:
#interface backendController : NSObject {
NSMutableDictionary *searchResults, *plantInfoResults, *bookmarkList, *userLoginResult;
}
and functions like getBookmarkList, getPlantInfo. Right now i am printing plain XML return by the webserver by
NSLog(#"Result: :%#" [NSString stringWithContentsOfURL:url])
I want a generic function which gets the XML returned from the server, parseses it, makes a NSMutableDictionary of it containing XML opening tags' text representation as Keys and XML Tag Values as Values and return that.
Only one question, how to do that?.

Have you tried any of the XML Parsers you mentioned? This is how they set the key value of a node name:
[aBook setValue:currentElementValue forKey:elementName];
P.S. Double check your XML though, seems you are missing a root node on some of your results. Unless you left it out for simplicity.
Take a look at w3schools XML tutorial, it should point you in the right direction for XML syntax.

Consider the following code snippet, that uses libxml2, Matt Gallagher's libxml2 wrappers and Ben Copsey's ASIHTTPRequest to parse an HTTP document.
To parse XML, use PerformXMLXPathQuery instead of the PerformHTTPXPathQuery I use in my example.
The nodes instance of type NSArray * will contain NSDictionary * objects that you can parse recursively to get the data you want.
Or, if you know the scheme of your XML document, you can write an XPath query to get you to a nodeContent or nodeAttribute value directly.
ASIHTTPRequest *request = [ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:#"http://stackoverflow.com/"];
[request start];
NSError *error = [request error];
if (!error) {
NSData *response = [request responseData];
NSLog(#"Root node: %#", [[self query:#"//" withResponse:response] description]);
}
else
#throw [NSException exceptionWithName:#"kHTTPRequestFailed" reason:#"Request failed!" userInfo:nil];
[request release];
...
- (id) query:(NSString *)xpathQuery withResponse:(NSData *)respData {
NSArray *nodes = PerformHTMLXPathQuery(respData, xpathQuery);
if (nodes != nil)
return nodes;
return nil;
}

providing you one simple example of parsing XML in Table, Hope it would help you.
//XMLViewController.h
#import <UIKit/UIKit.h>
#interface TestXMLViewController : UIViewController<NSXMLParserDelegate,UITableViewDelegate,UITableViewDataSource>{
#private
NSXMLParser *xmlParser;
NSInteger depth;
NSMutableString *currentName;
NSString *currentElement;
NSMutableArray *data;
}
#property (nonatomic, strong) IBOutlet UITableView *tableView;
-(void)start;
#end
//TestXMLViewController.m
#import "TestXmlDetail.h"
#import "TestXMLViewController.h"
#interface TestXMLViewController ()
- (void)showCurrentDepth;
#end
#implementation TestXMLViewController
#synthesize tableView;
- (void)start
{
NSString *xml = #"<?xml version=\"1.0\" encoding=\"UTF-8\" ?><Node><name>Main</name><Node><name>first row</name></Node><Node><name>second row</name></Node><Node><name>third row</name></Node></Node>";
xmlParser = [[NSXMLParser alloc] initWithData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
[xmlParser setDelegate:self];
[xmlParser setShouldProcessNamespaces:NO];
[xmlParser setShouldReportNamespacePrefixes:NO];
[xmlParser setShouldResolveExternalEntities:NO];
[xmlParser parse];
}
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(#"Document started");
depth = 0;
currentElement = nil;
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(#"Error: %#", [parseError localizedDescription]);
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
currentElement = [elementName copy];
if ([currentElement isEqualToString:#"Node"])
{
++depth;
[self showCurrentDepth];
}
else if ([currentElement isEqualToString:#"name"])
{
currentName = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:#"Node"])
{
--depth;
[self showCurrentDepth];
}
else if ([elementName isEqualToString:#"name"])
{
if (depth == 1)
{
NSLog(#"Outer name tag: %#", currentName);
}
else
{
NSLog(#"Inner name tag: %#", currentName);
[data addObject:currentName];
}
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if ([currentElement isEqualToString:#"name"])
{
[currentName appendString:string];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(#"Document finished", nil);
}
- (void)showCurrentDepth
{
NSLog(#"Current depth: %d", depth);
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
data = [[NSMutableArray alloc]init ];
[self start];
self.title=#"XML parsing";
NSLog(#"string is %#",data);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
`enter code here`return [data count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [data objectAtIndex:indexPath.row];
return cell;
}
#end

Related

How to parse Multiple .xml files in iphone?

Its my first experience with xmls so please don't be harsh on me if my question is low quality. I am working on app where I retrieve all data using xml files from server.
Before posting question here I read some Tutorials about xml file parsing. But when I start to implement it in my app, then I am totally confused at the point when I am trying to parse the second Xml file and so on.
Now I want to explain my app flow using some screenshot so that it become easy for everyone that what I want.
First view
Second view
Third view
Now when I click in any row in first view it goes to second view and show all related data in second view and when I click any item in Second view it goes to the third view and show detail information about that particular item.
After explanation of app flow, now I show my code what I tried so far. Following a tutorial I just simply drag classes (XMLParser, Book) to my app for testing purpose.
Code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *url = [[NSURL alloc] initWithString:#"Firstviewxmlurl"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
XMLParser *parser = [[XMLParser alloc] initXMLParser];
[xmlParser setDelegate:parser];
BOOL success = [xmlParser parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
}
Now my XMLParser.m code is
- (XMLParser *) initXMLParser {
[super init];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"Collections"]) {
//Initialize the array.
appDelegate.books = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Collection"]) {
//Initialize the book.
aBook = [[Book alloc] init];
//Extract the attribute here.
aBook.bookID = [[attributeDict objectForKey:#"id"] integerValue];
NSLog(#"Reading id value :%i", aBook.bookID);
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
NSLog(#"Processing Value: %#", currentElementValue);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"Collections"])
return;
if([elementName isEqualToString:#"Collection"]) {
[appDelegate.books addObject:aBook];
[aBook release];
aBook = nil;
}
else
[aBook setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
Finaly my First view Class code is
#pragma mark Table Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//return [tblViewData count];
return [appDelegate.books count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
cell.selectionStyle=UITableViewCellSelectionStyleGray;
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
}
//cell.textLabel.text=[[tblViewData objectAtIndex:indexPath.row]
// stringByReplacingOccurrencesOfString:#"*" withString:#""];
Book *aBook = [appDelegate.books objectAtIndex:indexPath.row];
cell.textLabel.text = aBook.title;
if([deviceType isEqualToString:#"ipad"])
{
[cell.textLabel setFont:[UIFont fontWithName:#"Helvetica-Bold" size:20]];
}
//cell.textLabel.font=[UIFont fontWithName:#"Walkway_SemiBold" size:16];
return cell;
}
After implementation of all the above Code i got the result in form of this Now at this point i confuse how can i pass my Second view xml file url and then third view url.my xml files are in this format
First xml file
<?xml version="1.0" encoding="UTF-8"?>
<Collections> <Collection id="5"><title>Allegroo</title> </Collection>
Second xml file
<?xml version="1.0" encoding="UTF-8"?>
<Collection id="5"><colletciontitle>Allegroo</colletciontitle> <weaveimage>"imageurl" </weaveimage><Rug id="48"><Rugthumb>"firstimageurl"</Rugthumb><RugSku>AL-637</RugSku></Rug><Rug id="51"><Rugthumb>"Secondimageurl"</Rugthumb><RugSku>AL-641</RugSku></Rug>
Third xml file
<?xml version="1.0" encoding="UTF-8"?>
<Rug id="47"><Rugmainimage>"imageurl"</Rugmainimage> <Rugtitle>AL-636 Aged Indigo / Vintage Beige</Rugtitle> <Rugdiscription>Hand Knotted
Distressed Wool Pile / Cotton Foundation </Rugdiscription><Availablesizes><Size>10x14</Size><Size>12x15</Size><Size>2x3</Size><Size>3x5</Size><Size>4x6</Size><Size>6x9</Size><Size>8x10</Size><Size>9x12</Size><Runner>2'6"x10'</Runner><Runner>2'6"x12'</Runner><Runner>2'6"x8'</Runner></Availablesizes></Rug>
Any help in the form of link or sample code releated to my issue and suggestion will be highly appriated.Thanks
Hmm, So Defining long story short, you want to parse multiple urls in sequence ?
So here is the answer,
Use a variable / identifier in appDelegate that tells you which xml is being parsed.
Use your xml parser as delegate class object
Use delegate method to swich to next xml parsing
- (void)parserDidEndDocument:(NSXMLParser *)parser {
// Change URL accordingly
NSURL *url = [[NSURL alloc] initWithString:#"Firstviewxmlurl"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
XMLParser *parser = [[XMLParser alloc] initXMLParser];
[xmlParser setDelegate:parser];
BOOL success = [xmlParser parse];
}
I have added some of the code to make you understand. Try to implement according to your condition. Below code is just to refer as i havn't made all the changes u need to understand first and then implement accordingly
//int i = 0; // in AppDelegate
Code:
//Or ViewDidLoad Method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int = 1; //For First View
NSURL *url = [[NSURL alloc] initWithString:#"Firstviewxmlurl"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
XMLParser *parser = [[XMLParser alloc] initXMLParser];
[xmlParser setDelegate:parser];
BOOL success = [xmlParser parse];
if(success)
NSLog(#"No Errors");
else
NSLog(#"Error Error Error!!!");
}
XMLParser.m
- (XMLParser *) initXMLParser
{
[super init];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"Collections"])
{
//Initialize the array.
if (int == 1)
appDelegate.books = [[NSMutableArray alloc] init];
else if (int == 2)
appDelegate.secondArray = [[NSMutableArray alloc] init];
else if (int == 3)
appDelegate.thirdArray = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:#"Collection"])
{
if (i == 1)
{
//Initialize the book.
aBook = [[Book alloc] init];
//Extract the attribute here.
aBook.bookID = [[attributeDict objectForKey:#"id"] integerValue];
NSLog(#"Reading id value :%i", aBook.bookID);
}
else if (i == 2)
{
//Second Xml
}
else if (i == 3)
{
//Third Xml
}
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
//Check condition
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
NSLog(#"Processing Value: %#", currentElementValue);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
//Check COndition
if([elementName isEqualToString:#"Collections"])
return;
if([elementName isEqualToString:#"Collection"]) {
[appDelegate.books addObject:aBook];
[aBook release];
aBook = nil;
}
else
[aBook setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}

Desperate for NSXMLParser Guidance

I previously asked this question XMLParser Advice.
However I am still unable to get it to function properly....
So I guess I will start from scratch:
Located at a certain URL is an XML Tree that looks like this
<result>
//stuff that I dont need
<title>
//thing that I do need
</title>
//stuff that I dont need
<body>
//thing that I do need
</body>
<result>
How the heck do I go about parsing that?
The (useless) code I have so far can be found in the link at the top of this question.
Thank you for your time.
Write a simple class, which will be the parser's delegate.
#interface YourObject : NSObject <NSXMLParserDelegate> {
NSString *title, *body; // object attributes
NSXMLParser *parser; // will parse XML
NSMutableString *strData; // will contains string data being parsed
}
#property(readwrite, copy) NSString *title, body;
// will be used to set your object attributes
-(void)fetchValuesAtURL:(NSString *)url;
#end
The fetchValuesAtURL: method will initiate the parse operation.
#implementation YourObject
#synthesize title, body;
-(id)init {
self = [super init];
if(self) {
title = #"";
body = #"";
parser = nil;
strData = [[NSMutableString alloc] initWithCapacity:10];
}
return self;
}
-(void)fetchValuesAtURL:(NSString *)url {
if(parser) {
[parser release];
}
NSURL *xmlURL = [NSURL URLWithString:url];
parser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[parser setDelegate:self];
[parser parse];
}
-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
// element is about to be parsed, clean the mutable string
[strData setString:#""];
}
// the probably missing method
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
// content (or part of) has been found, append that to the current string
[strData appendString:string];
}
-(void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName {
// element has been parsed, test the element name
// and store strData accordingly
if([elementName isEqualToString:#"title"]) {
self.title = strData;
}
else { // or else if, here you got two elements to parse
self.body = strData;
}
}
-(void)dealloc {
[title release];
[body release];
[strData release];
if(parser) {
[parser release];
}
[super dealloc];
}
#end
Then :
YourObject *obj = [[YourObject alloc] init];
[obj fetchValuesAtURL:#"http://www.site.com/xml/url"];
NSXMLParser's delegate is able to do many more things, as described in Event-Driven XML Programming Guide from Apple.
For complete reference on delegate methods, see NSXMLParserDelegate Protocol Reference.

XML Parsing in iPhone

I am new in xml parsing.I am totaly cofused how many methods we should have to require for xml parsing and what does use of that method.I want to send input to the webservied and by use of xml parsing i want to display result in my text field.
See this questions for resources on how to pick an XML parser for your iOS application:
Choosing the right IOS XML parser
I choose TouchXML for my projects. It is a DOM parser and has XPath support:
https://github.com/TouchCode/TouchXML
You should use the following methods:
- (void)parseXMLFileAtURL:(NSString *)URL { //own method from me, URL could be local file or internet website
itemsOfFeed = [[NSMutableArray alloc] init];
NSURL *xmlURL = [NSURL URLWithString:URL];
feedParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[feedParser setDelegate:self];
[feedParser setShouldProcessNamespaces:NO];
[feedParser setShouldReportNamespacePrefixes:NO];
[feedParser setShouldResolveExternalEntities:NO];
[feedParser parse];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
//in case of an error
}
- (void)parserDidStartDocument:(NSXMLParser *)parser {
// start to parse xml
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
feedElement = [elementName copy];
if([elementName isEqualToString:#"item"]) { //main xml tag
item = [[NSMutableDictionary alloc] init];
feedTitle = [[NSMutableString alloc] init];
feedDate = [[NSMutableString alloc] init];
feedText = [[NSMutableString alloc] init];
feedLink = [[NSMutableString alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if([feedElement isEqualToString:#"title"]) {
[feedTitle appendString:string];
} else if([feedElement isEqualToString:#"link"]) { // some examples of tags
[feedLink appendString:string];
} else if([feedElement isEqualToString:#"content:encoded"]) {
[feedText appendString:string];
} else if([feedElement isEqualToString:#"pubDate"]) {
[feedDate appendString:string];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"item"]) {
[item setObject:feedTitle forKey:#"title"];
[item setObject:feedDate forKey:#"date"];
[item setObject:feedText forKey:#"text"];
[item setObject:feedLink forKey:#"link"];
[itemsOfFeed addObject:item];
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[self.myTableView reloadData]; // for example reload table view
[self writeArrayToFile]; //or write to a local property list
}
in your header file:
NSMutableArray *itemsOfFeed;
NSXMLParser *feedParser;
NSMutableDictionary *item;
NSMutableString *feedElement;
NSMutableString *feedTitle, feedDate, feedText, feedLink; //strings of your tags
Then you have:
NSArray
NSDictionary
object a
object b
object c
Just access 'object a' and put it in your text field
hopefully this code example helps you
Here is the very helpful tutorial.
http://www.edumobile.org/iphone/iphone-programming-tutorials/parsing-an-xml-file/
Hi I would personally prefer to use NSXMLParser.
Write your own code which uses NSXMLParserDelegate methods implementation.
But still there are some third party libraries available. Here is a nice example to compare how all those parser differs from each other and also having nice explanation. Code is also available over there.
Hope this will be helpful to you.
-Mrunal
i have a demo app for parsing static XML to UITableView, I think this one will surely will help you.
Availiable third party libraries available below, depend on developer choice this, which is best?
NSXMLParser
libxml2
TBXMLParser
TouchXMLParser
KissXMLParser
TinyXMLParser
GDataXMLParser
And you can also get more information from this great tutorial link
http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project
Try this:
XMLReader.h
//
// XMLReader.h
//
//
#import <Foundation/Foundation.h>
#interface XMLReader : NSObject <NSXMLParserDelegate>
{
NSMutableArray *dictionaryStack;
NSMutableString *textInProgress;
NSError *errorPointer;
}
+ (NSDictionary *)dictionaryForPath:(NSString *)path error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)errorPointer;
#end
XMLReader.m
//
// XMLReader.m
//
#import "XMLReader.h"
//NSString *const kXMLReaderTextNodeKey = #"text";
#interface XMLReader (Internal)
- (id)initWithError:(NSError **)error;
- (NSDictionary *)objectWithData:(NSData *)data;
#end
#implementation XMLReader
#pragma mark -
#pragma mark Public methods
+ (NSDictionary *)dictionaryForPath:(NSString *)path error:(NSError **)errorPointer
{
NSString *fullpath = [[NSBundle bundleForClass:self] pathForResource:path ofType:#"xml"];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:fullpath];
NSDictionary *rootDictionary = [XMLReader dictionaryForXMLData:data error:errorPointer];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)error
{
XMLReader *reader = [[XMLReader alloc] initWithError:error];
NSDictionary *rootDictionary = [reader objectWithData:data];
[reader release];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)error
{
NSArray* lines = [string componentsSeparatedByString:#"\n"];
NSMutableString* strData = [NSMutableString stringWithString:#""];
for (int i = 0; i < [lines count]; i++)
{
[strData appendString:[[lines objectAtIndex:i] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
NSData *data = [strData dataUsingEncoding:NSUTF8StringEncoding];
return [XMLReader dictionaryForXMLData:data error:error];
}
#pragma mark -
#pragma mark Parsing
- (id)initWithError:(NSError **)error
{
if ((self = [super init]))
{
errorPointer = *error;
}
return self;
}
- (void)dealloc
{
[dictionaryStack release];
[textInProgress release];
[super dealloc];
}
- (NSDictionary *)objectWithData:(NSData *)data
{
// Clear out any old data
[dictionaryStack release];
[textInProgress release];
dictionaryStack = [[NSMutableArray alloc] init];
textInProgress = [[NSMutableString alloc] init];
// Initialize the stack with a fresh dictionary
[dictionaryStack addObject:[NSMutableDictionary dictionary]];
// Parse the XML
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
BOOL success = [parser parse];
[parser release];
// Return the stack's root dictionary on success
if (success){
NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
return resultDict;
}
return nil;
}
# pragma mark
# pragma mark - NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// Get the dictionary for the current level in the stack
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
// Create the child dictionary for the new element
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
// Initialize child dictionary with the attributes, prefixed with '#'
for (NSString *key in attributeDict) {
[childDict setValue:[attributeDict objectForKey:key]
forKey:key];
}
// If there's already an item for this key, it means we need to create an array
id existingValue = [parentDict objectForKey:elementName];
if (existingValue){
NSMutableArray *array = nil;
if ([existingValue isKindOfClass:[NSMutableArray class]]){
// The array exists, so use it
array = (NSMutableArray *) existingValue;
}
else{
// Create an array if it doesn't exist
array = [NSMutableArray array];
[array addObject:existingValue];
// Replace the child dictionary with an array of children dictionaries
[parentDict setObject:array forKey:elementName];
}
// Add the new child dictionary to the array
[array addObject:childDict];
}
else{
// No existing value, so update the dictionary
[parentDict setObject:childDict forKey:elementName];
}
// Update the stack
[dictionaryStack addObject:childDict];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Update the parent dict with text info
NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];
// Pop the current dict
[dictionaryStack removeLastObject];
// Set the text property
if ([textInProgress length] > 0){
if ([dictInProgress count] > 0){
[dictInProgress setObject:textInProgress forKey:kXMLReaderTextNodeKey];
}
else{
// Given that there will only ever be a single value in this dictionary, let's replace the dictionary with a simple string.
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
id parentObject = [parentDict objectForKey:elementName];
// Parent is an Array
if ([parentObject isKindOfClass:[NSArray class]]){
[parentObject removeLastObject];
[parentObject addObject:textInProgress];
}
// Parent is a Dictionary
else{
[parentDict removeObjectForKey:elementName];
[parentDict setObject:textInProgress forKey:elementName];
}
}
// Reset the text
[textInProgress release];
textInProgress = [[NSMutableString alloc] init];
}
// If there was no value for the tag, and no attribute, then remove it from the dictionary.
else if ([dictInProgress count] == 0){
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
[parentDict removeObjectForKey:elementName];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Build the text value
[textInProgress appendString:[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
// Set the error pointer to the parser's error object
if (errorPointer)
errorPointer = parseError;
}
#end
Use it:
NSMutableDictionary *yourDic= (NSMutableDictionary *)[XMLReader dictionaryForXMLData:yourData error:&error];

XML parser SDK for IOS

I need to be able to parse XML for a project I'm working on.
How can I parse XML from a web page to the iPhone then read its contents?
Follow this , how to parse XML in Objective c using ASIHTTPRequest and handle all this methods
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
See this link too
NSString *url=#"http://www.lancers.jp/work";
NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
NSDictionary *dict=[XMLParser dictionaryForXMLData:data error:nil];
NSLog(#"%#",[dict description]);
and use below file::::::
XMLParser.h
//
// XMLReader.h
//
// Created by Troy on 9/18/10.
// Copyright 2010 Troy Brant. All rights reserved.
//
#import <Foundation/Foundation.h>
#interface XMLParser : NSObject<NSXMLParserDelegate>
{
NSMutableArray *dictionaryStack;
NSMutableString *textInProgress;
NSError **errorPointer;
}
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)errorPointer;
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)errorPointer;
#end
XMLParser.m
//
// XMLReader.m
//
// Created by Troy on 9/18/10.
// Copyright 2010 Troy Brant. All rights reserved.
//
#import "XMLParser.h"
NSString *const kXMLReaderTextNodeKey = #"text";
#interface XMLParser (Internal)
- (id)initWithError:(NSError **)error;
- (NSDictionary *)objectWithData:(NSData *)data;
#end
//NSString *url=[NSString stringWithFormat:#"%#",NSLocalizedString(#"locationname", nil)];
//url=[NSString stringWithFormat:url,app.latnear,app.lngnear];
//NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
//NSDictionary *dict=[XMLReader dictionaryForXMLData:data error:nil];
#implementation XMLParser
#pragma mark -
#pragma mark Public methods
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError **)error
{
XMLParser *reader = [[XMLParser alloc] initWithError:error];
NSDictionary *rootDictionary = [reader objectWithData:data];
[reader release];
return rootDictionary;
}
+ (NSDictionary *)dictionaryForXMLString:(NSString *)string error:(NSError **)error
{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return [XMLParser dictionaryForXMLData:data error:error];
}
#pragma mark -
#pragma mark Parsing
- (id)initWithError:(NSError **)error
{
if (self = [super init])
{
errorPointer = error;
}
return self;
}
- (void)dealloc
{
[dictionaryStack release];
[textInProgress release];
[super dealloc];
}
- (NSDictionary *)objectWithData:(NSData *)data
{
// Clear out any old data
[dictionaryStack release];
[textInProgress release];
dictionaryStack = [[NSMutableArray alloc] init];
textInProgress = [[NSMutableString alloc] init];
// Initialize the stack with a fresh dictionary
[dictionaryStack addObject:[NSMutableDictionary dictionary]];
// Parse the XML
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
BOOL success = [parser parse];
// Return the stack's root dictionary on success
if (success)
{
NSDictionary *resultDict = [dictionaryStack objectAtIndex:0];
return resultDict;
}
return nil;
}
#pragma mark -
#pragma mark NSXMLParserDelegate methods
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// Get the dictionary for the current level in the stack
NSMutableDictionary *parentDict = [dictionaryStack lastObject];
// Create the child dictionary for the new element, and initilaize it with the attributes
NSMutableDictionary *childDict = [NSMutableDictionary dictionary];
[childDict addEntriesFromDictionary:attributeDict];
// If there's already an item for this key, it means we need to create an array
id existingValue = [parentDict objectForKey:elementName];
if (existingValue)
{
NSMutableArray *array = nil;
if ([existingValue isKindOfClass:[NSMutableArray class]])
{
// The array exists, so use it
array = (NSMutableArray *) existingValue;
}
else
{
// Create an array if it doesn't exist
array = [NSMutableArray array];
[array addObject:existingValue];
// Replace the child dictionary with an array of children dictionaries
[parentDict setObject:array forKey:elementName];
}
// Add the new child dictionary to the array
[array addObject:childDict];
}
else
{
// No existing value, so update the dictionary
[parentDict setObject:childDict forKey:elementName];
}
// Update the stack
[dictionaryStack addObject:childDict];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// Update the parent dict with text info
NSMutableDictionary *dictInProgress = [dictionaryStack lastObject];
// Set the text property
if ([textInProgress length] > 0)
{
[dictInProgress setObject:textInProgress forKey:kXMLReaderTextNodeKey];
// Reset the text
[textInProgress release];
textInProgress = [[NSMutableString alloc] init];
}
// Pop the current dict
[dictionaryStack removeLastObject];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Build the text value
[textInProgress appendString:string];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
// Set the error pointer to the parser's error object
*errorPointer = parseError;
}
#end

UITableView crashes when trying to scroll

I have a problem with data in UITableView. I have UIViewController, that contains UITableView outlet and few more things I am using and ... It works :) ... it works lovely, but ...
I've created an RSS reader class that is using delegates to deploy the data to the table ... and once again, If I'll just create dummy data in the main controller everything works!
problem is with this line: rss.delegate = self;
Preview looks a little bit broken than here are those RSS reader files on Google code:
(Link to the header file on GoogleCode)
(Link to the implementation file on Google code)
viewDidLoad function of my controller:
IGDataRss20 *rss = [[[IGDataRss20 alloc] init] autorelease];
rss.delegate = self;
[rss initWithContentsOfUrl:#"http://rss.cnn.com/rss/cnn_topstories.rss"];
and my delegate methods:
- (void)parsingEnded:(NSArray *)result {
super.data = [[NSMutableArray alloc] initWithArray:result];
NSLog(#"My Items: %d", [super.data count]);
[super.table reloadData];
NSLog(#"Parsing ended");
}
- (void)parsingError:(NSString *)message {
NSLog(#"MyMessage: %#", message);
}
- (void)parsingStarted:(NSXMLParser *)parser {
NSLog(#"Parsing started");
}
Just to clarify, NSLog(#"Parsing ended"); is being executed and I have 10 items in the array.
Hope someone will be able to help me as I am becoming to be quite desperate, and I thought I am not already such a greenhorn :)
Thanks,
Ondrej
Full copy of my header file (table controller)
the WGTempTableController class is UIViewController with table outlet, data array etc ...
//
// CRFeedController.h
// czReader
//
// Created by Ondrej Rafaj on 5.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "WGTempTableController.h"
#import <IGDataRss20.h>
#interface CRFeedController : WGTempTableController <IGDataRss20Delegate> {
//NSString *startUrl;
}
#end
Full copy of my implementation file (table controller)
All other functions like numberOfSectionsInTableView or numberOfRowsInSection are in that WGTempTableController
//
// CRFeedController.m
// czReader
//
// Created by Ondrej Rafaj on 5.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import "CRFeedController.h"
#import "WGTempCell.h"
#implementation CRFeedController
- (void)viewDidLoad {
[super viewDidLoad];
IGDataRss20 *rss = [[[IGDataRss20 alloc] init] autorelease];
rss.delegate = self;
[rss initWithContentsOfUrl:#"http://rss.cnn.com/rss/cnn_topstories.rss"];
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)parsingEnded:(NSArray *)result {
super.data = [[NSMutableArray alloc] initWithArray:result];
NSLog(#"My Items: %d", [super.data count]);
[super.table reloadData];
NSLog(#"Parsing ended");
}
- (void)parsingError:(NSString *)message {
NSLog(#"MyMessage: %#", message);
}
- (void)parsingStarted:(NSXMLParser *)parser {
NSLog(#"Parsing started");
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#pragma mark Table view
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"MyCell";
WGTempCell *cell = (WGTempCell *) [table dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CRFeedCell" owner:nil options:nil];
for(id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[WGTempCell class]]) {
cell = (WGTempCell *) currentObject;
break;
}
}
}
NSDictionary *d = [super.data objectAtIndex:indexPath.row];
[[cell cellTitle] setText:[d objectForKey:#"title"]];
return cell;
}
- (void)dealloc {
[super dealloc];
}
#end
Full copy of my header file (rss reader)
//
// IGDataRss20.h
// IGFrameworkProject
//
// Created by Ondrej Rafaj on 4.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import <Foundation/Foundation.h>
#class IGDataRss20;
#protocol IGDataRss20Delegate <NSObject>
#optional
- (void)parsingStarted:(NSXMLParser *)parser;
- (void)parsingError:(NSString *)message;
- (void)parsingEnded:(NSArray *)result;
#end
#interface IGDataRss20 : NSObject {
NSXMLParser *rssParser;
NSMutableArray *data;
NSMutableDictionary *currentItem;
NSString *currentElement;
id <IGDataRss20Delegate> delegate;
}
#property (nonatomic, retain) NSMutableArray *data;
#property (nonatomic, assign) id <IGDataRss20Delegate> delegate;
- (void)initWithContentsOfUrl:(NSString *)rssUrl;
- (void)initWithContentsOfData:(NSData *)inputData;
#end
Full copy of my implementation file (rss reader)
//
// IGDataRss20.m
// IGFrameworkProject
//
// Created by Ondrej Rafaj on 4.4.10.
// Copyright 2010 Home. All rights reserved.
//
#import "IGDataRss20.h"
#implementation IGDataRss20
#synthesize data, delegate;
- (void)initWithContentsOfUrl:(NSString *)rssUrl {
self.data = [[NSMutableArray alloc] init];
NSURL *xmlURL = [NSURL URLWithString:rssUrl];
rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
[rssParser setDelegate:self];
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)initWithContentsOfData:(NSData *)inputData {
self.data = [[NSMutableArray alloc] init];
rssParser = [[NSXMLParser alloc] initWithData:inputData];
[rssParser setDelegate:self];
[rssParser setShouldProcessNamespaces:NO];
[rssParser setShouldReportNamespacePrefixes:NO];
[rssParser setShouldResolveExternalEntities:NO];
[rssParser parse];
}
- (void)parserDidStartDocument:(NSXMLParser *)parser {
[[self delegate] parsingStarted:parser];
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to parse RSS feed (Error code %i )", [parseError code]];
NSLog(#"Error parsing XML: %#", errorString);
if ([parseError code] == 31) NSLog(#"Error code 31 is usually caused by encoding problem.");
[[self delegate] parsingError:errorString];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
currentElement = [elementName copy];
if ([elementName isEqualToString:#"item"]) currentItem = [[NSMutableDictionary alloc] init];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"item"]) {
[data addObject:(NSDictionary *)[currentItem copy]];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (![currentItem objectForKey:currentElement]) [currentItem setObject:[[[NSMutableString alloc] init] autorelease] forKey:currentElement];
[[currentItem objectForKey:currentElement] appendString:string];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
//NSLog(#"RSS array has %d items: %#", [data count], data);
[[self delegate] parsingEnded:(NSArray *)self.data];
}
- (void)dealloc {
[data, delegate release];
[super dealloc];
}
#end
Your subject says it crashes when you try to scroll. I don't know what this would have to do with your rss.delegate, so I'm just going to ignore that and focus on probable scrolling-related bugs here, which are usually in tableView:cellForRowAtIndexPath:.
Check your CRFeedCell.xib, view info on your WGTempCell object, and make sure its Identifier field matches your CellIdentifier in your code. ("MyCell")
Make sure you're not using that same CellIdentifier for some other UITableViewCell subclass elsewhere in your code.
What kind of crash is it? If it's EXC_BAD_ACCESS, double-click on your executable, go to Arguments, create an NSZombieEnabled environment variable, and set it to YES. (Uncheck it when you're done debugging to avoid leaking memory.) This will show you which object you were trying to access when the app crashed.
Set a breakpoint on the setText: call in tableView:cellForRowAtIndexPath:. Then at your gdb prompt, type po [d objectForKey:#"title"]. Make sure that object is really an NSString.
It looks to me, as if you initialize the NSMutableArray data twice: First in initWithContentsOfUrl: , then again in parsingEnded: . Maybe you should do a removeAllObjects in parsingEnded instead.