1 package org.jsoup.select; 2 3 import org.jsoup.internal.StringUtil; 4 import org.jsoup.nodes.Document; 5 import org.jsoup.nodes.Element; 6 import org.jsoup.nodes.Node; 7 8 public class EvaluatorDebug { 9 10 /** 11 Cast an Evaluator into a pseudo Document, to help visualize the query. Quite coupled to the current impl. 12 */ asDocument(Evaluator eval)13 public static Document asDocument(Evaluator eval) { 14 Document doc = new Document(null); 15 doc.outputSettings().outline(true).indentAmount(2); 16 17 Element el = asElement(eval); 18 doc.appendChild(el); 19 20 return doc; 21 } 22 asDocument(String query)23 public static Document asDocument(String query) { 24 Evaluator eval = QueryParser.parse(query); 25 return asDocument(eval); 26 } 27 asElement(Evaluator eval)28 public static Element asElement(Evaluator eval) { 29 Class<? extends Evaluator> evalClass = eval.getClass(); 30 Element el = new Element(evalClass.getSimpleName()); 31 el.attr("css", eval.toString()); 32 el.attr("cost", Integer.toString(eval.cost())); 33 34 if (eval instanceof CombiningEvaluator) { 35 for (Evaluator inner : ((CombiningEvaluator) eval).sortedEvaluators) { 36 el.appendChild(asElement(inner)); 37 } 38 } else if (eval instanceof StructuralEvaluator.ImmediateParentRun) { 39 for (Evaluator inner : ((StructuralEvaluator.ImmediateParentRun) eval).evaluators) { 40 el.appendChild(asElement(inner)); 41 } 42 } else if (eval instanceof StructuralEvaluator) { 43 Evaluator inner = ((StructuralEvaluator) eval).evaluator; 44 el.appendChild(asElement(inner)); 45 } 46 47 return el; 48 } 49 sexpr(String query)50 public static String sexpr(String query) { 51 Document doc = asDocument(query); 52 53 SexprVisitor sv = new SexprVisitor(); 54 doc.childNode(0).traverse(sv); // skip outer #document 55 return sv.result(); 56 } 57 58 static class SexprVisitor implements NodeVisitor { 59 StringBuilder sb = StringUtil.borrowBuilder(); 60 head(Node node, int depth)61 @Override public void head(Node node, int depth) { 62 sb 63 .append('(') 64 .append(node.nodeName()); 65 66 if (node.childNodeSize() == 0) 67 sb 68 .append(" '") 69 .append(node.attr("css")) 70 .append("'"); 71 else 72 sb.append(" "); 73 } 74 tail(Node node, int depth)75 @Override public void tail(Node node, int depth) { 76 sb.append(')'); 77 } 78 result()79 String result() { 80 return StringUtil.releaseBuilder(sb); 81 } 82 } 83 } 84