Parsing HTML from string - html

I am getting a string like this <b><i>Hello there </i></b> but in HTML format. This string is supposed to be bold and italicised. How would i convert this into "Hello there" and store it in a string to be used later on. Would i need to do something like HTML parsing?

To store it you'd just assign it to a variable like:
NSString *helloWorldString = #"<b><i>Hello there </i></b>";
Later on, when you want to use it in a UILabel you can do something like this:
NSError *error = nil;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 500, 100)];
label.attributedText =
[[NSAttributedString alloc]
initWithData: [helloWorldString dataUsingEncoding:NSUTF8StringEncoding]
options: #{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType}
documentAttributes: nil
error: &error];

Related

Check if an NSString is an html string?

I am creating an application that should display a list of strings, the string is returned from the server and can be either an html or not.
I am currently setting the text inside a UILabel. to do that i am using the below
NSMutableAttributedString *attributedTitleString = [[NSMutableAttributedString alloc] initWithData:[title dataUsingEncoding:NSUnicodeStringEncoding] options:#{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
cell.label.attributedText =attributedTitleString;
When the text is an html, everything work perfectly since the font and alignments are returned inside the html. The issue is occurring when the text is a normal text. The font, text alignment, text size and others are not being respected anymore.
So how can I check if the text is an html string or not?
I will be using the following in case of normal text:
cell.label.text =title;
I have tried to search on forums but still didn't get any answer for my issue.
This is working fine, you need to put:
cell.label. attributedText = title; incase of normal text too.
As It is working fine. Run the below code.
//If HTML Text
NSString *htmlstr = `#"This is <font color='red'>simple</font>"`;
NSMutableAttributedString *attributedTitleString = [[NSMutableAttributedString alloc] initWithData:[htmlstr dataUsingEncoding:NSUnicodeStringEncoding] options:#{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
textField.attributedText =attributedTitleString;
textField.font = [UIFont fontWithName:#"vardana" size:20.0];
//If Normal text.
NSString *normalStr = #"This is Renuka";
NSMutableAttributedString *NorAttributedTitleString = [[NSMutableAttributedString alloc] initWithData:[normalStr dataUsingEncoding:NSUnicodeStringEncoding] options:#{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType } documentAttributes:nil error:nil];
textField.attributedText = NorAttributedTitleString;
textField.font = [UIFont fontWithName:#"vardana" size:20.0];
You can check if your string contains html tag :
// iOS8 +
NSString *string = #"<TAG>bla bla bla html</TAG>";
if ([string containsString:#"<TAG"]) {
NSLog(#"html string");
} else {
NSLog(#"no html string");
}
// iOS7 +
NSString *string = #"<TAG>bla bla bla html</TAG>";
if ([string rangeOfString:#"<TAG"].location != NSNotFound) {
NSLog(#"html string");
} else {
NSLog(#"no html string");
}
Since the syntax and structure of HTML and XML is quite similar, you can utilize XMLDocument to check whether a given data object is HTML or plain text.
So data is from the type Data and is returned by an URLSession dataTask.
// Default to plain text
var options : [NSAttributedString.DocumentReadingOptionKey: Any] = [.documentType: NSAttributedString.DocumentType.plain]
// This will succeed for HTML, but not for plain text
if let _ = try? XMLDocument(data: data, options: []) {
options[.documentType] = NSAttributedString.DocumentType.html
}
guard let string = try? NSAttributedString(data: data, options: options, documentAttributes: nil) else { return }
Update
The above method works sort of. I had trouble with some HTML not creating an XML document. For the moment I have a different solution, that I don't really like.
As the symptom is that we get only one line back in the attributed string, simply check for that and create a new attributed string if there is only one line.
var options : [NSAttributedString.DocumentReadingOptionKey: Any] = [.documentType: NSAttributedString.DocumentType.html]
guard var string = try? NSAttributedString(data: data, options: options, documentAttributes: nil) else { return }
if string.string.split(separator: "\n").count == 1 {
options[.documentType] = NSAttributedString.DocumentType.plain
guard let tempString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) else { return }
string = tempString
}

Facebook Applinks - pass custom JSON data in al_applink_data

is it possible to pass custom data in al_applink_data using Facebook applinks?
I can retrieve this JSON example but I cannot see a place where to append my custom data to it. If this is not possible than my only solution is to parse obtained URL but this doesn't seem much bulletproof.
{
"target_url": "https://www.example.com/abc.html",
"extras": {
"fb_app_id": [YOUR_FACEBOOK_APP_ID],
"fb_access_token": "[ACCESS_TOKEN']",
"fb_expires_in": "3600"
},
"referer_app_link": {
"url": "[FACEBOOK_APP_BACK_LINK]",
"app_name": "Facebook"
}
}
Parsing Data
My solution by creating custom data for target_url.
NSDictionary *dictionary = #{ #"target_url" : #"YOUR_VALUE"};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
Then, append with your Facebook app link ID with al_applink_data key in FB Graph Object dictionary.
[NSString stringWithFormat:#"https://fb.me/FB_LINK_ID?al_applink_data=%#", jsonString]
That's it.!!
Retrieving Callback URL
if([[call appLinkData] targetURL] != nil)
{
NSURL *targetUrl = [[call appLinkData] targetURL];
//Actual URL
NSString *urlString = [[targetUrl absoluteString] stringByRemovingPercentEncoding];
URLParser *parser = [[URLParser alloc] initWithURLString:urlString];
//Fetching value for 'al_applink_data'
NSString *appLinkData = [parser valueForVariable:#"al_applink_data"];
NSData *objectData = [appLinkData dataUsingEncoding:NSUTF8StringEncoding];
//Dictionary with 'target_key' key and its value.
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:objectData options:NSJSONReadingMutableContainers error:nil];
NSLog(#"%#", json);
}
Reference for URL parsing : URLParser
Thanks.
The "extras" map was designed to carry arbitrary metadata. What type of custom data do you need? Passing of custom data through the "extras" blob requires the caller to know something about your app (so they can actually add the data).

Assigning HTML text to NSAttributedString throws EXC_BAD_ACESS on global queue

I am assigning HTML text to NSAttributedString. This attributed string is then assigned to one of the UILabel in UitableViewCell in cellForRowAtIndexPath Method. Due to cell reuse initWithData: method is causing sluggishness at UI. Hence, I made the code to execute on global queue. I am doing something like this:
-(void)assignAttrText:(NSDictionary *)dict{
NSDictionary *msgThreadDict = [dict objectForKey:#"messgDict"];
__block DRMessageThreadTableViewCell *cell = [dict objectForKey:#"cell"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSError *err = nil;
NSAttributedString *attributedString =
[[NSAttributedString alloc]
initWithData: [[msgThreadDict objectForKey:#"text"] dataUsingEncoding:NSUTF8StringEncoding]
options: #{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType }
documentAttributes: nil
error: &err];
if(err){
NSLog(#"Unable to parse label text: %#", err);
}
else{
cell.messageTextLabel.attributedText = attributedString;
}
});
Any leads as to what is causing the app to crash with EXC_BAD_ACCESS at the method:
[[NSAttributedString alloc]
initWithData: [[msgThreadDict objectForKey:#"text"] dataUsingEncoding:NSUTF8StringEncoding]
options: #{ NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType }
documentAttributes: nil
error: &err];
Make a NSData *mydata object from [msgThreadDict objectForKey:#"text"], then use [[NSAttributedString alloc] initWithData: mydata ...
I think your object is not of NSData type, use string then convert to data, hence EXC_BAD_ACCESS .
NSString *ceva = [NSString stringWithFormat:#"%#",[msgThreadDict objectForKey:#"text"]];
NSData *mydata = [ceva dataUsingEncoding:NSUTF8StringEncoding];

IOS Regular parse HTML

i want to parse html content into Dictionary
EDIT:
I need to parse just simple HTML, don't need to consider the complex situation.
WEB side: when I was in the system input information, using the HTML editor. But fix the old WEB system , need to modify the place more, so temporary use parsing HTML mode in the current version of the APP。
END:
Html just like this:
<p>hahaha</p><img src="aaaa.jpg"/>heihei<img src="bbb.jpg"/>guagua
i want the result is:
text hahaha
img aaaa.jpg
text heihei
img bbb.jpg
text guagua
my code is:
//<p>hahaha</p><img src="aaaa.jpg"/>heihei<img src="bbb.jpg"/>guagua
//for this
//NSArray = {0,1,2,3,4}
//NSDictionary{Sort-Key,V}={{0,{text,hahaha}},{1,{img,aaaa.jpg}},{2,{text,heihei}},{3, {img,bbb.jpg}},{4,{text,guagua}}}
-(NSArray*)RegularExpression:(NSString *)str dic:(NSMutableDictionary**)dic
{
if(str == nil) return nil;
NSString *pgnText = str;
NSString* tags=#"<[p|div].*?>(.*?)</[p|div].*?>";
NSString *regTags = tags;
NSError *error;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regTags options:NSRegularExpressionCaseInsensitive error:&error];
NSArray *matches = [regex matchesInString:pgnText
options:0
range:NSMakeRange(0, [pgnText length])];
NSMutableArray* arrItems = [[NSMutableArray alloc] initWithCapacity:[matches count]];
if(matches.count >0){
for (NSTextCheckingResult *match in matches) {
NSString *tagValue = [pgnText substringWithRange:[match rangeAtIndex:1]];
NSArray* arr = [self RegularExpression:tagValue dic:dic];
[arrItems addObjectsFromArray:arr];
}
}
else{
NSString* regTags2 = #".*?<img.*?src.*?=.*?[\"|”](.*?)[\"|”].*?/>";
NSRegularExpression *regex2 = [NSRegularExpression regularExpressionWithPattern:regTags2 options:NSRegularExpressionCaseInsensitive|NSRegularExpressionAnchorsMatchLines error:&error];
pgnText = str;
NSArray *matches2 = [regex2 matchesInString:pgnText
options:0
range:NSMakeRange(0, [pgnText length])];
for (NSTextCheckingResult *match in matches2) {
NSString *tagValue = [pgnText substringWithRange:[match rangeAtIndex:1]];
NSLog(#"%#",tagValue);
}
}
return [arrItems autorelease];
}
Who has done similar function?
Keys in a dictionary must be unique. You cannot have more than one "img" key.
Check out this SO question: Objective-C DOM XML parser for iPhone

Parsing JSON string to a NSMutableArray

This is my string:
[{"id":"1","nome":"Adriatik"},{"id":"2","nome":"Ard"},{"id":"3","nome":"Albana"},{"id":"4","nome":"Adriana"}]
I would like to parse all 'name' of the JSON string into a NSMutableArray.
Sorry for my english!
Whenever I have to handle some JSON code, the first thing I like to do is create a class based on the JSON text. So, for example if your JSON is representing a U.S. state, create a "State" class.
There's a cool little product that you can use for this. It's called Objectify and costs about $15. No doubt people can advise on other free stuff that might do something similar.
For the actual Json parsing, I use SBJson. There's quite a few Json parsing frameworks out there for Objective-C so definitely have a look around to see what takes your fancy.
Next, with SBJson, do the actual parsing:
-(NSDictionary *)parseJsonFromUrl
{
NSAssert(mUrl, #"Must set a url before invoking %#", __PRETTY_FUNCTION__);
// Create new SBJSON parser object
SBJsonParser *parser = [[SBJsonParser alloc] init];
// Prepare URL request to download JSON
NSURLRequest *request = [NSURLRequest requestWithURL:mUrl];
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// Get JSON as a NSString from NSData response
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
// parse the JSON response into an object
// Here we're using NSArray since we're parsing an array of JSON status objects
return [parser objectWithString:json_string error:nil];
}
That returns a NSDictionary. You know have to look through that dictionary to set the values of your model class. Here's how to do that whilst at the same time loading the values into the NSMutableArray:
-(void)downloadJsonData
{
NSDictionary *statesDict = [self parseJsonFromUrl];
NSMutableArray *statesArray = [NSMutableArray arrayWithCapacity:[statesDict count]];
for (NSDictionary *stateDict in stateDict)
{
State *aState = [[[State alloc] init] autorelease];
aState.stateId = [stateDict valueForKey:#"id"];
aState.name = [stateDict valueForKey:#"name"];
[statesArray addObject:aState];
}
}
Note that I use a property name of stateId not id so as not to clash with the Objective-C object pointer type.
Use SBJson classes and call -JSONValue method
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
// NSLog(#" Response String %#", responseString);
//converted response json string to a simple NSdictionary
NSMutableArray *results = [responseString JSONValue];