Objective-C: Parsing a non-xml website - iphone

I'd like to develop a very simple "bus timetable" app that loads a particular URL and can use the HTML to figure out bus numbers, their routes and expected times. Unfortunately it's a very simple website, so the data is spread across TD and DIV fields, rather than in xml.
Can anyone provide some pointers on where to start? I've had a look at NSURL, NSURLConnection and the like, and am able to download the contents of an HTML file, but I'm unsure what to do next.
Many thanks.

There are many ways to accomplish this task. Ultimately, you will want to retrieve something an easily-processed format other than raw html. Here is one way to do it:
I would recommend writing a server-side script that converts the html into an easily-digestible format, such as JSON.
If you have php experience, you write a script / web-service that grabs the needed elements and place the content in an associative array. Place the script on your server and have your application call the web-service URL when ready to retrieve the info.
Finally, return the information as a JSON object and parse the JSON into your app.
<?php
//parse html into the $array variable.
$array = json_encode($array);
echo $array;
?>
I would recommend using the SBJSON library for parsing the JSON object: Take a look at SBJSON
Initiate your NSURL request by calling the script URL.
NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.yoursite/script.php"]];
If the request is successful, parse the resulting JSON: (assuming use of SBJSON library)
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData: responseData encoding: NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJSON *json = [[[SBJSON alloc] init]autorelease];
NSDictionary *busData = [json objectWithString:responseString error: &error];
//busData contains bus data that you formatted...
Beware, this is assuming that you want to add your data to a dictionary and then display it appropriately. I consider this a mere snippet for formatting data in a way you desire. Parsing all of the html within the app may difficult and that is why I advocate formatting the data as JSON first. If you decide to go the XML route, there are several XML parsers as well.

Related

NSXMLParser Doesn't Parse when URL contains chars from different language

hi there I am working on a program that sends requests via XML Webservice and parses the data using NSXML parser.
I've used that method for anything on my program and it works flawlessly until I had this:
NSXML Parser returns data and parses when the URL is like that:
http://someasp.netserver/xmlservices/service1.asmx/getSales?date1=01.03.2011%2000:00:00&date2=%2023.03.2011%2000:00:00%20&Name=JOHN
but when I change the URL to this:
http://someasp.netserver/xmlservices/service1.asmx/getSales?date1=01.03.2011%2000:00:00&date2=%2023.03.2011%2000:00:00%20&Name=JÜRGEN
it doesn't return anything.
I copy and paste those URL addresses into a web browser and I can see the XML results but on the iPhone NSXMLparser just ignores the parsing and returns nothing.
I have a list of 15 "Name" values in my program, and whenever the name contains characters like 'ö,ü,ş,İ,ç' it just returns zero, otherwise it's working normally.
Thanks for helping.
Also, here's my parsing code in the program :
NSURL *URL=[[NSURL alloc] initWithString:testURL]; //test url is the request string
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL :URL];
[parser setDelegate:self];
[parser parse];
You need to perform URL encoding, you can't just shove special characters into a URL as-is.
Please see this question:
iPhone URL encoding Problem
Or search for "iphone url encoding".

How to fetch web service response as a string in iPhone?

I've webservice which converts CelsiusToFahrenheit. This webservice response is in string format instead of xml so how can I display a response in a label programmatically?
Is there a sample available for that?
The simplest method is a one-liner:
NSError *error = nil;
myLabel.text = [NSString stringWithContentsOfURL:myURL encoding:NSUTF8StringEncoding error:&error];
As with most one-line solutions, there's a caveat. This method blocks the current thread until the request completes or fails, so you'd better use it in conjunction with performSelectorInBackground:withObject: to avoid locking UI.
Here is a tutorial that I used to retrieve data from a web service using the requestWithURL method of NSURLRequest:
http://mobileorchard.com/tutorial-json-over-http-on-the-iphone/
The example is for JSON, but you can just omit all of the JSON stuff from the tutorial, since the string response is going to be fed into your connectionDidFinishLoading method.

iPhone NSURLConnection: What to do with returned NSData Object? Google Docs API

I'm working with the Google Docs API in my iPhone application. I've sent the proper POST request, and received a response along with some NSData. If I NSLog the NSData object, I get this:
NSData *returnedData = [NSURLConnection sendSynchronousRequest:request returningResponse:theResponse error:NULL];
NSLog(#"%#",returnedData);
//output : <4572726f 723d4261 64417574 68656e74 69636174 696f6e0a>
I think the NSData is either an NSDictionary or an NSArray. I'm supposed to receive a couple of items back, an SID, an LSID, and an Auth.
If I could turn the NSData chunk into an NSDictionary I could just find the object for whichever key.
Can anyone help?
You will have to decode the data. Try the following:
NSString *result= [[NSString alloc] initWithData:returnedData encoding:NSASCIIStringEncoding];
Of course this will depend on how the data is encoded. NSUTF8StringEncoding might work instead.
You may just need to pass the data to an NSXMLParser
The best way to deal with web data is Doing NSXML parsing. No need of decoding data the parser will handle itself

NSXMLParser init with XML in NSString format

I just ran into this one and couldn't seem to get any clear answer from the documentation.
Im retrieving some XML through a HTTPS connection. I do all sorts of authentication etc. so I have a set of classes that deals with this in a nice threaded way.
The result is an NSString that goes something like:
<response>
//some XML formatted test
</response>
This means that there is no encoding="UTF-8" indent="yes" method="xml" or other header blocks to indicate that this is actual XML and not just an NSString.
I guess I will use [NSXMLParser initWithData:NSData] to construct the parser, but how will I format or cast my NSString of xml formatted text into a proper NSData object that NSXMLParser will understand and parse?
Hope it makes sense, thank you for any help given :)
You can convert a string to a NSData object using the dataUsingEncoding method:
NSData *data = [myString dataUsingEncoding:NSUTF8StringEncoding];
You can then feed this to NSXMLParser.
The headers are optional, but you can insert the appropriate headers yourself if needed:
NSString *header = #"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
NSString *xml = [NSString stringWithFormat:#"%#\n%#", header, response);
NSData *data = [xml dataUsingEncoding:NSUTF8StringEncoding];
NSXMLParser *praser = [NSXMLParser initWithData:data];
By the time NSXMLParser has the data it's pretty much going to be expecting it to be XML ;-)
I'm pretty sure the processing instruction header is optional in this context. The way you get the NSString into the NSData is going to dictate the encoding (using dataUsingEncoding:).
(edit: I was looking for the encoding enum, but Philippe Leybaert beat me to it, but to repeat it here anyway, something like: [nsString dataUsingEncoding:NSUTF8StringEncoding])
I've passed NSStrings of XML in this way before with no issues.
Not specific to this question as such, but on the subject of XML parsing in an iPhone context in general you may find this blog entry of mine interesting, too.

Creating a highscore like system, iPhone side

I'm sorry for opening a new question, I had to - as I wrote the other question from my iPhone as unregistered user and it is not very comfortable to write from the iPhone.
Rephrasing the question:
Is it possible to use the:
[NSMutableArray writeToURL:(NSString *)path atomically:(BOOL)AuxSomething];
In order to send a file (NSMutableArray) XML file to a url, and update the url to contain that file?
for example:
I have an array and I want to upload it to a specific URL and the next time the app launches I want to download that array.
NSMutableArray *arrayToWrite = [[NSMutableArray alloc] initWithObjects:#"One",#"Two",nil];
[arrayToWrite writeToURL:
[NSURL urlWithString:#"mywebsite.atwebpages.com/myArray.plist"] atomically:YES];
And at runtime:
NSMutableArray *arrayToRead =
[[NSMutableArray alloc] initWithContentsOfURL:[NSURL urlWithString:#"mywebsite.atwebpages.com/myArray.plist"]];
Meaning, I want to write an NSMutableArray to a URL, which is on a web hosting service (e.g. batcave.net), the URL receives the information and updates server sided files accordingly.
A highscore like setup, user sends his scores, the server updates it's files, other users download the highscores at runtime.
I hope this is clarified.
Edit: What I am looking for is scripting PHP or ASP so the website, the URL where the data is sent to would know how to handle it. I want an example or a tutorial on how to implement this scripting for handling data, if it's possible to do this on a web hosting service.
~Thanks in advance.
To answer the question "How do I create a high score like system?", there are multiple parts of the system:
You need an ID for each user (a GUID generated on the iPhone, together with the users name should be sufficient).
You need a server that: remembers high scores; receives high scores from users; either displays (on a web site) the high scores and/or makes the high scores available for download to the phone.
You need some fraud protection, although that is likely fighting a losing battle against jailbreakers.
On the iPhone app side, you might want to be able to download the current high scores for display, which is done easily enough with something like:
int statusCode = 0;
NSData* result = nil;
NSHTTPURLResponse* response = nil;
NSError* error = nil;
NSString* url = #"http://www.yourserver.com/highscores.php"; // returns XML plist data
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:180];
result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// NSLog( #"NSURLConnection result %d %# %#", [response statusCode], [request description], [error description] );
statusCode = [response statusCode];
if ( (statusCode == 0) || (!result && statusCode == 200) ) {
statusCode = 500;
}
Since it is synchronous, you might want to put it inside an NSOperation. Alternatively, you can use
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate
To send high score data, because it is so small, the easiest way is simply to encode it in the URL.
NSString* url = [NSString stringWithFormat:#"http://www.yourserver.com/sethighscores.php?uid=%#;name=%#;score=%d;antifraud=%#", [uid encodeParameter], [name encodeParameter], score, [secureHash encodeParameter]];
Where encodeParameter is a custom category on NSString that encodes URL parameters and secureHash is a string representing a one way secure hashing of the uid, name, score and some secret known to your iPhone app and your web site. You'll need to figure these out on your own or ask separate questions since this is already getting long.
According to NSData writeToURL docs (at least for iPhone OS 2.2.1):
"Since at present only file:// URLs are supported, there is no difference between this method and writeToFile:atomically:, except for the type of the first argument."
Although the docs for NSArray/NSDictionary/NSString do not specifically mention the restriction, it would seem highly likely that the same restriction applies.
So you will have to upload the XML using some other mechanism.
Also, web sites generally are read only, unless you provide specific code on the web server to support uploading.