123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- // Copyright 2006 The Closure Library Authors. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS-IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- /**
- * @fileoverview
- * Implementations of DataNode for wrapping XML data.
- *
- */
- goog.provide('goog.ds.XmlDataSource');
- goog.provide('goog.ds.XmlHttpDataSource');
- goog.require('goog.Uri');
- goog.require('goog.dom.NodeType');
- goog.require('goog.dom.xml');
- goog.require('goog.ds.BasicNodeList');
- goog.require('goog.ds.DataManager');
- goog.require('goog.ds.DataNode');
- goog.require('goog.ds.LoadState');
- goog.require('goog.ds.logger');
- goog.require('goog.log');
- goog.require('goog.net.XhrIo');
- goog.require('goog.string');
- /**
- * Data source whose backing is an xml node
- *
- * @param {Node} node The XML node. Can be null.
- * @param {goog.ds.XmlDataSource} parent Parent of XML element. Can be null.
- * @param {string=} opt_name The name of this node relative to the parent node.
- *
- * @extends {goog.ds.DataNode}
- * @constructor
- */
- // TODO(arv): Use interfaces when available.
- goog.ds.XmlDataSource = function(node, parent, opt_name) {
- this.parent_ = parent;
- this.dataName_ = opt_name || (node ? node.nodeName : '');
- this.setNode_(node);
- };
- /**
- * Constant to select XML attributes for getChildNodes
- * @type {string}
- * @private
- */
- goog.ds.XmlDataSource.ATTRIBUTE_SELECTOR_ = '@*';
- /**
- * Set the current root nodeof the data source.
- * Can be an attribute node, text node, or element node
- * @param {Node} node The node. Can be null.
- *
- * @private
- */
- goog.ds.XmlDataSource.prototype.setNode_ = function(node) {
- this.node_ = node;
- if (node != null) {
- switch (node.nodeType) {
- case goog.dom.NodeType.ATTRIBUTE:
- case goog.dom.NodeType.TEXT:
- this.value_ = node.nodeValue;
- break;
- case goog.dom.NodeType.ELEMENT:
- if (node.childNodes.length == 1 &&
- node.firstChild.nodeType == goog.dom.NodeType.TEXT) {
- this.value_ = node.firstChild.nodeValue;
- }
- }
- }
- };
- /**
- * Creates the DataNodeList with the child nodes for this element.
- * Allows for only building list as needed.
- *
- * @private
- */
- goog.ds.XmlDataSource.prototype.createChildNodes_ = function() {
- if (this.childNodeList_) {
- return;
- }
- var childNodeList = new goog.ds.BasicNodeList();
- if (this.node_ != null) {
- var childNodes = this.node_.childNodes;
- for (var i = 0, childNode; childNode = childNodes[i]; i++) {
- if (childNode.nodeType != goog.dom.NodeType.TEXT ||
- !goog.ds.XmlDataSource.isEmptyTextNodeValue_(childNode.nodeValue)) {
- var newNode =
- new goog.ds.XmlDataSource(childNode, this, childNode.nodeName);
- childNodeList.add(newNode);
- }
- }
- }
- this.childNodeList_ = childNodeList;
- };
- /**
- * Creates the DataNodeList with the attributes for the element
- * Allows for only building list as needed.
- *
- * @private
- */
- goog.ds.XmlDataSource.prototype.createAttributes_ = function() {
- if (this.attributes_) {
- return;
- }
- var attributes = new goog.ds.BasicNodeList();
- if (this.node_ != null && this.node_.attributes != null) {
- var atts = this.node_.attributes;
- for (var i = 0, att; att = atts[i]; i++) {
- var newNode = new goog.ds.XmlDataSource(att, this, att.nodeName);
- attributes.add(newNode);
- }
- }
- this.attributes_ = attributes;
- };
- /**
- * Get the value of the node
- * @return {Object} The value of the node, or null if no value.
- * @override
- */
- goog.ds.XmlDataSource.prototype.get = function() {
- this.createChildNodes_();
- return this.value_;
- };
- /**
- * Set the value of the node
- * @param {*} value The new value of the node.
- * @override
- */
- goog.ds.XmlDataSource.prototype.set = function(value) {
- throw Error('Can\'t set on XmlDataSource yet');
- };
- /** @override */
- goog.ds.XmlDataSource.prototype.getChildNodes = function(opt_selector) {
- if (opt_selector &&
- opt_selector == goog.ds.XmlDataSource.ATTRIBUTE_SELECTOR_) {
- this.createAttributes_();
- return this.attributes_;
- } else if (
- opt_selector == null ||
- opt_selector == goog.ds.STR_ALL_CHILDREN_SELECTOR) {
- this.createChildNodes_();
- return this.childNodeList_;
- } else {
- throw Error('Unsupported selector');
- }
- };
- /**
- * Gets a named child node of the current node
- * @param {string} name The node name.
- * @return {goog.ds.DataNode} The child node, or null if
- * no node of this name exists.
- * @override
- */
- goog.ds.XmlDataSource.prototype.getChildNode = function(name) {
- if (goog.string.startsWith(name, goog.ds.STR_ATTRIBUTE_START)) {
- var att = this.node_.getAttributeNode(name.substring(1));
- return att ? new goog.ds.XmlDataSource(att, this) : null;
- } else {
- return /** @type {goog.ds.DataNode} */ (this.getChildNodes().get(name));
- }
- };
- /**
- * Gets the value of a child node
- * @param {string} name The node name.
- * @return {*} The value of the node, or null if no value or the child node
- * doesn't exist.
- * @override
- */
- goog.ds.XmlDataSource.prototype.getChildNodeValue = function(name) {
- if (goog.string.startsWith(name, goog.ds.STR_ATTRIBUTE_START)) {
- var node = this.node_.getAttributeNode(name.substring(1));
- return node ? node.nodeValue : null;
- } else {
- var node = this.getChildNode(name);
- return node ? node.get() : null;
- }
- };
- /**
- * Get the name of the node relative to the parent node
- * @return {string} The name of the node.
- * @override
- */
- goog.ds.XmlDataSource.prototype.getDataName = function() {
- return this.dataName_;
- };
- /**
- * Setthe name of the node relative to the parent node
- * @param {string} name The name of the node.
- * @override
- */
- goog.ds.XmlDataSource.prototype.setDataName = function(name) {
- this.dataName_ = name;
- };
- /**
- * Gets the a qualified data path to this node
- * @return {string} The data path.
- * @override
- */
- goog.ds.XmlDataSource.prototype.getDataPath = function() {
- var parentPath = '';
- if (this.parent_) {
- parentPath = this.parent_.getDataPath() +
- (this.dataName_.indexOf(goog.ds.STR_ARRAY_START) != -1 ?
- '' :
- goog.ds.STR_PATH_SEPARATOR);
- }
- return parentPath + this.dataName_;
- };
- /**
- * Load or reload the backing data for this node
- * @override
- */
- goog.ds.XmlDataSource.prototype.load = function() {
- // Nothing to do
- };
- /**
- * Gets the state of the backing data for this node
- * @return {goog.ds.LoadState} The state.
- * @override
- */
- goog.ds.XmlDataSource.prototype.getLoadState = function() {
- return this.node_ ? goog.ds.LoadState.LOADED : goog.ds.LoadState.NOT_LOADED;
- };
- /**
- * Check whether a node is an empty text node. Nodes consisting of only white
- * space (#x20, #xD, #xA, #x9) can generally be collapsed to a zero length
- * text string.
- * @param {string} str String to match.
- * @return {boolean} True if string equates to empty text node.
- * @private
- */
- goog.ds.XmlDataSource.isEmptyTextNodeValue_ = function(str) {
- return /^[\r\n\t ]*$/.test(str);
- };
- /**
- * Creates an XML document with one empty node.
- * Useful for places where you need a node that
- * can be queried against.
- *
- * @return {Document} Document with one empty node.
- * @private
- */
- goog.ds.XmlDataSource.createChildlessDocument_ = function() {
- return goog.dom.xml.createDocument('nothing');
- };
- /**
- * Data source whose backing is an XMLHttpRequest,
- *
- * A URI of an empty string will mean that no request is made
- * and the data source will be a single, empty node.
- *
- * @param {(string|goog.Uri)} uri URL of the XMLHttpRequest.
- * @param {string} name Name of the datasource.
- *
- * implements goog.ds.XmlHttpDataSource.
- * @constructor
- * @extends {goog.ds.XmlDataSource}
- * @final
- */
- goog.ds.XmlHttpDataSource = function(uri, name) {
- goog.ds.XmlDataSource.call(this, null, null, name);
- if (uri) {
- this.uri_ = new goog.Uri(uri);
- } else {
- this.uri_ = null;
- }
- };
- goog.inherits(goog.ds.XmlHttpDataSource, goog.ds.XmlDataSource);
- /**
- * Default load state is NOT_LOADED
- * @private
- */
- goog.ds.XmlHttpDataSource.prototype.loadState_ = goog.ds.LoadState.NOT_LOADED;
- /**
- * Load or reload the backing data for this node.
- * Fires the XMLHttpRequest
- * @override
- */
- goog.ds.XmlHttpDataSource.prototype.load = function() {
- if (this.uri_) {
- goog.log.info(
- goog.ds.logger, 'Sending XML request for DataSource ' +
- this.getDataName() + ' to ' + this.uri_);
- this.loadState_ = goog.ds.LoadState.LOADING;
- goog.net.XhrIo.send(this.uri_, goog.bind(this.complete_, this));
- } else {
- this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
- this.loadState_ = goog.ds.LoadState.NOT_LOADED;
- }
- };
- /**
- * Gets the state of the backing data for this node
- * @return {goog.ds.LoadState} The state.
- * @override
- */
- goog.ds.XmlHttpDataSource.prototype.getLoadState = function() {
- return this.loadState_;
- };
- /**
- * Handles the completion of an XhrIo request. Dispatches to success or load
- * based on the result.
- * @param {!goog.events.Event} e The XhrIo event object.
- * @private
- */
- goog.ds.XmlHttpDataSource.prototype.complete_ = function(e) {
- var xhr = /** @type {goog.net.XhrIo} */ (e.target);
- if (xhr && xhr.isSuccess()) {
- this.success_(xhr);
- } else {
- this.failure_();
- }
- };
- /**
- * Success result. Checks whether valid XML was returned
- * and sets the XML and loadstate.
- *
- * @param {!goog.net.XhrIo} xhr The successful XhrIo object.
- * @private
- */
- goog.ds.XmlHttpDataSource.prototype.success_ = function(xhr) {
- goog.log.info(
- goog.ds.logger, 'Got data for DataSource ' + this.getDataName());
- var xml = xhr.getResponseXml();
- // Fix for case where IE returns valid XML as text but
- // doesn't parse by default
- if (xml && !xml.hasChildNodes() && goog.isObject(xhr.getResponseText())) {
- xml = goog.dom.xml.loadXml(xhr.getResponseText());
- }
- // Failure result
- if (!xml || !xml.hasChildNodes()) {
- this.loadState_ = goog.ds.LoadState.FAILED;
- this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
- } else {
- this.loadState_ = goog.ds.LoadState.LOADED;
- this.node_ = xml.documentElement;
- }
- if (this.getDataName()) {
- goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());
- }
- };
- /**
- * Failure result
- *
- * @private
- */
- goog.ds.XmlHttpDataSource.prototype.failure_ = function() {
- goog.log.info(
- goog.ds.logger,
- 'Data retrieve failed for DataSource ' + this.getDataName());
- this.loadState_ = goog.ds.LoadState.FAILED;
- this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
- if (this.getDataName()) {
- goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());
- }
- };
|