iphone xml binding / parsing to objects - objective-c

I'm new to iphone developing and what I want is an xml parser that I can bind to Objects. I searched a lot but I still need some help. For example I have the following xml structure:
<xml>
<hotels>
<hotel>
<id>1</id>
<name>Hotel Name</name>
</hotel>
<hotel>
....
</hotel>
</hotels>
<beaches>
<beach>
<id>11</id>
<name>Beach Name</name>
</beach>
<beach>
....
</beach>
</beaches>
</xml>
Now my question is...which is the best (or maybe easier) way to read this xml file and parse for example...:
Now I want a list of all hotels...so I want o parse and get that list...etc.
Now I want beach with id = 11 etc.
Can this be done easily in iphone? Which is the best approach? I would be thankful if you could give me examples with source code or such. Thanks in advance.
NOTE: I will support at least ios 4.3 or later.

you can try implementing NSXMLParserDelegate then write your logic in
- (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
Example code:-
Create XMLParser class, then bean classes for Hotel, Beach and arrays for storing these objects.
XMLParser.h
#import <Foundation/Foundation.h>
#interface XMLParser : NSObject <NSXMLParserDelegate>
#property (strong, readonly) NSMutableArray *yourObjects;
-(id) parseXML:(NSString *)url;
#end
XMLParser.m
#import "XMLParser.h"
#import "YourObject.h"
#implementation XMLParser
#synthesize yourObjects =_yourObjects;
NSMutableString *currentNode;
NSXMLParser *parser;
YourObject *YourObject;
-(id) parseXML:(NSString *)url
{
_yourObjects = [[NSMutableArray alloc]init];
NSURL *nsURL = [NSURL URLWithString:url];
NSData *data = [[NSData alloc] initWithContentsOfURL:nsURL];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNode = (NSMutableString *) [string stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:
(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary
*)attributeDict
{
if ([elementName isEqualToString:#"hotel"])
{
yourObject = [YourObject alloc]; //eg:- Hotel
//any logic that you want to include.....
}
if ([elementName isEqualToString:#"beach"])
{
yourObject = [YourObject alloc]; //eg:- beach
//any logic that you want to include.....
}
}
#end
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:
(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if([elementName isEqualToString:#"status"])
{
[self.yourObjects addObject:yourObject];
yourObject = nil;
currentNode = nil;
}
}
call -(id) parseXML:(NSString *)url; to parse the required XML and retrieve the Objects.
Hope this helps.

Related

Trouble Parsing XML and fetching data

I have need to parse the following xml from webservicex.net, for and iPhone App. I need to store the verse Verse and BibleWords into some NSArray/NSDictionary or something.
<string xmlns="http://www.webserviceX.NET">
<NewDataSet>
<Table>
<Book>1</Book>
<BookTitle>Genesis</BookTitle>
<Chapter>1</Chapter>
<Verse>1</Verse>
<BibleWords>In the beginning God created the heaven and the earth.</BibleWords>
</Table>
<Table>
<Book>1</Book>
<BookTitle>Genesis</BookTitle>
<Chapter>1</Chapter>
<Verse>2</Verse>
<BibleWords>And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.</BibleWords>
</Table>
<Table>
<Book>1</Book>
<BookTitle>Genesis</BookTitle>
<Chapter>1</Chapter>
<Verse>3</Verse>
<BibleWords>And God said, Let there be light: and there was light.</BibleWords>
</Table>
<Table>
<Book>1</Book>
<BookTitle>Genesis</BookTitle>
<Chapter>1</Chapter>
<Verse>4</Verse>
<BibleWords>And God saw the light, that it was good: and God divided the light from the darkness.</BibleWords>
</Table>
</NewDataSet>
</string>
I wrote the following code for parsing the data.
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if ([elementName isEqualToString:#"string"]) {
model = [[Model alloc]init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentElementValue) {
currentElementValue = [[NSMutableString alloc]initWithString:string];
}
else {
[currentElementValue appendString:string];
}
NSLog(#"%#", currentElementValue);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"NewDataSet"]) {
return;
}
if ([elementName isEqualToString:#"Table"]) {
[verses addObject:model];
model = nil;
}
else {
[model setValue:currentElementValue forKey:elementName]; //The exception break point hits here
}
currentElementValue = nil;
}
The currentElementValue is displayed correctly. model is and object of a class named Model, currentElementValue is a NSMutableString object verses is an NSMutableArray. I am a beginner in objective C and haven't done parsing before. The problem is that the method:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
is not working as expected. The app got broken after hitting the exception break point that i have commented in the code. How can I get the value of Verse and BibleWords and store it to some NSArray/NSMutableArray/NSDictionary/NSMutableDictionary. Please ask if there is anything else I need to mention to see where the problem actually lies.
EDIT:
Tried with this:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
captureCharacters = NO;
[currentElementValue setString : #""];
if ([elementName isEqualToString:#"Table"]) { //set a break point here as well. The elementName is string and hence is not entering any of the conditions in this delegate method. Hence captureCharacters is always set to NO and nothing is working.
model = [[Model alloc]init];
}
else if ([elementName isEqualToString:#"Verse"]) {
capturingCharacters = yes;
}
else if ([elementName isEqualToString:#"BibleWords"]) {
capturingCharacters = yes;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(capturingCharacters) {
[currentElementValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"Table"]) {
[array addObject : model];
model = nil;
}
else if ([elementName isEqualToString:#"Verse"]) { //set a break point here
model.Verse = currentElementValue; //not entering this condition
}
else if ([elementName isEqualToString:#"BibleWords"]) {
model.BibleWords = currentElementValue; //not entering this condition
}
}
It is not working and I am getting null values for model.Verse and model.BibleWords.
How does these methods work?
EDIT-2
Model Interface:
//model.h
#protocol HttpRequestHandler <NSObject>
- (void)returnFromSiteParsedData:(NSMutableArray *)parsedData;
#end
#interface Model : NSObject <NSURLConnectionDelegate, NSXMLParserDelegate>
{
NSString *urlToLoad;
NSMutableURLRequest *requestSiteToSendData;
NSURLConnection *connectionToSiteToSendData;
NSString *verseText;
int verseNumber;
}
#property(nonatomic, retain) NSString *verseText;
#property(nonatomic, assign) int verseNumber;
- (void)loadSiteToSendDataWithChapterNumber:(int)chapterNumber AndBookNumber:(int)bookNumber;
#property(nonatomic, retain)id<HttpRequestHandler>httpRequestHandlerDelegate;
#end
Model Implementation
//model.m
#implementation Model
#synthesize verseNumber;
#synthesize verseText;
- (void)loadSiteToSendDataWithChapterNumber:(int)chapterNumber AndBookNumber:(int)bookNumber {
urlToLoad = [[NSString alloc]initWithFormat:#"http://www.webservicex.net/BibleWebservice.asmx/GetBibleWordsByBookTitleAndChapter?BookTitle=Genesis&chapter=1"];
requestSiteToSendData = [NSMutableURLRequest requestWithURL:[[NSURL alloc]initWithString:urlToLoad] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
connectionToSiteToSendData = [[NSURLConnection alloc]initWithRequest:requestSiteToSendData delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Parse the XML into a dictionary
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
VBSParser *vbsParser = [[VBSParser alloc]initVBSParser];
[parser setDelegate:vbsParser];
BOOL success = [parser parse];
if (success) {
NSMutableArray *verses = [vbsParser verses];
NSLog(#"%#", verses);
NSLog(#"Number: %d\n Text: %#", verseNumber,verseText);
[self.httpRequestHandlerDelegate returnFromSiteParsedData:verses];
}
// Print the dictionary
}
#end
A delegate is used to return parsed data to the view controller.
Make a BOOL capturingCharacters;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
captureCharacters = NO;
[currentElementValue setString : #""];
if ([elementName isEqualToString:#"Table"]) {
model = [[Model alloc]init];
}
else if ([elementName isEqualToString:#"Verse"]) {
capturingCharacters = yes;
}
else if ([elementName isEqualToString:#"BibleWords"]) {
capturingCharacters = yes;
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(capturingCharacters) {
[currentElementValue appendString:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:#"Table"]) {
[array addObject : model];
model = nil;
}
else if ([elementName isEqualToString:#"Verse"]) {
model.Verse = currentElementValue;
}
else if ([elementName isEqualToString:#"BibleWords"]) {
model.BibleWords = currentElementValue;
}
}

Feeding XML into custom objects?

I have some XML being returned from a web query, with multiple parameters wrapped up inside a tag, like so:
<game>
<name>First game title</name>
<id>12345</id>
<desc>A game..</desc>
</game>
<game>
<name>Second game title</name>
<id>67890</id>
<desc>Another game..</desc>
</game>
I'm using NSXMLParser to parse it, and it's spitting out each line one by one into my console as I NSLog them. I'm trying to feed each <game> into one of my Game objects, with name as an NSString, ID as an NSNumber, etc. However, I'm struggling to work out how I'd tell it to begin a new object, since the <game> tag isn't being returned in any of my NSLog statements, only those with actual data are (such as each name, id, etc.)
If I want to get all of the data within each <game> </game> tag into a separate object, how can I do so? Here's the parser code:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
element = [NSMutableString string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(#"ELEMENT TYPE: %# VALUE: %#", elementName, element);
}
First make yourself a Game class. We will parse the XML into Games objects.
Game.h like so:
#interface Game : NSObject
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSNumber *gameID;
#property (nonatomic, retain) NSString *gameDescription;
#end
Now in the class you are parsing the XML in (in this example ViewController), create a NSMutableArray property to store the Game objects as we parse them, a Game property to use as we create new Game objects, a NSString property to store the current element we are parsing in the XML, and a property for the NSXMLParser instance we are using. Also make sure it conforms to the NSXMLParserDelegate protocol.
So the header ViewController.h:
#interface ViewController : UIViewController <NSXMLParserDelegate>
#property (nonatomic, retain) NSString *currentElement;
#property (nonatomic, retain) NSMutableArray *games;
#property (nonatomic, retain) Game *gameBeingParsed;
#property (nonatomic, retain) NSXMLParser *xmlParser;
#end
Now in the implementation ViewController.m we parse the XML:
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Make an NSMutableArray to put the parsed Game objects in
self.games = [NSMutableArray array];
// Get the XML data to parse
// We need it in an NSdata object
NSString *xmlString = #"<?xml version=\"1.0\" encoding=\"utf-8\"?><xml><game><name>First game title</name><id>12345</id><desc>A game..</desc></game><game><name>Second game title</name><id>67890</id><desc>Another game..</desc></game></xml>";
NSData *xmlData = [xmlString dataUsingEncoding:NSStringEncodingConversionAllowLossy];
// Set up an NSXMLParser to use
// Set the delegate and start parsing!
self.xmlParser = [[[NSXMLParser alloc] initWithData:xmlData] autorelease];
_xmlParser.delegate = self;
[_xmlParser parse];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
// If we have a <game> tag then we are starting to parse a new Game object
if ([elementName isEqualToString:#"game"]) {
self.gameBeingParsed = [[[Game alloc] init] autorelease];
}
// If not then we need to keep track of the element name so we know which property to set on the Game object
else {
self.currentElement = elementName;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
// If we have a closing </game> tag we are done parsing a Game so add it to the array
if ([elementName isEqualToString:#"game"]) {
[_games addObject:_gameBeingParsed];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// Work out which element we have the characters for
// Then set the property of the Game object
if ([_currentElement isEqualToString:#"name"]){
_gameBeingParsed.name = string;
}
if ([_currentElement isEqualToString:#"id"]){
_gameBeingParsed.gameID = [NSNumber numberWithInt:[string intValue]];
}
if ([_currentElement isEqualToString:#"name"]){
_gameBeingParsed.gameDescription = string;
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser{
// We are done parsing XML
NSLog(#"Parsed %d Games", _games.count);
for (Game *game in _games) {
NSLog(#"%# : %# : %#", game.name, game.gameID, game.gameDescription);
}
}
After parsing has finished and we get a call back in parserDidEndDocument: At this point the _games property will be populated we instances of Games.

How to get tags parameters with NSXMLParser in Objective-C?

In XML struct i have:
<font fontsize="10" fontcolor="#000000" fontface="file.ttf"/>
How do i get fontsize, color and face using NSXMLParser?
Of course i have the standard implementation
-(id)init
{
self = [super init];
parser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"myxmlfile" ofType:#"xml"]]];
[parser setDelegate:self];
[parser parse];
return self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(#"Started Element %#", elementName);
element = [NSMutableString string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
NSLog(#"Found an element named: %# with a value of: %#", elementName, element);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (element == nil)
element = [[NSMutableString alloc] init];
[element appendString:string];
}
And it works beautifly for a <mytag>something</mytag>. How to get tag attributes?
Your attributeDictionary from
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
contains them. Just call [atrributeDict objectForKey:#"fontColor"] for example
The NSXMLParserDelegate protocol has a – parser:foundAttributeDeclarationWithName:forElement:type:defaultValue: method that the parser uses to tell the delegate about each attribute. Implement that method in your delegate and you'll get the attributes.
Use xpathQuery.. Its the most simple, quickest solution for XML parsing.. This will solve your problem..
here is the link..
http://cocoawithlove.com/2008/10/using-libxml2-for-parsing-and-xpath.html
BTW: for 'query' part, you need to put '//' for root element, '//root//item' for inner hierarchy for example.

How to parse this XML file using Objective C?

I have an XML file of the following structure:
<xmlDocument version="1">
<subject id="1">
<maths marks="65"/>
<science marks="80"/>
<tamil marks="90"/>
<social marks="79"/>
<English marks="70"/>
</subject>
</xmlDocument>
How to parse and get this data using Objective C?
Create an instance of NSXMLParser and assign a delegate to the parser.
In your delegate class, implement the relevant methods of the NSXMLParserDelegate protocol.
Call the parser's parse method.
Ask more specific questions if you encounter problems.
Since you don't have any text inside your tags you can use the parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName attributes:(NSDictionary *)attributeDict method on your delegate. Than you can store the values inside a dictionary or object. If you have multiple subject tags you can use the parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName to change the context of your parser. The official documentation should give you more details on which methods are available.
You could do something like that (incomplete implementation):
/*
* Incomplete implementation just to give some pointers
*/
#implementation MyDelegate
-(void) init {
if((self = [super init])) {
_subjects = [NSMutableArray new];
}
}
-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName attributes:(NSDictionary *)attributeDict {
if([elementName equalsIgnoreCase:#"subject"]) {
_context = [NSMutableDictionary new];
} else {
[_context setObject:[attributeDict valueForKey:#"mark"] forKey:elementName];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName {
[_subjects addObject:_context]
[_context release]; _context = nil;
}
#end

How to read the content of an XML tag

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