SwiftSoup/Sources/select/CombiningEvaluator.swift

124 lines
3.4 KiB
Swift

//
// CombiningEvaluator.swift
// SwiftSoup
//
// Created by Nabil Chatbi on 23/10/16.
// Copyright © 2016 Nabil Chatbi.. All rights reserved.
//
import Foundation
/**
* Base combining (and, or) evaluator.
*/
public class CombiningEvaluator : Evaluator {
public private(set) var evaluators: Array<Evaluator>;
var num : Int = 0;
public override init() {
evaluators = Array<Evaluator>();
super.init()
}
public init(_ evaluators: Array<Evaluator>) {
self.evaluators = evaluators
super.init()
updateNumEvaluators()
}
func rightMostEvaluator()->Evaluator? {
return num > 0 && evaluators.count > 0 ? evaluators[num - 1] : nil
}
func replaceRightMostEvaluator(_ replacement: Evaluator) {
evaluators[num - 1] = replacement
}
func updateNumEvaluators() {
// used so we don't need to bash on size() for every match test
num = evaluators.count
}
public final class And : CombiningEvaluator {
public override init(_ evaluators: Array<Evaluator>) {
super.init(evaluators);
}
public override init(_ evaluators: Evaluator...) {
super.init(evaluators);
}
public override func matches(_ root: Element, _ node: Element)->Bool {
for i in 0..<num
{
let s = evaluators[i]
do{
if (try !s.matches(root, node)){
return false;
}
}catch{}
}
return true;
}
public override func toString()->String {
let ar : [String] = evaluators.map { String($0.toString()) }
return StringUtil.join(ar, sep: " ");
}
}
public final class Or : CombiningEvaluator {
/**
* Create a new Or evaluator. The initial evaluators are ANDed together and used as the first clause of the OR.
* @param evaluators initial OR clause (these are wrapped into an AND evaluator).
*/
public override init(_ evaluators: Array<Evaluator>) {
super.init();
if (num > 1){
self.evaluators.append(And(evaluators));
}else{ // 0 or 1
self.evaluators.append(contentsOf: evaluators);
}
updateNumEvaluators();
}
override init(_ evaluators: Evaluator...) {
super.init();
if (num > 1){
self.evaluators.append(And(evaluators));
}else{ // 0 or 1
self.evaluators.append(contentsOf: evaluators);
}
updateNumEvaluators();
}
override init() {
super.init();
}
public func add(_ e: Evaluator) {
evaluators.append(e);
updateNumEvaluators();
}
public override func matches(_ root: Element, _ node: Element)->Bool {
for i in 0..<num
{
let s : Evaluator = evaluators[i]
do{
if (try s.matches(root, node)){
return true;
}
}catch{}
}
return false;
}
public override func toString()->String {
return ":or\(evaluators.map{String($0.toString())})"
}
}
}