Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/datasource/xmldatasource.js
2868 views
1
// Copyright 2006 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview
17
* Implementations of DataNode for wrapping XML data.
18
*
19
*/
20
21
goog.provide('goog.ds.XmlDataSource');
22
goog.provide('goog.ds.XmlHttpDataSource');
23
24
goog.require('goog.Uri');
25
goog.require('goog.dom.NodeType');
26
goog.require('goog.dom.xml');
27
goog.require('goog.ds.BasicNodeList');
28
goog.require('goog.ds.DataManager');
29
goog.require('goog.ds.DataNode');
30
goog.require('goog.ds.LoadState');
31
goog.require('goog.ds.logger');
32
goog.require('goog.log');
33
goog.require('goog.net.XhrIo');
34
goog.require('goog.string');
35
36
37
38
/**
39
* Data source whose backing is an xml node
40
*
41
* @param {Node} node The XML node. Can be null.
42
* @param {goog.ds.XmlDataSource} parent Parent of XML element. Can be null.
43
* @param {string=} opt_name The name of this node relative to the parent node.
44
*
45
* @extends {goog.ds.DataNode}
46
* @constructor
47
*/
48
// TODO(arv): Use interfaces when available.
49
goog.ds.XmlDataSource = function(node, parent, opt_name) {
50
this.parent_ = parent;
51
this.dataName_ = opt_name || (node ? node.nodeName : '');
52
this.setNode_(node);
53
};
54
55
56
/**
57
* Constant to select XML attributes for getChildNodes
58
* @type {string}
59
* @private
60
*/
61
goog.ds.XmlDataSource.ATTRIBUTE_SELECTOR_ = '@*';
62
63
64
/**
65
* Set the current root nodeof the data source.
66
* Can be an attribute node, text node, or element node
67
* @param {Node} node The node. Can be null.
68
*
69
* @private
70
*/
71
goog.ds.XmlDataSource.prototype.setNode_ = function(node) {
72
this.node_ = node;
73
if (node != null) {
74
switch (node.nodeType) {
75
case goog.dom.NodeType.ATTRIBUTE:
76
case goog.dom.NodeType.TEXT:
77
this.value_ = node.nodeValue;
78
break;
79
case goog.dom.NodeType.ELEMENT:
80
if (node.childNodes.length == 1 &&
81
node.firstChild.nodeType == goog.dom.NodeType.TEXT) {
82
this.value_ = node.firstChild.nodeValue;
83
}
84
}
85
}
86
};
87
88
89
/**
90
* Creates the DataNodeList with the child nodes for this element.
91
* Allows for only building list as needed.
92
*
93
* @private
94
*/
95
goog.ds.XmlDataSource.prototype.createChildNodes_ = function() {
96
if (this.childNodeList_) {
97
return;
98
}
99
var childNodeList = new goog.ds.BasicNodeList();
100
if (this.node_ != null) {
101
var childNodes = this.node_.childNodes;
102
for (var i = 0, childNode; childNode = childNodes[i]; i++) {
103
if (childNode.nodeType != goog.dom.NodeType.TEXT ||
104
!goog.ds.XmlDataSource.isEmptyTextNodeValue_(childNode.nodeValue)) {
105
var newNode =
106
new goog.ds.XmlDataSource(childNode, this, childNode.nodeName);
107
childNodeList.add(newNode);
108
}
109
}
110
}
111
this.childNodeList_ = childNodeList;
112
};
113
114
115
/**
116
* Creates the DataNodeList with the attributes for the element
117
* Allows for only building list as needed.
118
*
119
* @private
120
*/
121
goog.ds.XmlDataSource.prototype.createAttributes_ = function() {
122
if (this.attributes_) {
123
return;
124
}
125
var attributes = new goog.ds.BasicNodeList();
126
if (this.node_ != null && this.node_.attributes != null) {
127
var atts = this.node_.attributes;
128
for (var i = 0, att; att = atts[i]; i++) {
129
var newNode = new goog.ds.XmlDataSource(att, this, att.nodeName);
130
attributes.add(newNode);
131
}
132
}
133
this.attributes_ = attributes;
134
};
135
136
137
/**
138
* Get the value of the node
139
* @return {Object} The value of the node, or null if no value.
140
* @override
141
*/
142
goog.ds.XmlDataSource.prototype.get = function() {
143
this.createChildNodes_();
144
return this.value_;
145
};
146
147
148
/**
149
* Set the value of the node
150
* @param {*} value The new value of the node.
151
* @override
152
*/
153
goog.ds.XmlDataSource.prototype.set = function(value) {
154
throw Error('Can\'t set on XmlDataSource yet');
155
};
156
157
158
/** @override */
159
goog.ds.XmlDataSource.prototype.getChildNodes = function(opt_selector) {
160
if (opt_selector &&
161
opt_selector == goog.ds.XmlDataSource.ATTRIBUTE_SELECTOR_) {
162
this.createAttributes_();
163
return this.attributes_;
164
} else if (
165
opt_selector == null ||
166
opt_selector == goog.ds.STR_ALL_CHILDREN_SELECTOR) {
167
this.createChildNodes_();
168
return this.childNodeList_;
169
} else {
170
throw Error('Unsupported selector');
171
}
172
173
};
174
175
176
/**
177
* Gets a named child node of the current node
178
* @param {string} name The node name.
179
* @return {goog.ds.DataNode} The child node, or null if
180
* no node of this name exists.
181
* @override
182
*/
183
goog.ds.XmlDataSource.prototype.getChildNode = function(name) {
184
if (goog.string.startsWith(name, goog.ds.STR_ATTRIBUTE_START)) {
185
var att = this.node_.getAttributeNode(name.substring(1));
186
return att ? new goog.ds.XmlDataSource(att, this) : null;
187
} else {
188
return /** @type {goog.ds.DataNode} */ (this.getChildNodes().get(name));
189
}
190
};
191
192
193
/**
194
* Gets the value of a child node
195
* @param {string} name The node name.
196
* @return {*} The value of the node, or null if no value or the child node
197
* doesn't exist.
198
* @override
199
*/
200
goog.ds.XmlDataSource.prototype.getChildNodeValue = function(name) {
201
if (goog.string.startsWith(name, goog.ds.STR_ATTRIBUTE_START)) {
202
var node = this.node_.getAttributeNode(name.substring(1));
203
return node ? node.nodeValue : null;
204
} else {
205
var node = this.getChildNode(name);
206
return node ? node.get() : null;
207
}
208
};
209
210
211
/**
212
* Get the name of the node relative to the parent node
213
* @return {string} The name of the node.
214
* @override
215
*/
216
goog.ds.XmlDataSource.prototype.getDataName = function() {
217
return this.dataName_;
218
};
219
220
221
/**
222
* Setthe name of the node relative to the parent node
223
* @param {string} name The name of the node.
224
* @override
225
*/
226
goog.ds.XmlDataSource.prototype.setDataName = function(name) {
227
this.dataName_ = name;
228
};
229
230
231
/**
232
* Gets the a qualified data path to this node
233
* @return {string} The data path.
234
* @override
235
*/
236
goog.ds.XmlDataSource.prototype.getDataPath = function() {
237
var parentPath = '';
238
if (this.parent_) {
239
parentPath = this.parent_.getDataPath() +
240
(this.dataName_.indexOf(goog.ds.STR_ARRAY_START) != -1 ?
241
'' :
242
goog.ds.STR_PATH_SEPARATOR);
243
}
244
245
return parentPath + this.dataName_;
246
};
247
248
249
/**
250
* Load or reload the backing data for this node
251
* @override
252
*/
253
goog.ds.XmlDataSource.prototype.load = function() {
254
// Nothing to do
255
};
256
257
258
/**
259
* Gets the state of the backing data for this node
260
* @return {goog.ds.LoadState} The state.
261
* @override
262
*/
263
goog.ds.XmlDataSource.prototype.getLoadState = function() {
264
return this.node_ ? goog.ds.LoadState.LOADED : goog.ds.LoadState.NOT_LOADED;
265
};
266
267
268
/**
269
* Check whether a node is an empty text node. Nodes consisting of only white
270
* space (#x20, #xD, #xA, #x9) can generally be collapsed to a zero length
271
* text string.
272
* @param {string} str String to match.
273
* @return {boolean} True if string equates to empty text node.
274
* @private
275
*/
276
goog.ds.XmlDataSource.isEmptyTextNodeValue_ = function(str) {
277
return /^[\r\n\t ]*$/.test(str);
278
};
279
280
281
/**
282
* Creates an XML document with one empty node.
283
* Useful for places where you need a node that
284
* can be queried against.
285
*
286
* @return {Document} Document with one empty node.
287
* @private
288
*/
289
goog.ds.XmlDataSource.createChildlessDocument_ = function() {
290
return goog.dom.xml.createDocument('nothing');
291
};
292
293
294
295
/**
296
* Data source whose backing is an XMLHttpRequest,
297
*
298
* A URI of an empty string will mean that no request is made
299
* and the data source will be a single, empty node.
300
*
301
* @param {(string|goog.Uri)} uri URL of the XMLHttpRequest.
302
* @param {string} name Name of the datasource.
303
*
304
* implements goog.ds.XmlHttpDataSource.
305
* @constructor
306
* @extends {goog.ds.XmlDataSource}
307
* @final
308
*/
309
goog.ds.XmlHttpDataSource = function(uri, name) {
310
goog.ds.XmlDataSource.call(this, null, null, name);
311
if (uri) {
312
this.uri_ = new goog.Uri(uri);
313
} else {
314
this.uri_ = null;
315
}
316
};
317
goog.inherits(goog.ds.XmlHttpDataSource, goog.ds.XmlDataSource);
318
319
320
/**
321
* Default load state is NOT_LOADED
322
* @private
323
*/
324
goog.ds.XmlHttpDataSource.prototype.loadState_ = goog.ds.LoadState.NOT_LOADED;
325
326
327
/**
328
* Load or reload the backing data for this node.
329
* Fires the XMLHttpRequest
330
* @override
331
*/
332
goog.ds.XmlHttpDataSource.prototype.load = function() {
333
if (this.uri_) {
334
goog.log.info(
335
goog.ds.logger, 'Sending XML request for DataSource ' +
336
this.getDataName() + ' to ' + this.uri_);
337
this.loadState_ = goog.ds.LoadState.LOADING;
338
339
goog.net.XhrIo.send(this.uri_, goog.bind(this.complete_, this));
340
} else {
341
this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
342
this.loadState_ = goog.ds.LoadState.NOT_LOADED;
343
}
344
};
345
346
347
/**
348
* Gets the state of the backing data for this node
349
* @return {goog.ds.LoadState} The state.
350
* @override
351
*/
352
goog.ds.XmlHttpDataSource.prototype.getLoadState = function() {
353
return this.loadState_;
354
};
355
356
357
/**
358
* Handles the completion of an XhrIo request. Dispatches to success or load
359
* based on the result.
360
* @param {!goog.events.Event} e The XhrIo event object.
361
* @private
362
*/
363
goog.ds.XmlHttpDataSource.prototype.complete_ = function(e) {
364
var xhr = /** @type {goog.net.XhrIo} */ (e.target);
365
if (xhr && xhr.isSuccess()) {
366
this.success_(xhr);
367
} else {
368
this.failure_();
369
}
370
};
371
372
373
/**
374
* Success result. Checks whether valid XML was returned
375
* and sets the XML and loadstate.
376
*
377
* @param {!goog.net.XhrIo} xhr The successful XhrIo object.
378
* @private
379
*/
380
goog.ds.XmlHttpDataSource.prototype.success_ = function(xhr) {
381
goog.log.info(
382
goog.ds.logger, 'Got data for DataSource ' + this.getDataName());
383
var xml = xhr.getResponseXml();
384
385
// Fix for case where IE returns valid XML as text but
386
// doesn't parse by default
387
if (xml && !xml.hasChildNodes() && goog.isObject(xhr.getResponseText())) {
388
xml = goog.dom.xml.loadXml(xhr.getResponseText());
389
}
390
// Failure result
391
if (!xml || !xml.hasChildNodes()) {
392
this.loadState_ = goog.ds.LoadState.FAILED;
393
this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
394
} else {
395
this.loadState_ = goog.ds.LoadState.LOADED;
396
this.node_ = xml.documentElement;
397
}
398
399
if (this.getDataName()) {
400
goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());
401
}
402
};
403
404
405
/**
406
* Failure result
407
*
408
* @private
409
*/
410
goog.ds.XmlHttpDataSource.prototype.failure_ = function() {
411
goog.log.info(
412
goog.ds.logger,
413
'Data retrieve failed for DataSource ' + this.getDataName());
414
415
this.loadState_ = goog.ds.LoadState.FAILED;
416
this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
417
418
if (this.getDataName()) {
419
goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());
420
}
421
};
422
423