* 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,10 +1,20 @@
# Change Log
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]
## [1.6.3](https://github.com/scinfu/SwiftSoup/tree/1.6.3)
* Add newer tvOS simulators to targeted devices to build with Carthage.
* Add newer watchOS simulators to targeted devices to build with Carthage.
* Add newer watchOS simulators to targeted devices to build with Carthage.

View File

@ -13,7 +13,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
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:.
}
}

View File

@ -12,14 +12,13 @@ class QueryViewControllerCell: UITableViewCell {
@IBOutlet weak var selector: UILabel!
@IBOutlet weak var example: UILabel!
@IBOutlet weak var descriptionLabel: UILabel!
}
}
class QueryViewController: UIViewController {
typealias Item = (selector: String,example: String, description: String)
typealias Item = (selector: String, example: String, description: String)
//example items
let items: [
Item] = [ Item(selector: "*", example: "*", description: "any element"),
@ -36,51 +35,47 @@ 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$=.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: "[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!
override func viewDidLoad() {
super.viewDidLoad()
self.title = ""
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension
}
}
extension QueryViewController: UITableViewDataSource
{
extension QueryViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
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
cell.selector.text = items[indexPath.row].selector
cell.example.text = items[indexPath.row].example
cell.descriptionLabel.text = items[indexPath.row].description
let color1 = UIColor.init(red: 245.0/255, green: 245.0/255, blue: 245.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
return cell
}
}
extension QueryViewController: UITableViewDelegate
{
extension QueryViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// user select an item
completionHandler(items[indexPath.row])

View File

@ -10,43 +10,42 @@ import UIKit
import SwiftSoup
class ViewController: UIViewController {
typealias Item = (text: String, html: String)
@IBOutlet weak var tableView: UITableView!
@IBOutlet var urlTextField: UITextField!
@IBOutlet var cssTextField: UITextField!
// current document
var document: Document = Document.init("")
// item founds
var items: [Item] = []
override func viewDidLoad() {
super.viewDidLoad()
self.title = "SwiftSoup Example"
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension
urlTextField.text = "http://www.facebook.com"
cssTextField.text = "div"
// start first request
downloadHTML()
}
//Download HTML
func downloadHTML(){
func downloadHTML() {
// url string to URL
guard let url = URL(string: urlTextField.text ?? "") else {
// an error occurred
UIAlertController.showAlert("Error: \(urlTextField.text ?? "") doesn't seem to be a valid URL", self)
return
}
do {
// content of url
let html = try String.init(contentsOf: url)
@ -58,32 +57,32 @@ class ViewController: UIViewController {
// an error occurred
UIAlertController.showAlert("Error: \(error)", self)
}
}
//Parse CSS selector
func parse(){
func parse() {
do {
//empty old items
items = []
// firn css selector
let elements: Elements = try document.select(cssTextField.text ?? "")
//transform it into a local object (Item)
for element in elements{
for element in elements {
let text = try element.text()
let html = try element.outerHtml()
items.append(Item(text: text, html: html))
}
} catch let error {
UIAlertController.showAlert("Error: \(error)", self)
}
tableView.reloadData()
}
@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
}
vc.completionHandler = {[weak self](resilt) in
@ -93,78 +92,67 @@ class ViewController: UIViewController {
}
self.show(vc, sender: self)
}
}
extension ViewController: UITableViewDataSource
{
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
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")
if cell == nil {
cell = UITableViewCell.init(style: UITableViewCellStyle.subtitle , reuseIdentifier: "cell")
cell = UITableViewCell.init(style: UITableViewCellStyle.subtitle, reuseIdentifier: "cell")
cell?.textLabel?.numberOfLines = 2
cell?.detailTextLabel?.numberOfLines = 6
cell?.textLabel?.textColor = UIColor.init(red: 1.0/255, green: 174.0/255, blue: 66.0/255, alpha: 1)
cell?.detailTextLabel?.textColor = UIColor.init(red: 55.0/255, green: 67.0/255, blue: 55.0/255, alpha: 1)
cell?.backgroundColor = UIColor.init(red: 245.0/255, green: 245.0/255, blue: 245.0/255, alpha: 1)
}
cell?.textLabel?.text = items[indexPath.row].text
cell?.detailTextLabel?.text = items[indexPath.row].html
let color1 = UIColor.init(red: 245.0/255, green: 245.0/255, blue: 245.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
return cell!
}
}
extension ViewController: UITableViewDelegate
{
extension ViewController: UITableViewDelegate {
}
extension ViewController: UITextFieldDelegate
{
public func textFieldShouldReturn(_ textField: UITextField) -> Bool{
extension ViewController: UITextFieldDelegate {
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return false
}
public func textFieldDidEndEditing(_ textField: UITextField) {
if textField == urlTextField {
downloadHTML()
}
if textField == cssTextField {
parse()
}
}
}
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)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
controller.present(alert, animated: true, completion: nil)
}
}

View File

@ -5,10 +5,10 @@ import PackageDescription
let package = Package(
name: "SwiftSoup",
products: [
.library(name: "SwiftSoup", targets: ["SwiftSoup"]),
.library(name: "SwiftSoup", targets: ["SwiftSoup"])
],
targets: [
.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 {
return lhs.value == rhs.value && lhs.key == rhs.key
}

View File

@ -38,7 +38,7 @@ open class Attributes: NSCopying {
@see #hasKey(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() : ""
}
@ -86,7 +86,7 @@ open class Attributes: NSCopying {
@param 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> {
var list = attributes.orderedValues
return AnyIterator {

View File

@ -21,10 +21,10 @@ extension Character {
public static let MIN_SUPPLEMENTARY_CODE_POINT: UInt32 = 0x010000
/// True for any space character, and the control characters \t, \n, \r, \f, \v.
var isWhitespace: Bool {
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
default: return false

View File

@ -169,7 +169,7 @@ public final class CharacterReader {
let val = input
while (pos < remaining) {
if chars.contains(val[pos]) {
break
}

View File

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

View File

@ -41,7 +41,7 @@ private final class Accumulator: NodeVisitor {
self.elements = elements
self.eval = eval
}
open func head(_ node: Node, _ depth: Int) {
guard let el = node as? Element else {
return

View File

@ -26,7 +26,7 @@ public class CombiningEvaluator: Evaluator {
super.init()
updateNumEvaluators()
}
public init(_ evaluators: Evaluator...) {
self.evaluators = evaluators
super.init()

View File

@ -13,7 +13,7 @@ import Foundation
*/
public class DocumentType: Node {
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 PUB_SYS_KEY: String = "pubSysKey"; // PUBLIC or SYSTEM
private static let PUBLIC_ID: String = "publicId"
@ -30,15 +30,15 @@ public class DocumentType: Node {
public init(_ name: String, _ publicId: String, _ systemId: String, _ baseUri: String) {
super.init(baseUri)
do {
try attr(DocumentType.NAME, name);
try attr(DocumentType.PUBLIC_ID, publicId);
try attr(DocumentType.NAME, name)
try attr(DocumentType.PUBLIC_ID, publicId)
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 {}
}
/**
* Create a new doctype element.
* @param name the doctype's name
@ -50,17 +50,13 @@ public class DocumentType: Node {
super.init(baseUri)
do {
try attr(DocumentType.NAME, name)
if(pubSysKey != nil){
if(pubSysKey != nil) {
try attr(DocumentType.PUB_SYS_KEY, pubSysKey!)
}
try attr(DocumentType.PUBLIC_ID, publicId);
try attr(DocumentType.SYSTEM_ID, systemId);
try attr(DocumentType.PUBLIC_ID, publicId)
try attr(DocumentType.SYSTEM_ID, systemId)
} catch {}
}
public override func nodeName() -> String {
return "#doctype"
@ -79,16 +75,16 @@ public class DocumentType: Node {
} catch {}
}
if (has(DocumentType.PUB_SYS_KEY)){
if (has(DocumentType.PUB_SYS_KEY)) {
do {
try accum.append(" ").append(attr(DocumentType.PUB_SYS_KEY))
} catch {}
}
if (has(DocumentType.PUBLIC_ID)) {
do {
try accum.append(" \"").append(attr(DocumentType.PUBLIC_ID)).append("\"");
try accum.append(" \"").append(attr(DocumentType.PUBLIC_ID)).append("\"")
} catch {}
}

View File

@ -10,12 +10,12 @@ import Foundation
open class Element: Node {
var _tag: Tag
private static let classString = "class"
private static let emptyString = ""
private static let idString = "id"
private static let rootString = "#root"
//private static let classSplit : Pattern = Pattern("\\s+")
private static let classSplit = "\\s+"
@ -276,16 +276,16 @@ open class Element: Node {
public func select(_ cssQuery: String)throws->Elements {
return try Selector.select(cssQuery, self)
}
/**
* Check if this element matches the given {@link Selector} CSS query.
* @param cssQuery a {@link Selector} CSS query
* @return if this element matches the query
*/
public func iS(_ cssQuery: String)throws->Bool {
return try iS(QueryParser.parse(cssQuery));
return try iS(QueryParser.parse(cssQuery))
}
/**
* Check if this element matches the given {@link Selector} CSS query.
* @param cssQuery a {@link Selector} CSS query
@ -293,15 +293,11 @@ open class Element: Node {
*/
public func iS(_ evaluator: Evaluator)throws->Bool {
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.
*
@ -512,7 +508,7 @@ open class Element: Node {
if (elementId.count > 0) {
return "#" + elementId
}
// Translate HTML namespace ns:tag to CSS namespace syntax ns|tag
let tagName: String = self.tagName().replacingOccurrences(of: ":", with: "|")
var selector: String = tagName
@ -522,17 +518,17 @@ open class Element: Node {
selector.append(".")
selector.append(classes)
}
if (parent() == nil || ((parent() as? Document) != nil)) // don't add Document to selector, as will always have a html node
{
return selector
}
selector.insert(contentsOf: " > ", at: selector.startIndex)
if (try parent()!.select(selector).array().count > 1) {
selector.append(":nth-child(\(try elementSiblingIndex() + 1))")
}
return try parent()!.cssSelector() + (selector)
}
@ -1065,9 +1061,9 @@ open class Element: Node {
* @return set of classnames, empty if no class attribute
*/
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 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
return classNames
}

View File

@ -459,14 +459,14 @@ open class Elements: NSCopying {
* @return true if at least one element in the list matches the query.
*/
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 {
if (try e.iS(eval)){
return true;
if (try e.iS(eval)) {
return true
}
}
return false;
return false
}
/**
@ -591,16 +591,16 @@ public struct ElementsIterator: IteratorProtocol {
let elements: Elements
//current element index
var index = 0
/// Initializer
init(_ countdown: Elements) {
self.elements = countdown
}
/// Advances to the next element and returns it, or `nil` if no next element
mutating public func next() -> Element? {
let result = index < elements.size() ? elements.get(index) : nil
index += 1;
index += 1
return result
}
}
@ -614,6 +614,3 @@ extension Elements: Sequence {
return ElementsIterator(self)
}
}

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@ -153,7 +153,7 @@ enum HtmlTreeBuilderState: String, HtmlTreeBuilderStateProtocol {
// todo: charset switches
} else if (name.equals("title")) {
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)
} else if (name.equals("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"))! {
tb.pop()
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)
} else {
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
*/
open func nextSibling() -> Node? {
guard let siblings: Array<Node> = parentNode?.childNodes else{
guard let siblings: Array<Node> = parentNode?.childNodes else {
return nil
}
@ -708,7 +708,7 @@ open class Node: Equatable, Hashable {
let currParent: Node = nodesToProcess.removeFirst()
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
nodesToProcess.append(childClone)
}
@ -778,7 +778,7 @@ open class Node: Equatable, Hashable {
}
extension Node : CustomStringConvertible {
extension Node: CustomStringConvertible {
public var description: String {
do {
return try outerHtml()
@ -789,7 +789,7 @@ extension Node : CustomStringConvertible {
}
}
extension Node : CustomDebugStringConvertible {
extension Node: CustomDebugStringConvertible {
private static let space = " "
public var debugDescription: String {
do {

View File

@ -74,7 +74,7 @@ public class OrderedDictionary<Key: Hashable, Value: Equatable>: MutableCollecti
}
public var orderedValues: [Value] {
return _orderedKeys.flatMap { _keysToValues[$0] }
return _orderedKeys.compactMap { _keysToValues[$0] }
}
// ======================================================= //
@ -117,7 +117,7 @@ public class OrderedDictionary<Key: Hashable, Value: Equatable>: MutableCollecti
@discardableResult
private func updateValue(value: Value, forKey key: Key) -> Value? {
guard let currentValue = _keysToValues[key] else {
_orderedKeys.append(key)
_keysToValues[key] = value
@ -125,7 +125,7 @@ public class OrderedDictionary<Key: Hashable, Value: Equatable>: MutableCollecti
}
_keysToValues[key] = value
return currentValue
// if _orderedKeys.contains(key) {
// guard let currentValue = _keysToValues[key] else {
// fatalError("Inconsistency error occured in OrderedDictionary")
@ -148,7 +148,7 @@ public class OrderedDictionary<Key: Hashable, Value: Equatable>: MutableCollecti
public func putAll(all: OrderedDictionary<Key, Value>) {
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
public func remove(key: Key) -> Value? {
return removeValueForKey(key:key)
return removeValueForKey(key: key)
}
public func removeAll(keepCapacity: Bool = true) {
@ -391,28 +391,26 @@ extension OrderedDictionary: Equatable {
// return lhs._orderedKeys == rhs._orderedKeys && lhs._keysToValues == rhs._keysToValues
//}
/**
* Elements IteratorProtocol.
*/
public struct OrderedDictionaryIterator<Key: Hashable, Value: Equatable>: IteratorProtocol {
/// Elements reference
let orderedDictionary: OrderedDictionary<Key, Value>
//current element index
var index = 0
/// Initializer
init(_ od: OrderedDictionary<Key, Value>) {
self.orderedDictionary = od
}
/// Advances to the next element and returns it, or `nil` if no next element
mutating public func next() -> Value? {
let result = index < orderedDictionary.orderedKeys.count ? orderedDictionary[orderedDictionary.orderedKeys[index]] : nil
index += 1;
index += 1
return result
}
}
@ -422,13 +420,7 @@ public struct OrderedDictionaryIterator<Key: Hashable, Value: Equatable>: Iterat
*/
extension OrderedDictionary: Sequence {
/// Returns an iterator over the elements of this sequence.
func generate()->OrderedDictionaryIterator<Key, Value>
{
func generate()->OrderedDictionaryIterator<Key, Value> {
return OrderedDictionaryIterator(self)
}
}

View File

@ -107,7 +107,7 @@ public class OrderedSet<T: Hashable> {
public func remove(_ object: T) {
if let index = contents[object] {
contents[object] = nil
sequencedContents[index].deallocate(capacity: 1)
sequencedContents[index].deallocate()
sequencedContents.remove(at: index)
for (object, i) in contents {
@ -151,7 +151,7 @@ public class OrderedSet<T: Hashable> {
contents.removeAll()
for sequencedContent in sequencedContents {
sequencedContent.deallocate(capacity: 1)
sequencedContent.deallocate()
}
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)
//var nodes: [Node] = nodeList.toArray(Node[nodeList.size()]) // the node list gets modified when re-parented
if nodeList.count > 0 {
for i in 1..<nodeList.count{
for i in 1..<nodeList.count {
try nodeList[i].remove()
}
}

View File

@ -24,14 +24,14 @@ public struct Pattern {
}
func validate()throws {
_ = try NSRegularExpression(pattern: self.pattern, options:[])
_ = try NSRegularExpression(pattern: self.pattern, options: [])
}
func matcher(in text: String) -> Matcher {
do {
let regex = try NSRegularExpression(pattern: self.pattern, options:[])
let regex = try NSRegularExpression(pattern: self.pattern, options: [])
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)
} catch let error {
@ -73,7 +73,7 @@ public class Matcher {
#else
let c = b.range(at: i)
#endif
if(c.location == NSNotFound) {return nil}
let result = string.substring(c.location, c.length)
return result

View File

@ -140,7 +140,7 @@ public class QueryParser {
} 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
{
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("~=")) {
evals.append( Evaluator.AttributeWithValueMatching(key, Pattern.compile(cq.remainder())))
} 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()
b = Int(mB.group()!.replaceFirst(of: "^\\+", with: ""))!
} 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 (backwards) {

View File

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

View File

@ -17,9 +17,8 @@ extension String {
subscript (i: Int) -> String {
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 = ""
s.unicodeScalars.append(contentsOf: ucs)
self = s
@ -91,7 +90,7 @@ extension String {
}
static func toHexString(n: Int) -> String {
return String(format:"%2x", n)
return String(format: "%2x", n)
}
func insert(string: String, ind: Int) -> String {

View File

@ -4,7 +4,7 @@
*/
open class StringBuilder {
fileprivate var stringValue: Array<Character>
/**
Construct with initial String contents
@ -13,11 +13,11 @@ open class StringBuilder {
public init(string: String = "") {
self.stringValue = Array(string)
}
public init(_ size: Int) {
self.stringValue = Array()
}
/**
Return the String object
@ -26,7 +26,7 @@ open class StringBuilder {
open func toString() -> String {
return String(stringValue)
}
/**
Return the current length of the String object
*/
@ -34,7 +34,7 @@ open class StringBuilder {
return self.stringValue.count
//return countElements(stringValue)
}
/**
Append a String to the object
@ -45,29 +45,29 @@ open class StringBuilder {
open func append(_ string: String) {
stringValue.append(contentsOf: string)
}
open func appendCodePoint(_ chr: Character) {
stringValue.append(chr)
}
open func appendCodePoints(_ chr: [Character]) {
stringValue.append(contentsOf: chr)
}
open func appendCodePoint(_ ch: Int) {
stringValue.append(Character(UnicodeScalar(ch)!))
}
open func appendCodePoint(_ ch: UnicodeScalar) {
stringValue.append(Character(ch))
}
open func appendCodePoints(_ chr: [UnicodeScalar]) {
for c in chr {
appendCodePoint(c)
}
}
/**
Append a Printable to the object
@ -80,19 +80,19 @@ open class StringBuilder {
stringValue.append(contentsOf: value.description)
return self
}
@discardableResult
open func append(_ value: UnicodeScalar) -> StringBuilder {
stringValue.append(contentsOf: value.description)
return self
}
@discardableResult
open func insert<T: CustomStringConvertible>(_ offset: Int, _ value: T) -> StringBuilder {
stringValue.insert(contentsOf: value.description, at: offset)
return self
}
/**
Append a String and a newline to the object
@ -105,7 +105,7 @@ open class StringBuilder {
stringValue.append(contentsOf: "\n")
return self
}
/**
Append a Printable and a newline to the object
@ -119,7 +119,7 @@ open class StringBuilder {
stringValue.append(contentsOf: "\n")
return self
}
/**
Reset the object to an empty string
@ -127,7 +127,7 @@ open class StringBuilder {
*/
@discardableResult
open func clear() -> StringBuilder {
stringValue = Array();
stringValue = Array()
return self
}
}

View File

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

View File

@ -232,7 +232,7 @@ open class SwiftSoup {
clean.outputSettings(outputSettings)
return try clean.body()?.html()
}
/**
Test if the input HTML has only tags and attributes allowed by the Whitelist. Useful for form validation. The input HTML should
still be run through the cleaner to set up enforced attributes, and to tidy the output.
@ -242,9 +242,9 @@ open class SwiftSoup {
@see #clean(String, org.jsoup.safety.Whitelist)
*/
public static func isValid(_ bodyHtml: String, _ whitelist: Whitelist)throws->Bool {
let dirty = try parseBodyFragment(bodyHtml, "");
let cleaner = Cleaner(whitelist);
return try cleaner.isValid(dirty);
let dirty = try parseBodyFragment(bodyHtml, "")
let cleaner = Cleaner(whitelist)
return try cleaner.isValid(dirty)
}
}

View File

@ -215,7 +215,7 @@ open class Tag: Hashable {
let this = lhs
let o = rhs
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

View File

@ -60,13 +60,11 @@ open class Token {
func getName() -> String {
return name.toString()
}
func getPubSysKey()->String? {
return pubSysKey;
}
func getPubSysKey() -> String? {
return pubSysKey
}
func getPublicIdentifier() -> String {
return publicIdentifier.toString()
}
@ -389,9 +387,9 @@ open class Token {
extension Token: CustomDebugStringConvertible {
public var debugDescription: String {
do{
do {
return try self.toString()
}catch{
} catch {
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 emitPending: Token? // the token we are about to emit on next read
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
let dataBuffer: StringBuilder = StringBuilder(1024) // buffers data looking for </script>

View File

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

View File

@ -16,17 +16,17 @@ private let symbolSet = CharacterSet.symbols
private let digitSet = CharacterSet.decimalDigits
extension UnicodeScalar {
public static let Ampersand : UnicodeScalar = "&"
public static let LessThan : UnicodeScalar = "<"
public static let GreaterThan : UnicodeScalar = ">"
public static let Ampersand: UnicodeScalar = "&"
public static let LessThan: UnicodeScalar = "<"
public static let GreaterThan: UnicodeScalar = ">"
public static let Space: UnicodeScalar = " "
public static let BackslashF: UnicodeScalar = UnicodeScalar(12)
public static let BackslashT: UnicodeScalar = "\t"
public static let BackslashN: UnicodeScalar = "\n"
public static let BackslashR: UnicodeScalar = "\r"
public static let Slash: UnicodeScalar = "/"
public static let FormFeed: UnicodeScalar = "\u{000B}"// Form Feed
public static let VerticalTab: UnicodeScalar = "\u{000C}"// vertical tab

View File

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

View File

@ -63,7 +63,7 @@ public class Whitelist {
private var enforcedAttributes: Dictionary<TagName, Dictionary<AttributeKey, AttributeValue>> // always set these attribute values
private var protocols: Dictionary<TagName, Dictionary<AttributeKey, Set<Protocol>>> // allowed URL protocols for attributes
private var preserveRelativeLinks: Bool // option to preserve relative links
/**
This whitelist allows only text nodes: all HTML will be stripped.
@ -72,7 +72,7 @@ public class Whitelist {
public static func none() -> Whitelist {
return Whitelist()
}
/**
This whitelist allows only simple text formatting: <code>b, em, i, strong, u</code>. All other HTML (tags and
attributes) will be removed.
@ -82,7 +82,7 @@ public class Whitelist {
public static func simpleText()throws ->Whitelist {
return try Whitelist().addTags("b", "em", "i", "strong", "u")
}
/**
<p>
This whitelist allows a fuller range of text nodes: <code>a, b, blockquote, br, cite, code, dd, dl, dt, em, i, li,
@ -104,18 +104,18 @@ public class Whitelist {
"a", "b", "blockquote", "br", "cite", "code", "dd", "dl", "dt", "em",
"i", "li", "ol", "p", "pre", "q", "small", "span", "strike", "strong", "sub",
"sup", "u", "ul")
.addAttributes("a", "href")
.addAttributes("blockquote", "cite")
.addAttributes("q", "cite")
.addProtocols("a", "href", "ftp", "http", "https", "mailto")
.addProtocols("blockquote", "cite", "http", "https")
.addProtocols("cite", "cite", "http", "https")
.addEnforcedAttribute("a", "rel", "nofollow")
}
/**
This whitelist allows the same text tags as {@link #basic}, and also allows <code>img</code> tags, with appropriate
attributes, with <code>src</code> pointing to <code>http</code> or <code>https</code>.
@ -127,9 +127,9 @@ public class Whitelist {
.addTags("img")
.addAttributes("img", "align", "alt", "height", "src", "title", "width")
.addProtocols("img", "src", "http", "https")
}
/**
This whitelist allows a full range of text and structural body HTML: <code>a, b, blockquote, br, caption, cite,
code, col, colgroup, dd, div, dl, dt, em, h1, h2, h3, h4, h5, h6, i, img, li, ol, p, pre, q, small, span, strike, strong, sub,
@ -148,7 +148,7 @@ public class Whitelist {
"i", "img", "li", "ol", "p", "pre", "q", "small", "span", "strike", "strong",
"sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "u",
"ul")
.addAttributes("a", "href", "title")
.addAttributes("blockquote", "cite")
.addAttributes("col", "span", "width")
@ -162,14 +162,14 @@ public class Whitelist {
"th", "abbr", "axis", "colspan", "rowspan", "scope",
"width")
.addAttributes("ul", "type")
.addProtocols("a", "href", "ftp", "http", "https", "mailto")
.addProtocols("blockquote", "cite", "http", "https")
.addProtocols("cite", "cite", "http", "https")
.addProtocols("img", "src", "http", "https")
.addProtocols("q", "cite", "http", "https")
}
/**
Create a new, empty whitelist. Generally it will be better to start with a default prepared whitelist instead.
@ -185,7 +185,7 @@ public class Whitelist {
protocols = Dictionary<TagName, Dictionary<AttributeKey, Set<Protocol>>>()
preserveRelativeLinks = false
}
/**
Add a list of allowed elements to a whitelist. (If a tag is not allowed, it will be removed from the HTML.)
@ -200,7 +200,7 @@ public class Whitelist {
}
return self
}
/**
Remove a list of allowed elements from a whitelist. (If a tag is not allowed, it will be removed from the HTML.)
@ -209,12 +209,12 @@ public class Whitelist {
*/
@discardableResult
open func removeTags(_ tags: String...)throws ->Whitelist {
try Validate.notNull(obj:tags)
try Validate.notNull(obj: tags)
for tag in tags {
try Validate.notEmpty(string: tag)
let tagName: TagName = TagName.valueOf(tag)
if(tagNames.contains(tagName)) { // Only look in sub-maps if tag was allowed
tagNames.remove(tagName)
attributes.removeValue(forKey: tagName)
@ -224,7 +224,7 @@ public class Whitelist {
}
return self
}
/**
Add a list of allowed attributes to a tag. (If an attribute is not allowed on an element, it will be removed.)
<p>
@ -244,7 +244,7 @@ public class Whitelist {
open func addAttributes(_ tag: String, _ keys: String...)throws->Whitelist {
try Validate.notEmpty(string: tag)
try Validate.isTrue(val: keys.count > 0, msg: "No attributes supplied.")
let tagName = TagName.valueOf(tag)
if (!tagNames.contains(tagName)) {
tagNames.insert(tagName)
@ -254,7 +254,7 @@ public class Whitelist {
try Validate.notEmpty(string: key)
attributeSet.insert(AttributeKey.valueOf(key))
}
if var currentSet = attributes[tagName] {
for at in attributeSet {
currentSet.insert(at)
@ -263,10 +263,10 @@ public class Whitelist {
} else {
attributes[tagName] = attributeSet
}
return self
}
/**
Remove a list of allowed attributes from a tag. (If an attribute is not allowed on an element, it will be removed.)
<p>
@ -286,14 +286,14 @@ public class Whitelist {
open func removeAttributes(_ tag: String, _ keys: String...)throws->Whitelist {
try Validate.notEmpty(string: tag)
try Validate.isTrue(val: keys.count > 0, msg: "No attributes supplied.")
let tagName: TagName = TagName.valueOf(tag)
var attributeSet = Set<AttributeKey>()
for key in keys {
try Validate.notEmpty(string: key)
attributeSet.insert(AttributeKey.valueOf(key))
}
if(tagNames.contains(tagName)) { // Only look in sub-maps if tag was allowed
if var currentSet = attributes[tagName] {
for l in attributeSet {
@ -304,9 +304,9 @@ public class Whitelist {
attributes.removeValue(forKey: tagName)
}
}
}
if(tag == ":all") { // Attribute needs to be removed from all individually set tags
for name in attributes.keys {
var currentSet: Set<AttributeKey> = attributes[name]!
@ -321,7 +321,7 @@ public class Whitelist {
}
return self
}
/**
Add an enforced attribute to a tag. An enforced attribute will always be added to the element. If the element
already has the attribute set, it will be overridden.
@ -340,14 +340,14 @@ public class Whitelist {
try Validate.notEmpty(string: tag)
try Validate.notEmpty(string: key)
try Validate.notEmpty(string: value)
let tagName: TagName = TagName.valueOf(tag)
if (!tagNames.contains(tagName)) {
tagNames.insert(tagName)
}
let attrKey: AttributeKey = AttributeKey.valueOf(key)
let attrVal: AttributeValue = AttributeValue.valueOf(value)
if (enforcedAttributes[tagName] != nil) {
enforcedAttributes[tagName]?[attrKey] = attrVal
} else {
@ -357,7 +357,7 @@ public class Whitelist {
}
return self
}
/**
Remove a previously configured enforced attribute from a tag.
@ -369,21 +369,21 @@ public class Whitelist {
open func removeEnforcedAttribute(_ tag: String, _ key: String)throws->Whitelist {
try Validate.notEmpty(string: tag)
try Validate.notEmpty(string: key)
let tagName: TagName = TagName.valueOf(tag)
if(tagNames.contains(tagName) && (enforcedAttributes[tagName] != nil)) {
let attrKey: AttributeKey = AttributeKey.valueOf(key)
var attrMap: Dictionary<AttributeKey, AttributeValue> = enforcedAttributes[tagName]!
attrMap.removeValue(forKey: attrKey)
enforcedAttributes[tagName] = attrMap
if(attrMap.isEmpty) { // Remove tag from enforced attribute map if no enforced attributes are present
enforcedAttributes.removeValue(forKey: tagName)
}
}
return self
}
/**
* Configure this Whitelist to preserve relative links in an element's URL attribute, or convert them to absolute
* links. By default, this is <b>false</b>: URLs will be made absolute (e.g. start with an allowed protocol, like
@ -404,7 +404,7 @@ public class Whitelist {
preserveRelativeLinks = preserve
return self
}
/**
Add allowed URL protocols for an element's URL attribute. This restricts the possible values of the attribute to
URLs with the defined protocol.
@ -425,19 +425,19 @@ public class Whitelist {
open func addProtocols(_ tag: String, _ key: String, _ protocols: String...)throws->Whitelist {
try Validate.notEmpty(string: tag)
try Validate.notEmpty(string: key)
let tagName: TagName = TagName.valueOf(tag)
let attrKey: AttributeKey = AttributeKey.valueOf(key)
var attrMap: Dictionary<AttributeKey, Set<Protocol>>
var protSet: Set<Protocol>
if (self.protocols[tagName] != nil) {
attrMap = self.protocols[tagName]!
} else {
attrMap = Dictionary<AttributeKey, Set<Protocol>>()
self.protocols[tagName] = attrMap
}
if (attrMap[attrKey] != nil) {
protSet = attrMap[attrKey]!
} else {
@ -452,10 +452,10 @@ public class Whitelist {
}
attrMap[attrKey] = protSet
self.protocols[tagName] = attrMap
return self
}
/**
Remove allowed URL protocols for an element's URL attribute.
<p>
@ -471,10 +471,10 @@ public class Whitelist {
open func removeProtocols(_ tag: String, _ key: String, _ protocols: String...)throws->Whitelist {
try Validate.notEmpty(string: tag)
try Validate.notEmpty(string: key)
let tagName: TagName = TagName.valueOf(tag)
let attrKey: AttributeKey = AttributeKey.valueOf(key)
if(self.protocols[tagName] != nil) {
var attrMap: Dictionary<AttributeKey, Set<Protocol>> = self.protocols[tagName]!
if(attrMap[attrKey] != nil) {
@ -485,20 +485,20 @@ public class Whitelist {
protSet.remove(prot)
}
attrMap[attrKey] = protSet
if(protSet.isEmpty) { // Remove protocol set if empty
attrMap.removeValue(forKey: attrKey)
if(attrMap.isEmpty) { // Remove entry for tag if empty
self.protocols.removeValue(forKey: tagName)
}
}
}
self.protocols[tagName] = attrMap
}
return self
}
/**
* Test if the supplied tag is allowed by this whitelist
* @param tag test tag
@ -507,7 +507,7 @@ public class Whitelist {
public func isSafeTag(_ tag: String) -> Bool {
return tagNames.contains(TagName.valueOf(tag))
}
/**
* Test if the supplied attribute is allowed by this whitelist for this tag
* @param tagName tag to consider allowing the attribute in
@ -518,7 +518,7 @@ public class Whitelist {
public func isSafeAttribute(_ tagName: String, _ el: Element, _ attr: Attribute)throws -> Bool {
let tag: TagName = TagName.valueOf(tagName)
let key: AttributeKey = AttributeKey.valueOf(attr.getKey())
if (attributes[tag] != nil) {
if (attributes[tag]?.contains(key))! {
if (protocols[tag] != nil) {
@ -533,7 +533,7 @@ public class Whitelist {
// no attributes defined for tag, try :all tag
return try !(tagName == ":all") && isSafeAttribute(":all", el, attr)
}
private func testValidProtocol(_ el: Element, _ attr: Attribute, _ protocols: Set<Protocol>)throws->Bool {
// try to resolve relative urls to abs, and optionally update the attribute so output html has abs.
// rels without a baseuri get removed
@ -544,10 +544,10 @@ public class Whitelist {
if (!preserveRelativeLinks) {
attr.setValue(value: value)
}
for ptl in protocols {
var prot: String = ptl.toString()
if (prot=="#") { // allows anchor links
if (isValidAnchor(value)) {
return true
@ -555,22 +555,22 @@ public class Whitelist {
continue
}
}
prot += ":"
if (value.lowercased().hasPrefix(prot)) {
return true
}
}
return false
}
private func isValidAnchor(_ value: String) -> Bool {
return value.startsWith("#") && !(Pattern(".*\\s.*").matcher(in: value).count > 0)
}
public func getEnforcedAttributes(_ tagName: String)throws->Attributes {
let attrs: Attributes = Attributes()
let tag: TagName = TagName.valueOf(tagName)
@ -581,7 +581,7 @@ public class Whitelist {
}
return attrs
}
}
// named types for config. All just hold strings, but here for my sanity.
@ -590,7 +590,7 @@ open class TagName: TypedValue {
override init(_ value: String) {
super.init(value)
}
static func valueOf(_ value: String) -> TagName {
return TagName(value)
}
@ -600,7 +600,7 @@ open class AttributeKey: TypedValue {
override init(_ value: String) {
super.init(value)
}
static func valueOf(_ value: String) -> AttributeKey {
return AttributeKey(value)
}
@ -610,7 +610,7 @@ open class AttributeValue: TypedValue {
override init(_ value: String) {
super.init(value)
}
static func valueOf(_ value: String) -> AttributeValue {
return AttributeValue(value)
}
@ -620,7 +620,7 @@ open class Protocol: TypedValue {
override init(_ value: String) {
super.init(value)
}
static func valueOf(_ value: String) -> Protocol {
return Protocol(value)
}
@ -628,11 +628,11 @@ open class Protocol: TypedValue {
open class TypedValue {
fileprivate let value: String
init(_ value: String) {
self.value = value
}
public func toString() -> String {
return value
}

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>"; };
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>"; };
BD76883E206D8B6900B7F940 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -522,6 +523,7 @@
isa = PBXGroup;
children = (
BD36975B20135EBB00D8FAC6 /* SwiftSoup.podspec */,
BD76883E206D8B6900B7F940 /* CHANGELOG.md */,
8CE418181DAA54A900240B42 /* Sources */,
8CE418231DAA54A900240B42 /* Tests */,
8CE418171DAA54A900240B42 /* Products */,
@ -667,6 +669,7 @@
8CE418121DAA54A900240B42 /* Frameworks */,
8CE418131DAA54A900240B42 /* Headers */,
8CE418141DAA54A900240B42 /* Resources */,
BD76883F206D9DAC00B7F940 /* ShellScript */,
);
buildRules = (
);
@ -756,7 +759,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0800;
LastUpgradeCheck = 0900;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Nabil Chatbi";
TargetAttributes = {
8CE418151DAA54A900240B42 = {
@ -836,6 +839,22 @@
};
/* 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 */
8CE418111DAA54A900240B42 /* Sources */ = {
isa = PBXSourcesBuildPhase;
@ -1144,6 +1163,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@ -1151,6 +1171,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_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_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@ -1206,6 +1227,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@ -1213,6 +1235,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_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_ROOT_CLASS = YES_ERROR;
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"?>
<Scheme
LastUpgradeVersion = "0900"
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
@ -56,7 +55,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ class AttributeTest: XCTestCase {
XCTAssertEqual(s + "=\"A" + s + "B\"", attr.html())
XCTAssertEqual(attr.html(), attr.toString())
}
func testRemoveCaseSensitive()throws {
let a: Attributes = Attributes()
try a.put("Tot", "a&p")
@ -39,22 +39,21 @@ class AttributeTest: XCTestCase {
try a.put("Hello", "There")
try a.put("hello", "There")
try a.put("data-name", "Jsoup")
XCTAssertEqual(5, a.size());
try a.remove(key: "Tot");
try a.remove(key: "Hello");
XCTAssertEqual(3, a.size());
XCTAssertTrue(a.hasKey(key: "tot"));
XCTAssertFalse(a.hasKey(key: "Tot"));
}
XCTAssertEqual(5, a.size())
try a.remove(key: "Tot")
try a.remove(key: "Hello")
XCTAssertEqual(3, a.size())
XCTAssertTrue(a.hasKey(key: "tot"))
XCTAssertFalse(a.hasKey(key: "Tot"))
}
static var allTests = {
return [
("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
("testHtml", testHtml),
("testWithSupplementaryCharacterInAttributeKeyAndValue", testWithSupplementaryCharacterInAttributeKeyAndValue),
("testRemoveCaseSensitive",testRemoveCaseSensitive)
("testRemoveCaseSensitive", testRemoveCaseSensitive)
]
}()

View File

@ -10,7 +10,7 @@ import XCTest
@testable import SwiftSoup
class CleanerTest: XCTestCase {
func testLinuxTestSuiteIncludesAllTests() {
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
let thisClass = type(of: self)
@ -19,145 +19,144 @@ class CleanerTest: XCTestCase {
XCTAssertEqual(linuxCount, darwinCount, "\(darwinCount - linuxCount) tests are missing from allTests")
#endif
}
func testHandlesCustomProtocols()throws{
func testHandlesCustomProtocols()throws {
let html = "<img src='cid:12345' /> <img src='data:gzzt' />"
// let dropped = try SwiftSoup.clean(html, Whitelist.basicWithImages())
// XCTAssertEqual("<img> \n<img>", dropped)
let preserved = try SwiftSoup.clean(html, Whitelist.basicWithImages().addProtocols("img", "src", "cid", "data"))
XCTAssertEqual("<img src=\"cid:12345\"> \n<img src=\"data:gzzt\">", preserved)
}
func testSimpleBehaviourTest()throws {
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())
XCTAssertEqual("Hello <b>there</b>!", TextUtil.stripNewlines(cleanHtml!))
}
func testSimpleBehaviourTest2()throws {
let h = "Hello <b>there</b>!"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.simpleText())
XCTAssertEqual("Hello <b>there</b>!", TextUtil.stripNewlines(cleanHtml!))
}
func testBasicBehaviourTest()throws {
let h = "<div><p><a href='javascript:sendAllMoney()'>Dodgy</a> <A HREF='HTTP://nice.com'>Nice</a></p><blockquote>Hello</blockquote>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.basic())
XCTAssertEqual("<p><a rel=\"nofollow\">Dodgy</a> <a href=\"HTTP://nice.com\" rel=\"nofollow\">Nice</a></p><blockquote>Hello</blockquote>",
TextUtil.stripNewlines(cleanHtml!))
}
func testBasicWithImagesTest()throws {
let h = "<div><p><img src='http://example.com/' alt=Image></p><p><img src='ftp://ftp.example.com'></p></div>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.basicWithImages())
XCTAssertEqual("<p><img src=\"http://example.com/\" alt=\"Image\"></p><p><img></p>", TextUtil.stripNewlines(cleanHtml!))
}
func testRelaxed()throws {
let h = "<h1>Head</h1><table><tr><td>One<td>Two</td></tr></table>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<h1>Head</h1><table><tbody><tr><td>One</td><td>Two</td></tr></tbody></table>", TextUtil.stripNewlines(cleanHtml!))
}
func testRemoveTags()throws {
let h = "<div><p><A HREF='HTTP://nice.com'>Nice</a></p><blockquote>Hello</blockquote>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeTags("a"))
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 cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeAttributes("blockquote", "cite"))
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 cleanHtml = try SwiftSoup.clean(h, Whitelist.basic().removeEnforcedAttribute("a", "rel"))
XCTAssertEqual("<p><a href=\"HTTP://nice.com\">Nice</a></p><blockquote>Hello</blockquote>",
TextUtil.stripNewlines(cleanHtml!))
}
func testRemoveProtocols()throws{
func testRemoveProtocols()throws {
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"))
XCTAssertEqual("<p>Contact me <a rel=\"nofollow\">here</a></p>",
TextUtil.stripNewlines(cleanHtml!))
}
func testDropComments()throws{
func testDropComments()throws {
let h = "<p>Hello<!-- no --></p>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<p>Hello</p>", cleanHtml)
}
func testDropXmlProc()throws{
func testDropXmlProc()throws {
let h = "<?import namespace=\"xss\"><p>Hello</p>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
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 cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("", cleanHtml)
}
func testDropImageScript()throws{
func testDropImageScript()throws {
let h = "<IMG SRC=\"javascript:alert('XSS')\">"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<img>", cleanHtml)
}
func testCleanJavascriptHref()throws{
func testCleanJavascriptHref()throws {
let h = "<A HREF=\"javascript:document.location='http://www.google.com/'\">XSS</A>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<a>XSS</a>", cleanHtml)
}
func testCleanAnchorProtocol()throws{
func testCleanAnchorProtocol()throws {
let validAnchor = "<a href=\"#valid\">Valid anchor</a>"
let invalidAnchor = "<a href=\"#anchor with spaces\">Invalid anchor</a>"
// A Whitelist that does not allow anchors will strip them out.
var cleanHtml = try SwiftSoup.clean(validAnchor, Whitelist.relaxed())
XCTAssertEqual("<a>Valid anchor</a>", cleanHtml)
cleanHtml = try SwiftSoup.clean(invalidAnchor, Whitelist.relaxed())
XCTAssertEqual("<a>Invalid anchor</a>", cleanHtml)
// A Whitelist that allows them will keep them.
let relaxedWithAnchor: Whitelist = try Whitelist.relaxed().addProtocols("a", "href", "#")
cleanHtml = try SwiftSoup.clean(validAnchor, relaxedWithAnchor)
XCTAssertEqual(validAnchor, cleanHtml)
// An invalid anchor is never valid.
cleanHtml = try SwiftSoup.clean(invalidAnchor, relaxedWithAnchor)
XCTAssertEqual("<a>Invalid anchor</a>", cleanHtml)
}
func testDropsUnknownTags()throws{
func testDropsUnknownTags()throws {
let h = "<p><custom foo=true>Test</custom></p>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.relaxed())
XCTAssertEqual("<p>Test</p>", cleanHtml)
}
func testtestHandlesEmptyAttributes()throws{
func testtestHandlesEmptyAttributes()throws {
let h = "<img alt=\"\" src= unknown=''>"
let cleanHtml = try SwiftSoup.clean(h, Whitelist.basicWithImages())
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 nok1 = "<p><script></script>Not <b>OK</b></p>"
let nok2 = "<p align=right>Test Not <b>OK</b></p>"
@ -167,39 +166,37 @@ class CleanerTest: XCTestCase {
XCTAssertFalse(try SwiftSoup.isValid(nok2, 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 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)
}
func testPreservesRelativeLinksIfConfigured()throws{
func testPreservesRelativeLinksIfConfigured()throws {
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))
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 clean = try SwiftSoup.clean(html, Whitelist.basic())
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 whitelist: Whitelist = try Whitelist()
.addAttributes(":all", "class")
.addAttributes("p", "style")
.addTags("p", "a")
let clean = try SwiftSoup.clean(html, whitelist)
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 whitelist = try Whitelist()
.addAttributes("p", "class")
@ -207,7 +204,7 @@ class CleanerTest: XCTestCase {
let clean = try SwiftSoup.clean(html, whitelist)
XCTAssertEqual("<p class=\"foo\">One</p>", clean)
}
// func testSupplyOutputSettings()throws{
// // test that one can override the default document output settings
// let os: OutputSettings = OutputSettings()
@ -230,29 +227,28 @@ class CleanerTest: XCTestCase {
// let customOut2 = try SwiftSoup.clean(html, "http://foo.com/", Whitelist.relaxed(), os)
// 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 clean = try SwiftSoup.clean(dirty, Whitelist.basic())
XCTAssertEqual("", clean) // nothing good can come out of that
let dirtyDoc: Document = try SwiftSoup.parse(dirty)
let cleanDoc: Document? = try Cleaner(Whitelist.basic()).clean(dirtyDoc)
XCTAssertFalse(cleanDoc == nil)
XCTAssertEqual(0, cleanDoc?.body()?.childNodeSize())
}
func testCleansInternationalText()throws{
func testCleansInternationalText()throws {
XCTAssertEqual("привет", try SwiftSoup.clean("привет", Whitelist.none()))
}
func testScriptTagInWhiteList()throws{
func testScriptTagInWhiteList()throws {
let whitelist: Whitelist = try Whitelist.relaxed()
try whitelist.addTags( "script" )
XCTAssertTrue( try SwiftSoup.isValid("Hello<script>alert('Doh')</script>World !", whitelist ) )
}
// func testHandlesFramesetsw()throws{
//
//
@ -322,6 +318,5 @@ class CleanerTest: XCTestCase {
("testScriptTagInWhiteList", testScriptTagInWhiteList)
]
}()
}
}

View File

@ -16,7 +16,7 @@ class CssTest: XCTestCase {
override func 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'>")
for i in 1...10 {

View File

@ -13,7 +13,7 @@ class DocumentTest: XCTestCase {
private static let charsetUtf8 = String.Encoding.utf8
private static let charsetIso8859 = String.Encoding.iso2022JP //"ISO-8859-1"
// func testT()throws
// {
// do{
@ -59,7 +59,7 @@ class DocumentTest: XCTestCase {
XCTAssertEqual(linuxCount, darwinCount, "\(darwinCount - linuxCount) tests are missing from allTests")
#endif
}
func testSetTextPreservesDocumentStructure() {
do {
let doc: Document = try SwiftSoup.parse("<p>Hello</p>")
@ -441,10 +441,8 @@ class DocumentTest: XCTestCase {
return doc
}
func testThai()
{
func testThai() {
let str = "บังคับ"
guard let doc = try? SwiftSoup.parse(str) else {
XCTFail()
@ -454,7 +452,7 @@ class DocumentTest: XCTestCase {
return}
XCTAssertEqual("<html>\n <head></head>\n <body>\n บังคับ\n </body>\n</html>", txt)
}
//todo:
// func testShiftJisRoundtrip()throws {
// let input =
@ -477,10 +475,10 @@ class DocumentTest: XCTestCase {
// assertTrue("Should have contained a '&#xa0;' or a '&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 doc: Document = try! SwiftSoup.parse(h)
let text = try! doc.text()
XCTAssertEqual(text, "TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST")
@ -514,8 +512,8 @@ class DocumentTest: XCTestCase {
("testMetaCharsetUpdateXmlDisabled", testMetaCharsetUpdateXmlDisabled),
("testMetaCharsetUpdateXmlDisabledNoChanges", testMetaCharsetUpdateXmlDisabledNoChanges),
("testMetaCharsetUpdatedDisabledPerDefault", testMetaCharsetUpdatedDisabledPerDefault),
("testThai",testThai),
("testNewLine", testNewLine),
("testThai", testThai),
("testNewLine", testNewLine)
]
}()

View File

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

View File

@ -823,7 +823,7 @@ class ElementTest: XCTestCase {
// Update the class names to a fresh set
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
try div.classNames(newSet)
@ -936,7 +936,7 @@ class ElementTest: XCTestCase {
XCTAssertEqual(1, els.size())
XCTAssertEqual("html > body > fb|comments", try els.get(0).cssSelector())
}
func testChainedRemoveAttributes()throws {
let html = "<a one two three four>Text</a>"
let doc = try SwiftSoup.parse(html)
@ -946,34 +946,32 @@ class ElementTest: XCTestCase {
.removeAttr("two")
.removeAttr("three")
.removeAttr("four")
.removeAttr("five");
XCTAssertEqual("<a>Text</a>", try a.outerHtml());
.removeAttr("five")
XCTAssertEqual("<a>Text</a>", try a.outerHtml())
}
func testIs()throws {
let html = "<div><p>One <a class=big>Two</a> Three</p><p>Another</p>"
let doc: Document = try SwiftSoup.parse(html)
let p: Element = try doc.select("p").first()!
try XCTAssertTrue(p.iS("p"));
try XCTAssertFalse(p.iS("div"));
try XCTAssertTrue(p.iS("p:has(a)"));
try XCTAssertTrue(p.iS("p:first-child"));
try XCTAssertFalse(p.iS("p:last-child"));
try XCTAssertTrue(p.iS("*"));
try XCTAssertTrue(p.iS("div p"));
try XCTAssertTrue(p.iS("p"))
try XCTAssertFalse(p.iS("div"))
try XCTAssertTrue(p.iS("p:has(a)"))
try XCTAssertTrue(p.iS("p:first-child"))
try XCTAssertFalse(p.iS("p:last-child"))
try XCTAssertTrue(p.iS("*"))
try XCTAssertTrue(p.iS("div p"))
let q: Element = try doc.select("p").last()!
try XCTAssertTrue(q.iS("p"));
try XCTAssertTrue(q.iS("p ~ p"));
try XCTAssertTrue(q.iS("p + p"));
try XCTAssertTrue(q.iS("p:last-child"));
try XCTAssertFalse(q.iS("p a"));
try XCTAssertFalse(q.iS("a"));
try XCTAssertTrue(q.iS("p"))
try XCTAssertTrue(q.iS("p ~ p"))
try XCTAssertTrue(q.iS("p + p"))
try XCTAssertTrue(q.iS("p:last-child"))
try XCTAssertFalse(q.iS("p a"))
try XCTAssertFalse(q.iS("a"))
}
static var allTests = {
return [
("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
@ -1046,8 +1044,8 @@ class ElementTest: XCTestCase {
("testAppendMustCorrectlyMoveChildrenInsideOneParentElement", testAppendMustCorrectlyMoveChildrenInsideOneParentElement),
("testHashcodeIsStableWithContentChanges", testHashcodeIsStableWithContentChanges),
("testNamespacedElements", testNamespacedElements),
("testChainedRemoveAttributes",testChainedRemoveAttributes),
("testIs",testIs)
("testChainedRemoveAttributes", testChainedRemoveAttributes),
("testIs", testIs)
]
}()
}

View File

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

View File

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

View File

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

View File

@ -164,7 +164,7 @@ class XmlTreeBuilderTest: XCTestCase {
let doc = try SwiftSoup.parse(xml, "", Parser.xmlParser().settings(ParseSettings.htmlDefault))
try XCTAssertEqual("<test id=\"1\">Check</test>", TextUtil.stripNewlines(doc.html()))
}
func testNilReplaceInQueue()throws {
let html: String = "<TABLE><TBODY><TR><TD></TD><TD><FONT color=#000000 size=1><I><FONT size=5><P align=center></FONT></I></FONT>&nbsp;</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></DIV></DIV></DIV><BLOCKQUOTE></BLOCKQUOTE><DIV style=\"FONT: 10pt Courier New\"><BR><BR>&nbsp;</DIV></BODY></HTML>"
_ = try SwiftSoup.parse(html)
@ -187,7 +187,7 @@ class XmlTreeBuilderTest: XCTestCase {
("testCreatesValidProlog", testCreatesValidProlog),
("testPreservesCaseByDefault", testPreservesCaseByDefault),
("testCanNormalizeCase", testCanNormalizeCase),
("testNilReplaceInQueue",testNilReplaceInQueue)
("testNilReplaceInQueue", testNilReplaceInQueue)
]
}()