1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host.dom;
16
17 import java.util.List;
18
19 import org.htmlunit.html.DomAttr;
20 import org.htmlunit.html.DomNode;
21 import org.htmlunit.javascript.HtmlUnitScriptable;
22 import org.htmlunit.javascript.JavaScriptEngine;
23 import org.htmlunit.javascript.configuration.JsxClass;
24 import org.htmlunit.javascript.configuration.JsxConstant;
25 import org.htmlunit.javascript.configuration.JsxConstructor;
26 import org.htmlunit.javascript.configuration.JsxFunction;
27 import org.htmlunit.javascript.configuration.JsxGetter;
28
29
30
31
32
33
34
35
36 @JsxClass
37 public class XPathResult extends HtmlUnitScriptable {
38
39
40
41
42
43
44 @JsxConstant
45 public static final int ANY_TYPE = 0;
46
47
48
49
50 @JsxConstant
51 public static final int NUMBER_TYPE = 1;
52
53
54
55
56 @JsxConstant
57 public static final int STRING_TYPE = 2;
58
59
60
61
62 @JsxConstant
63 public static final int BOOLEAN_TYPE = 3;
64
65
66
67
68
69 @JsxConstant
70 public static final int UNORDERED_NODE_ITERATOR_TYPE = 4;
71
72
73
74
75 @JsxConstant
76 public static final int ORDERED_NODE_ITERATOR_TYPE = 5;
77
78
79
80
81
82 @JsxConstant
83 public static final int UNORDERED_NODE_SNAPSHOT_TYPE = 6;
84
85
86
87
88
89 @JsxConstant
90 public static final int ORDERED_NODE_SNAPSHOT_TYPE = 7;
91
92
93
94
95
96
97 @JsxConstant
98 public static final int ANY_UNORDERED_NODE_TYPE = 8;
99
100
101
102
103
104
105 @JsxConstant
106 public static final int FIRST_ORDERED_NODE_TYPE = 9;
107
108 private List<?> result_;
109 private int resultType_;
110
111
112
113
114 private int iteratorIndex_;
115
116
117
118
119 @JsxConstructor
120 public void jsConstructor() {
121 throw JavaScriptEngine.typeErrorIllegalConstructor();
122 }
123
124
125
126
127
128
129
130
131 void init(final List<?> result, final int type) {
132 result_ = result;
133 resultType_ = type;
134
135 if (type == ANY_TYPE) {
136 resultType_ = UNORDERED_NODE_ITERATOR_TYPE;
137
138 if (result_.size() == 1) {
139 final Object o = result_.get(0);
140 if (o instanceof Number) {
141 resultType_ = NUMBER_TYPE;
142 }
143 else if (o instanceof String) {
144 resultType_ = STRING_TYPE;
145 }
146 else if (o instanceof Boolean) {
147 resultType_ = BOOLEAN_TYPE;
148 }
149 }
150 }
151
152 iteratorIndex_ = 0;
153 }
154
155
156
157
158
159
160 @JsxGetter
161 public int getResultType() {
162 return resultType_;
163 }
164
165
166
167
168
169
170 @JsxGetter
171 public int getSnapshotLength() {
172 if (resultType_ != UNORDERED_NODE_SNAPSHOT_TYPE && resultType_ != ORDERED_NODE_SNAPSHOT_TYPE) {
173 throw JavaScriptEngine.reportRuntimeError("Cannot get snapshotLength for type: " + resultType_);
174 }
175 return result_.size();
176 }
177
178
179
180
181
182
183 @JsxGetter
184 public Node getSingleNodeValue() {
185 if (resultType_ != ANY_UNORDERED_NODE_TYPE && resultType_ != FIRST_ORDERED_NODE_TYPE) {
186 throw JavaScriptEngine.reportRuntimeError("Cannot get singleNodeValue for type: " + resultType_);
187 }
188 if (!result_.isEmpty()) {
189 return ((DomNode) result_.get(0)).getScriptableObject();
190 }
191 return null;
192 }
193
194
195
196
197
198
199
200
201
202 @JsxGetter
203 public boolean isInvalidIteratorState() {
204 return false;
205 }
206
207
208
209
210
211
212 @JsxFunction
213 public Node iterateNext() {
214 if (resultType_ != UNORDERED_NODE_ITERATOR_TYPE && resultType_ != ORDERED_NODE_ITERATOR_TYPE) {
215 throw JavaScriptEngine.reportRuntimeError("Cannot get iterateNext for type: " + resultType_);
216 }
217 if (iteratorIndex_ < result_.size()) {
218 return ((DomNode) result_.get(iteratorIndex_++)).getScriptableObject();
219 }
220 return null;
221 }
222
223
224
225
226
227
228
229
230 @JsxFunction
231 public Node snapshotItem(final int index) {
232 if (resultType_ != UNORDERED_NODE_SNAPSHOT_TYPE && resultType_ != ORDERED_NODE_SNAPSHOT_TYPE) {
233 throw JavaScriptEngine.reportRuntimeError("Cannot get snapshotLength for type: " + resultType_);
234 }
235 if (index >= 0 && index < result_.size()) {
236 return ((DomNode) result_.get(index)).getScriptableObject();
237 }
238 return null;
239 }
240
241
242
243
244
245
246 @JsxGetter
247 public double getNumberValue() {
248 if (resultType_ != NUMBER_TYPE) {
249 throw JavaScriptEngine.reportRuntimeError("Cannot get numberValue for type: " + resultType_);
250 }
251
252 if (result_.size() == 1) {
253 final Object o = result_.get(0);
254 if (o instanceof Number) {
255 return ((Double) o).doubleValue();
256 }
257 if (o instanceof Boolean boolean1) {
258 return boolean1.booleanValue() ? 1 : 0;
259 }
260 }
261
262 final String asString = asString();
263 double answer;
264 try {
265 answer = Double.parseDouble(asString);
266 }
267 catch (final NumberFormatException e) {
268 answer = Double.NaN;
269 }
270 return answer;
271 }
272
273
274
275
276
277
278 @JsxGetter
279 @SuppressWarnings("PMD.BooleanGetMethodName")
280 public boolean getBooleanValue() {
281 if (resultType_ != BOOLEAN_TYPE) {
282 throw JavaScriptEngine.reportRuntimeError("Cannot get booleanValue for type: " + resultType_);
283 }
284
285 if (result_.size() == 1) {
286 final Object o = result_.get(0);
287 if (o instanceof Number) {
288 final double d = ((Double) o).doubleValue();
289 if (Double.isNaN(d) || Double.isInfinite(d)) {
290 return true;
291 }
292
293 return 0.0 != d;
294 }
295 if (o instanceof String string) {
296 return !string.isEmpty();
297 }
298 if (o instanceof Boolean boolean1) {
299 return boolean1.booleanValue();
300 }
301 }
302
303 return !result_.isEmpty();
304 }
305
306
307
308
309
310
311 @JsxGetter
312 public String getStringValue() {
313 if (resultType_ != STRING_TYPE) {
314 throw JavaScriptEngine.reportRuntimeError("Cannot get stringValue for type: " + resultType_);
315 }
316 return asString();
317 }
318
319 private String asString() {
320 if (result_.isEmpty()) {
321 return "";
322 }
323
324 final Object resultObj = result_.get(0);
325 if (resultObj instanceof DomAttr attr) {
326 return attr.getValue();
327 }
328 if (resultObj instanceof DomNode node) {
329 return node.asNormalizedText();
330 }
331 return resultObj.toString();
332 }
333 }