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.xpath;
21
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.Optional;
25
26 import com.puppycrawl.tools.checkstyle.xpath.iterators.DescendantIterator;
27 import com.puppycrawl.tools.checkstyle.xpath.iterators.FollowingIterator;
28 import com.puppycrawl.tools.checkstyle.xpath.iterators.PrecedingIterator;
29 import com.puppycrawl.tools.checkstyle.xpath.iterators.ReverseListIterator;
30 import net.sf.saxon.om.AxisInfo;
31 import net.sf.saxon.om.NamespaceUri;
32 import net.sf.saxon.om.NodeInfo;
33 import net.sf.saxon.tree.iter.ArrayIterator;
34 import net.sf.saxon.tree.iter.AxisIterator;
35 import net.sf.saxon.tree.iter.EmptyIterator;
36 import net.sf.saxon.tree.iter.SingleNodeIterator;
37 import net.sf.saxon.tree.util.Navigator;
38 import net.sf.saxon.type.Type;
39
40
41
42
43 public abstract class AbstractElementNode extends AbstractNode {
44
45
46 protected static final String TEXT_ATTRIBUTE_NAME = "text";
47
48
49 private static final AbstractNode[] EMPTY_ABSTRACT_NODE_ARRAY = new AbstractNode[0];
50
51
52 private static final AttributeNode ATTRIBUTE_NODE_UNINITIALIZED = new AttributeNode(null, null);
53
54
55 private final AbstractNode root;
56
57
58 private final AbstractNode parent;
59
60
61 private final int depth;
62
63
64 private final int indexAmongSiblings;
65
66
67 private AttributeNode attributeNode = ATTRIBUTE_NODE_UNINITIALIZED;
68
69
70
71
72
73
74
75
76
77 protected AbstractElementNode(AbstractNode root, AbstractNode parent,
78 int depth, int indexAmongSiblings) {
79 super(root.getTreeInfo());
80 this.parent = parent;
81 this.root = root;
82 this.depth = depth;
83 this.indexAmongSiblings = indexAmongSiblings;
84 }
85
86
87
88
89
90
91 protected abstract AttributeNode createAttributeNode();
92
93
94
95
96
97
98
99 @Override
100 public int compareOrder(NodeInfo other) {
101 int result = 0;
102 if (other instanceof AbstractNode) {
103 result = Integer.compare(depth, ((AbstractNode) other).getDepth());
104 if (result == 0) {
105 result = compareCommonAncestorChildrenOrder(this, other);
106 }
107 }
108 return result;
109 }
110
111
112
113
114
115
116
117
118
119
120
121 private static int compareCommonAncestorChildrenOrder(NodeInfo first, NodeInfo second) {
122 NodeInfo child1 = first;
123 NodeInfo child2 = second;
124 while (!child1.getParent().equals(child2.getParent())) {
125 child1 = child1.getParent();
126 child2 = child2.getParent();
127 }
128 final int index1 = ((AbstractElementNode) child1).indexAmongSiblings;
129 final int index2 = ((AbstractElementNode) child2).indexAmongSiblings;
130 return Integer.compare(index1, index2);
131 }
132
133
134
135
136
137
138 @Override
139 public int getDepth() {
140 return depth;
141 }
142
143
144
145
146
147
148
149
150 @Override
151 public String getAttributeValue(NamespaceUri namespace, String localPart) {
152 final String result;
153 if (TEXT_ATTRIBUTE_NAME.equals(localPart)) {
154 result = Optional.ofNullable(getAttributeNode())
155 .map(AttributeNode::getStringValue)
156 .orElse(null);
157 }
158 else {
159 result = null;
160 }
161 return result;
162 }
163
164
165
166
167
168
169 @Override
170 public int getNodeKind() {
171 return Type.ELEMENT;
172 }
173
174
175
176
177
178
179 @Override
180 public NodeInfo getParent() {
181 return parent;
182 }
183
184
185
186
187
188
189 @Override
190 public AbstractNode getRoot() {
191 return root;
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206 @Override
207 public AxisIterator iterateAxis(int axisNumber) {
208 final AxisIterator result;
209 switch (axisNumber) {
210 case AxisInfo.ANCESTOR:
211 result = new Navigator.AncestorEnumeration(this, false);
212 break;
213 case AxisInfo.ANCESTOR_OR_SELF:
214 result = new Navigator.AncestorEnumeration(this, true);
215 break;
216 case AxisInfo.ATTRIBUTE:
217 result = SingleNodeIterator.makeIterator(getAttributeNode());
218 break;
219 case AxisInfo.CHILD:
220 if (hasChildNodes()) {
221 result = new ArrayIterator.OfNodes<>(
222 getChildren().toArray(EMPTY_ABSTRACT_NODE_ARRAY));
223 }
224 else {
225 result = EmptyIterator.ofNodes();
226 }
227 break;
228 case AxisInfo.DESCENDANT:
229 if (hasChildNodes()) {
230 result = new DescendantIterator(this, DescendantIterator.StartWith.CHILDREN);
231 }
232 else {
233 result = EmptyIterator.ofNodes();
234 }
235 break;
236 case AxisInfo.DESCENDANT_OR_SELF:
237 result = new DescendantIterator(this, DescendantIterator.StartWith.CURRENT_NODE);
238 break;
239 case AxisInfo.PARENT:
240 result = SingleNodeIterator.makeIterator(parent);
241 break;
242 case AxisInfo.SELF:
243 result = SingleNodeIterator.makeIterator(this);
244 break;
245 case AxisInfo.FOLLOWING_SIBLING:
246 result = getFollowingSiblingsIterator();
247 break;
248 case AxisInfo.PRECEDING_SIBLING:
249 result = getPrecedingSiblingsIterator();
250 break;
251 case AxisInfo.FOLLOWING:
252 result = new FollowingIterator(this);
253 break;
254 case AxisInfo.PRECEDING:
255 result = new PrecedingIterator(this);
256 break;
257 default:
258 throw throwUnsupportedOperationException();
259 }
260
261 return result;
262 }
263
264
265
266
267
268
269
270
271
272
273
274 private AxisIterator getPrecedingSiblingsIterator() {
275 final AxisIterator result;
276 if (indexAmongSiblings == 0) {
277 result = EmptyIterator.ofNodes();
278 }
279 else {
280 result = new ReverseListIterator(getPrecedingSiblings());
281 }
282 return result;
283 }
284
285
286
287
288
289
290
291
292
293
294
295 private AxisIterator getFollowingSiblingsIterator() {
296 final AxisIterator result;
297 if (indexAmongSiblings == parent.getChildren().size() - 1) {
298 result = EmptyIterator.ofNodes();
299 }
300 else {
301 result = new ArrayIterator.OfNodes<>(
302 getFollowingSiblings().toArray(EMPTY_ABSTRACT_NODE_ARRAY));
303 }
304 return result;
305 }
306
307
308
309
310
311
312 private List<AbstractNode> getFollowingSiblings() {
313 final List<AbstractNode> siblings = parent.getChildren();
314 return siblings.subList(indexAmongSiblings + 1, siblings.size());
315 }
316
317
318
319
320
321
322 private List<AbstractNode> getPrecedingSiblings() {
323 final List<AbstractNode> siblings = parent.getChildren();
324 return Collections.unmodifiableList(siblings.subList(0, indexAmongSiblings));
325 }
326
327
328
329
330
331
332
333
334 private AttributeNode getAttributeNode() {
335 if (attributeNode == ATTRIBUTE_NODE_UNINITIALIZED) {
336 attributeNode = createAttributeNode();
337 }
338 return attributeNode;
339 }
340
341
342
343
344
345
346 private static UnsupportedOperationException throwUnsupportedOperationException() {
347 return new UnsupportedOperationException("Operation is not supported");
348 }
349 }