1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.utils;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.BitSet;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.regex.Pattern;
29 import java.util.stream.Collectors;
30
31 import com.puppycrawl.tools.checkstyle.AstTreeStringPrinter;
32 import com.puppycrawl.tools.checkstyle.JavaParser;
33 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
34 import com.puppycrawl.tools.checkstyle.api.DetailAST;
35 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36 import com.puppycrawl.tools.checkstyle.xpath.AbstractNode;
37 import com.puppycrawl.tools.checkstyle.xpath.ElementNode;
38 import com.puppycrawl.tools.checkstyle.xpath.RootNode;
39 import net.sf.saxon.Configuration;
40 import net.sf.saxon.om.Item;
41 import net.sf.saxon.om.NodeInfo;
42 import net.sf.saxon.sxpath.XPathDynamicContext;
43 import net.sf.saxon.sxpath.XPathEvaluator;
44 import net.sf.saxon.sxpath.XPathExpression;
45 import net.sf.saxon.trans.XPathException;
46
47
48
49
50
51 public final class XpathUtil {
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 private static final BitSet TOKEN_TYPES_WITH_TEXT_ATTRIBUTE = TokenUtil.asBitSet(
106 TokenTypes.IDENT, TokenTypes.STRING_LITERAL, TokenTypes.CHAR_LITERAL,
107 TokenTypes.NUM_LONG, TokenTypes.NUM_INT, TokenTypes.NUM_DOUBLE, TokenTypes.NUM_FLOAT,
108 TokenTypes.TEXT_BLOCK_CONTENT, TokenTypes.COMMENT_CONTENT
109 );
110
111
112
113
114 private static final Pattern NEWLINE_TO_TAG = Pattern.compile("\n");
115
116
117
118
119 private static final Pattern CARRIAGE_RETURN_TO_TAG = Pattern.compile("\r");
120
121
122 private static final String DELIMITER = "---------" + System.lineSeparator();
123
124
125 private XpathUtil() {
126 }
127
128
129
130
131
132
133
134
135
136 public static List<AbstractNode> createChildren(AbstractNode root, AbstractNode parent,
137 DetailAST firstChild) {
138 DetailAST currentChild = firstChild;
139 final int depth = parent.getDepth() + 1;
140 final List<AbstractNode> result = new ArrayList<>();
141 while (currentChild != null) {
142 final int index = result.size();
143 final ElementNode child = new ElementNode(root, parent, currentChild, depth, index);
144 result.add(child);
145 currentChild = currentChild.getNextSibling();
146 }
147 return result;
148 }
149
150
151
152
153
154
155
156 public static boolean supportsTextAttribute(DetailAST ast) {
157 return TOKEN_TYPES_WITH_TEXT_ATTRIBUTE.get(ast.getType());
158 }
159
160
161
162
163
164
165
166 public static String getTextAttributeValue(DetailAST ast) {
167 String text = ast.getText();
168 if (ast.getType() == TokenTypes.STRING_LITERAL) {
169 text = text.substring(1, text.length() - 1);
170 }
171 text = CARRIAGE_RETURN_TO_TAG.matcher(text).replaceAll("\\\\r");
172 return NEWLINE_TO_TAG.matcher(text).replaceAll("\\\\n");
173 }
174
175
176
177
178
179
180
181
182
183
184 public static String printXpathBranch(String xpath, File file) throws CheckstyleException,
185 IOException {
186 try {
187 final RootNode rootNode = new RootNode(JavaParser.parseFile(file,
188 JavaParser.Options.WITH_COMMENTS));
189 final List<NodeInfo> matchingItems = getXpathItems(xpath, rootNode);
190 return matchingItems.stream()
191 .map(item -> ((ElementNode) item).getUnderlyingNode())
192 .map(AstTreeStringPrinter::printBranch)
193 .collect(Collectors.joining(DELIMITER));
194 }
195 catch (XPathException ex) {
196 final String errMsg = String.format(Locale.ROOT,
197 "Error during evaluation for xpath: %s, file: %s", xpath, file.getCanonicalPath());
198 throw new CheckstyleException(errMsg, ex);
199 }
200 }
201
202
203
204
205
206
207
208
209
210 public static List<NodeInfo> getXpathItems(String xpath, AbstractNode rootNode)
211 throws XPathException {
212 final XPathEvaluator xpathEvaluator = new XPathEvaluator(Configuration.newConfiguration());
213 final XPathExpression xpathExpression = xpathEvaluator.createExpression(xpath);
214 final XPathDynamicContext xpathDynamicContext = xpathExpression
215 .createDynamicContext(rootNode);
216 final List<Item> items = xpathExpression.evaluate(xpathDynamicContext);
217 return UnmodifiableCollectionUtil.unmodifiableList(items, NodeInfo.class);
218 }
219 }