* Removed StringBuilder from Element.cssSelector
* Lint Code * Swift 4.1
This commit is contained in:
parent
306be6efbe
commit
d98300a7ec
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -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)
|
||||||
|
|
|
@ -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:.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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"])
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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(";")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -57,8 +57,3 @@ open class ParseSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
])
|
])
|
||||||
|
|
|
@ -115,7 +115,7 @@ class AttributeParseTest: XCTestCase {
|
||||||
("teststrictAttributeUnescapes", teststrictAttributeUnescapes),
|
("teststrictAttributeUnescapes", teststrictAttributeUnescapes),
|
||||||
("testmoreAttributeUnescapes", testmoreAttributeUnescapes),
|
("testmoreAttributeUnescapes", testmoreAttributeUnescapes),
|
||||||
("testparsesBooleanAttributes", testparsesBooleanAttributes),
|
("testparsesBooleanAttributes", testparsesBooleanAttributes),
|
||||||
("testdropsSlashFromAttributeName", testdropsSlashFromAttributeName),
|
("testdropsSlashFromAttributeName", testdropsSlashFromAttributeName)
|
||||||
]
|
]
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
]
|
]
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -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>ℬ</p></div>", customOut2)
|
// XCTAssertEqual("<div><p>ℬ</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 {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(" ") || output.contains(" "));
|
// output.contains(" ") || output.contains(" "));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
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;\"> 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;\"> 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)
|
||||||
]
|
]
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ class DocumentTypeTest: XCTestCase {
|
||||||
("testConstructorValidationOkWithBlankName", testConstructorValidationOkWithBlankName),
|
("testConstructorValidationOkWithBlankName", testConstructorValidationOkWithBlankName),
|
||||||
("testConstructorValidationThrowsExceptionOnNulls", testConstructorValidationThrowsExceptionOnNulls),
|
("testConstructorValidationThrowsExceptionOnNulls", testConstructorValidationThrowsExceptionOnNulls),
|
||||||
("testConstructorValidationOkWithBlankPublicAndSystemIds", testConstructorValidationOkWithBlankPublicAndSystemIds),
|
("testConstructorValidationOkWithBlankPublicAndSystemIds", testConstructorValidationOkWithBlankPublicAndSystemIds),
|
||||||
("testOuterHtmlGeneration", testOuterHtmlGeneration),
|
("testOuterHtmlGeneration", testOuterHtmlGeneration)
|
||||||
]
|
]
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
]
|
]
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,6 @@ class EntitiesTest: XCTestCase {
|
||||||
XCTAssertEqual("<a title=\"<p>One</p>\">One</a>", try element.outerHtml())
|
XCTAssertEqual("<a title=\"<p>One</p>\">One</a>", try element.outerHtml())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static var allTests = {
|
static var allTests = {
|
||||||
return [
|
return [
|
||||||
("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
|
("testLinuxTestSuiteIncludesAllTests", testLinuxTestSuiteIncludesAllTests),
|
||||||
|
|
|
@ -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)
|
||||||
]
|
]
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ class TagTest: XCTestCase {
|
||||||
("testPSemantics", testPSemantics),
|
("testPSemantics", testPSemantics),
|
||||||
("testImgSemantics", testImgSemantics),
|
("testImgSemantics", testImgSemantics),
|
||||||
("testDefaultSemantics", testDefaultSemantics),
|
("testDefaultSemantics", testDefaultSemantics),
|
||||||
("testValueOfChecksNotEmpty", testValueOfChecksNotEmpty),
|
("testValueOfChecksNotEmpty", testValueOfChecksNotEmpty)
|
||||||
]
|
]
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,7 +187,7 @@ class XmlTreeBuilderTest: XCTestCase {
|
||||||
("testCreatesValidProlog", testCreatesValidProlog),
|
("testCreatesValidProlog", testCreatesValidProlog),
|
||||||
("testPreservesCaseByDefault", testPreservesCaseByDefault),
|
("testPreservesCaseByDefault", testPreservesCaseByDefault),
|
||||||
("testCanNormalizeCase", testCanNormalizeCase),
|
("testCanNormalizeCase", testCanNormalizeCase),
|
||||||
("testNilReplaceInQueue",testNilReplaceInQueue)
|
("testNilReplaceInQueue", testNilReplaceInQueue)
|
||||||
]
|
]
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue