* Removed StringBuilder from Element.cssSelector

* Lint Code
* Swift 4.1
This commit is contained in:
Nabil Chatbi 2018-03-31 19:42:13 +02:00
parent 306be6efbe
commit d98300a7ec
57 changed files with 473 additions and 504 deletions

View File

@ -1,7 +1,17 @@
# Change Log # Change Log
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [1.6.3](https://github.com/scinfu/SwiftSoup/tree/1.6.4) ## [1.6.6](https://github.com/scinfu/SwiftSoup/tree/1.6.6)
* Removed StringBuilder from Element.cssSelector
* Lint Code
* Swift 4.1
## [1.6.5](https://github.com/scinfu/SwiftSoup/tree/1.6.5)
* Removed StringBuilder from Element.cssSelector
* Lint Code
*
## [1.6.4](https://github.com/scinfu/SwiftSoup/tree/1.6.4)
* Add newer simulators to targeted devices to build with Carthage [tvOS] * Add newer simulators to targeted devices to build with Carthage [tvOS]
## [1.6.3](https://github.com/scinfu/SwiftSoup/tree/1.6.3) ## [1.6.3](https://github.com/scinfu/SwiftSoup/tree/1.6.3)

View File

@ -13,7 +13,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch. // Override point for customization after application launch.
return true return true
@ -41,6 +40,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
} }
} }

View File

@ -15,10 +15,9 @@ class QueryViewControllerCell: UITableViewCell {
} }
class QueryViewController: UIViewController { class QueryViewController: UIViewController {
typealias Item = (selector: String,example: String, description: String) typealias Item = (selector: String, example: String, description: String)
//example items //example items
let items: [ let items: [
@ -36,35 +35,32 @@ class QueryViewController: UIViewController {
Item(selector: "[attribute^=value]", example: "a[href^=https]", description: "Selects every <a> element whose href attribute value begins with \"https\""), Item(selector: "[attribute^=value]", example: "a[href^=https]", description: "Selects every <a> element whose href attribute value begins with \"https\""),
Item(selector: "[attribute$=value]", example: "a[href$=.com/]", description: "Selects every <a> element whose href attribute value ends with \".com/\""), Item(selector: "[attribute$=value]", example: "a[href$=.com/]", description: "Selects every <a> element whose href attribute value ends with \".com/\""),
Item(selector: "[attribute*=value]", example: "a[href*=login]", description: "Selects every <a> element whose href attribute value contains the substring \"login\""), Item(selector: "[attribute*=value]", example: "a[href*=login]", description: "Selects every <a> element whose href attribute value contains the substring \"login\""),
Item(selector: "[attr~=regex]", example: "img[src~=[gif]]", description: "elements with an attribute named \"img\", and value matching the regular expression"), Item(selector: "[attr~=regex]", example: "img[src~=[gif]]", description: "elements with an attribute named \"img\", and value matching the regular expression")
] ]
var completionHandler: (Item)->Void = { arg in } var completionHandler: (Item) -> Void = { arg in }
@IBOutlet weak var tableView: UITableView! @IBOutlet weak var tableView: UITableView!
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
self.title = "" self.title = ""
self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension; self.tableView.estimatedRowHeight = UITableViewAutomaticDimension
} }
} }
extension QueryViewController: UITableViewDataSource extension QueryViewController: UITableViewDataSource {
{
func numberOfSections(in tableView: UITableView) -> Int { func numberOfSections(in tableView: UITableView) -> Int {
return 1 return 1
} }
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count return items.count
} }
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell = tableView.dequeueReusableCell(withIdentifier: "QueryViewControllerCell", for: indexPath) as! QueryViewControllerCell let cell = tableView.dequeueReusableCell(withIdentifier: "QueryViewControllerCell", for: indexPath) as! QueryViewControllerCell
cell.selector.text = items[indexPath.row].selector cell.selector.text = items[indexPath.row].selector
@ -79,8 +75,7 @@ extension QueryViewController: UITableViewDataSource
} }
} }
extension QueryViewController: UITableViewDelegate extension QueryViewController: UITableViewDelegate {
{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// user select an item // user select an item
completionHandler(items[indexPath.row]) completionHandler(items[indexPath.row])

View File

@ -27,8 +27,8 @@ class ViewController: UIViewController {
self.title = "SwiftSoup Example" self.title = "SwiftSoup Example"
self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension; self.tableView.estimatedRowHeight = UITableViewAutomaticDimension
urlTextField.text = "http://www.facebook.com" urlTextField.text = "http://www.facebook.com"
cssTextField.text = "div" cssTextField.text = "div"
@ -37,9 +37,8 @@ class ViewController: UIViewController {
downloadHTML() downloadHTML()
} }
//Download HTML //Download HTML
func downloadHTML(){ func downloadHTML() {
// url string to URL // url string to URL
guard let url = URL(string: urlTextField.text ?? "") else { guard let url = URL(string: urlTextField.text ?? "") else {
// an error occurred // an error occurred
@ -62,14 +61,14 @@ class ViewController: UIViewController {
} }
//Parse CSS selector //Parse CSS selector
func parse(){ func parse() {
do { do {
//empty old items //empty old items
items = [] items = []
// firn css selector // firn css selector
let elements: Elements = try document.select(cssTextField.text ?? "") let elements: Elements = try document.select(cssTextField.text ?? "")
//transform it into a local object (Item) //transform it into a local object (Item)
for element in elements{ for element in elements {
let text = try element.text() let text = try element.text()
let html = try element.outerHtml() let html = try element.outerHtml()
items.append(Item(text: text, html: html)) items.append(Item(text: text, html: html))
@ -83,7 +82,7 @@ class ViewController: UIViewController {
} }
@IBAction func chooseQuery(_ sender: Any) { @IBAction func chooseQuery(_ sender: Any) {
guard let vc = storyboard?.instantiateViewController(withIdentifier: "QueryViewController") as? QueryViewController else{ guard let vc = storyboard?.instantiateViewController(withIdentifier: "QueryViewController") as? QueryViewController else {
return return
} }
vc.completionHandler = {[weak self](resilt) in vc.completionHandler = {[weak self](resilt) in
@ -94,25 +93,21 @@ class ViewController: UIViewController {
self.show(vc, sender: self) self.show(vc, sender: self)
} }
} }
extension ViewController: UITableViewDataSource extension ViewController: UITableViewDataSource {
{
func numberOfSections(in tableView: UITableView) -> Int { func numberOfSections(in tableView: UITableView) -> Int {
return 1 return 1
} }
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count return items.count
} }
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
var cell = tableView.dequeueReusableCell(withIdentifier: "cell") var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil { if cell == nil {
cell = UITableViewCell.init(style: UITableViewCellStyle.subtitle , reuseIdentifier: "cell") cell = UITableViewCell.init(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell")
cell?.textLabel?.numberOfLines = 2 cell?.textLabel?.numberOfLines = 2
cell?.detailTextLabel?.numberOfLines = 6 cell?.detailTextLabel?.numberOfLines = 6
@ -129,19 +124,15 @@ extension ViewController: UITableViewDataSource
let color2 = UIColor.init(red: 240.0/255, green: 240.0/255, blue: 240.0/255, alpha: 1) let color2 = UIColor.init(red: 240.0/255, green: 240.0/255, blue: 240.0/255, alpha: 1)
cell?.backgroundColor = (indexPath.row % 2) == 0 ? color1 : color2 cell?.backgroundColor = (indexPath.row % 2) == 0 ? color1 : color2
return cell! return cell!
} }
} }
extension ViewController: UITableViewDelegate extension ViewController: UITableViewDelegate {
{
} }
extension ViewController: UITextFieldDelegate extension ViewController: UITextFieldDelegate {
{ public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
public func textFieldShouldReturn(_ textField: UITextField) -> Bool{
textField.resignFirstResponder() textField.resignFirstResponder()
return false return false
} }
@ -158,13 +149,10 @@ extension ViewController: UITextFieldDelegate
} }
} }
extension UIAlertController { extension UIAlertController {
static public func showAlert(_ message: String, _ controller: UIViewController){ static public func showAlert(_ message: String, _ controller: UIViewController) {
let alert = UIAlertController(title: "Alert", message: message, preferredStyle: UIAlertControllerStyle.alert) let alert = UIAlertController(title: "Alert", message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
controller.present(alert, animated: true, completion: nil) controller.present(alert, animated: true, completion: nil)
} }
} }

View File

@ -5,10 +5,10 @@ import PackageDescription
let package = Package( let package = Package(
name: "SwiftSoup", name: "SwiftSoup",
products: [ products: [
.library(name: "SwiftSoup", targets: ["SwiftSoup"]), .library(name: "SwiftSoup", targets: ["SwiftSoup"])
], ],
targets: [ targets: [
.target(name: "SwiftSoup", path: "Sources"), .target(name: "SwiftSoup", path: "Sources"),
.testTarget(name: "SwiftSoupTests", dependencies: ["SwiftSoup"]), .testTarget(name: "SwiftSoupTests", dependencies: ["SwiftSoup"])
] ]
) )

View File

@ -140,7 +140,7 @@ open class Attribute {
} }
} }
extension Attribute : Equatable { extension Attribute: Equatable {
static public func == (lhs: Attribute, rhs: Attribute) -> Bool { static public func == (lhs: Attribute, rhs: Attribute) -> Bool {
return lhs.value == rhs.value && lhs.key == rhs.key return lhs.value == rhs.value && lhs.key == rhs.key
} }

View File

@ -38,7 +38,7 @@ open class Attributes: NSCopying {
@see #hasKey(String) @see #hasKey(String)
*/ */
open func get(key: String) -> String { open func get(key: String) -> String {
let attr: Attribute? = attributes.get(key:key) let attr: Attribute? = attributes.get(key: key)
return attr != nil ? attr!.getValue() : "" return attr != nil ? attr!.getValue() : ""
} }
@ -86,7 +86,7 @@ open class Attributes: NSCopying {
@param attribute attribute @param attribute attribute
*/ */
open func put(attribute: Attribute) { open func put(attribute: Attribute) {
attributes.put(value: attribute, forKey:attribute.getKey()) attributes.put(value: attribute, forKey: attribute.getKey())
} }
/** /**
@ -254,7 +254,7 @@ open class Attributes: NSCopying {
} }
extension Attributes : Sequence { extension Attributes: Sequence {
public func makeIterator() -> AnyIterator<Attribute> { public func makeIterator() -> AnyIterator<Attribute> {
var list = attributes.orderedValues var list = attributes.orderedValues
return AnyIterator { return AnyIterator {

View File

@ -24,7 +24,7 @@ extension Character {
var isWhitespace: Bool { var isWhitespace: Bool {
switch self { switch self {
case Character.space, Character.BackslashT, Character.BackslashN,Character.BackslashF,Character.BackslashR: return true case Character.space, Character.BackslashT, Character.BackslashN, Character.BackslashF, Character.BackslashR: return true
case Character.BackshashRBackslashN: return true case Character.BackshashRBackslashN: return true
default: return false default: return false

View File

@ -118,7 +118,7 @@ extension Cleaner {
//let sourceData: DataNode = (DataNode) source //let sourceData: DataNode = (DataNode) source
let destData: DataNode = DataNode(sourceData.getWholeData(), source.getBaseUri()) let destData: DataNode = DataNode(sourceData.getWholeData(), source.getBaseUri())
try destination?.appendChild(destData) try destination?.appendChild(destData)
}else{ } else {
numDiscarded+=1 numDiscarded+=1
} }
} else { // else, we don't care about comments, xml proc instructions, etc } else { // else, we don't care about comments, xml proc instructions, etc

View File

@ -13,7 +13,7 @@ import Foundation
*/ */
public class DocumentType: Node { public class DocumentType: Node {
static let PUBLIC_KEY: String = "PUBLIC" static let PUBLIC_KEY: String = "PUBLIC"
static let SYSTEM_KEY: String = "SYSTEM"; static let SYSTEM_KEY: String = "SYSTEM"
private static let NAME: String = "name" private static let NAME: String = "name"
private static let PUB_SYS_KEY: String = "pubSysKey"; // PUBLIC or SYSTEM private static let PUB_SYS_KEY: String = "pubSysKey"; // PUBLIC or SYSTEM
private static let PUBLIC_ID: String = "publicId" private static let PUBLIC_ID: String = "publicId"
@ -30,12 +30,12 @@ public class DocumentType: Node {
public init(_ name: String, _ publicId: String, _ systemId: String, _ baseUri: String) { public init(_ name: String, _ publicId: String, _ systemId: String, _ baseUri: String) {
super.init(baseUri) super.init(baseUri)
do { do {
try attr(DocumentType.NAME, name); try attr(DocumentType.NAME, name)
try attr(DocumentType.PUBLIC_ID, publicId); try attr(DocumentType.PUBLIC_ID, publicId)
if (has(DocumentType.PUBLIC_ID)) { if (has(DocumentType.PUBLIC_ID)) {
try attr(DocumentType.PUB_SYS_KEY, DocumentType.PUBLIC_KEY); try attr(DocumentType.PUB_SYS_KEY, DocumentType.PUBLIC_KEY)
} }
try attr(DocumentType.SYSTEM_ID, systemId); try attr(DocumentType.SYSTEM_ID, systemId)
} catch {} } catch {}
} }
@ -50,18 +50,14 @@ public class DocumentType: Node {
super.init(baseUri) super.init(baseUri)
do { do {
try attr(DocumentType.NAME, name) try attr(DocumentType.NAME, name)
if(pubSysKey != nil){ if(pubSysKey != nil) {
try attr(DocumentType.PUB_SYS_KEY, pubSysKey!) try attr(DocumentType.PUB_SYS_KEY, pubSysKey!)
} }
try attr(DocumentType.PUBLIC_ID, publicId); try attr(DocumentType.PUBLIC_ID, publicId)
try attr(DocumentType.SYSTEM_ID, systemId); try attr(DocumentType.SYSTEM_ID, systemId)
} catch {} } catch {}
} }
public override func nodeName() -> String { public override func nodeName() -> String {
return "#doctype" return "#doctype"
} }
@ -80,7 +76,7 @@ public class DocumentType: Node {
} }
if (has(DocumentType.PUB_SYS_KEY)){ if (has(DocumentType.PUB_SYS_KEY)) {
do { do {
try accum.append(" ").append(attr(DocumentType.PUB_SYS_KEY)) try accum.append(" ").append(attr(DocumentType.PUB_SYS_KEY))
} catch {} } catch {}
@ -88,7 +84,7 @@ public class DocumentType: Node {
if (has(DocumentType.PUBLIC_ID)) { if (has(DocumentType.PUBLIC_ID)) {
do { do {
try accum.append(" \"").append(attr(DocumentType.PUBLIC_ID)).append("\""); try accum.append(" \"").append(attr(DocumentType.PUBLIC_ID)).append("\"")
} catch {} } catch {}
} }

View File

@ -283,7 +283,7 @@ open class Element: Node {
* @return if this element matches the query * @return if this element matches the query
*/ */
public func iS(_ cssQuery: String)throws->Bool { public func iS(_ cssQuery: String)throws->Bool {
return try iS(QueryParser.parse(cssQuery)); return try iS(QueryParser.parse(cssQuery))
} }
/** /**
@ -293,15 +293,11 @@ open class Element: Node {
*/ */
public func iS(_ evaluator: Evaluator)throws->Bool { public func iS(_ evaluator: Evaluator)throws->Bool {
guard let od = self.ownerDocument() else { guard let od = self.ownerDocument() else {
return false; return false
} }
return try evaluator.matches(od, self); return try evaluator.matches(od, self)
} }
/** /**
* Add a node child node to this element. * Add a node child node to this element.
* *
@ -1065,9 +1061,9 @@ open class Element: Node {
* @return set of classnames, empty if no class attribute * @return set of classnames, empty if no class attribute
*/ */
public func classNames()throws->OrderedSet<String> { public func classNames()throws->OrderedSet<String> {
let fitted = try className().replaceAll(of: Element.classSplit, with: " ", options:.caseInsensitive) let fitted = try className().replaceAll(of: Element.classSplit, with: " ", options: .caseInsensitive)
let names: [String] = fitted.components(separatedBy: " ") let names: [String] = fitted.components(separatedBy: " ")
let classNames: OrderedSet<String> = OrderedSet(sequence:names) let classNames: OrderedSet<String> = OrderedSet(sequence: names)
classNames.remove(Element.emptyString) // if classNames() was empty, would include an empty class classNames.remove(Element.emptyString) // if classNames() was empty, would include an empty class
return classNames return classNames
} }

View File

@ -459,13 +459,13 @@ open class Elements: NSCopying {
* @return true if at least one element in the list matches the query. * @return true if at least one element in the list matches the query.
*/ */
open func iS(_ query: String)throws->Bool { open func iS(_ query: String)throws->Bool {
let eval: Evaluator = try QueryParser.parse(query); let eval: Evaluator = try QueryParser.parse(query)
for e: Element in this { for e: Element in this {
if (try e.iS(eval)){ if (try e.iS(eval)) {
return true; return true
} }
} }
return false; return false
} }
@ -600,7 +600,7 @@ public struct ElementsIterator: IteratorProtocol {
/// Advances to the next element and returns it, or `nil` if no next element /// Advances to the next element and returns it, or `nil` if no next element
mutating public func next() -> Element? { mutating public func next() -> Element? {
let result = index < elements.size() ? elements.get(index) : nil let result = index < elements.size() ? elements.get(index) : nil
index += 1; index += 1
return result return result
} }
} }
@ -614,6 +614,3 @@ extension Elements: Sequence {
return ElementsIterator(self) return ElementsIterator(self)
} }
} }

View File

@ -21,11 +21,11 @@ public class Entities {
public struct EscapeMode: Equatable { public struct EscapeMode: Equatable {
/** Restricted entities suitable for XHTML output: lt, gt, amp, and quot only. */ /** Restricted entities suitable for XHTML output: lt, gt, amp, and quot only. */
public static let xhtml: EscapeMode = EscapeMode(string:Entities.xhtml, size: 4, id: 0) public static let xhtml: EscapeMode = EscapeMode(string: Entities.xhtml, size: 4, id: 0)
/** Default HTML output entities. */ /** Default HTML output entities. */
public static let base: EscapeMode = EscapeMode(string:Entities.base, size: 106, id: 1) public static let base: EscapeMode = EscapeMode(string: Entities.base, size: 106, id: 1)
/** Complete HTML entities. */ /** Complete HTML entities. */
public static let extended: EscapeMode = EscapeMode(string:Entities.full, size: 2125, id: 2) public static let extended: EscapeMode = EscapeMode(string: Entities.full, size: 2125, id: 2)
fileprivate let value: Int fileprivate let value: Int
@ -45,7 +45,7 @@ public class Entities {
return left.value != right.value return left.value != right.value
} }
private static let codeDelims : [UnicodeScalar] = [",", ";"] private static let codeDelims: [UnicodeScalar] = [",", ";"]
init(string: String, size: Int, id: Int) { init(string: String, size: Int, id: Int) {
nameKeys = [String](repeating: "", count: size) nameKeys = [String](repeating: "", count: size)
@ -54,35 +54,34 @@ public class Entities {
nameVals = [String](repeating: "", count: size) nameVals = [String](repeating: "", count: size)
value = id value = id
//Load() //Load()
var i = 0; var i = 0
let reader: CharacterReader = CharacterReader(string); let reader: CharacterReader = CharacterReader(string)
while (!reader.isEmpty()) { while (!reader.isEmpty()) {
// NotNestedLessLess=10913,824;1887 // NotNestedLessLess=10913,824;1887
let name: String = reader.consumeTo("="); let name: String = reader.consumeTo("=")
reader.advance(); reader.advance()
let cp1: Int = Int(reader.consumeToAny(EscapeMode.codeDelims), radix: codepointRadix) ?? 0 let cp1: Int = Int(reader.consumeToAny(EscapeMode.codeDelims), radix: codepointRadix) ?? 0
let codeDelim: UnicodeScalar = reader.current(); let codeDelim: UnicodeScalar = reader.current()
reader.advance(); reader.advance()
let cp2: Int; let cp2: Int
if (codeDelim == ",") { if (codeDelim == ",") {
cp2 = Int(reader.consumeTo(";"), radix: codepointRadix) ?? 0 cp2 = Int(reader.consumeTo(";"), radix: codepointRadix) ?? 0
reader.advance(); reader.advance()
} else { } else {
cp2 = empty; cp2 = empty
} }
let index: Int = Int(reader.consumeTo("\n"), radix: codepointRadix) ?? 0 let index: Int = Int(reader.consumeTo("\n"), radix: codepointRadix) ?? 0
reader.advance(); reader.advance()
nameKeys[i] = name; nameKeys[i] = name
codeVals[i] = cp1; codeVals[i] = cp1
codeKeys[index] = cp1; codeKeys[index] = cp1
nameVals[index] = name; nameVals[index] = name
if (cp2 != empty) { if (cp2 != empty) {
var s = String() var s = String()
@ -94,8 +93,6 @@ public class Entities {
} }
} }
// init(string: String, size: Int, id: Int) { // init(string: String, size: Int, id: Int) {
// nameKeys = [String](repeating: "", count: size) // nameKeys = [String](repeating: "", count: size)
// codeVals = [Int](repeating: 0, count: size) // codeVals = [Int](repeating: 0, count: size)
@ -199,7 +196,7 @@ public class Entities {
* @deprecated does not support characters outside the BMP or multiple character names * @deprecated does not support characters outside the BMP or multiple character names
*/ */
open static func getCharacterByName(name: String) -> Character { open static func getCharacterByName(name: String) -> Character {
return Character.convertFromIntegerLiteral(value:EscapeMode.extended.codepointForName(name)) return Character.convertFromIntegerLiteral(value: EscapeMode.extended.codepointForName(name))
} }
/** /**
@ -233,7 +230,7 @@ public class Entities {
return 0 return 0
} }
open static func escape(_ string: String, _ encode: String.Encoding = .utf8 )-> String{ open static func escape(_ string: String, _ encode: String.Encoding = .utf8 ) -> String {
return Entities.escape(string, OutputSettings().charset(encode).escapeMode(Entities.EscapeMode.extended)) return Entities.escape(string, OutputSettings().charset(encode).escapeMode(Entities.EscapeMode.extended))
} }
@ -333,7 +330,7 @@ public class Entities {
if (name != emptyName) // ok for identity check if (name != emptyName) // ok for identity check
{accum.append(UnicodeScalar.Ampersand).append(name).append(";") {accum.append(UnicodeScalar.Ampersand).append(name).append(";")
} else { } else {
accum.append("&#x").append(String.toHexString(n:Int(codePoint.value)) ).append(";") accum.append("&#x").append(String.toHexString(n: Int(codePoint.value)) ).append(";")
} }
} }

View File

@ -278,7 +278,7 @@ public class Evaluator {
open override func matches(_ root: Element, _ element: Element)throws->Bool { open override func matches(_ root: Element, _ element: Element)throws->Bool {
if(element.hasAttr(key)) { if(element.hasAttr(key)) {
let s = try element.attr(key) let s = try element.attr(key)
return pattern.matcher(in:s).find() return pattern.matcher(in: s).find()
} }
return false return false
} }

View File

@ -87,7 +87,7 @@ class HtmlTreeBuilder: TreeBuilder {
} }
root = try Element(Tag.valueOf("html", settings), baseUri) root = try Element(Tag.valueOf("html", settings), baseUri)
try Validate.notNull(obj:root) try Validate.notNull(obj: root)
try doc.appendChild(root!) try doc.appendChild(root!)
stack.append(root!) stack.append(root!)
resetInsertionMode() resetInsertionMode()
@ -422,8 +422,8 @@ class HtmlTreeBuilder: TreeBuilder {
private func replaceInQueue(_ queue: Array<Element?>, _ out: Element, _ input: Element)throws->Array<Element?> { private func replaceInQueue(_ queue: Array<Element?>, _ out: Element, _ input: Element)throws->Array<Element?> {
var queue = queue var queue = queue
var i: Int = -1 var i: Int = -1
for index in 0..<queue.count{ for index in 0..<queue.count {
if(out == queue[index]){ if(out == queue[index]) {
i = index i = index
} }
} }

View File

@ -153,7 +153,7 @@ enum HtmlTreeBuilderState: String, HtmlTreeBuilderStateProtocol {
// todo: charset switches // todo: charset switches
} else if (name.equals("title")) { } else if (name.equals("title")) {
try HtmlTreeBuilderState.handleRcData(start, tb) try HtmlTreeBuilderState.handleRcData(start, tb)
} else if (StringUtil.inString(name, haystack:"noframes", "style")) { } else if (StringUtil.inString(name, haystack: "noframes", "style")) {
try HtmlTreeBuilderState.handleRawtext(start, tb) try HtmlTreeBuilderState.handleRawtext(start, tb)
} else if (name.equals("noscript")) { } else if (name.equals("noscript")) {
// else if noscript && scripting flag = true: rawtext (jsoup doesn't run script, to handle as noscript) // else if noscript && scripting flag = true: rawtext (jsoup doesn't run script, to handle as noscript)
@ -179,7 +179,7 @@ enum HtmlTreeBuilderState: String, HtmlTreeBuilderStateProtocol {
if (name?.equals("head"))! { if (name?.equals("head"))! {
tb.pop() tb.pop()
tb.transition(.AfterHead) tb.transition(.AfterHead)
} else if (name != nil && StringUtil.inString(name!, haystack:"body", "html", "br")) { } else if (name != nil && StringUtil.inString(name!, haystack: "body", "html", "br")) {
return try anythingElse(t, tb) return try anythingElse(t, tb)
} else { } else {
tb.error(self) tb.error(self)

View File

@ -560,7 +560,7 @@ open class Node: Equatable, Hashable {
@return next sibling, or null if this is the last sibling @return next sibling, or null if this is the last sibling
*/ */
open func nextSibling() -> Node? { open func nextSibling() -> Node? {
guard let siblings: Array<Node> = parentNode?.childNodes else{ guard let siblings: Array<Node> = parentNode?.childNodes else {
return nil return nil
} }
@ -708,7 +708,7 @@ open class Node: Equatable, Hashable {
let currParent: Node = nodesToProcess.removeFirst() let currParent: Node = nodesToProcess.removeFirst()
for i in 0..<currParent.childNodes.count { for i in 0..<currParent.childNodes.count {
let childClone: Node = currParent.childNodes[i].copy(parent:currParent) let childClone: Node = currParent.childNodes[i].copy(parent: currParent)
currParent.childNodes[i] = childClone currParent.childNodes[i] = childClone
nodesToProcess.append(childClone) nodesToProcess.append(childClone)
} }
@ -778,7 +778,7 @@ open class Node: Equatable, Hashable {
} }
extension Node : CustomStringConvertible { extension Node: CustomStringConvertible {
public var description: String { public var description: String {
do { do {
return try outerHtml() return try outerHtml()
@ -789,7 +789,7 @@ extension Node : CustomStringConvertible {
} }
} }
extension Node : CustomDebugStringConvertible { extension Node: CustomDebugStringConvertible {
private static let space = " " private static let space = " "
public var debugDescription: String { public var debugDescription: String {
do { do {

View File

@ -74,7 +74,7 @@ public class OrderedDictionary<Key: Hashable, Value: Equatable>: MutableCollecti
} }
public var orderedValues: [Value] { public var orderedValues: [Value] {
return _orderedKeys.flatMap { _keysToValues[$0] } return _orderedKeys.compactMap { _keysToValues[$0] }
} }
// ======================================================= // // ======================================================= //
@ -148,7 +148,7 @@ public class OrderedDictionary<Key: Hashable, Value: Equatable>: MutableCollecti
public func putAll(all: OrderedDictionary<Key, Value>) { public func putAll(all: OrderedDictionary<Key, Value>) {
for i in all.orderedKeys { for i in all.orderedKeys {
put(value:all[i]!, forKey: i) put(value: all[i]!, forKey: i)
} }
} }
@ -170,7 +170,7 @@ public class OrderedDictionary<Key: Hashable, Value: Equatable>: MutableCollecti
@discardableResult @discardableResult
public func remove(key: Key) -> Value? { public func remove(key: Key) -> Value? {
return removeValueForKey(key:key) return removeValueForKey(key: key)
} }
public func removeAll(keepCapacity: Bool = true) { public func removeAll(keepCapacity: Bool = true) {
@ -391,8 +391,6 @@ extension OrderedDictionary: Equatable {
// return lhs._orderedKeys == rhs._orderedKeys && lhs._keysToValues == rhs._keysToValues // return lhs._orderedKeys == rhs._orderedKeys && lhs._keysToValues == rhs._keysToValues
//} //}
/** /**
* Elements IteratorProtocol. * Elements IteratorProtocol.
*/ */
@ -412,7 +410,7 @@ public struct OrderedDictionaryIterator<Key: Hashable, Value: Equatable>: Iterat
mutating public func next() -> Value? { mutating public func next() -> Value? {
let result = index < orderedDictionary.orderedKeys.count ? orderedDictionary[orderedDictionary.orderedKeys[index]] : nil let result = index < orderedDictionary.orderedKeys.count ? orderedDictionary[orderedDictionary.orderedKeys[index]] : nil
index += 1; index += 1
return result return result
} }
} }
@ -422,13 +420,7 @@ public struct OrderedDictionaryIterator<Key: Hashable, Value: Equatable>: Iterat
*/ */
extension OrderedDictionary: Sequence { extension OrderedDictionary: Sequence {
/// Returns an iterator over the elements of this sequence. /// Returns an iterator over the elements of this sequence.
func generate()->OrderedDictionaryIterator<Key, Value> func generate()->OrderedDictionaryIterator<Key, Value> {
{
return OrderedDictionaryIterator(self) return OrderedDictionaryIterator(self)
} }
} }

View File

@ -107,7 +107,7 @@ public class OrderedSet<T: Hashable> {
public func remove(_ object: T) { public func remove(_ object: T) {
if let index = contents[object] { if let index = contents[object] {
contents[object] = nil contents[object] = nil
sequencedContents[index].deallocate(capacity: 1) sequencedContents[index].deallocate()
sequencedContents.remove(at: index) sequencedContents.remove(at: index)
for (object, i) in contents { for (object, i) in contents {
@ -151,7 +151,7 @@ public class OrderedSet<T: Hashable> {
contents.removeAll() contents.removeAll()
for sequencedContent in sequencedContents { for sequencedContent in sequencedContents {
sequencedContent.deallocate(capacity: 1) sequencedContent.deallocate()
} }
sequencedContents.removeAll() sequencedContents.removeAll()

View File

@ -57,8 +57,3 @@ open class ParseSettings {
} }
} }

View File

@ -146,7 +146,7 @@ public class Parser {
let nodeList: Array<Node> = try parseFragment(bodyHtml, body, baseUri) let nodeList: Array<Node> = try parseFragment(bodyHtml, body, baseUri)
//var nodes: [Node] = nodeList.toArray(Node[nodeList.size()]) // the node list gets modified when re-parented //var nodes: [Node] = nodeList.toArray(Node[nodeList.size()]) // the node list gets modified when re-parented
if nodeList.count > 0 { if nodeList.count > 0 {
for i in 1..<nodeList.count{ for i in 1..<nodeList.count {
try nodeList[i].remove() try nodeList[i].remove()
} }
} }

View File

@ -24,14 +24,14 @@ public struct Pattern {
} }
func validate()throws { func validate()throws {
_ = try NSRegularExpression(pattern: self.pattern, options:[]) _ = try NSRegularExpression(pattern: self.pattern, options: [])
} }
func matcher(in text: String) -> Matcher { func matcher(in text: String) -> Matcher {
do { do {
let regex = try NSRegularExpression(pattern: self.pattern, options:[]) let regex = try NSRegularExpression(pattern: self.pattern, options: [])
let nsString = NSString(string: text) let nsString = NSString(string: text)
let results = regex.matches(in: text, options:[], range: NSRange(location: 0, length: nsString.length)) let results = regex.matches(in: text, options: [], range: NSRange(location: 0, length: nsString.length))
return Matcher(results, text) return Matcher(results, text)
} catch let error { } catch let error {

View File

@ -140,7 +140,7 @@ public class QueryParser {
} else if (tq.matchChomp(".")) { } else if (tq.matchChomp(".")) {
try byClass()} else if (tq.matchesWord() || tq.matches("*|")) {try byTag()} else if (tq.matches("[")) {try byAttribute()} else if (tq.matchChomp("*")) { allElements()} else if (tq.matchChomp(":lt(")) {try indexLessThan()} else if (tq.matchChomp(":gt(")) {try indexGreaterThan()} else if (tq.matchChomp(":eq(")) {try indexEquals()} else if (tq.matches(":has(")) {try has()} else if (tq.matches(":contains(")) {try contains(false)} else if (tq.matches(":containsOwn(")) {try contains(true)} else if (tq.matches(":matches(")) {try matches(false)} else if (tq.matches(":matchesOwn(")) {try matches(true)} else if (tq.matches(":not(")) {try not()} else if (tq.matchChomp(":nth-child(")) {try cssNthChild(false, false)} else if (tq.matchChomp(":nth-last-child(")) {try cssNthChild(true, false)} else if (tq.matchChomp(":nth-of-type(")) {try cssNthChild(false, true)} else if (tq.matchChomp(":nth-last-of-type(")) {try cssNthChild(true, true)} else if (tq.matchChomp(":first-child")) {evals.append(Evaluator.IsFirstChild())} else if (tq.matchChomp(":last-child")) {evals.append(Evaluator.IsLastChild())} else if (tq.matchChomp(":first-of-type")) {evals.append(Evaluator.IsFirstOfType())} else if (tq.matchChomp(":last-of-type")) {evals.append(Evaluator.IsLastOfType())} else if (tq.matchChomp(":only-child")) {evals.append(Evaluator.IsOnlyChild())} else if (tq.matchChomp(":only-of-type")) {evals.append(Evaluator.IsOnlyOfType())} else if (tq.matchChomp(":empty")) {evals.append(Evaluator.IsEmpty())} else if (tq.matchChomp(":root")) {evals.append(Evaluator.IsRoot())} else // unhandled try byClass()} else if (tq.matchesWord() || tq.matches("*|")) {try byTag()} else if (tq.matches("[")) {try byAttribute()} else if (tq.matchChomp("*")) { allElements()} else if (tq.matchChomp(":lt(")) {try indexLessThan()} else if (tq.matchChomp(":gt(")) {try indexGreaterThan()} else if (tq.matchChomp(":eq(")) {try indexEquals()} else if (tq.matches(":has(")) {try has()} else if (tq.matches(":contains(")) {try contains(false)} else if (tq.matches(":containsOwn(")) {try contains(true)} else if (tq.matches(":matches(")) {try matches(false)} else if (tq.matches(":matchesOwn(")) {try matches(true)} else if (tq.matches(":not(")) {try not()} else if (tq.matchChomp(":nth-child(")) {try cssNthChild(false, false)} else if (tq.matchChomp(":nth-last-child(")) {try cssNthChild(true, false)} else if (tq.matchChomp(":nth-of-type(")) {try cssNthChild(false, true)} else if (tq.matchChomp(":nth-last-of-type(")) {try cssNthChild(true, true)} else if (tq.matchChomp(":first-child")) {evals.append(Evaluator.IsFirstChild())} else if (tq.matchChomp(":last-child")) {evals.append(Evaluator.IsLastChild())} else if (tq.matchChomp(":first-of-type")) {evals.append(Evaluator.IsFirstOfType())} else if (tq.matchChomp(":last-of-type")) {evals.append(Evaluator.IsLastOfType())} else if (tq.matchChomp(":only-child")) {evals.append(Evaluator.IsOnlyChild())} else if (tq.matchChomp(":only-of-type")) {evals.append(Evaluator.IsOnlyOfType())} else if (tq.matchChomp(":empty")) {evals.append(Evaluator.IsEmpty())} else if (tq.matchChomp(":root")) {evals.append(Evaluator.IsRoot())} else // unhandled
{ {
throw Exception.Error(type: ExceptionType.SelectorParseException, Message:"Could not parse query \(query): unexpected token at \(tq.remainder())") throw Exception.Error(type: ExceptionType.SelectorParseException, Message: "Could not parse query \(query): unexpected token at \(tq.remainder())")
} }
} }
@ -203,7 +203,7 @@ public class QueryParser {
} else if (cq.matchChomp("~=")) { } else if (cq.matchChomp("~=")) {
evals.append( Evaluator.AttributeWithValueMatching(key, Pattern.compile(cq.remainder()))) evals.append( Evaluator.AttributeWithValueMatching(key, Pattern.compile(cq.remainder())))
} else { } else {
throw Exception.Error(type: ExceptionType.SelectorParseException, Message:"Could not parse attribute query '\(query)': unexpected token at '\(cq.remainder())'") throw Exception.Error(type: ExceptionType.SelectorParseException, Message: "Could not parse attribute query '\(query)': unexpected token at '\(cq.remainder())'")
} }
} }
} }
@ -250,7 +250,7 @@ public class QueryParser {
mB.find() mB.find()
b = Int(mB.group()!.replaceFirst(of: "^\\+", with: ""))! b = Int(mB.group()!.replaceFirst(of: "^\\+", with: ""))!
} else { } else {
throw Exception.Error(type: ExceptionType.SelectorParseException, Message:"Could not parse nth-index '\(argS)': unexpected format") throw Exception.Error(type: ExceptionType.SelectorParseException, Message: "Could not parse nth-index '\(argS)': unexpected format")
} }
if (ofType) { if (ofType) {
if (backwards) { if (backwards) {

View File

@ -67,20 +67,20 @@ class StreamReader {
} }
/// Start reading from the beginning of file. /// Start reading from the beginning of file.
func rewind() -> Void { func rewind() {
fileHandle.seek(toFileOffset: 0) fileHandle.seek(toFileOffset: 0)
buffer.count = 0 buffer.count = 0
atEof = false atEof = false
} }
/// Close the underlying file. No reading must be done after calling this method. /// Close the underlying file. No reading must be done after calling this method.
func close() -> Void { func close() {
fileHandle?.closeFile() fileHandle?.closeFile()
fileHandle = nil fileHandle = nil
} }
} }
extension StreamReader : Sequence { extension StreamReader: Sequence {
func makeIterator() -> AnyIterator<String> { func makeIterator() -> AnyIterator<String> {
return AnyIterator { return AnyIterator {
return self.nextLine() return self.nextLine()

View File

@ -18,8 +18,7 @@ extension String {
return String(self[i] as Character) return String(self[i] as Character)
} }
init<S: Sequence>(_ ucs: S)where S.Iterator.Element == UnicodeScalar init<S: Sequence>(_ ucs: S)where S.Iterator.Element == UnicodeScalar {
{
var s = "" var s = ""
s.unicodeScalars.append(contentsOf: ucs) s.unicodeScalars.append(contentsOf: ucs)
self = s self = s
@ -91,7 +90,7 @@ extension String {
} }
static func toHexString(n: Int) -> String { static func toHexString(n: Int) -> String {
return String(format:"%2x", n) return String(format: "%2x", n)
} }
func insert(string: String, ind: Int) -> String { func insert(string: String, ind: Int) -> String {

View File

@ -127,7 +127,7 @@ open class StringBuilder {
*/ */
@discardableResult @discardableResult
open func clear() -> StringBuilder { open func clear() -> StringBuilder {
stringValue = Array(); stringValue = Array()
return self return self
} }
} }

View File

@ -215,7 +215,7 @@ open class StringUtil {
if(base.pathComponents.count == 0 && base.absoluteString.last != "/" && !base.isFileURL) { if(base.pathComponents.count == 0 && base.absoluteString.last != "/" && !base.isFileURL) {
base = base.appendingPathComponent("/", isDirectory: false) base = base.appendingPathComponent("/", isDirectory: false)
} }
let u = URL(string: relUrl, relativeTo : base) let u = URL(string: relUrl, relativeTo: base)
return u return u
} }

View File

@ -242,9 +242,9 @@ open class SwiftSoup {
@see #clean(String, org.jsoup.safety.Whitelist) @see #clean(String, org.jsoup.safety.Whitelist)
*/ */
public static func isValid(_ bodyHtml: String, _ whitelist: Whitelist)throws->Bool { public static func isValid(_ bodyHtml: String, _ whitelist: Whitelist)throws->Bool {
let dirty = try parseBodyFragment(bodyHtml, ""); let dirty = try parseBodyFragment(bodyHtml, "")
let cleaner = Cleaner(whitelist); let cleaner = Cleaner(whitelist)
return try cleaner.isValid(dirty); return try cleaner.isValid(dirty)
} }
} }

View File

@ -215,7 +215,7 @@ open class Tag: Hashable {
let this = lhs let this = lhs
let o = rhs let o = rhs
if (this === o) {return true} if (this === o) {return true}
if (type(of:this) != type(of:o)) {return false} if (type(of: this) != type(of: o)) {return false}
let tag: Tag = o let tag: Tag = o

View File

@ -61,12 +61,10 @@ open class Token {
return name.toString() return name.toString()
} }
func getPubSysKey()->String? { func getPubSysKey() -> String? {
return pubSysKey; return pubSysKey
} }
func getPublicIdentifier() -> String { func getPublicIdentifier() -> String {
return publicIdentifier.toString() return publicIdentifier.toString()
} }
@ -389,9 +387,9 @@ open class Token {
extension Token: CustomDebugStringConvertible { extension Token: CustomDebugStringConvertible {
public var debugDescription: String { public var debugDescription: String {
do{ do {
return try self.toString() return try self.toString()
}catch{ } catch {
return "Error while get string debug" return "Error while get string debug"
} }
} }

View File

@ -18,7 +18,7 @@ final class Tokeniser {
private var state: TokeniserState = TokeniserState.Data // current tokenisation state private var state: TokeniserState = TokeniserState.Data // current tokenisation state
private var emitPending: Token? // the token we are about to emit on next read private var emitPending: Token? // the token we are about to emit on next read
private var isEmitPending: Bool = false private var isEmitPending: Bool = false
private var charsString: String? = nil // characters pending an emit. Will fall to charsBuilder if more than one private var charsString: String? // characters pending an emit. Will fall to charsBuilder if more than one
private let charsBuilder: StringBuilder = StringBuilder(1024) // buffers characters to output as one token, if more than one emit per read private let charsBuilder: StringBuilder = StringBuilder(1024) // buffers characters to output as one token, if more than one emit per read
let dataBuffer: StringBuilder = StringBuilder(1024) // buffers data looking for </script> let dataBuffer: StringBuilder = StringBuilder(1024) // buffers data looking for </script>

View File

@ -620,7 +620,7 @@ enum TokeniserState: TokeniserStateProtocol {
t.eofError(self) t.eofError(self)
t.transition(.Data) t.transition(.Data)
break break
case "\"", "'",UnicodeScalar.LessThan, "=": case "\"", "'", UnicodeScalar.LessThan, "=":
t.error(self) t.error(self)
try t.tagPending.newAttribute() try t.tagPending.newAttribute()
t.tagPending.appendAttributeName(c) t.tagPending.appendAttributeName(c)
@ -1185,7 +1185,7 @@ enum TokeniserState: TokeniserStateProtocol {
t.doctypePending.pubSysKey = DocumentType.PUBLIC_KEY t.doctypePending.pubSysKey = DocumentType.PUBLIC_KEY
t.transition(.AfterDoctypePublicKeyword) t.transition(.AfterDoctypePublicKeyword)
} else if (r.matchConsumeIgnoreCase(DocumentType.SYSTEM_KEY)) { } else if (r.matchConsumeIgnoreCase(DocumentType.SYSTEM_KEY)) {
t.doctypePending.pubSysKey = DocumentType.SYSTEM_KEY; t.doctypePending.pubSysKey = DocumentType.SYSTEM_KEY
t.transition(.AfterDoctypeSystemKeyword) t.transition(.AfterDoctypeSystemKeyword)
} else { } else {
t.error(self) t.error(self)

View File

@ -16,9 +16,9 @@ private let symbolSet = CharacterSet.symbols
private let digitSet = CharacterSet.decimalDigits private let digitSet = CharacterSet.decimalDigits
extension UnicodeScalar { extension UnicodeScalar {
public static let Ampersand : UnicodeScalar = "&" public static let Ampersand: UnicodeScalar = "&"
public static let LessThan : UnicodeScalar = "<" public static let LessThan: UnicodeScalar = "<"
public static let GreaterThan : UnicodeScalar = ">" public static let GreaterThan: UnicodeScalar = ">"
public static let Space: UnicodeScalar = " " public static let Space: UnicodeScalar = " "
public static let BackslashF: UnicodeScalar = UnicodeScalar(12) public static let BackslashF: UnicodeScalar = UnicodeScalar(12)

View File

@ -14,7 +14,7 @@ struct Validate {
* Validates that the object is not null * Validates that the object is not null
* @param obj object to test * @param obj object to test
*/ */
public static func notNull(obj:Any?) throws { public static func notNull(obj: Any?) throws {
if (obj == nil) { if (obj == nil) {
throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "Object must not be null") throw Exception.Error(type: ExceptionType.IllegalArgumentException, Message: "Object must not be null")
} }

View File

@ -209,7 +209,7 @@ public class Whitelist {
*/ */
@discardableResult @discardableResult
open func removeTags(_ tags: String...)throws ->Whitelist { open func removeTags(_ tags: String...)throws ->Whitelist {
try Validate.notNull(obj:tags) try Validate.notNull(obj: tags)
for tag in tags { for tag in tags {
try Validate.notEmpty(string: tag) try Validate.notEmpty(string: tag)

View File

@ -366,6 +366,7 @@
BD3B5BED1FC063BD001FDB3B /* InfotvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = InfotvOS.plist; path = /Users/nabil/Documents/nabil/SwiftSoup/Sources/InfotvOS.plist; sourceTree = "<absolute>"; }; BD3B5BED1FC063BD001FDB3B /* InfotvOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = InfotvOS.plist; path = /Users/nabil/Documents/nabil/SwiftSoup/Sources/InfotvOS.plist; sourceTree = "<absolute>"; };
BD3B5C2F1FC06423001FDB3B /* SwiftSoup.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftSoup.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BD3B5C2F1FC06423001FDB3B /* SwiftSoup.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftSoup.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BD3B5C301FC06424001FDB3B /* InfoWatchOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = InfoWatchOS.plist; path = /Users/nabil/Documents/nabil/SwiftSoup/Sources/InfoWatchOS.plist; sourceTree = "<absolute>"; }; BD3B5C301FC06424001FDB3B /* InfoWatchOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = InfoWatchOS.plist; path = /Users/nabil/Documents/nabil/SwiftSoup/Sources/InfoWatchOS.plist; sourceTree = "<absolute>"; };
BD76883E206D8B6900B7F940 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -522,6 +523,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BD36975B20135EBB00D8FAC6 /* SwiftSoup.podspec */, BD36975B20135EBB00D8FAC6 /* SwiftSoup.podspec */,
BD76883E206D8B6900B7F940 /* CHANGELOG.md */,
8CE418181DAA54A900240B42 /* Sources */, 8CE418181DAA54A900240B42 /* Sources */,
8CE418231DAA54A900240B42 /* Tests */, 8CE418231DAA54A900240B42 /* Tests */,
8CE418171DAA54A900240B42 /* Products */, 8CE418171DAA54A900240B42 /* Products */,
@ -667,6 +669,7 @@
8CE418121DAA54A900240B42 /* Frameworks */, 8CE418121DAA54A900240B42 /* Frameworks */,
8CE418131DAA54A900240B42 /* Headers */, 8CE418131DAA54A900240B42 /* Headers */,
8CE418141DAA54A900240B42 /* Resources */, 8CE418141DAA54A900240B42 /* Resources */,
BD76883F206D9DAC00B7F940 /* ShellScript */,
); );
buildRules = ( buildRules = (
); );
@ -756,7 +759,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0800; LastSwiftUpdateCheck = 0800;
LastUpgradeCheck = 0900; LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Nabil Chatbi"; ORGANIZATIONNAME = "Nabil Chatbi";
TargetAttributes = { TargetAttributes = {
8CE418151DAA54A900240B42 = { 8CE418151DAA54A900240B42 = {
@ -836,6 +839,22 @@
}; };
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
BD76883F206D9DAC00B7F940 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
8CE418111DAA54A900240B42 /* Sources */ = { 8CE418111DAA54A900240B42 /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
@ -1144,6 +1163,7 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES; CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
@ -1151,6 +1171,7 @@
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@ -1206,6 +1227,7 @@
CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES; CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_EMPTY_BODY = YES;
@ -1213,6 +1235,7 @@
CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0900" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
@ -56,7 +55,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0910" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@ -46,7 +45,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0910" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@ -37,7 +36,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0910" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
@ -37,7 +36,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0900" LastUpgradeVersion = "0930"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
<TestableReference <TestableReference
@ -56,7 +55,6 @@
buildConfiguration = "Debug" buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"

View File

@ -31,5 +31,5 @@ XCTMain([
testCase(NodeTest.allTests), testCase(NodeTest.allTests),
testCase(AttributeTest.allTests), testCase(AttributeTest.allTests),
testCase(CleanerTest.allTests), testCase(CleanerTest.allTests),
testCase(StringUtilTest.allTests), testCase(StringUtilTest.allTests)
]) ])

View File

@ -115,7 +115,7 @@ class AttributeParseTest: XCTestCase {
("teststrictAttributeUnescapes", teststrictAttributeUnescapes), ("teststrictAttributeUnescapes", teststrictAttributeUnescapes),
("testmoreAttributeUnescapes", testmoreAttributeUnescapes), ("testmoreAttributeUnescapes", testmoreAttributeUnescapes),
("testparsesBooleanAttributes", testparsesBooleanAttributes), ("testparsesBooleanAttributes", testparsesBooleanAttributes),
("testdropsSlashFromAttributeName", testdropsSlashFromAttributeName), ("testdropsSlashFromAttributeName", testdropsSlashFromAttributeName)
] ]
}() }()

View File

@ -40,21 +40,20 @@ class AttributeTest: XCTestCase {
try a.put("hello", "There") try a.put("hello", "There")
try a.put("data-name", "Jsoup") try a.put("data-name", "Jsoup")
XCTAssertEqual(5, a.size()); XCTAssertEqual(5, a.size())
try a.remove(key: "Tot"); try a.remove(key: "Tot")
try a.remove(key: "Hello"); try a.remove(key: "Hello")
XCTAssertEqual(3, a.size()); XCTAssertEqual(3, a.size())
XCTAssertTrue(a.hasKey(key: "tot")); XCTAssertTrue(a.hasKey(key: "tot"))
XCTAssertFalse(a.hasKey(key: "Tot")); XCTAssertFalse(a.hasKey(key: "Tot"))
} }
static var allTests = { static var allTests = {
return [ return [
("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests), ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
("testHtml", testHtml), ("testHtml", testHtml),
("testWithSupplementaryCharacterInAttributeKeyAndValue", testWithSupplementaryCharacterInAttributeKeyAndValue), ("testWithSupplementaryCharacterInAttributeKeyAndValue", testWithSupplementaryCharacterInAttributeKeyAndValue),
("testRemoveCaseSensitive",testRemoveCaseSensitive) ("testRemoveCaseSensitive", testRemoveCaseSensitive)
] ]
}() }()

View File

@ -20,7 +20,7 @@ class CleanerTest: XCTestCase {
#endif #endif
} }
func testHandlesCustomProtocols()throws{ func testHandlesCustomProtocols()throws {
let html = "<img src='cid:12345' /> <img src='data:gzzt' />" let html = "<img src='cid:12345' /> <img src='data:gzzt' />"
// let dropped = try SwiftSoup.clean(html, Whitelist.basicWithImages()) // let dropped = try SwiftSoup.clean(html, Whitelist.basicWithImages())
// XCTAssertEqual("<img> \n<img>", dropped) // XCTAssertEqual("<img> \n<img>", dropped)
@ -29,7 +29,6 @@ class CleanerTest: XCTestCase {
XCTAssertEqual("<img src=\"cid:12345\"> \n<img src=\"data:gzzt\">", preserved) XCTAssertEqual("<img src=\"cid:12345\"> \n<img src=\"data:gzzt\">", preserved)
} }
func testSimpleBehaviourTest()throws { func testSimpleBehaviourTest()throws {
let h = "<div><p class=foo><a href='http://evil.com'>Hello <b id=bar>there</b>!</a></div>" let h = "<div><p class=foo><a href='http://evil.com'>Hello <b id=bar>there</b>!</a></div>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.simpleText()) let cleanHtml = try SwiftSoup.clean(h, Whitelist.simpleText())
@ -70,14 +69,14 @@ class CleanerTest: XCTestCase {
XCTAssertEqual("<p>Nice</p><blockquote>Hello</blockquote>", TextUtil.stripNewlines(cleanHtml!)) XCTAssertEqual("<p>Nice</p><blockquote>Hello</blockquote>", TextUtil.stripNewlines(cleanHtml!))
} }
func testRemoveAttributes()throws{ func testRemoveAttributes()throws {
let h = "<div><p>Nice</p><blockquote cite='http://example.com/quotations'>Hello</blockquote>" let h = "<div><p>Nice</p><blockquote cite='http://example.com/quotations'>Hello</blockquote>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeAttributes("blockquote", "cite")) let cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeAttributes("blockquote", "cite"))
XCTAssertEqual("<p>Nice</p><blockquote>Hello</blockquote>", TextUtil.stripNewlines(cleanHtml!)) XCTAssertEqual("<p>Nice</p><blockquote>Hello</blockquote>", TextUtil.stripNewlines(cleanHtml!))
} }
func testRemoveEnforcedAttributes()throws{ func testRemoveEnforcedAttributes()throws {
let h = "<div><p><A HREF='HTTP://nice.com'>Nice</a></p><blockquote>Hello</blockquote>" let h = "<div><p><A HREF='HTTP://nice.com'>Nice</a></p><blockquote>Hello</blockquote>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeEnforcedAttribute("a", "rel")) let cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeEnforcedAttribute("a", "rel"))
@ -85,7 +84,7 @@ class CleanerTest: XCTestCase {
TextUtil.stripNewlines(cleanHtml!)) TextUtil.stripNewlines(cleanHtml!))
} }
func testRemoveProtocols()throws{ func testRemoveProtocols()throws {
let h = "<p>Contact me <a href='mailto:info@example.com'>here</a></p>" let h = "<p>Contact me <a href='mailto:info@example.com'>here</a></p>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeProtocols("a", "href", "ftp", "mailto")) let cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeProtocols("a", "href", "ftp", "mailto"))
@ -93,37 +92,37 @@ class CleanerTest: XCTestCase {
TextUtil.stripNewlines(cleanHtml!)) TextUtil.stripNewlines(cleanHtml!))
} }
func testDropComments()throws{ func testDropComments()throws {
let h = "<p>Hello<!-- no --></p>" let h = "<p>Hello<!-- no --></p>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed()) let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<p>Hello</p>", cleanHtml) XCTAssertEqual("<p>Hello</p>", cleanHtml)
} }
func testDropXmlProc()throws{ func testDropXmlProc()throws {
let h = "<?import namespace=\"xss\"><p>Hello</p>" let h = "<?import namespace=\"xss\"><p>Hello</p>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed()) let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<p>Hello</p>", cleanHtml) XCTAssertEqual("<p>Hello</p>", cleanHtml)
} }
func testDropScript()throws{ func testDropScript()throws {
let h = "<SCRIPT SRC=//ha.ckers.org/.j><SCRIPT>alert(/XSS/.source)</SCRIPT>" let h = "<SCRIPT SRC=//ha.ckers.org/.j><SCRIPT>alert(/XSS/.source)</SCRIPT>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed()) let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("", cleanHtml) XCTAssertEqual("", cleanHtml)
} }
func testDropImageScript()throws{ func testDropImageScript()throws {
let h = "<IMG SRC=\"javascript:alert('XSS')\">" let h = "<IMG SRC=\"javascript:alert('XSS')\">"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed()) let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<img>", cleanHtml) XCTAssertEqual("<img>", cleanHtml)
} }
func testCleanJavascriptHref()throws{ func testCleanJavascriptHref()throws {
let h = "<A HREF=\"javascript:document.location='http://www.google.com/'\">XSS</A>" let h = "<A HREF=\"javascript:document.location='http://www.google.com/'\">XSS</A>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed()) let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<a>XSS</a>", cleanHtml) XCTAssertEqual("<a>XSS</a>", cleanHtml)
} }
func testCleanAnchorProtocol()throws{ func testCleanAnchorProtocol()throws {
let validAnchor = "<a href=\"#valid\">Valid anchor</a>" let validAnchor = "<a href=\"#valid\">Valid anchor</a>"
let invalidAnchor = "<a href=\"#anchor with spaces\">Invalid anchor</a>" let invalidAnchor = "<a href=\"#anchor with spaces\">Invalid anchor</a>"
@ -145,19 +144,19 @@ class CleanerTest: XCTestCase {
XCTAssertEqual("<a>Invalid anchor</a>", cleanHtml) XCTAssertEqual("<a>Invalid anchor</a>", cleanHtml)
} }
func testDropsUnknownTags()throws{ func testDropsUnknownTags()throws {
let h = "<p><custom foo=true>Test</custom></p>" let h = "<p><custom foo=true>Test</custom></p>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed()) let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<p>Test</p>", cleanHtml) XCTAssertEqual("<p>Test</p>", cleanHtml)
} }
func testtestHandlesEmptyAttributes()throws{ func testtestHandlesEmptyAttributes()throws {
let h = "<img alt=\"\" src= unknown=''>" let h = "<img alt=\"\" src= unknown=''>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.basicWithImages()) let cleanHtml = try SwiftSoup.clean(h, Whitelist.basicWithImages())
XCTAssertEqual("<img alt=\"\">", cleanHtml) XCTAssertEqual("<img alt=\"\">", cleanHtml)
} }
func testIsValid()throws{ func testIsValid()throws {
let ok = "<p>Test <b><a href='http://example.com/'>OK</a></b></p>" let ok = "<p>Test <b><a href='http://example.com/'>OK</a></b></p>"
let nok1 = "<p><script></script>Not <b>OK</b></p>" let nok1 = "<p><script></script>Not <b>OK</b></p>"
let nok2 = "<p align=right>Test Not <b>OK</b></p>" let nok2 = "<p align=right>Test Not <b>OK</b></p>"
@ -168,27 +167,25 @@ class CleanerTest: XCTestCase {
XCTAssertFalse(try SwiftSoup.isValid(nok3, Whitelist.basic())) XCTAssertFalse(try SwiftSoup.isValid(nok3, Whitelist.basic()))
} }
func testResolvesRelativeLinks()throws{ func testResolvesRelativeLinks()throws {
let html = "<a href='/foo'>Link</a><img src='/bar'>" let html = "<a href='/foo'>Link</a><img src='/bar'>"
let clean = try SwiftSoup.clean(html, "http://example.com/", Whitelist.basicWithImages()) let clean = try SwiftSoup.clean(html, "http://example.com/", Whitelist.basicWithImages())
XCTAssertEqual("<a href=\"http://example.com/foo\" rel=\"nofollow\">Link</a>\n<img src=\"http://example.com/bar\">", clean) XCTAssertEqual("<a href=\"http://example.com/foo\" rel=\"nofollow\">Link</a>\n<img src=\"http://example.com/bar\">", clean)
} }
func testPreservesRelativeLinksIfConfigured()throws{ func testPreservesRelativeLinksIfConfigured()throws {
let html = "<a href='/foo'>Link</a><img src='/bar'> <img src='javascript:alert()'>" let html = "<a href='/foo'>Link</a><img src='/bar'> <img src='javascript:alert()'>"
let clean = try SwiftSoup.clean(html, "http://example.com/", Whitelist.basicWithImages().preserveRelativeLinks(true)) let clean = try SwiftSoup.clean(html, "http://example.com/", Whitelist.basicWithImages().preserveRelativeLinks(true))
XCTAssertEqual("<a href=\"/foo\" rel=\"nofollow\">Link</a>\n<img src=\"/bar\"> \n<img>", clean) XCTAssertEqual("<a href=\"/foo\" rel=\"nofollow\">Link</a>\n<img src=\"/bar\"> \n<img>", clean)
} }
func testDropsUnresolvableRelativeLinks()throws{ func testDropsUnresolvableRelativeLinks()throws {
let html = "<a href='/foo'>Link</a>" let html = "<a href='/foo'>Link</a>"
let clean = try SwiftSoup.clean(html, Whitelist.basic()) let clean = try SwiftSoup.clean(html, Whitelist.basic())
XCTAssertEqual("<a rel=\"nofollow\">Link</a>", clean) XCTAssertEqual("<a rel=\"nofollow\">Link</a>", clean)
} }
func testHandlesAllPseudoTag()throws {
func testHandlesAllPseudoTag()throws{
let html = "<p class='foo' src='bar'><a class='qux'>link</a></p>" let html = "<p class='foo' src='bar'><a class='qux'>link</a></p>"
let whitelist: Whitelist = try Whitelist() let whitelist: Whitelist = try Whitelist()
.addAttributes(":all", "class") .addAttributes(":all", "class")
@ -199,7 +196,7 @@ class CleanerTest: XCTestCase {
XCTAssertEqual("<p class=\"foo\"><a class=\"qux\">link</a></p>", clean) XCTAssertEqual("<p class=\"foo\"><a class=\"qux\">link</a></p>", clean)
} }
func testAddsTagOnAttributesIfNotSet()throws{ func testAddsTagOnAttributesIfNotSet()throws {
let html = "<p class='foo' src='bar'>One</p>" let html = "<p class='foo' src='bar'>One</p>"
let whitelist = try Whitelist() let whitelist = try Whitelist()
.addAttributes("p", "class") .addAttributes("p", "class")
@ -231,7 +228,7 @@ class CleanerTest: XCTestCase {
// XCTAssertEqual("<div><p>&#x212c;</p></div>", customOut2) // XCTAssertEqual("<div><p>&#x212c;</p></div>", customOut2)
// } // }
func testHandlesFramesets()throws{ func testHandlesFramesets()throws {
let dirty = "<html><head><script></script><noscript></noscript></head><frameset><frame src=\"foo\" /><frame src=\"foo\" /></frameset></html>" let dirty = "<html><head><script></script><noscript></noscript></head><frameset><frame src=\"foo\" /><frame src=\"foo\" /></frameset></html>"
let clean = try SwiftSoup.clean(dirty, Whitelist.basic()) let clean = try SwiftSoup.clean(dirty, Whitelist.basic())
XCTAssertEqual("", clean) // nothing good can come out of that XCTAssertEqual("", clean) // nothing good can come out of that
@ -242,12 +239,11 @@ class CleanerTest: XCTestCase {
XCTAssertEqual(0, cleanDoc?.body()?.childNodeSize()) XCTAssertEqual(0, cleanDoc?.body()?.childNodeSize())
} }
func testCleansInternationalText()throws{ func testCleansInternationalText()throws {
XCTAssertEqual("привет", try SwiftSoup.clean("привет", Whitelist.none())) XCTAssertEqual("привет", try SwiftSoup.clean("привет", Whitelist.none()))
} }
func testScriptTagInWhiteList()throws {
func testScriptTagInWhiteList()throws{
let whitelist: Whitelist = try Whitelist.relaxed() let whitelist: Whitelist = try Whitelist.relaxed()
try whitelist.addTags( "script" ) try whitelist.addTags( "script" )
XCTAssertTrue( try SwiftSoup.isValid("Hello<script>alert('Doh')</script>World !", whitelist ) ) XCTAssertTrue( try SwiftSoup.isValid("Hello<script>alert('Doh')</script>World !", whitelist ) )
@ -324,4 +320,3 @@ class CleanerTest: XCTestCase {
}() }()
} }

View File

@ -16,7 +16,7 @@ class CssTest: XCTestCase {
override func setUp() { override func setUp() {
super.setUp() super.setUp()
let sb: StringBuilder = StringBuilder(string:"<html><head></head><body>") let sb: StringBuilder = StringBuilder(string: "<html><head></head><body>")
sb.append("<div id='pseudo'>") sb.append("<div id='pseudo'>")
for i in 1...10 { for i in 1...10 {

View File

@ -442,9 +442,7 @@ class DocumentTest: XCTestCase {
return doc return doc
} }
func testThai() {
func testThai()
{
let str = "บังคับ" let str = "บังคับ"
guard let doc = try? SwiftSoup.parse(str) else { guard let doc = try? SwiftSoup.parse(str) else {
XCTFail() XCTFail()
@ -478,7 +476,7 @@ class DocumentTest: XCTestCase {
// output.contains("&#xa0;") || output.contains("&nbsp;")); // output.contains("&#xa0;") || output.contains("&nbsp;"));
// } // }
func testNewLine(){ func testNewLine() {
let h = "<html><body><div>\r\n<div dir=\"ltr\">\r\n<div id=\"divtagdefaultwrapper\"><font face=\"Calibri,Helvetica,sans-serif\" size=\"3\" color=\"black\"><span style=\"font-size:12pt;\" id=\"divtagdefaultwrapper\">\r\n<div style=\"margin-top:0;margin-bottom:0;\">&nbsp;TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n</span></font></div>\r\n</div>\r\n</div>\r\n</body></html>" let h = "<html><body><div>\r\n<div dir=\"ltr\">\r\n<div id=\"divtagdefaultwrapper\"><font face=\"Calibri,Helvetica,sans-serif\" size=\"3\" color=\"black\"><span style=\"font-size:12pt;\" id=\"divtagdefaultwrapper\">\r\n<div style=\"margin-top:0;margin-bottom:0;\">&nbsp;TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\"><br>\r\n\r\n</div>\r\n<div style=\"margin-top:0;margin-bottom:0;\">TEST</div>\r\n</span></font></div>\r\n</div>\r\n</div>\r\n</body></html>"
let doc: Document = try! SwiftSoup.parse(h) let doc: Document = try! SwiftSoup.parse(h)
@ -514,8 +512,8 @@ class DocumentTest: XCTestCase {
("testMetaCharsetUpdateXmlDisabled", testMetaCharsetUpdateXmlDisabled), ("testMetaCharsetUpdateXmlDisabled", testMetaCharsetUpdateXmlDisabled),
("testMetaCharsetUpdateXmlDisabledNoChanges", testMetaCharsetUpdateXmlDisabledNoChanges), ("testMetaCharsetUpdateXmlDisabledNoChanges", testMetaCharsetUpdateXmlDisabledNoChanges),
("testMetaCharsetUpdatedDisabledPerDefault", testMetaCharsetUpdatedDisabledPerDefault), ("testMetaCharsetUpdatedDisabledPerDefault", testMetaCharsetUpdatedDisabledPerDefault),
("testThai",testThai), ("testThai", testThai),
("testNewLine", testNewLine), ("testNewLine", testNewLine)
] ]
}() }()

View File

@ -55,7 +55,7 @@ class DocumentTypeTest: XCTestCase {
("testConstructorValidationOkWithBlankName", testConstructorValidationOkWithBlankName), ("testConstructorValidationOkWithBlankName", testConstructorValidationOkWithBlankName),
("testConstructorValidationThrowsExceptionOnNulls", testConstructorValidationThrowsExceptionOnNulls), ("testConstructorValidationThrowsExceptionOnNulls", testConstructorValidationThrowsExceptionOnNulls),
("testConstructorValidationOkWithBlankPublicAndSystemIds", testConstructorValidationOkWithBlankPublicAndSystemIds), ("testConstructorValidationOkWithBlankPublicAndSystemIds", testConstructorValidationOkWithBlankPublicAndSystemIds),
("testOuterHtmlGeneration", testOuterHtmlGeneration), ("testOuterHtmlGeneration", testOuterHtmlGeneration)
] ]
}() }()
} }

View File

@ -823,7 +823,7 @@ class ElementTest: XCTestCase {
// Update the class names to a fresh set // Update the class names to a fresh set
let newSet = OrderedSet<String>() let newSet = OrderedSet<String>()
newSet.append(contentsOf:set1) newSet.append(contentsOf: set1)
//newSet["c3"] //todo: nabil not a set , add == append but not change exists c3 //newSet["c3"] //todo: nabil not a set , add == append but not change exists c3
try div.classNames(newSet) try div.classNames(newSet)
@ -946,8 +946,8 @@ class ElementTest: XCTestCase {
.removeAttr("two") .removeAttr("two")
.removeAttr("three") .removeAttr("three")
.removeAttr("four") .removeAttr("four")
.removeAttr("five"); .removeAttr("five")
XCTAssertEqual("<a>Text</a>", try a.outerHtml()); XCTAssertEqual("<a>Text</a>", try a.outerHtml())
} }
func testIs()throws { func testIs()throws {
@ -955,25 +955,23 @@ class ElementTest: XCTestCase {
let doc: Document = try SwiftSoup.parse(html) let doc: Document = try SwiftSoup.parse(html)
let p: Element = try doc.select("p").first()! let p: Element = try doc.select("p").first()!
try XCTAssertTrue(p.iS("p")); try XCTAssertTrue(p.iS("p"))
try XCTAssertFalse(p.iS("div")); try XCTAssertFalse(p.iS("div"))
try XCTAssertTrue(p.iS("p:has(a)")); try XCTAssertTrue(p.iS("p:has(a)"))
try XCTAssertTrue(p.iS("p:first-child")); try XCTAssertTrue(p.iS("p:first-child"))
try XCTAssertFalse(p.iS("p:last-child")); try XCTAssertFalse(p.iS("p:last-child"))
try XCTAssertTrue(p.iS("*")); try XCTAssertTrue(p.iS("*"))
try XCTAssertTrue(p.iS("div p")); try XCTAssertTrue(p.iS("div p"))
let q: Element = try doc.select("p").last()! let q: Element = try doc.select("p").last()!
try XCTAssertTrue(q.iS("p")); try XCTAssertTrue(q.iS("p"))
try XCTAssertTrue(q.iS("p ~ p")); try XCTAssertTrue(q.iS("p ~ p"))
try XCTAssertTrue(q.iS("p + p")); try XCTAssertTrue(q.iS("p + p"))
try XCTAssertTrue(q.iS("p:last-child")); try XCTAssertTrue(q.iS("p:last-child"))
try XCTAssertFalse(q.iS("p a")); try XCTAssertFalse(q.iS("p a"))
try XCTAssertFalse(q.iS("a")); try XCTAssertFalse(q.iS("a"))
} }
static var allTests = { static var allTests = {
return [ return [
("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests), ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
@ -1046,8 +1044,8 @@ class ElementTest: XCTestCase {
("testAppendMustCorrectlyMoveChildrenInsideOneParentElement", testAppendMustCorrectlyMoveChildrenInsideOneParentElement), ("testAppendMustCorrectlyMoveChildrenInsideOneParentElement", testAppendMustCorrectlyMoveChildrenInsideOneParentElement),
("testHashcodeIsStableWithContentChanges", testHashcodeIsStableWithContentChanges), ("testHashcodeIsStableWithContentChanges", testHashcodeIsStableWithContentChanges),
("testNamespacedElements", testNamespacedElements), ("testNamespacedElements", testNamespacedElements),
("testChainedRemoveAttributes",testChainedRemoveAttributes), ("testChainedRemoveAttributes", testChainedRemoveAttributes),
("testIs",testIs) ("testIs", testIs)
] ]
}() }()
} }

View File

@ -148,7 +148,6 @@ class EntitiesTest: XCTestCase {
XCTAssertEqual("<a title=\"&lt;p>One&lt;/p>\">One</a>", try element.outerHtml()) XCTAssertEqual("<a title=\"&lt;p>One&lt;/p>\">One</a>", try element.outerHtml())
} }
static var allTests = { static var allTests = {
return [ return [
("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests), ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),

View File

@ -124,15 +124,14 @@ class StringUtilTest: XCTestCase {
return [ return [
("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests), ("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
("testJoin", testJoin), ("testJoin", testJoin),
("testPadding",testPadding), ("testPadding", testPadding),
("testIsBlank", testIsBlank), ("testIsBlank", testIsBlank),
("testIsNumeric", testIsNumeric), ("testIsNumeric", testIsNumeric),
("testIsWhitespace", testIsWhitespace), ("testIsWhitespace", testIsWhitespace),
("testNormaliseWhiteSpace", testNormaliseWhiteSpace), ("testNormaliseWhiteSpace", testNormaliseWhiteSpace),
("testNormaliseWhiteSpaceHandlesHighSurrogates", testNormaliseWhiteSpaceHandlesHighSurrogates), ("testNormaliseWhiteSpaceHandlesHighSurrogates", testNormaliseWhiteSpaceHandlesHighSurrogates),
("testResolvesRelativeUrls", testResolvesRelativeUrls), ("testResolvesRelativeUrls", testResolvesRelativeUrls)
] ]
}() }()
} }

View File

@ -90,7 +90,7 @@ class TagTest: XCTestCase {
("testPSemantics", testPSemantics), ("testPSemantics", testPSemantics),
("testImgSemantics", testImgSemantics), ("testImgSemantics", testImgSemantics),
("testDefaultSemantics", testDefaultSemantics), ("testDefaultSemantics", testDefaultSemantics),
("testValueOfChecksNotEmpty", testValueOfChecksNotEmpty), ("testValueOfChecksNotEmpty", testValueOfChecksNotEmpty)
] ]
}() }()
} }

View File

@ -187,7 +187,7 @@ class XmlTreeBuilderTest: XCTestCase {
("testCreatesValidProlog", testCreatesValidProlog), ("testCreatesValidProlog", testCreatesValidProlog),
("testPreservesCaseByDefault", testPreservesCaseByDefault), ("testPreservesCaseByDefault", testPreservesCaseByDefault),
("testCanNormalizeCase", testCanNormalizeCase), ("testCanNormalizeCase", testCanNormalizeCase),
("testNilReplaceInQueue",testNilReplaceInQueue) ("testNilReplaceInQueue", testNilReplaceInQueue)
] ]
}() }()