Swift: how to display image from html source - html

How can I display image from html source in some of sites in swift 2.2?
Actually I don't have any JSON or XML.
The important thing is that I have to use regex.
I tried this:
if htmlContent != nil
{
let htmlContent = (item?.htmlContent)! as NSString
var imageSource = ""
let rangeOfString = NSMakeRange(0, htmlContent.length)
let regex = try! NSRegularExpression(pattern: "(<img.*?src=\")(.*?)(\".*?>)", options: [.CaseInsensitive])
if htmlContent.length > 0
{
let match = regex.firstMatchInString(htmlContent as String, options: [.WithTransparentBounds], range: rangeOfString)
if match != nil
{
let imageURL = htmlContent.substringWithRange(match!.rangeAtIndex(2)) as NSString
print(imageURL)
if NSString(string: imageURL.lowercaseString).rangeOfString("feedBurner").location == NSNotFound
{
imageSource = imageURL as String
}
}
}
if imageSource != ""
{
imgHTMLLoader.setImageWithURL(NSURL(fileURLWithPath: imageSource), placeholderImage: UIImage(named: "placeholder"))
print("placeholderImage is not! nil")
}
else
{
imgHTMLLoader.image = UIImage(named: "placeholder")
print("placeholderImage is nil")
}
}
in this sample(library)... htmlContent always is nil.
this sample , use "Helper library" but it dosn't work...
thanks

Using SwiftSoup third party library and Swift 3.0
let doc = try SwiftSoup.parse("<div id=div1><p>Hello</p><p>Another <b>element</b></p><div id=div2><img src=foo.png></div></div>");
for element in try doc.select("img").array(){
try print(element.attr("src"))
}
//foo.png

Related

SWIFT Json check if object title exists

My code checks if code: "this data" is not empty, how can I check also if code itself exists. Some responses might give me almost an empty JSON with just time stamp. So the var code won't be there.
Or is there a better way altogether to do this? as My JSON is
"Variable Based on text input" which leads to "code" which might not be there which will have "some info" or ""
Top of script:
struct Variables: Decodable {
var code: String
}
typealias DecoderX = [String: Variables]
Previous function sets inputs from user text which are cross checked with the database so GetInfo will only be called if UserDefault inputs are set.
func GetInfo() {
let Input1 = UserDefaults.standard.string(forKey: “UserInput1”) ?? “”
let Input2 = UserDefaults.standard.string(forKey: “UserInput2”) ?? “”
let Input3 = UserDefaults.standard.string(forKey: “UserInput3”) ?? “”
print(“Input Check 1: \(Input1) \(Input2) \(Input3)”)
// URL INFO With API key hidden
let jsonTask = URLSession.shared.dataTask(with: requestURL) { data, response, error in
if response == response {
if let data = data, let body = String(data: data, encoding: .utf8) {
do {
let json = try? decoder.decode(DeocderX.self, from: data);
DispatchQueue.main.async {
print(“Input Check 2: \(json![Input1]!.code) \(json![Input2]!.code) \(json![Input3]!.code)”)
if json?[Input1]?.code != nil {
print("Good Information 1")
} else {
print("Found Nothing 1")
}
if json?[Input2]?.code != nil {
print("Good Information 2")
} else {
print("Found Nothing 2")
}
if json?[Input3]?.code != nil {
print("Good Information 3")
} else {
print("Found Nothing 3")
}
}
// rest of code not applicable
You can use SwiftyJSON library. You can find it at this link
if let json = try? JSON(data: response.data!){
if json["yourKey"]["otherKey"].exists() {
print("exists")
}
}
Hope it helps...

Swift JSON Parsing with a filter in url

I am trying to parse JSON, everything works fine, but when I try to give a filter with the url, it says found nil while unwrapping an optional value. I was wondering if I should give the filters in some other way. PS.. The url works fine when I use it in the browser
this is how the url with filter looks like:
https://start.jamespro.nl/v4/api/json/tasks/?filter=[{"column":"Date","operator":"=","value":"2017-08-04"}, {"column":"UserId","operator":"=","value":"2"}]
and this is my whole code:
func apiRequestTasks(url: String) {
apiRequestHeader(userName: "*******", passWord: "******")
var running = false
let urlProjects = NSURL(string: url)
let task = session?.dataTask(with: urlProjects! as URL) {
( data, response, error) in
if let taskHeader = response as? HTTPURLResponse {
print(taskHeader.statusCode)
}
if error != nil {
print("There is an error!!!")
print(error ?? "")
} else {
if let content = data {
do {
let dictionary = try JSONSerialization.jsonObject(with: content) as! [String:Any]
print(dictionary)
}
catch {
print("Error: Could not get any data")
}
}
}
running = false
}
running = true
task?.resume()
while running {
print("waiting...")
sleep(1)
}
}
I think the problem is the way you create your URL, try something like this:
let filters = "[\"column\":\"Date\",\"operator\":\"=\",\"value\":\"2017-08-04\"}, {\"column\":\"UserId\",\"operator\":\"=\",\"value\":\"2\"}]"
if var url = URLComponents(string: "https://start.jamespro.nl/v4/api/json/tasks") {
url.query = "filter=:\(filters)"
print ("url", url.string ? "invalid url")
}
I just encoded the filter part of my url and it worked. But thanx for the reactions !!!
let filter = "[{\"column\":\"Date\",\"operator\":\"=\",\"value\":\"2017-08-04\"}, {\"column\":\"UserId\",\"operator\":\"=\",\"value\":\"2\"}]"
let encodedFilter = filter.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
let baseUrl = "https://start.jamespro.nl/v4/api/json/tasks/?filter="
let url = baseUrl + encodedFilter!
apiRequestTasks(url: url)

NSAttributedString to HTML in iOS Swift 3

I have searched a lot but can only find HTML to plain text, not the other way around, I have email implementation in my app, thus need to send the content of email as HTML to the backend.
Edit 1: I have rich text that includes bold, italic, ordered/unordered list, underlined words.
If you are looking to convert NSAttributedString to String, here is the extension method you are looking for. Simply call yourAttributtedString.htmlString() and print it out.
extension NSAttributedString {
func htmlString() -> String? {
let documentAttributes = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
do {
let htmlData = try self.data(from: NSMakeRange(0, self.length), documentAttributes:documentAttributes)
if let htmlString = String(data:htmlData, encoding:String.Encoding.utf8) {
return htmlString
}
}
catch {}
return nil
}
}
According to this post:
private func getHtmlLabel(text: String) -> UILabel {
let label = UILabel()
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.attributedString = stringFromHtml(string: text)
return label
}
private func stringFromHtml(string: String) -> NSAttributedString? {
do {
let data = string.data(using: String.Encoding.utf8, allowLossyConversion: true)
if let d = data {
let str = try NSAttributedString(data: d,
options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
documentAttributes: nil)
return str
}
} catch { }
return nil
}

What is the best practice to parse html in swift?

I'm a Swift newbie. I need for something like Python's BeautifulSoup in Swift iOS project. Precisely, I need to get all href of <a> that ends with ".txt". What are the steps that I should take?
There are several nice libraries of HTML Parsing using Swift and Objective-C like the followings:
hpple
NDHpple
Kanna( old Swift-HTML-Parser)
Fuzi
SwiftSoup
Ji
Take a look in the following examples in the four libraries posted above, mainly parsed using XPath 2.0:
hpple:
let data = NSData(contentsOfFile: path)
let doc = TFHpple(htmlData: data)
if let elements = doc.searchWithXPathQuery("//a/#href[ends-with(.,'.txt')]") as? [TFHppleElement] {
for element in elements {
println(element.content)
}
}
NDHpple:
let data = NSData(contentsOfFile: path)!
let html = NSString(data: data, encoding: NSUTF8StringEncoding)!
let doc = NDHpple(HTMLData: html)
if let elements = doc.searchWithXPathQuery("//a/#href[ends-with(.,'.txt')]") {
for element in elements {
println(element.children?.first?.content)
}
}
Kanna (Xpath and CSS Selectors):
let html = "<html><head></head><body><ul><li><input type='image' name='input1' value='string1value' class='abc' /></li><li><input type='image' name='input2' value='string2value' class='def' /></li></ul><span class='spantext'><b>Hello World 1</b></span><span class='spantext'><b>Hello World 2</b></span><a href='example.com'>example(English)</a><a href='example.co.jp'>example(JP)</a></body>"
if let doc = Kanna.HTML(html: html, encoding: NSUTF8StringEncoding) {
var bodyNode = doc.body
if let inputNodes = bodyNode?.xpath("//a/#href[ends-with(.,'.txt')]") {
for node in inputNodes {
println(node.contents)
}
}
}
Fuzi (Xpath and CSS Selectors):
let html = "<html><head></head><body><ul><li><input type='image' name='input1' value='string1value' class='abc' /></li><li><input type='image' name='input2' value='string2value' class='def' /></li></ul><span class='spantext'><b>Hello World 1</b></span><span class='spantext'><b>Hello World 2</b></span><a href='example.com'>example(English)</a><a href='example.co.jp'>example(JP)</a></body>"
do {
// if encoding is omitted, it defaults to NSUTF8StringEncoding
let doc = try HTMLDocument(string: html, encoding: NSUTF8StringEncoding)
// XPath queries
for anchor in doc.xpath("//a/#href[ends-with(.,'.txt')]") {
print(anchor.stringValue)
}
} catch let error {
print(error)
}
The ends-with function is part of Xpath 2.0.
SwiftSoup (CSS Selectors):
do{
let doc: Document = try SwiftSoup.parse("...")
let links: Elements = try doc.select("a[href]") // a with href
let pngs: Elements = try doc.select("img[src$=.png]")
// img with src ending .png
let masthead: Element? = try doc.select("div.masthead").first()
// div with class=masthead
let resultLinks: Elements? = try doc.select("h3.r > a") // direct a after h3
} catch Exception.Error(let type, let message){
print(message)
} catch {
print("error")
}
Ji (XPath):
let jiDoc = Ji(htmlURL: URL(string: "http://www.apple.com/support")!)
let titleNode = jiDoc?.xPath("//head/title")?.first
print("title: \(titleNode?.content)") // title: Optional("Official Apple Support")
Try SwiftSoup, a port of jsoup to Swift.
let html: String = "<a id=1 href='?foo=bar&mid&lt=true'>One</a> <a id=2 href='?foo=bar<qux&lg=1'>Two</a>";
let els: Elements = try SwiftSoup.parse(html).select("a");
for element: Element in els.array(){
print(try element.attr("href"))
}
You could try this swift-html-parser:
https://github.com/tid-kijyun/Swift-HTML-Parser
It helps a lot.
And for getting your html from a txt you can:
let file = "file.txt"
if let dirs : [String] = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.AllDomainsMask, true) as? [String] {
let dir = dirs[0] //documents directory
let path = dir.stringByAppendingPathComponent(file);
let html = String(contentsOfFile: path, encoding: NSUTF8StringEncoding, error: nil)
Edit:
To get what you need you could use as the exemple:
import Foundation
let html = "theHtmlYouWannaParse"
var err : NSError?
var parser = HTMLParser(html: html, error: &err)
if err != nil {
println(err)
exit(1)
}
var bodyNode = parser.body
if let inputNodes = bodyNode?.findChildTags("b") {
for node in inputNodes {
println(node.contents)
}
}
if let inputNodes = bodyNode?.findChildTags("a") {
for node in inputNodes {
println(node.getAttributeNamed("href")) //<- Here you would get your files link
}
}

Swifty Json getting unknown but long way works fine?

I'm attempting to use SwiftyJson to pull some JSON data.
What's unusual is the "println(json)" says "unknowon" while if I pull the JSON data the regular way it works just fine -- the "println(pop)" says medium, as expected.
Below is the code I'm using. I started cutting out parts until I got to "println(json)" and then decided to try and handle it manually to see if it's SwiftyJson or me.
Any suggestions? I'm fairly new to iOS programming so I'm assuming I'm being silly in some form or another.
var ghostlandsJsonUrl: NSURL = NSURL(string: "http://us.battle.net/api/wow/realm/status?realm=Ghostlands")!
var jsonData: NSData!
var request: NSURLRequest = NSURLRequest(URL: ghostlandsJsonUrl)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config)
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
jsonData = data
if(jsonData != nil) {
let json = JSON(jsonData)
println(json)
} else {
println("jsonData: nil value... net down again?")
}
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let statuses = jsonObject as? NSDictionary{
if let realms = statuses["realms"] as? NSArray{
if let realm = realms[0] as? NSDictionary{
if let pop = realm["population"] as? NSString{
println(pop)
}
}
}
}
});
task.resume()
Looking at SwiftyJSON source code I can see that JSON is a simple struct. It implements the Printable protocol. Which give support to the print methods.
public var description: String {
if let string = self.rawString(options:.PrettyPrinted) {
return string
} else {
return "unknown"
}
}
Which means that for a reason or another the rawString method returns nil.
public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
switch self.type {
case .Array, .Dictionary:
if let data = self.rawData(options: opt) {
return NSString(data: data, encoding: encoding)
} else {
return nil
}
case .String:
return (self.object as String)
case .Number:
return (self.object as NSNumber).stringValue
case .Bool:
return (self.object as Bool).description
case .Null:
return "null"
default:
return nil
}
}
As you are fairly new to iOS development, I will tell you that the constructor doesn't expect a NSData object.
Here is the source:
public var object: AnyObject {
get {
return _object
}
set {
_object = newValue
switch newValue {
case let number as NSNumber:
if number.isBool {
_type = .Bool
} else {
_type = .Number
}
case let string as NSString:
_type = .String
case let null as NSNull:
_type = .Null
case let array as [AnyObject]:
_type = .Array
case let dictionary as [String : AnyObject]:
_type = .Dictionary
default:
_type = .Unknown
_object = NSNull()
_error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
}
}
}
So you should pass it the unserialized NSData as it:
if let jsonData = data {
//jsonData can't be nil with this kind of if
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil)
let json = JSON(jsonObject)
println(json)
//...
The constructor of JSON does the serialisation. Below is the constructor code from SwiftyJSON git repo where you can directly pass the NSData.
public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
do {
let object: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: opt)
self.init(object)
} catch let aError as NSError {
if error != nil {
error.memory = aError
}
self.init(NSNull())
}
}
In simple, you can directly use the data returned in the completion handler of NSURLSession data task as below in your code.
let json = JSON(data: jsonData)