how to parse gdata xml in iPhone? - iphone

here is xml
Root--->
Subject--->
SubjectID 1 /SubjectID
SubjectName MatheMatics /SubjectName
Sub_Subject---->
Sub_SubjectID 1 /Sub_SubjectID
Sub_SubjectName Calculus /Sub_SubjectName
/Sub_Subject
Sub_Subject
Sub_SubjectID 2 /Sub_SubjectID
Sub_SubjectName Geometry /Sub_SubjectName
/Sub_Subject
/Subject
Subject---->
SubjectID 2 /SubjectID
SubjectName Physics /SubjectName
/Subject
/Root
in app i want to show subject name in tableviewcontroller when application launch & when we clicked on tableviewcell it leads on another table view which shows sub_subject list.
how to achieve this
for that.
+ (NSString *)dataFilePath:(BOOL)forSave {
return [[NSBundle mainBundle] pathForResource:#"SubjectData" ofType:#"xml"];
}
+ (RootSubject *)loadParty {
NSString *filePath = [self dataFilePath:FALSE];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData
options:0 error:&error];
/* if (doc == nil) { return nil; }
NSLog(#"%#", doc.rootElement);
[doc release];
[xmlData release];
return nil;*/
RootSubject *rootSubject = [[[RootSubject alloc] init] autorelease];
NSArray *partyMembers = [doc nodesForXPath:#"//Root/Subject" error:nil];
//NSArray *patry = [doc nodesForXPath:#"//Root/Subject/SunjectID" error:nil];
for (GDataXMLElement *partyMember in partyMembers) {
// Let's fill these in!
NSString *subjectId, *subjectName, *sub_SubjectId, *sub_SubjectName;
// senderName
NSArray *subjectIds = [partyMember elementsForName:#"SubjectID"];
if (subjectIds.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [subjectIds objectAtIndex:0];
subjectId = firstName.stringValue;
} else continue;
// senderEmail
NSArray *subjectNames = [partyMember elementsForName:#"SubjectName"];
if (subjectNames.count > 0) {
GDataXMLElement *firstLevel = (GDataXMLElement *) [subjectNames objectAtIndex:0];
subjectName = firstLevel.stringValue;
} else continue;
/* //senderPhone
NSArray *sub_SubjectIds = [partyMember elementsForName:#"Sub_SubjectID"];
if (sub_SubjectIds.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [sub_SubjectIds objectAtIndex:0];
sub_SubjectId = firstName.stringValue;
} else continue;
//senderLocation
NSArray *sub_SubjectNames = [partyMember elementsForName:#"Sub_SubjectName"];
if (sub_SubjectNames.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [sub_SubjectNames objectAtIndex:0];
sub_SubjectName = firstName.stringValue;
} else continue;*/
//Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:subjectName sub_SubjectId:sub_SubjectId sub_SubjectName:sub_SubjectName]autorelease];
Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:subjectName sub_SubjectId:nil sub_SubjectName:nil]autorelease];
//Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:nil sub_SubjectId:sub_SubjectId sub_SubjectName:sub_SubjectName]autorelease];
//[rootGroup.groups addObject:group];
[rootSubject.subjects addObject:subject];
}
[doc release];
[xmlData release];
return rootSubject;
}
through this we get subject name and show it perfectly in tableviewcontroller but when i clicked on particular subject which provides subsubject in another view controller

Here is a good tutorial that shows XML parsing using GDataXMLParser.
how-to-read-and-write-xml-documents-with-gdataxml

Related

Parsing RSS feed - retrieve images, urls?

Hello I am parsing a RSS And Atom feeds, and my question is how can I check for < img > and < url > tags in < description >?
There must be some sort of check. Thanks.
Here is how I parse them:
- (NSArray *)parseFeed:(NSURL *)feedURL{
NSError *error;
NSData *data = [NSData dataWithContentsOfURL:feedURL];
GDataXMLDocument *xmlParse = [[GDataXMLDocument alloc] initWithData:data error:&error];
GDataXMLElement *rootElement = xmlParse.rootElement;
NSArray *array = [[NSArray alloc] init];
if ([rootElement.name compare:#"rss"] == NSOrderedSame) {
array = [self parseRSSFeed:rootElement];
return array;
} else if ([rootElement.name compare:#"feed"] == NSOrderedSame) {
array = [self parseAtomFeed:rootElement];
return array;
} else {
NSLog(#"Unsupported root element: %#", rootElement.name);
return nil;
}
}
-(NSArray *)parseRSSFeed:(GDataXMLElement *) rootElement
{
NSMutableArray *entries = [[NSMutableArray alloc] init];
NSArray *channels = [rootElement elementsForName:#"channel"];
for (GDataXMLElement *channel in channels) {
NSArray *items = [channel elementsForName:#"item"];
for (GDataXMLElement *item in items) {
FeedItem *itemF = [[FeedItem alloc] init];
itemF.title = [item valueForChild:#"title"];
itemF.description = [item valueForChild:#"description"];
NSLog(#"IMAGE - %#", [item valueForChild:#"img"]);
itemF.dateString = [item valueForChild:#"pubDate"];
itemF.link = [NSURL URLWithString:[item valueForChild:#"link"]];
itemF.dateString = [item valueForChild:#"updated"];
itemF.author = [item valueForChild:#"author"];
[entries addObject:itemF];
NSLog(#"RSS - %#", itemF.title);
}
}
NSArray *RSSArray = [entries copy];
return RSSArray;
}
-(NSArray *)parseAtomFeed:(GDataXMLElement *) rootElement
{
NSMutableArray *entries = [[NSMutableArray alloc] init];
NSArray *entry = [rootElement elementsForName:#"entry"];
for (GDataXMLElement *entryElement in entry) {
// NSArray *items = [channel elementsForName:#"item"];
//for (GDataXMLElement *item in items) {
FeedItem *itemF = [[FeedItem alloc] init];
itemF.title = [entryElement valueForChild:#"title"];
itemF.description = [entryElement valueForChild:#"summary"];
NSArray *links = [entryElement elementsForName:#"link"];
for (GDataXMLElement *link in links) {
itemF.link = [NSURL URLWithString:[[link attributeForName:#"href"] stringValue]];
}
itemF.dateString = [entryElement valueForChild:#"updated"];
NSArray *authors = [entryElement elementsForName:#"author"];
for (GDataXMLElement *authorElement in authors) {
itemF.author = [authorElement valueForChild:#"name"];
}
[entries addObject:itemF];
NSLog(#"Atom - %#", itemF.title);
}
NSArray *atomArray = [entries copy];
return atomArray;
}
I am parsing them using GDataXMLParser, and my own parser class.
Do it like this:
NSString *Str=[item valueForChild:#"description"];
NSArray *tmp=[Str componentsSeparatedByString:#"<Img>"];
if([tmp count]>1){
NSString *urlstr=[[tmp objectatindex:1] stringByReplacingOccurrencesOfString:#" </Img>" withString:#""];
}
Now urlstr contains your image url.
Enjoy
I thought that
itemF.description = [item valueForChild:#"description"];
is NSString. So you can use componentsSeparatedByString with "your tag".
It will return array. In array at postion 1 you will get your img url.
This url has closing bracket "your closing tag".
Replace "your closing tag" with space. You will get image url.
Hope, this will help you.

how to capture the required values from a URL

I need to extract a variable's value from a string, which happens to be a URL. The string/url is loaded as part of a separate php query, not the url in the browser.
The url's will look like:
http://gmail.com?access_token=ab8w4azq2xv3dr4ab37vvzmh&token_type=bearer&expires_in=3600
How can I capture the value of the access_token which in this example is ab8w4azq2xv3dr4ab37vvzmh?
This code should do it:
- (NSString *)extractToken:(NSURL *)URL
{
NSString *urlString = [URL absoluteString];
NSRange start = [urlString rangeOfString:#"access_token="];
if (start.location != NSNotFound)
{
NSString *token = [urlString substringFromIndex:start.location+start.length];
NSRange end = [token rangeOfString:#"&"];
if (end.location != NSNotFound)
{
//trim off other parameters
token = [token substringToIndex:end.location];
}
return token;
}
//not found
return nil;
}
Alternatively, here is a more general solution that will extract all the query parameters into a dictionary:
- (NSDictionary *)URLQueryParameters:(NSURL *)URL
{
NSString *queryString = [URL query];
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *parameters = [queryString componentsSeparatedByString:#"&"];
for (NSString *parameter in parameters)
{
NSArray *parts = [parameter componentsSeparatedByString:#"="];
NSString *key = [[parts objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
if ([parts count] > 1)
{
id value = [[parts objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[result setObject:value forKey:key];
}
}
return result;
}
Good Category for NSDictionary:
#import "NSDictionary+URL.h"
#implementation NSDictionary (URL)
+ (NSDictionary *)dictionaryWithUrlString:(NSString *)urlString{
NSRange urlRange = [urlString rangeOfString:#"?"];
if(urlRange.length>0){
urlString = [urlString substringFromIndex:urlRange.length+urlRange.location];
}
NSArray *pairsArray = [urlString componentsSeparatedByString:#"&"];
NSMutableDictionary *parametersDictionary = [[NSMutableDictionary alloc] initWithCapacity:[pairsArray count]];
for(NSString *pairString in pairsArray){
NSArray *valuesArray = [pairString componentsSeparatedByString:#"="];
if([valuesArray count]==2){
[parametersDictionary setValue:[valuesArray objectAtIndex:1] forKey:[valuesArray objectAtIndex:0]];
}
}
return [parametersDictionary autorelease];
}
#end
NSMutableDictionary *querycomponent = [[NSMutableDictionary alloc] init];
if (![query isEqualToString:#""]){
NSArray *queryArray = [query componentsSeparatedByString:#"&"];
for (NSString *subquery in queryArray){
NSArray *subqueryArray = [subquery componentsSeparatedByString:#"="];
NSString *key = [subqueryArray objectAtIndex:0];
NSString *val = [subqueryArray objectAtIndex:1];
[querycomponent setObject:val forKey:key];
}
NSLog(#"querycomponent %#",querycomponent);
}

initWithDocPath not found

it shows me warning that initWithDocPath not found when i want to get private directory content..
+ (NSMutableArray *)loadScaryBugDocs {
NSString *documentsDirectory = [VideoDatabase getPrivateDocsDir];
NSError *error;
NSArray *files =[NSFileManagerdefaultManager]contentsOfDirectoryAtPath:documentsDirectory error:&error];
if (files == nil) {
return nil;
}
NSMutableArray *retval = [NSMutableArray arrayWithCapacity:files.count];
for (NSString *file in files) {
if ([file.pathExtension compare:#"scarybug" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:file];
VideoNotepadViewController *doc = [[[VideoNotepadViewController alloc] initWithDocPath:fullPath] autorelease];
//shows warning here
[retval addObject:doc];
}
}
return retval;
}
You need to implement the initWithDocPath: method in VideoNotepadViewController. Apple doesn't provide a method by that name.

Not able to resolve a leak detected by leaks tool. Can i ignore it?

I am not able to find a way to remove a leak detected by leaks tool.
Here is my problem...
I have a singleton object in my delegate which stores data on a global level. Now, I have a array of objects which i maintain here and add or modify it from controllers.
Below is a function which fills the objects and sets the above global array,
Now, the highlighted lines(marked by //LEAK) are where the leaks tool tell me its a leak. I require this array for my session. I release the array at the end when i logout.
Should i be worried about this kind leak?
-(LayoutInfo *) fillLayout: (GDataXMLElement *) layoutElement {
LayoutInfo *layout = [[LayoutInfo alloc] init];
layout.dataTableCount = 0;
layout.chartsCount = 0;
NSArray *templateNameArr = [layoutElement elementsForName:#"TemplateName"];
NSMutableArray *chartElements = [[NSMutableArray alloc] init]; // LEAK
NSMutableArray *dtElements = [[NSMutableArray alloc] init];
NSArray *charts = [layoutElement elementsForName:#"chart"]; // LEAK
if (charts.count > 0) {
for (GDataXMLElement *singleChart in charts) {
chart *chartInfo = [[chart alloc] init]; // LEAK
layout.chartsCount = layout.chartsCount + 1;
NSArray *imageName = [singleChart elementsForName:#"imageName"];
if (imageName.count > 0) {
GDataXMLElement *imageNameStr = (GDataXMLElement *) [imageName objectAtIndex:0];
chartInfo.imageName = imageNameStr.stringValue; // LEAK
}
NSArray *imagePath = [singleChart elementsForName:#"imagePath"];
if (imagePath.count > 0) {
GDataXMLElement *imagePathStr = (GDataXMLElement *) [imagePath objectAtIndex:0];
chartInfo.imagePath = imagePathStr.stringValue; // LEAK
}
NSArray *imageFileName = [singleChart elementsForName:#"imageFileName"];
if (imageFileName.count > 0) {
GDataXMLElement *imageFileNameStr = (GDataXMLElement *) [imageFileName objectAtIndex:0];
chartInfo.imageFileName = imageFileNameStr.stringValue;
}
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:chartInfo.imagePath]];
[request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"]
stringByAppendingPathComponent:chartInfo.imageFileName]];
[request setDidFinishSelector:#selector(fillLayout_requestDone:)];
[request setDidFailSelector:#selector(fillLayout_requestWentWrong:)];
[request startSynchronous];
NSString *imagePath1 = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:chartInfo.imageFileName];
if([[NSFileManager defaultManager] fileExistsAtPath:imagePath1]) {
NSLog(#" --- IMAGE SAVED -- %#", imagePath1);
}
[chartElements addObject:chartInfo];
} //for
layout.chartElement = chartElements; // THIS IS WHERE I ASSIGN THE GLOBAL ARRAY
//[chartElements release];
}
return layout;
}
-(LayoutInfo *) fillLayout: (GDataXMLElement *) layoutElement {
LayoutInfo *layout = [[LayoutInfo alloc] init];
layout.dataTableCount = 0;
layout.chartsCount = 0;
NSArray *templateNameArr = [layoutElement elementsForName:#"TemplateName"];
NSMutableArray *chartElements = [[NSMutableArray alloc] init]; // LEAK
//NSMutableArray *dtElements = [[NSMutableArray alloc] init];
NSArray *charts = [layoutElement elementsForName:#"chart"]; // LEAK
if (charts.count > 0) {
for (GDataXMLElement *singleChart in charts) {
chart *chartInfo = [[chart alloc] init]; // LEAK
layout.chartsCount = layout.chartsCount + 1;
NSArray *imageName = [singleChart elementsForName:#"imageName"];
if (imageName.count > 0) {
GDataXMLElement *imageNameStr = (GDataXMLElement *) [imageName objectAtIndex:0];
chartInfo.imageName = imageNameStr.stringValue; // LEAK
}
NSArray *imagePath = [singleChart elementsForName:#"imagePath"];
if (imagePath.count > 0) {
GDataXMLElement *imagePathStr = (GDataXMLElement *) [imagePath objectAtIndex:0];
chartInfo.imagePath = imagePathStr.stringValue; // LEAK
}
NSArray *imageFileName = [singleChart elementsForName:#"imageFileName"];
if (imageFileName.count > 0) {
GDataXMLElement *imageFileNameStr = (GDataXMLElement *) [imageFileName objectAtIndex:0];
chartInfo.imageFileName = imageFileNameStr.stringValue;
}
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:chartInfo.imagePath]];
[request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"]
stringByAppendingPathComponent:chartInfo.imageFileName]];
[request setDidFinishSelector:#selector(fillLayout_requestDone:)];
[request setDidFailSelector:#selector(fillLayout_requestWentWrong:)];
[request startSynchronous];
NSString *imagePath1 = [[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:chartInfo.imageFileName];
if([[NSFileManager defaultManager] fileExistsAtPath:imagePath1]) {
NSLog(#" --- IMAGE SAVED -- %#", imagePath1);
}
[chartElements addObject:chartInfo];
[chartInfo release]; // it's retained in chartElements until removed, or until chartElements is deallocced
} //for
if(layout.charElement){
[layout.charElement release]; // you should however consider in making charElement property as retain;
layout.charElement = nil; // this isn't required here (since you're assigning it a new value), but you should usually set it to nil after a release to prevent EXC_BADACCESS
}
layout.chartElement = chartElements; // THIS IS WHERE I ASSIGN THE GLOBAL ARRAY
//[chartElements release];
}
return [layout autorelease]; // in case you don't want it autoreleased you should call your method something like: createFilledLayout ('create' is usually used so anyone that uses the method knows it's responsible for releasing the return value)
}
you should have a look at Memory Management Programming Guide

parse a NSURL mailto

How can I parse a mailto request ?
'mailto:someone#example.com?cc=someone_else#example.com&subject=This%20is%20the%20subject&body=This%20is%20the%20body'
From this NSURL, I want to extract the recipient, the subject and the body. How should I do ?
Thanks
Here is some code that will parse any URL and return a dictionary with the parameters and the associated objects in a dictionary. It works for mailto URLs, too.
Please note: This code assumes you're using ARC!
#interface NSString (URLDecoding)
- (NSString *) URLDecodedString;
#end
#implementation NSString (URLDecoding)
- (NSString *) URLDecodedString {
NSString *result = (__bridge_transfer NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (__bridge CFStringRef)self, CFSTR(""), kCFStringEncodingUTF8);
return result;
}
#end
- (NSDictionary *) parameterDictionaryFromURL:(NSURL *)url {
NSMutableDictionary *parameterDictionary = [[NSMutableDictionary alloc] init];
if ([[url scheme] isEqualToString:#"mailto"]) {
NSString *mailtoParameterString = [[url absoluteString] substringFromIndex:[#"mailto:" length]];
NSUInteger questionMarkLocation = [mailtoParameterString rangeOfString:#"?"].location;
[parameterDictionary setObject:[mailtoParameterString substringToIndex:questionMarkLocation] forKey:#"recipient"];
if (questionMarkLocation != NSNotFound) {
NSString *parameterString = [mailtoParameterString substringFromIndex:questionMarkLocation + 1];
NSArray *keyValuePairs = [parameterString componentsSeparatedByString:#"&"];
for (NSString *queryString in keyValuePairs) {
NSArray *keyValuePair = [queryString componentsSeparatedByString:#"="];
if (keyValuePair.count == 2)
[parameterDictionary setObject:[[keyValuePair objectAtIndex:1] URLDecodedString] forKey:[[keyValuePair objectAtIndex:0] URLDecodedString]];
}
}
}
else {
NSString *parameterString = [url parameterString];
NSArray *keyValuePairs = [parameterString componentsSeparatedByString:#"&"];
for (NSString *queryString in keyValuePairs) {
NSArray *keyValuePair = [queryString componentsSeparatedByString:#"="];
if (keyValuePair.count == 2)
[parameterDictionary setObject:[[keyValuePair objectAtIndex:1] URLDecodedString] forKey:[[keyValuePair objectAtIndex:0] URLDecodedString]];
}
}
return [parameterDictionary copy];
}
And here is how you use it:
NSURL *mailtoURL = [NSURL URLWithString:#"mailto:foo#example.com?cc=bar#example.com&subject=Greetings%20from%20Cupertino!&body=Wish%20you%20were%20here!"];
NSDictionary *parameterDictionary = [self parameterDictionaryFromURL:mailtoURL];
NSString *recipient = [parameterDictionary objectForKey:#"recipient"];
NSString *subject = [parameterDictionary objectForKey:#"subject"];
NSString *body = [parameterDictionary objectForKey:#"body"];
EDIT:
I updated the code to work with any URL and recipients are now in the dictionary for mailto URLs.
I would pull the email from that like this:
NSString * mailToString = #"'mailto:someone#example.com?cc=someone_else#example.com&subject=This%20is%20the%20subject&body=This%20is%20the%20body'";
NSArray *tempArray = [mailToString componentsSeparatedByString:#"?"];
//get email address from array
NSString * emailString = [[tempArray objectAtIndex:0]description];
//clean up string
emailString = [emailString stringByReplacingOccurrencesOfString:#"'mailto:" withString:#""];
//and here is your email string
NSLog(#"%#",emailString);
Since iOS 7 this is easily doable with NSURLComponents. You can create that object with:
if let components = NSURLComponents(URL: url, resolvingAgainstBaseURL:false) { ...
Then you can get the recipient accessing the path property of NSURLComponents; and the parameters with the queryItems property. For instance, if we wanted to get the subject, something like this would do our job
let queryItems = components.queryItems as? [NSURLQueryItem]
let subject = queryItems?.filter({$0.name == "subject"}).first?.value
NSURL category for just mailto: This method also has a fix for a crash bug in Fabian's answer above when mailto: url doesn't contain a ?. It also doesn't require the URLDecodedString category method.
#implementation NSURL (Additions)
- (NSDictionary *) parameterDictionaryForMailTo {
NSMutableDictionary *parameterDictionary = [[NSMutableDictionary alloc] init];
NSString *mailtoParameterString = [[self absoluteString] substringFromIndex:[#"mailto:" length]];
NSUInteger questionMarkLocation = [mailtoParameterString rangeOfString:#"?"].location;
if (questionMarkLocation != NSNotFound) {
[parameterDictionary setObject:[mailtoParameterString substringToIndex:questionMarkLocation] forKey:#"recipient"];
NSString *parameterString = [mailtoParameterString substringFromIndex:questionMarkLocation + 1];
NSArray *keyValuePairs = [parameterString componentsSeparatedByString:#"&"];
for (NSString *queryString in keyValuePairs) {
NSArray *keyValuePair = [queryString componentsSeparatedByString:#"="];
if (keyValuePair.count == 2)
[parameterDictionary setObject:[[keyValuePair objectAtIndex:1] stringByRemovingPercentEncoding] forKey:[[keyValuePair objectAtIndex:0] stringByRemovingPercentEncoding]];
}
}
else {
[parameterDictionary setObject:mailtoParameterString forKey:#"recipient"];
}
return [parameterDictionary copy];
}
- (NSDictionary *) parameterDictionaryFromURL:(NSURL *)url {
NSMutableDictionary *parameterDictionary = [[NSMutableDictionary alloc] init];
NSURLComponents * urlComponents = [NSURLComponents componentsWithString:url.absoluteString];
for (NSURLQueryItem *item in urlComponents.queryItems) {
parameterDictionary[item.name] = item.value;
}
if ([url.scheme isEqualToString:#"mailto"]) {
NSUInteger questionMarkLocation = [url.resourceSpecifier rangeOfString:#"?"].location;
if (questionMarkLocation == NSNotFound) {
parameterDictionary[#"recipient"] = url.resourceSpecifier;
} else {
parameterDictionary[#"recipient"] = [url.resourceSpecifier substringToIndex:questionMarkLocation];
}
}
return [parameterDictionary copy];
}