xref: /aosp_15_r20/external/jsoup/src/test/java/org/jsoup/select/EvaluatorDebug.java (revision 6da8f8c4bc310ad659121b84dd089062417a2ce2)
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