Extracting HTML Attribute from string iPhone - iphone

I have an html string that I get from the response of a website. Everything I do there works awesome and I have no difficulty. What I need to go is grab the only href attribute within the html. What is the best approach for getting this URL that is contained within that attribute. I am open to any external libraries if that is necessary, I just want the most efficient way possible. Thanks.

Use this API to parse the HTML code and pick the elements you want.
ElementParser is lightweight framework to provide easy access to xml and html content. Rather than get lost in the complexities of the HTML and XML specifications, it aspires to not obscure their essential simplicity. It doesn’t do everything, it aspires to do “just enough”.
Source: http://touchtank.wordpress.com/element-parser/
Here is an example of how to use the ElementParser with your own example. I hope this is helpful.
Merry Xmas! Ho-Ho-Ho
// Here you create the parser, don't forget to #import "Element.h" and #import "ElementParser.h"
ElementParser * parser = [[ElementParser alloc] init];
// This is the HTML source code that you want to parse
DocumentRoot* document = [parser parseHTML:#"<html>Google Link</html>"];
// Create an array where you will put all the <a></a> elements
NSArray* elements = [document selectElements: #"a"];
// Iterate though the array, for each element pick the "href" attribute
NSMutableArray* results = [NSMutableArray array];
for (Element* element in elements){
NSString* snipet = [element attribute:#"href"];
// Add the result for each element to the "results" array
[results addObject: snipet];
}
// Print the results on the screen
NSLog(#"%#",[results componentsJoinedByString: #"\n"]);

You could use NSRegularExpresion for extracting the url of the html tag.
NSString *regexStr = #"http?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)?";
NSString * url = #"stackoverflow";
NSError *error;
NSRegularExpression *testRegex = [NSRegularExpression regularExpressionWithPattern:regexStr options:0 error:&error];
if( testRegex == nil ) NSLog( #"Error making regex: %#", error );
NSRange range = [testRegex rangeOfFirstMatchInString:url options:0 range:NSMakeRange(0, [url length])];
NSString * href = [url substringWithRange:range];
Bear in mind that NSRegularExpression needs IOS 4 or 5.

Related

Youtube API auto-complete search

I'm using Youtube API, I'd like to have a search auto-complete feature, just like int the site, when you type into the search input box for iPhone App, it gives you terms suggestions. I've read the docs, but still missing, Is this possible using the API?
Well, i know it's too late to answer here, but i will post this answer because it's something that drove me crazy for a couple of days!!! and hope it will save to others...
So... i'm using this API :
http://suggestqueries.google.com/complete/search?client=youtube&ds=yt&alt=json&q=%#
(q is the query for the autocomplete search).
Now, if you try to open a browser, paste this API and change q=%# to (lets say): q=br, you will notice that some file with the suffix .js is downloaded to your computer.
For some reason, i couldn't parse the JSON like that, so i did that trick:
#property(strong, nonatomic) NSMutableArray *ParsingArray // Put that in .h file or after #interface in your .m file
-(void)autocompleteSegesstions : (NSString *)searchWish{
//searchWish is the text from your search bar (self.searchBar.text)
NSString *jsonString = [NSString stringWithFormat:#"http://suggestqueries.google.com/complete/search?client=youtube&ds=yt&alt=json&q=%#", searchWish];
NSString *URLString = [jsonString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; // Encoding to identify where, for example, there are spaces in your query.
NSLog(#"%#", URLString);
NSData *allVideosData = [[NSData alloc]initWithContentsOfURL:[[NSURL alloc]initWithString:URLString]];
NSString *str = [[NSString alloc]initWithData:allVideosData encoding:NSUTF8StringEncoding];
NSLog(#"%#", str); //Now you have NSString contain JSON.
NSString *json = nil;
NSScanner *scanner = [NSScanner scannerWithString:str];
[scanner scanUpToString:#"[[" intoString:NULL]; // Scan to where the JSON begins
[scanner scanUpToString:#"]]" intoString:&json];
//The idea is to identify where the "real" JSON begins and ends.
json = [NSString stringWithFormat:#"%#%#", json, #"]]"];
NSLog(#"json = %#", json);
NSArray *jsonObject = [NSJSONSerialization JSONObjectWithData:[json dataUsingEncoding:NSUTF8StringEncoding] //Push all the JSON autocomplete detail in to jsonObject array.
options:0 error:NULL];
self.ParsingArray = [[NSMutableArray alloc]init]; //array that contains the objects.
for (int i=0; i != [jsonObject count]; i++) {
for (int j=0; j != 1; j++) {
NSLog(#"%#", [[jsonObject objectAtIndex:i] objectAtIndex:j]);
[self.ParsingArray addObject:[[jsonObject objectAtIndex:i] objectAtIndex:j]];
//Parse the JSON here...
}
}}
That's it. now ParsingArray is the array that contains all autocomplete information from youTube! to be able to change it every time the user clicks another character on the searchBar, use this function:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
[self autocompleteSegesstions:self.searchBar.text];}
Now, this is the main code you should have. to make this code faster (because you can now see that you have a writing delay on the keyboard), use another thread to download ParsingArray or use Asynchronous block. (just insert the content of the first method to Async block...)
Remember- maybe there is another way to implement autocomplete youTube search much better then this, but i just did not found it, and i searched a lot! if anyone know a better way, i'll be more then glad if he post it here.
Have fun!!!
Not the Youtube API -- but you can use the Google Suggest API. Make calls to this URL:
http://suggestqueries.google.com/complete/search?client=youtube&ds=yt&q=QUERY
Which will return a json response of the suggest terms that your app can parse and display. If you prefer XML to json, change
client=youtube
to
output=toolbar
(leave the rest of the parameters the same).

Parse NSString from right hand side?

> (2009 RX7)</font></td>
>monospace" size="-1">214869 (2007 PAZ)</font></td>
>monospace" size="-1"> 4155 Accord</font></td>
I wonder if someone could offer me a little help, I have a list of NSString items (See Above) that I want to parse some data from. My problem is that there are no tags that I can use within the strings nor do the items I want have fixed positions. The data I want to extract is:
2009 RX7
2007 PAZ
4155 Accord
My thinking is that its going to be easier to parse from the right hand end, remove the </font></td> and then use ";" to separate the data items:
(2009&nbsp RX7)
(2007&nbsp PAZ)
4155&nbsp Accord
which can them be cleaned up to match the example given. Any pointers on doing this or working through from the right would be very much appreciated.
Personally I think you are better off with a regex. So my solution would be:
Regex of: ([0-9]+)[^;]+;([A-Za-z0-9]+)
Which for all the example text provides 3 matches. ie for:
(2009 RX7)</font></td>
0: 2009 RX7)<
1: 2009
2: RX7
I haven't coded this up, but did test the Regex at www.regextester.com
Regex's are implemented via NSRegularExpression and are available in iOS 4.0 and later.
Edit
Given that this appears to be a web scraping application, you never know when those pesky HTML code monkeys will change their output and break your carefully crafted matching methodology. As such I would change my regex to:
([0-9]+)([^;]+;)+([A-Za-z0-9]+)
Which adds an extra group, but allows for any number of elements between the number and the string.
Try this code:
NSString *str = #"> (2009 RX7)</font></td>";
NSRange fontRange = [str rangeOfString:#"</Font>" options:NSBackwardsSearch];
NSRange lastSemi = [str rangeOfString:#";" options:NSBackwardsSearch range:NSMakeRange(0, fontRange.location-1)];
NSRange priorSemi = [str rangeOfString:#";" options:NSBackwardsSearch range:NSMakeRange(0, lastSemi.location-1)];
NSString *yourString = [str substringWithRange:NSMakeRange(priorSemi.location+1, fontRange.location-1)];
The key element here is the NSBackwardsSearch search option.
This should do the trick:
NSString *s = #">monospace\" size=\"-1\"> 4155 Accord</font></td>";
NSArray *strArray = [s componentsSeparatedByString:#";"];
// you're interested in last two objects
NSArray *tmp = [strArray subarrayWithRange:NSMakeRange(strArray.count - 2, 2)];
In tmp you'll have something like:
"4155&nbsp",
"Accord</font></td>"
strip unneeded chars and you're all set.
Using NSRegularExpression:
NSRegularExpression *regex;
NSTextCheckingResult *match;
NSString *pattern = #"([0-9]+) ([A-Za-z0-9]+)[)]?</font></td>";
NSString *string = #"> (2009 RX7)</font></td>";
regex = [NSRegularExpression
regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive
error:nil];
match = [regex firstMatchInString:string options:0 range:NSMakeRange(0, [string length])];
NSLog(#"'%#'", [string substringWithRange:[match rangeAtIndex:1]]);
NSLog(#"'%#'", [string substringWithRange:[match rangeAtIndex:2]]);
NSLog output:
'2009'
'RX7'

How to convert XML string to JSON using iPhone sdk

I am implementing a client based application. In that I have an xml string. I need to convert it to JSON format and send to the server. I have no idea on converting this. Can you guys please suggest me any documentation or idea to this?
Step #1: Read XML into NSDictionary: http://troybrant.net/blog/2010/09/simple-xml-to-nsdictionary-converter/
Step #2: Convert NSDictionary into JSON: http://code.google.com/p/json-framework/
As Steve said the two steps are those, I leave you a bit of code, maybe can help you a bit more:
// Don't forget the imports ;)
#import "XMLReader.h"
// You must have a XML string from somewhere
NSString XMLString = yourXML;
// I remove all returns and tabs from the text, after i would be annoying if you don't remove it
XMLString = [XMLString stringByReplacingOccurrencesOfString:#"\r" withString:#""];
XMLString = [XMLString stringByReplacingOccurrencesOfString:#"\t" withString:#""];
// Parse the XML into a dictionary
NSError *parseError = nil;
NSDictionary *xmlDictionary = [XMLReader dictionaryForXMLString:XMLString error:&parseError];
NSError *error;
self.dataParsed = [NSJSONSerialization dataWithJSONObject:xmlDictionary
options: NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
error:&error];
// Print the dictionary
NSLog(#"%#", xmlDictionary);

NSRegularExpression: Replace url text with <a> tags

I am currently using a UIWebView to stylize posts from twitter. Some tweets of course contain URL's, but do not contain the <a> tags. I am able to pull out the URL, however I am not sure how to add the <a> tags and place back into the tweet. I will then use the same approach here to add links to the #usernames and #hashtags. Here is an example of my current code:
NSString *tweet = #"Sync your files to your Google Docs with a folder on your desktop. Like Dropbox. Good choice, Google storage is cheap. http://ow.ly/4OaOo";
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:#"(?i)\\b((?:[a-z][\\w-]+:(?:/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:'\".,<>?«»“”‘’]))" options:NSRegularExpressionCaseInsensitive error:NULL];
NSString *match = [tweet substringWithRange:[expression rangeOfFirstMatchInString:tweet options:NSMatchingCompleted range:NSMakeRange(0, [tweet length])]];
NSLog(#"%#", match);// == http://ow.ly/4OaOo
Ultimately, I would like the final string to look like this:
Sync your files to your Google Docs with a folder on your desktop. Like Dropbox. Good choice, Google storage is cheap. <a href="http://ow.ly/4OaOo>http://ow.ly/4OaOo</a>
Any help would be much appreciated.
And here is an objective-c version:
NSString *regexToReplaceRawLinks = #"(\\b(https?):\\/\\/[-A-Z0-9+&##\\/%?=~_|!:,.;]*[-A-Z0-9+&##\\/%=~_|])";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexToReplaceRawLinks
options:NSRegularExpressionCaseInsensitive
error:&error];
NSString *string = #"Sync your files to your Google Docs with a folder on your desktop. Like Dropbox. Good choice, Google storage is cheap. http://ow.ly/4OaOo";
NSString *modifiedString = [regex stringByReplacingMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
withTemplate:#"$1"];
NSLog(#"%#", modifiedString);
I did something like this before, but I used javascript to do it. When the view has loaded, use the delegate method webViewDidFinishLoad, and inject javascript:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString *jsReplaceLinkCode =
#"document.body.innerHTML = "
#"document.body.innerHTML.replace("
#"/(\\b(https?):\\/\\/[-A-Z0-9+&##\\/%?=~_|!:,.;]*[-A-Z0-9+&##\\/%=~_|])/ig, "
#"\"<a href='$1'>$1</a>\""
#");";
[webVew stringByEvaluatingJavaScriptFromString:jsReplaceLinkCode];
}
Here's the javascript call in a non objective-c nsstring quotes version:
document.body.innerHTML = document.body.innerHTML.replace(
/(\b(https?):\/\/[-A-Z0-9+&##\/%?=~_|!:,.;]*[-A-Z0-9+&##\/%=~_|])/ig,
"<a href='document.location=$1'>$1</a>"
);
The regex is not perfect but will catch most of the links.
You could use stringByReplacingOccurrencesOfString:withString: to search for your match and replace it with the HTML link.
NSString *htmlTweet = [tweet stringByReplacingOccurrencesOfString:match withString:html];
(You might also use the range that you get from rangeOfFirstMatchInString:options:range in stringByReplacingCharactersInRange:withString: but I'm not sure what happens you pass a string thats longer than the ranges length in this case).
Note that your search will only find the first link in a tweet, and if there are several matches you'll miss those.

Convert Excel document (xls) to a plist

I have a pretty straightforward Excel spreadsheet, and I need to use the data in an iPhone app. The xls document has 6 columns, and > 200 rows.
I would like to create a plist from the xls document. How can I convert one to the other, programmatically?
I'm late to the party but I built a desktop utility that will convert CSV to a plist. You can download the binary or use this code, which requires cCSVParse. It uses whatever is in row 0 to create key names, then generates dictionaries for each successive row.
CSVParser *parser = [CSVParser new];
[parser openFileWithPath:pathAsString];
NSMutableArray *csvContent = [parser parseFile];
[parser closeFile];
if (pathAsString != nil)
{
NSArray *keyArray = [csvContent objectAtIndex:0];
NSMutableArray *plistOutputArray = [NSMutableArray array];
NSInteger i = 0;
for (NSArray *array in csvContent)
{
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
NSInteger keyNumber = 0;
for (NSString *string in array)
{
[dictionary setObject:string forKey:[keyArray objectAtIndex:keyNumber]];
keyNumber++;
}
if (i > 0)
{
[plistOutputArray addObject:dictionary];
}
i++;
}
NSMutableString *mutableString = [NSMutableString stringWithString:pathAsString];
[mutableString replaceOccurrencesOfString:#".csv" withString:#".plist" options:nil range:NSMakeRange([mutableString length]-4, 4)];
NSURL *url = [NSURL fileURLWithPath:mutableString];
[plistOutputArray writeToURL:url atomically:YES];
You could do this using a simple formula that you copy and pasted down a column beside each of your 200+ rows.
For example, assuming colum A contains a list of names, and column B contains a matching set of ages you could use a formula such as the following to end up with most of the XML for a plist based dictionary.
=CONCATENATE("<key>Name</key><string>", A1,"</string><key>Age</key><integer>",B1,"</integer>")
You then select all the cells within this new column you can copy and paste into notepad or another text editor to save it as a plist file (you may want to put some hardcoded text into a cell above and below your 200+ rows, in order to get the required tags etc as well...
Ladies and gentlemen,
I tried any other recommended solutions above but because of Unicode characters in my language (Turkish) none of them worked out for me... All unicode characters were all broken. Then I decided to make a tool for this.
I proudly present the simplest way to convert any XLS or XLSX or CVS file to a plist:
http://exceltoplist.herokuapp.com/
Just upload your XLS, XLSX or CSV and download your Apple Plist!
Enjoy!
Note: Because of Heroku's free dyno policy it might take a few moments to browse the page. Just keep waiting for 5-10 seconds to open page.
For OpenOffice, use this formula
=CONCATENATE("<key>number</key><integer>"; A2;"</integer><key>MyString</key><string>";B2;"</string>")
I found the CONCATENATE to work the best for this.
For my purpose I just need to convert CSV with two columns to plist file.
First column is keys and second are values. So, I slightly change Danilo Campos code as following:
CSVParser *parser = [CSVParser new];
[parser openFileWithPath:pathAsString];
NSMutableArray *csvContent = [parser parseFile];
[parser closeFile];
if (pathAsString != nil)
{
NSMutableDictionary *plistOutputArray = [NSMutableDictionary dictionary];
for (NSArray *array in csvContent)
{
NSString *key = (NSString *)([array objectAtIndex:0]);
NSString *value = (NSString *)([array objectAtIndex:1]);
[plistOutputArray setObject:value forKey:key];
}
NSMutableString *mutableString = [NSMutableString stringWithString:pathAsString];
[mutableString replaceOccurrencesOfString:#".csv" withString:#".plist" options:nil range:NSMakeRange([mutableString length]-4, 4)];
NSURL *url = [NSURL fileURLWithPath:mutableString];
[plistOutputArray writeToURL:url atomically:YES];
}
P.S. You can find his initial source code here - http://code.google.com/p/danilobits/source/checkout
Please note that to get his code work now you need to change "Base SDK" to "Latest OS X"
Use http://shancarter.github.io/mr-data-converter/ to convert xls to a Json(just copy & paste)(can re format it by remove white space in http://jsonviewer.stack.hu/). save json to text file named: in.json.
Use plutil command to format json to plist
plutil -convert xml1 in.json -o out.plist