How to parse this XML file using Objective C? - 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

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;
}
}

NSXMLParser can not parse special characters (german & french)

I am working on an App, which makes a search on a private server and shows the results to the user. The problem is NSXLParser can not parse the special german and french characters. For example: it should be:(Geschäftsführer) -> what i get is: (äftsführer)
How can i fix this ?
here is my code:
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([elementname isEqualToString:#"results"])
{
currentJob = [SearchResult alloc];
}
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"jobTitle"])
{
currentJob.jobTitle = currentNodeContent;
}
if ([elementname isEqualToString:#"location"])
{
currentJob.shortAddress = currentNodeContent;
}
if ([elementname isEqualToString:#"companyName"])
{
currentJob.employer = currentNodeContent;
}
if ([elementname isEqualToString:#"results"])
{
[self.jobs addObject:currentJob];
currentJob = nil;
currentNodeContent = nil;
}
}
Any help would be much appreciated...
Thanks in advance
Your foundCharacters method should append the string to a NSMutableString object, because it can be called multiple times for a single value. In didStartElement, initialize a NSMutableString object (let's call it elementContentString), then do this:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)chars
{
[self.elementContentString appendString:chars];
}
And in your didEndElement you can get the content as a string. Note that you should make a non-mutable copy of it (so you don't overwrite it with the next element), using [NSString stringWithString:self.elementContentString].

iphone xml binding / parsing to objects

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.

Parsing xml in NSXMLParser

I have read many examples of how to get text out of xml files, but just don't get how to. Here is a sample xml file:
<?xml version="1.0" encoding="UTF-8"?>
<questions>
<set>
<question>Question</question>
<answer>Answer</answer>
</set>
</questions>
Using -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI, what's the easiest way to get the values Question and Answer? I already have my parser delegate hooked up and all that blah.
For implementing NSXMLParser you need to implement delegate method of it.
First of all initiate NSXMLParser in this manner.
- (void)viewDidLoad {
[super viewDidLoad];
rssOutputData = [[NSMutableArray alloc]init];
//declare the object of allocated variable
NSData *xmlData=[[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:#""]];// URL that given to parse.
//allocate memory for parser as well as
xmlParserObject =[[NSXMLParser alloc]initWithData:xmlData];
[xmlParserObject setDelegate:self];
//asking the xmlparser object to beggin with its parsing
[xmlParserObject parse];
//releasing the object of NSData as a part of memory management
[xmlData release];
}
//-------------------------------------------------------------
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName
attributes: (NSDictionary *)attributeDict
{
if( [elementName isEqualToString:#"question"])
{
strquestion = [[NSMutableString alloc] init];
}
}
//-------------------------------------------------------------
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// init the ad hoc string with the value
currentElementValue = [[NSMutableString alloc] initWithString:string];
} else {
// append value to the ad hoc string
[currentElementValue appendString:string];
}
NSLog(#"Processing value for : %#", string);
}
//-------------------------------------------------------------
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if( [elementName isEqualToString:#"question"])
{
[strquestion setString:elementName];
}
[currentElementValue release];
currentElementValue = nil;
}
The above delegate method is sent by a parser object to its delegate when it encounters an end of specific element. In this method didEndElement you will get value of question.
// This one called out when it hit a starting tag on xml in your case <question>
BOOL got = FALSE;
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
{
if([elementName isEqualToString:#"question"])
{
got = TRUE;
}
}
// This is third one to called out which gives the end tag of xml in your case </question>
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
// This delegate is the second one to called out which gives the value of current read tag in xml
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if(got)
{
NSLog(#"your desired tag value %#",string);
got = FALSE;
}
}
You need to implement the method
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
Once you see the elements whose (inner)text you want to grab, set a flag in your program, and keep a string with the things that foundCharacters finds between the tags. Once you hit the didEndElement method, you can do what you want with the string and reset the flag.
For example
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (sawQuestion) {
// need to check here that self->myString has been initialized
[self->myString appendString:string];
}
}
and in didEndElement you can reset the flag sawQuestion
You have to implement the callbacks for NSXMLParserDelegate
The key ones are:
// called when it found an element - in your example, question or answer
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
// called when it hits the closing of the element (question or answer)
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI
// called when it found the characters in the data of the element
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
So, when you hit the elements, you can set state whether the parser is currently in the question or answer element (with an iVar) and then when you get called back with foundCharacters, based on the state you set when you hit the element, you know which variable (question or answer) to assign the data to.

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.