Introduction
NSXMLParser is a forward only reader or an event driven parser. What it means is, an event is raised whenever the parser comes across a start of an element, value, CDATA and so on. The delegate of NSXMLParser can then implement these events to capture XML data. Some of the events are raised multiple times like the start of an element, value of an element and so on. Since NSXMLParser is known as an event driven parser, we can only read data at the present node and cannot go back. The iPhone only supports NSXMLParser and not NSXMLDocument, which loads the whole XML tree in memory.
Books Application
To understand how to use an instance of NSXMLParser, let's create a simple navigation based application where we will list the title of the book in the table view and upon selecting a title, display the detail information in a detail view. Click here to see the sample XML file, used in this application.
Create a new application in XCode by selecting Navigation-Based Application, I have named my app XML. Since the NSXMLParser is a forward only parser or an event driven parser, we need to store the data locally, which can be used later. To store this data, we will create a class which replicates the elements and attributes in the XML file. An instance of this class represents one single Book element in the XML file. I have named this class "Book" and its source code is listed below
//Book.h
#import <UIKit/UIKit.h>
@interface Book : NSObject {
NSInteger bookID;
NSString *title; //Same name as the Entity Name.
NSString *author; //Same name as the Entity Name.
NSString *summary; //Same name as the Entity Name.
}
@property (nonatomic, readwrite) NSInteger bookID;
@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *author;
@property (nonatomic, retain) NSString *summary;
@end
//Book.m
#import "Book.h"
@implementation Book
@synthesize title, author, summary, bookID;
- (void) dealloc {
[summary release];
[author release];
[title release];
[super dealloc];
}
@end
Notice that the name of the property is the same as the element name in the XML file. Since the XML file has n number of Book elements, we need an array to hold all the books we read, so we declare an array in the application delegate and this is how the source code changes
//XMLAppDelegate.h
#import <UIKit/UIKit.h>
@interface XMLAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
NSMutableArray *books;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, retain) NSMutableArray *books;
@endThe Delegate
To keep the source code clean, we will also declare a delegate, which will be used by the instance of NSXMLParser and this how its source code looks like
//XMLParser.h
#import <UIKit/UIKit.h>
@class XMLAppDelegate, Book;
@interface XMLParser : NSObject {
NSMutableString *currentElementValue;
XMLAppDelegate *appDelegate;
Book *aBook;
}
- (XMLParser *) initXMLParser;
@endLet's look at how the variables will be used. currentElementValue holds the current element value, appDelegate so we can access the array which holds the list of books and finally a reference to the Book class itself. Notice that we do not keep track of the current element name being processed, because the event will tell us that. Finally, we have a constructor called initXMLParser and let's see what it does
//XMLParser.m
- (XMLParser *) initXMLParser {
[super init];
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}Very simple, gets a reference to the application delegate and returns itself.
Parsing the XML File
Now that we have everything set up, let's look at the code to read the XML file
//XMLAppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSURL *url = [[NSURL alloc] initWithString:@"http://sites.google.com/site/iphonesdktutorials/xml/Books.xml"];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
//Initialize the delegate.
XMLParser *parser = [[XMLParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
NSLog(@"No Errors");
else
NSLog(@"Error Error Error!!!");
// Configure and show the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}The code is very simple, we create an instance of NSURL, create an instance of NSXMLParser, initialize the delegate, assign the delegate and start parsing by passing the parse message. It returns YES, if the parsing is successful, NO if there is an error or if the operation is aborted.
Parsing the start of an element
The delegate of the parser does not have to implement all the methods that it raises, so we can pick and choose which events we care about. If we do not want to handle the event when the parser starts reading the document, we can choose to ignore it by not implementing it. We will only implement three methods which is called when the parser encounters the start of an element, end of an element or value of an element.
Let's look at parser:didStartElement:namespaceURI:qualifiedName:attributes method which is called when the parser encounters the start of an element.
//XMLParser.m
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:@"Books"]) {
//Initialize the array.
appDelegate.books = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:@"Book"]) {
//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);
}
From the above code we first initialize the array when it encounters the "Books" element, which can also be done in parserDidStartDocument method. If the element is "Book" then we initialize the local book object and read the attribute of the present XML book element from the attribute dictionary object.
Parsing an element's value
Now that we have a local book object representing the current book element in the XML tree, the next thing to do is to populate the local object with the XML data. The parser now moves to the title element and the same method is called again, but this time we do not do anything. Parser then moves to the element value and it sends parser:foundCharacters event to the delegate, let's see how the code look like
//XMLParser.m
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue)
currentElementValue = [[NSMutableString alloc] initWithString:string];
else
[currentElementValue appendString:string];
NSLog(@"Processing Value: %@", currentElementValue);
}The code is very easy to read, if the mutable string is nil then we initialize it with the string parameter. If the currentElementValue is not nil then we simply append the data to the existing string value.
Parsing the end of an element
The parser now moves to the end of the element and hence parser:didEndElement:namespaceURI:qualifiedName is sent to the delegate. This is where we set the currentElementValue to the correct property of the local book object and set the currentElementValue to nil. This is how the code looks like
//XMLParser.m
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:@"Books"])
return;
//There is nothing to do if we encounter the Books element here.
//If we encounter the Book element howevere, we want to add the book object to the array
// and release the object.
if([elementName isEqualToString:@"Book"]) {
[appDelegate.books addObject:aBook];
[aBook release];
aBook = nil;
}
else
[aBook setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}If the element it encounters is "Books" then there is nothing to do as we are almost done reading the file. If the element name is "Book" then we add the book object to the array and set the local book object to nil and release its memory, so it can be used again. If the end element is not "Books" or "Book" then it must be one of the sub element of "book" and we set the currentElementValue to the current book property using setValue:forKey. We can do this, because the properties declared in the book is the same as the XML element names.
The cycle starts again by initializing the book object and reading the attribute, reading the children elements and setting its value to the local object and finally adding the object to the array. The parser calls the three functions again and again as long as it does not encounters eof.
Complete listing of XMLParser.m file
//XMLParser.m
#import "XMLParser.h"
#import "XMLAppDelegate.h"
#import "Book.h"
@implementation XMLParser
- (XMLParser *) initXMLParser {
[super init];
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:@"Books"]) {
//Initialize the array.
appDelegate.books = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:@"Book"]) {
//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:@"Books"])
return;
//There is nothing to do if we encounter the Books element here.
//If we encounter the Book element howevere, we want to add the book object to the array
// and release the object.
if([elementName isEqualToString:@"Book"]) {
[appDelegate.books addObject:aBook];
[aBook release];
aBook = nil;
}
else
[aBook setValue:currentElementValue forKey:elementName];
[currentElementValue release];
currentElementValue = nil;
}
- (void) dealloc {
[aBook release];
[currentElementValue release];
[super dealloc];
}
@endThis is how the data looks like in the table view and the detail view controller.

The data is then shown in a UITableView with a detail view, the complete code is not shown here but you can download the source code and to get a better understanding UITableView, you can follow my suggested readings below.Summary
Reading XML files is very easy and it can be done with only three methods as seen above. I hope this tutorial has got you started in reading XML files.
Happy Programming,
iPhone SDK Articles
Attachments
Suggested Readings
- UITableView - Creating a simple table view
- UITableView - Loading a detail view
- UITableView - Adding a UISearchBar to the UITableView

56 comments:
Thanks for your tutorials. It's pretty much work and You, Jai are doing it for free. Do you have anything in appstore?
And please: I guess most of ass want to learn it. Show as how to implement some animations/transitions between views like page flip and others. And maybe some kind of blue pop-up msgboxes.
Thanks again
Chris [Poland]
I downloaded the sample code.Build failed with error "error:UIKit/UIKit.h:No such file or directory"
I have Mac OS X 10.4
What needs to done to build it....
Thanks in advance,Niranja
I love your tutorials. Can you make another one using SQLite with a Picker that holds data. Thanks, keep up the good work.
Just love your tutorials! Making it really easy jumping from the pc platform to iPhone/mobile obj-c programmering :)
Thank you so much!
Great tutorial!
I want to ask another thing:
How can I add a picture box into the detail page? Simply I want to display books' pictures in the detail page...
Thanks again!
Yes, I' am planning to write one soon.
Happy Programming,
iPhone SDK Articles
Hi Chris,
Glad you enjoyed the tutorials. I' am working on some tutorials and will put up on the site soon.
Happy Programming,
iPhone SDK Articles
@Trond Glad you enjoyed the tutorials.
Happy Programming,
iPhone SDK Articles
Thanks for the great tutorials! Very easy to catch on...
A quick question, is it possible like rexmont said to add a UIImageView to the detail page? and is it possible to make a row in the detail view to also carry a link, so when a user taps it, it opens a url like a button.
would it also be possible to create a search bar so a user could search for a certain book?
Hi there.
I`m currently trying to get the xml appi to work. If i use the normal xml tags structure everything works fine. But an other source xml has a slightly different structure. Like this:
(begintag)Books(endtag)
(begintag)Title= "Lorem"(/endtag)
(begintag)Author= "John Smith"(/endtag)
(begintag/)Books(endtag)
Could`t post the real xml with real begin and end tag so i wrote i down like this.
I can`t get it to work with this structure. Could someone please give me some directions on how i could it to work . Thanks very much in advance
@Katana I have a tutorial on searching UITableView here http://www.iphonesdkarticles.com/2009/01/uitableview-searching-table-view.html
Happy Programming,
iPhone SDK Articles
@Katana I think this tutorial will answer your question
http://www.iphonesdkarticles.com/2009/01/uitableview-loading-detail-view.html
The idea is to send something from one object to another object using parameters.
Please let me know if I can be of any more help.
Happy Programming,
iPhone SDK Articles
Pietje321 Is the XML valid?
Is it possible to prvide the XML source so I can test it out?
Happy Programming,
iPhone SDK Articles
Is it possible to bundle the XML file with the app and read it locally instead of reading it in from a URL?
Thanks.
For some reason i get a lot of white spaces in mijn strings like this:
2009-02-25 00:04:37.726 XML[21466:20b] Processing Value:
Leader voor het SBS 6 programma 'Lachen het jaar in'
Any idea why?
Thanks for this tutorial!
I noticed that when I put all my XML code on one line it works.. does someone know why? :)
Thank you sooooo much !!!!! for this code !!
you rock !!
@Rick
I think you created the XML file with line breaks in them.
@Reetu
Glad you it helped you
Happy Programming,
iPhone SDK Articles
Is is possible to use a local .xml file in this appliction?
I downloaded the code ad tried to write in the path to my own .xml file but it didnt work?
Thanks :)
I'm looking for the same answer as "vii" does. But i can't find any. Is it possible to use a local xml file instead of an URL.
Another question. How do you do if you want another step of categories.
Example:
Booktitle -> bookinfo -> images
tableview tableview tableview
It will be very useful :]
Thank you!
This turtorials rocks!!
//Ralf from Norway
Hello!
In my XML. the element 'Book' consists of attributes only instead of more elements, how do i get the value of them to show in the DetailView???
thank you, awsome tutorial btw!
@Gadget
In this method
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {
all the attributes for the Book element will be stored in attributeDict dictionary variable. You can get the attribute value like this
[[attributeDict objectForKey:@"id"] integerValue];
where "id" is the name of the attribute and the above line will give you the attribute value as integer.
I hope this helps.
Happy Programming,
iPhone SDK Articles
@Dajn @Ralf
Save the file in the resource folder and use this code
NSString *Path = [[NSBundle mainBundle] bundlePath];
NSString *DataPath = [Path stringByAppendingPathComponent:@"xmlfile.xml"];
NSData *Data = [[NSData alloc] initWithContentsOfFile:DataPath];
NSXMLParser xmlParser = [[NSXMLParser alloc] initWithData:Data];
Now that you have the NSXMLParser object, follow the same steps as this tutorial.
//Initialize the delegate.
XMLParser *parser = [[XMLParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
XMLPraser is a custom class created for this tutorial.
I hope this helps.
Happy Programming,
iPhone SDK Articles
@Ralf
are you speaking of a drill down table view? If yes, I will be publishing a new tutorial which will show you how to do it.
Happy Programming,
iPhone SDK Articles
Is it possible to put in a searchBar and search in the xml and then have the result in showing in the rootTableView??
That would be very nice :]
What if you want to have a searchBar in the rootView, where u can search on booktitles or something ?
@Gad I have a tutorial on searching the table view here
http://www.iphonesdkarticles.com/2009/01/uitableview-searching-table-view.html
After you have parsed the XML file you can search the table view in the same way, as show in the tutorial above.
I hope this helps.
Happy Programming,
iPhone SDK Articles
In my app I created a third tableView, But i can't get the xml data showing there. I used the didSelectRowAtIndexPath method in the second view just like u did on the rootView, Do you now what to do, do i have to send som kind of ID ?
thanks :]
Awsome tutorial
How can you do the opposite, I mean convert the
NSMutableArray *books;
to xml and then convert the xml to NSData?
Thanks
What happens when you want to save the contents of
NSMutableArray
into XML file?
Thanks
@cioannou You can save the contents of an NSMutableArray like this [array writeToFile:path atomically:YES];
Hope this helps.
Happy Programming,
iPhone SDK Articles
@Chris You can try saving the array
[array writeToFile:path atomically:YES];
to the disk and get it as NSData like this
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
Hope this helps.
Happy Programming,
iPhone SDK Articles
@RulleBulle You need some kind of mechanism to pass data to the table view. If you can send me an email with some more information on how the data is designed, I will be able to help you more.
This tutorial may help you
http://www.iphonesdkarticles.com/2009/01/uitableview-loading-detail-view.html
Happy Programming,
iPhone SDK Articles
@Nikeo This tutorial show how to add a UISearchBar to a UITableView
http://www.iphonesdkarticles.com/2009/01/uitableview-searching-table-view.html
Hope this helps.
Happy Programming,
iPhone SDK Articles
Ok, I did take a look at that tutorial, but i just end up with the same result. It works just great with 2 viewControllers, but it's the third one.
I did also send ju an email as you said :]
help :=)
if you just wanna add another view , say like ImageViewController.xib
And when you select a row in the first tableview a another xml is loading with images and so on.
How do I get a connection between the second third view and parsing a new xml?=) lot o questions. maybe just like RulleBulle?
thanks
Hi there - I've written an XML parser based on this code, and it works! However, it looks like ampersands (& characters) are not showing up. My XML (UTF-8 encoded) has ampersands in some strings, like "Joe's Bar & Grill." What I'm getting out of the parser is just "Joe's Bar Grill."
Is an ampersand considered some special character in XML?
Works great! Awesome Tutorial.
As other do, I have a question. One of the elements i am passing is either a 1 or a 0. I need to know which value it is before doing something with the data. I've been searching up and down for the past 2 days now and I got no luck. I've tried to convert it to a string and compare it string1.isEqualToString(string2) with no luck.
For example purposes, with your example in mind, how can i campare the bookid to a number.
Thanks,
RolYroLLs
@Higgins Try replacing & with & and see what happens.
Hope this helps.
Happy Programming,
iPhone SDK Articles
@RolYroLLs are you not able to compare the umber like this if (bookid == 1) { }
If it gives you can error can you tell me what the error is?
Happy Programming,
iphone SDK Articles
@Kiddo Clicking on a row loads the image view controller and also parses another XML file for images. Now you want know how to connect what the clicked row and the image?
I think I am confused by the question.
Are you parsing the same XML file whenever a row is clicked in the root view controller?
In your XML file you should have some kind of a foreign key with which you can find out which image to use based on the row clicked.
Hope this helps.
Happy Programming,
iPhone SDK Articles
hehe okej sry for my english :]
What i mean is that i have a 3 xml files.
The first one I parse just like you. But the xml just contains the element 'bookname' with the attribute 'id'. So you can search the bookname and then fill the tableview.
The second xml i suppose to parse when you click a row in the first tablewview. In the second xml there are more elemens like 'autour' etc. but it also contains the element 'bookname' with 'id'. But i can't get the author elements to parse and show in the second tableview.
The third xml is suppose to be like the on before. It contains the ''bookname' element with 'ID' and then more element with 'image' url.
This xml should be parsed when you click a row in the second tableView.
All this maybe seems to be a little bit confusing. The thing is that i have 3 XML files with different info but the same ID. Each XML should be parsed in a tableview.
:):):)
@Kiddo If you do not mind emailing your code I will be happy to take a look at it.
Happy Programming,
iPhone SDK Articles
Hi, Thanks for the article very useful but I have a question :
I try to save the NSMutableArray into a xml file like
You said [array writeToFile:path atomically:YES]; and didn't save a thing...
I must include or import an Framework?
Thanks You
Hey!
I've just tried do add another view where i want to show some pictures.
But my problem is that I can't pass the data value to the third view?
It's work just fine in the two first view, but in the third it always just takes the data from the first cell in the XML.
Do you think you can post some code or tip for me?=) Like your tutorials adder wise.
Hey!
I've created a app just like yours. But in the second View(detailView) I want to parse another XML file who will show it's data in a third View?
I tried do this myself but i wont work..
could someone help me out with this. I would be eternally grateful.
First, very nice tutorials u got here!
But if I don't want the summary element to display in the second View?
Instead I want to add a third View where summary could be display for it self. I've tried this many times. But I just can't send data between more then 2 Views.
Hi, I am looking for a way to create an XML file from an IPhone application. Can you give me any pointers/sample code for the same?
Thanks
Many many helpful document
Looks like there is a new parser on the block:
http://touchtank.wordpress.com/element-parser/
Hey, great tutorial. My question is how you could adapt this tutorial to handle more than one XML file, with different tags to run like this tutorial.
Hi (sorry i cant speak engels)
How i give more information by summary the mac is 32 element than you see '...' how i make that box bigger for more information?
This tutorial really helped me to learn xml parsing.
Suppose, there's also an image along with title,author,summary in the xml.How can i display an image from web in a cell of Table in Detailed View?Do I need to have a url-link of the image in a tag(e.g. start-tag http://...end-tag) in the xml and again load the image from the web by a http request and display it in ImageView in a cell of the Group Table?or, there's a different approach to load an image in detailed view through xml?
Any help is greatly appreciated.
Thank you for this great tutorial;this really helped me to learn xml parsing.
Suppose there's an image along with title,author,summary defined in the xml.How can you display the image in the detailed view in the group table?
Do I need to have a url link in a tag in xml and have a http request and load the image in a ImageView in a cell in the group table?
Any help is greatly appreciated.
Post a Comment