001package org.jsoup.select; 002 003import org.jsoup.helper.StringUtil; 004import org.jsoup.nodes.Element; 005 006import java.util.ArrayList; 007import java.util.Arrays; 008import java.util.Collection; 009 010/** 011 * Base combining (and, or) evaluator. 012 */ 013abstract class CombiningEvaluator extends Evaluator { 014 final ArrayList<Evaluator> evaluators; 015 int num = 0; 016 017 CombiningEvaluator() { 018 super(); 019 evaluators = new ArrayList<>(); 020 } 021 022 CombiningEvaluator(Collection<Evaluator> evaluators) { 023 this(); 024 this.evaluators.addAll(evaluators); 025 updateNumEvaluators(); 026 } 027 028 Evaluator rightMostEvaluator() { 029 return num > 0 ? evaluators.get(num - 1) : null; 030 } 031 032 void replaceRightMostEvaluator(Evaluator replacement) { 033 evaluators.set(num - 1, replacement); 034 } 035 036 void updateNumEvaluators() { 037 // used so we don't need to bash on size() for every match test 038 num = evaluators.size(); 039 } 040 041 static final class And extends CombiningEvaluator { 042 And(Collection<Evaluator> evaluators) { 043 super(evaluators); 044 } 045 046 And(Evaluator... evaluators) { 047 this(Arrays.asList(evaluators)); 048 } 049 050 @Override 051 public boolean matches(Element root, Element node) { 052 for (int i = 0; i < num; i++) { 053 Evaluator s = evaluators.get(i); 054 if (!s.matches(root, node)) 055 return false; 056 } 057 return true; 058 } 059 060 @Override 061 public String toString() { 062 return StringUtil.join(evaluators, " "); 063 } 064 } 065 066 static final class Or extends CombiningEvaluator { 067 /** 068 * Create a new Or evaluator. The initial evaluators are ANDed together and used as the first clause of the OR. 069 * @param evaluators initial OR clause (these are wrapped into an AND evaluator). 070 */ 071 Or(Collection<Evaluator> evaluators) { 072 super(); 073 if (num > 1) 074 this.evaluators.add(new And(evaluators)); 075 else // 0 or 1 076 this.evaluators.addAll(evaluators); 077 updateNumEvaluators(); 078 } 079 080 Or(Evaluator... evaluators) { this(Arrays.asList(evaluators)); } 081 082 Or() { 083 super(); 084 } 085 086 public void add(Evaluator e) { 087 evaluators.add(e); 088 updateNumEvaluators(); 089 } 090 091 @Override 092 public boolean matches(Element root, Element node) { 093 for (int i = 0; i < num; i++) { 094 Evaluator s = evaluators.get(i); 095 if (s.matches(root, node)) 096 return true; 097 } 098 return false; 099 } 100 101 @Override 102 public String toString() { 103 return StringUtil.join(evaluators, ", "); 104 } 105 } 106}