Search for XML feeds usind Iphone - iphone

hi can anyone give me hint of how to start coding for an app to search the internet and find the rss xml url's using a string provided by the user.
thanks upfront.

You need to use XML parsing to implement this.I suggest use touchXML
-(void)callwebservice{
NSString *path = #"YOUR URL";
[self grabRSSFeed:path];
}
pragma mark -
pragma mark Touch XML
pragma mark -
-(void) grabRSSFeed:(NSString *)blogAddress {
// Initialize the blogEntries MutableArray that we declared in the header
blogEntries = [[NSMutableArray alloc] init];
// Convert the supplied URL string into a usable URL object
NSURL *url = [NSURL URLWithString: blogAddress];
// Create a new rssParser object based on the TouchXML "CXMLDocument" class, this is the
// object that actually grabs and processes the RSS data
CXMLDocument *rssParser = [[[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil] autorelease];
// Create a new Array object to be used with the looping of the results from the rssParser
NSArray *resultNodes = NULL;
// Set the resultNodes Array to contain an object for every instance of an node in our RSS feed
resultNodes = [rssParser nodesForXPath:#"//Node you want to parse" error:nil];
// Loop through the resultNodes to access each items actual data
for (CXMLElement *resultElement in resultNodes) {
// Create a temporary MutableDictionary to store the items fields in, which will eventually end up in blogEntries
NSMutableDictionary *blogItem = [[NSMutableDictionary alloc] init];
// Create a counter variable as type "int"
int counter;
// Loop through the children of the current node
for(counter = 0; counter < [resultElement childCount]; counter++) {
// Add each field to the blogItem Dictionary with the node name as key and node value as the value
[blogItem setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];
NSLog(#"Data = %#",[[resultElement childAtIndex:counter] stringValue]);
}
// Add the blogItem to the global blogEntries Array so that the view can access it.
[blogEntries addObject:[blogItem copy]];
}
[YourTable reloadData];
}
Import touchXML library in you header file.
Thanks

Related

working with json data

I have the follow code that parses JSON data received from a server:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSArray *array_webdata=[[NSArray array] init];
NSString *searchStatus = [[NSString alloc] initWithData:webData encoding:NSUTF8StringEncoding];
array_webdata = [parsedata objectWithString:searchStatus error:nil];
NSDictionary *usersList = [array_webdata valueForKey:#"results"];
//I think that is not a real NSDictionary because if I write NSArray *keys = [usersList allKeys]; the execution crashes
NSLog(#"\n usersList =\n %# \n", usersList);
[searchStatus release];
[connection release];
[webData release];
[pool drain];}
the json data stored in usersList has the structure:
(
{
createTime = "date hour";
fullname = "user name";
"prof_id" = number;
thumb = "image.jpg";
},
{
data of rest of users...
}
)
And I would like create a class to store the data of each user and use "prof_id" when I want to use a particular use.
I need this because the app needs a list with all users (not tableview) and I think this is de easiest way.
Can someone help me? Thanks!!
Please used JsonKit Framework to parse json data received from web service.
Read data and parse using JSONKit:
NSData* jsonData = [NSData dataWithData:webData];
JSONDecoder* decoder = [[JSONDecoder alloc]
initWithParseOptions:JKParseOptionNone];
NSArray* json = [decoder objectWithData:jsonData];
After that, you'll have to iterate over the json variable using a for loop.
Create new class with the name User (file->new->file) inherited from NSObject class, create required parameters in .h/.m file.(do synthesize to generate getter/setter for attributes)
import User.h in your connection class and create objects of User entity in iterator loop and add those object in global scope array.
for(NSDictionary *userInfo in json) {
User* user=[[User alloc] init];
user.fullName=[userInfo valueForKey:#"fullname"];
user.prof_id=[[userInfo valueForKey:#"prof_id"] integerValue];
// Add into your global array
[usersList addObject:user];
[user release];// if ARC is not enable
}
// Check for successful object creation
NSLog(#"USER LIST contain User class Objects- %#",userList);
if i'm not wrong the only thing you need to do is :
NSMutableArray *yourArray = usersList;
and then with a for loop like
for(int i = 0;i<[usersList count] ;i++)
{
NSMutableDictionary *yourDictionary = [usersList objectAtIndex:i];
int prof_id = [yourDictionary valueForKey:#"prof_id"];
}
you can get your prof_id like that.
i hope this helps...
Use JSON Framework, and parse data using below code.
NSString* newStr = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"yout link to json file"] encoding:NSUTF8StringEncoding error:nil];
NSLog(#"new str - %#",newStr);
NSArray *response = [newStr JSONValue];
NSLog(#"json array - %#",response);
Use the response array to show your results.

Releasing 2 times?

I am confused with releasing the object that I first alloc/initialized and then copied. As far as I understood the memory management manual I should release the object 2 times because by allocating it and then later copying it I should have retain value of 2?
So first release would lower it to one and second to 0?
I get message sent to dealloc object if I release it twice. If I do it once there are no problems in application, but there is one in my understanding of Objetive C mem. management :)))
The only explanation that I can think of is when you release an object from soecific context it will release it instantly no matter the value of retain count ?
In the snippet bellow xmlElement is the confusing one....
// LSnippet of code for TouchXML
for (CXMLElement *resultElement in resultNodes) {
NSMutableDictionary *xmlElement = [[NSMutableDictionary alloc] init];
// Create a counter variable as type "int"
int counter;
// Loop through the children of the current node
for(counter = 0; counter < [resultElement childCount]; counter++) {
// Add each field to the blogItem Dictionary with the node name as key and node value as the value
[xmlElement setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];
}
// Add the blogItem to the global blogEntries Array so that the view can access it.
[tempReturnedElements addObject:[xmlElement copy]];
[xmlElement release];
//[xmlElement release]; but NOT!
}
UPDATE: whole method code:
+(void) runXPath:(NSString *)xPathExpression{
CXMLDocument *rssParser = [[[CXMLDocument alloc] initWithXMLString:xmlStringContent options:0 error:nil] autorelease];
// Create a new Array object to be used with the looping of the results from the rssParser
NSArray *resultNodes = NULL;
// Set the resultNodes Array to contain an object for every instance of an node in our RSS feed
resultNodes = [rssParser nodesForXPath:xPathExpression error:nil];
NSMutableArray *tempReturnedElements = [[NSMutableArray alloc]init];
// Loop through the resultNodes to access each items actual data
for (CXMLElement *resultElement in resultNodes) {
// Create a temporary MutableDictionary to store the items fields in, which will eventually end up in blogEntries
NSMutableDictionary *xmlElement = [[NSMutableDictionary alloc] init];
// Create a counter variable as type "int"
int counter;
// Loop through the children of the current node
for(counter = 0; counter < [resultElement childCount]; counter++) {
// Add each field to the blogItem Dictionary with the node name as key and node value as the value
[xmlElement setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];
}
// Add the blogItem to the global blogEntries Array so that the view can access it.
[tempReturnedElements addObject:[xmlElement copy]];
//***** Crushes if I use:
//***** [tempReturnedElements addObject:[[xmlElement copy] autorelease]];
[xmlElement release];
}
[lotojuegosAppDelegate setMyReturnedXmlElements:[tempReturnedElements copy]];
[tempReturnedElements release];
}
Thanks in advance,
Luka
In [xmlElement copy], only the returned object (i.e. the copy) needs to be released. The receiver (xmlElement)'s ownership (retain count) is not changed.
So the correct way should be
NSDictionary* xmlElemCopy = [xmlElement copy];
[tempReturnedElements addObject:xmlElemCopy];
[xmlElemCopy release];
[xmlElement release];
The rule is pretty simple: for each alloc/init, copy or retain you must call exactly one release or autorelease when you want to give up the ownership. You've only called one alloc/init, so you may only call release once.
This line:
[tempReturnedElements addObject:[xmlElement copy]];
should be written as:
[tempReturnedElements addObject:[[xmlElement copy] autorelease]];
The reason is: copy gives you a new object. The retain count/ownership of the object pointed to by xmlElement is unchanged, but the new object now belongs to you. You're responsible for releasing it now. See the first paragraph in this answer: you called copy, you need to call release on the resulting object.

Adding 2 keyvalues to list from JSON object

I want to append 2 key values from JSON object to my list in iPhone app. Below is my code for that,
SBJsonParser *jsonParser = [[[SBJsonParser alloc] init] autorelease];
NSString *jsonString=[[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://test/json/json_data.php"]];
id response = [jsonParser objectWithString:jsonString error:NULL];
NSDictionary *feed = (NSDictionary *)response;
list = (NSArray *)[feed valueForKey:#"fname"];
the above code properly displays the value from fname but what do i do if i want to add lname to it. for eg, my object is
[{"fname":"Bill","lname":"Jones"},{"fname":"John","lname":"Jacobs"}]
i want to display names as Bill Jones, John Jacobs and so on in the list. Currently it only displays Bill, John..I tried doing something like #"fname"#lname but it wont work..Can anybody please help me..
An observation: the response from the JSON parser is not a dictionary, but an array given the string you pass in. Your code works because -valueForKey: is something an array will respond to. The array sends -valueforKey: to each element and builds an array out of the responses.
There are two ways you can do what you want (at least)
Iterate through the array explicitly
NSMutableArray* list = [[NSMutableArray alloc] init];
for (id anObject in response)
{
[list addObject: [NSString stringWithFormat: #"%# %#",
[anObject objectForKey: #"fName"],
[anObject objectForKey: #"lname"]]];
}
Add a category to NSDictionary
#interface NSDictionary(FullName)
-(NSString*) fullName;
#end
#implementation NSDictionary(FullName)
-(NSString*) fullName
{
return [NSString stringWithFormat: #"%# %#",
[self objectForKey: #"fName"],
[self objectForKey: #"lname"]];
}
#end
Then your existing code changes to
list = (NSArray *)[feed valueForKey:#"fullName"];

Parsing multiple attributes in TouchXML

I'm in the making of an application where I'm using TouchXML to parse an XML containing airport flight information.
The XML looks like this:
<?xml version="1.0" encoding="iso-8859-1"?>
<airport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://flydata.avinor.no/XmlFeed.xsd" name="OSL">
<flights lastUpdate="2010-10-03T12:29:43">
<flight uniqueID="1273306">
<airline>DY</airline>
<flight_id>DY246</flight_id>
<dom_int>D</dom_int>
<schedule_time>2010-10-03T10:45:00</schedule_time>
<arr_dep>D</arr_dep>
<airport>TOS</airport>
<check_in>D</check_in>
<gate>18</gate>
<status code="D" time="2010-10-03T10:42:00"/>
</flight>
<flight uniqueID="1273799">
<airline>SK</airline>
<flight_id>SK263</flight_id>
<dom_int>D</dom_int>
<schedule_time>2010-10-03T10:50:00</schedule_time>
<arr_dep>D</arr_dep>
<airport>BGO</airport>
<check_in>EF</check_in>
<gate>23</gate>
</flight>
</flights>
</airport>
The TouchXML documentation tells me how to fetch attributes, which works for flights's lastUpdate attribute, but not for status's code and time attribute.
In addition, not all flight XML entries contain the status element, but I'm doing a check for this.
Currently, the code I have is the following:
-(void)grabXML {
flightEntries = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:#"http://flydata.avinor.no/XmlFeed.asp?TimeFrom=0&TimeTo=2&airport=OSL&direction=D"];
CXMLDocument *xmlParser = [[[CXMLDocument alloc] initWithContentsOfURL:url options:0 error:nil] autorelease];
NSArray *resultNodes = NULL;
resultNodes = [xmlParser nodesForXPath:#"//flight" error:nil];
for (CXMLElement *resultElement in resultNodes) {
NSMutableDictionary *flightItem = [[NSMutableDictionary alloc] init];
int counter;
for (counter = 0; counter < [resultElement childCount]; counter++) {
[flightItem setObject:[[resultElement childAtIndex:counter] stringValue] forKey:[[resultElement childAtIndex:counter] name]];
// Check if the node has the <status> element
if ([[[resultElement childAtIndex:counter] name] isEqualToString:#"status"]) {
// Fetch the code and time attribute here
}
}
// This gives me <flight uniqueID="*">
[flightItem setObject:[[resultElement attributeForName:#"uniqueID"] stringValue] forKey:#"uniqueID"];
[flightEntries addObject:[flightItem copy]];
}
}
The documentation does not tell how to parse multiple attributes, so I was hoping someone had a clue on how to do it?
First off, I have to say that your XML will be difficult to work with because you are trying to use a specific tag for each item in a list. For example:
<airline>DY</airline>
<flight_id>DY246</flight_id>
<dom_int>D</dom_int>
<schedule_time>2010-10-03T10:45:00</schedule_time>
<arr_dep>D</arr_dep>
<airport>TOS</airport>
<check_in>D</check_in>
<gate>18</gate>
the tags named , don't make sense as XML is intended to describe your data, not define it. If you have an entity called an item, you should probably just call it item and make the XML look like this:
<level1_items>
<level1_item>
<item index="1">text</item_1>
<item index="2">text</item_2>
</level1_item>
<level1_item>
<item index="1">some text</item_1>
<item index="2">some more text</item_2>
</level1_items>
Where each item has an index. For that matter, you could just load the document in your TouchXML CXMLDocument and grab the nodes you need with XPath and assume they're in the correct order ignoring the index= parameter I specified.
The next issue is that converting XML to an NSDictioanry or NSArray of dictionaries is a pretty involved task and what you gain isn't worth the effort. Just load your XML into a CXMLDocument and then start obtaining nodes using XPath. Something like this:
CXMLDocument *doc = [[CXMLDocument alloc] initWithXMLString:xmlString options:0 error:nil];
// Returns all 'level1_item' nodes in an array
NSArray *nodes = [[doc rootElement] nodesForXPath:#"//response/level1_items/level1_item" error:nil];
for (CXMLNode *itemNode in nodes)
{
for (CXMLNode *childNode in [itemNode children])
{
NSString *nodeName = [childNode name]; // should contain item_1 in first iteration
NSString *nodeValue = [childNode stringValue]; // should contain 'text' in first iteration
// Do something with the node data.
}
}
suggest trying to use the XML this way and then come back here and ask specific questions if you have problems.
hope that helps.
PK

iPhone loading xml file

what is the best way to load a xml file as an parsed object in objective c?
Check out TouchXML. It's the easiest library I've found so far. Supports xpath on a basic level. http://code.google.com/p/touchcode/wiki/TouchXML. Here's a sample (code removed) from a recent project:
CXMLDocument *parser = [[CXMLDocument alloc] initWithData:theData encoding:NSUTF8StringEncoding options:0 error:nil];
NSArray *nodes = [parser nodesForXPath:#"//item" error:nil];
for (CXMLElement *resultElement in nodes)
{
NSMutableDictionary *data = [[NSMutableDictionary alloc] initWithCapacity:0];
// Create a counter variable as type "int"
int counter;
// Loop through the children of the current node and add to dictionary
for (counter = 0; counter < [resultElement childCount]; counter++)
{
// Add each field to the dictionary with the node name as
// key and node value as the value
[data setObject:[[resultElement childAtIndex:counter] stringValue]
forKey:[[resultElement childAtIndex:counter] name]];
}
// do stuff with the dictionary by named keys
// ...
// release dict
[data release];
}
[parser release];
If you know some C, the best (i.e. fastest parsing, lowest memory footprint) way to parse XML into Objective-C objects is probably via the SAX event parser in libxml2. Apple has a sample project called XMLPerformance which demonstrates how this is done.
I recommend using TouchXML. Great documentation and relatively easy to use compared with the NSXMLParser.
Look into the NSXmlParser. It can read xml and gives you methods you can override to process the contents.