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 node) {
103 result = Integer.compare(depth, node.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 return switch (axisNumber) {
209 case AxisInfo.ANCESTOR -> new Navigator.AncestorEnumeration(this, false);
210 case AxisInfo.ANCESTOR_OR_SELF -> new Navigator.AncestorEnumeration(this, true);
211 case AxisInfo.ATTRIBUTE -> SingleNodeIterator.makeIterator(getAttributeNode());
212 case AxisInfo.CHILD -> {
213 if (hasChildNodes()) {
214 yield new ArrayIterator.OfNodes<>(
215 getChildren().toArray(EMPTY_ABSTRACT_NODE_ARRAY));
216 }
217 yield EmptyIterator.ofNodes();
218 }
219 case AxisInfo.DESCENDANT -> {
220 if (hasChildNodes()) {
221 yield new DescendantIterator(this, DescendantIterator.StartWith.CHILDREN);
222 }
223 yield EmptyIterator.ofNodes();
224 }
225 case AxisInfo.DESCENDANT_OR_SELF ->
226 new DescendantIterator(this, DescendantIterator.StartWith.CURRENT_NODE);
227 case AxisInfo.PARENT -> SingleNodeIterator.makeIterator(parent);
228 case AxisInfo.SELF -> SingleNodeIterator.makeIterator(this);
229 case AxisInfo.FOLLOWING_SIBLING -> getFollowingSiblingsIterator();
230 case AxisInfo.PRECEDING_SIBLING -> getPrecedingSiblingsIterator();
231 case AxisInfo.FOLLOWING -> new FollowingIterator(this);
232 case AxisInfo.PRECEDING -> new PrecedingIterator(this);
233 default -> throw throwUnsupportedOperationException();
234 };
235 }
236
237
238
239
240
241
242
243
244
245
246
247 private AxisIterator getPrecedingSiblingsIterator() {
248 final AxisIterator result;
249 if (indexAmongSiblings == 0) {
250 result = EmptyIterator.ofNodes();
251 }
252 else {
253 result = new ReverseListIterator(getPrecedingSiblings());
254 }
255 return result;
256 }
257
258
259
260
261
262
263
264
265
266
267
268 private AxisIterator getFollowingSiblingsIterator() {
269 final AxisIterator result;
270 if (indexAmongSiblings == parent.getChildren().size() - 1) {
271 result = EmptyIterator.ofNodes();
272 }
273 else {
274 result = new ArrayIterator.OfNodes<>(
275 getFollowingSiblings().toArray(EMPTY_ABSTRACT_NODE_ARRAY));
276 }
277 return result;
278 }
279
280
281
282
283
284
285 private List<AbstractNode> getFollowingSiblings() {
286 final List<AbstractNode> siblings = parent.getChildren();
287 return siblings.subList(indexAmongSiblings + 1, siblings.size());
288 }
289
290
291
292
293
294
295 private List<AbstractNode> getPrecedingSiblings() {
296 final List<AbstractNode> siblings = parent.getChildren();
297 return Collections.unmodifiableList(siblings.subList(0, indexAmongSiblings));
298 }
299
300
301
302
303
304
305
306
307 private AttributeNode getAttributeNode() {
308 if (attributeNode == ATTRIBUTE_NODE_UNINITIALIZED) {
309 attributeNode = createAttributeNode();
310 }
311 return attributeNode;
312 }
313
314
315
316
317
318
319 private static UnsupportedOperationException throwUnsupportedOperationException() {
320 return new UnsupportedOperationException("Operation is not supported");
321 }
322 }