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 void init(final List<?> result, final int type) {
129 result_ = result;
130 resultType_ = type;
131
132 if (type == ANY_TYPE) {
133 resultType_ = UNORDERED_NODE_ITERATOR_TYPE;
134
135 if (result_.size() == 1) {
136 final Object o = result_.get(0);
137 if (o instanceof Number) {
138 resultType_ = NUMBER_TYPE;
139 }
140 else if (o instanceof String) {
141 resultType_ = STRING_TYPE;
142 }
143 else if (o instanceof Boolean) {
144 resultType_ = BOOLEAN_TYPE;
145 }
146 }
147 }
148
149 iteratorIndex_ = 0;
150 }
151
152
153
154
155
156 @JsxGetter
157 public int getResultType() {
158 return resultType_;
159 }
160
161
162
163
164
165 @JsxGetter
166 public int getSnapshotLength() {
167 if (resultType_ != UNORDERED_NODE_SNAPSHOT_TYPE && resultType_ != ORDERED_NODE_SNAPSHOT_TYPE) {
168 throw JavaScriptEngine.reportRuntimeError("Cannot get snapshotLength for type: " + resultType_);
169 }
170 return result_.size();
171 }
172
173
174
175
176
177 @JsxGetter
178 public Node getSingleNodeValue() {
179 if (resultType_ != ANY_UNORDERED_NODE_TYPE && resultType_ != FIRST_ORDERED_NODE_TYPE) {
180 throw JavaScriptEngine.reportRuntimeError("Cannot get singleNodeValue for type: " + resultType_);
181 }
182 if (!result_.isEmpty()) {
183 return ((DomNode) result_.get(0)).getScriptableObject();
184 }
185 return null;
186 }
187
188
189
190
191
192
193 @JsxGetter
194 public boolean getInvalidIteratorState() {
195 return false;
196 }
197
198
199
200
201
202 @JsxFunction
203 public Node iterateNext() {
204 if (resultType_ != UNORDERED_NODE_ITERATOR_TYPE && resultType_ != ORDERED_NODE_ITERATOR_TYPE) {
205 throw JavaScriptEngine.reportRuntimeError("Cannot get iterateNext for type: " + resultType_);
206 }
207 if (iteratorIndex_ < result_.size()) {
208 return ((DomNode) result_.get(iteratorIndex_++)).getScriptableObject();
209 }
210 return null;
211 }
212
213
214
215
216
217
218
219 @JsxFunction
220 public Node snapshotItem(final int index) {
221 if (resultType_ != UNORDERED_NODE_SNAPSHOT_TYPE && resultType_ != ORDERED_NODE_SNAPSHOT_TYPE) {
222 throw JavaScriptEngine.reportRuntimeError("Cannot get snapshotLength for type: " + resultType_);
223 }
224 if (index >= 0 && index < result_.size()) {
225 return ((DomNode) result_.get(index)).getScriptableObject();
226 }
227 return null;
228 }
229
230
231
232
233
234 @JsxGetter
235 public double getNumberValue() {
236 if (resultType_ != NUMBER_TYPE) {
237 throw JavaScriptEngine.reportRuntimeError("Cannot get numberValue for type: " + resultType_);
238 }
239
240 if (result_.size() == 1) {
241 final Object o = result_.get(0);
242 if (o instanceof Number) {
243 return ((Double) o).doubleValue();
244 }
245 if (o instanceof Boolean) {
246 return ((Boolean) o).booleanValue() ? 1 : 0;
247 }
248 }
249
250 final String asString = asString();
251 double answer;
252 try {
253 answer = Double.parseDouble(asString);
254 }
255 catch (final NumberFormatException e) {
256 answer = Double.NaN;
257 }
258 return answer;
259 }
260
261
262
263
264
265 @JsxGetter
266 public boolean getBooleanValue() {
267 if (resultType_ != BOOLEAN_TYPE) {
268 throw JavaScriptEngine.reportRuntimeError("Cannot get booleanValue for type: " + resultType_);
269 }
270
271 if (result_.size() == 1) {
272 final Object o = result_.get(0);
273 if (o instanceof Number) {
274 final double d = ((Double) o).doubleValue();
275 if (Double.isNaN(d) || Double.isInfinite(d)) {
276 return true;
277 }
278
279 return 0.0 != d;
280 }
281 if (o instanceof String) {
282 return !((String) o).isEmpty();
283 }
284 if (o instanceof Boolean) {
285 return ((Boolean) o).booleanValue();
286 }
287 }
288
289 return !result_.isEmpty();
290 }
291
292
293
294
295
296 @JsxGetter
297 public String getStringValue() {
298 if (resultType_ != STRING_TYPE) {
299 throw JavaScriptEngine.reportRuntimeError("Cannot get stringValue for type: " + resultType_);
300 }
301 return asString();
302 }
303
304 private String asString() {
305 if (result_.isEmpty()) {
306 return "";
307 }
308
309 final Object resultObj = result_.get(0);
310 if (resultObj instanceof DomAttr) {
311 return ((DomAttr) resultObj).getValue();
312 }
313 if (resultObj instanceof DomNode) {
314 return ((DomNode) resultObj).asNormalizedText();
315 }
316 return resultObj.toString();
317 }
318 }