Adding float-no-zero branch hosted build
This commit is contained in:
544
float-no-zero/closure-library/closure/goog/datasource/expr.js
Normal file
544
float-no-zero/closure-library/closure/goog/datasource/expr.js
Normal file
@@ -0,0 +1,544 @@
|
||||
// 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
|
||||
* Expression evaluation utilities. Expression format is very similar to XPath.
|
||||
*
|
||||
* Expression details:
|
||||
* - Of format A/B/C, which will evaluate getChildNode('A').getChildNode('B').
|
||||
* getChildNodes('C')|getChildNodeValue('C')|getChildNode('C') depending on
|
||||
* call
|
||||
* - If expression ends with '/name()', will get the name() of the node
|
||||
* referenced by the preceding path.
|
||||
* - If expression ends with '/count()', will get the count() of the nodes that
|
||||
* match the expression referenced by the preceding path.
|
||||
* - If expression ends with '?', the value is OK to evaluate to null. This is
|
||||
* not enforced by the expression evaluation functions, instead it is
|
||||
* provided as a flag for client code which may ignore depending on usage
|
||||
* - If expression has [INDEX], will use getChildNodes().getByIndex(INDEX)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.ds.Expr');
|
||||
|
||||
goog.require('goog.ds.BasicNodeList');
|
||||
goog.require('goog.ds.EmptyNodeList');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new expression. An expression uses a string expression language, and
|
||||
* from this string and a passed in DataNode can evaluate to a value, DataNode,
|
||||
* or a DataNodeList.
|
||||
*
|
||||
* @param {string=} opt_expr The string expression.
|
||||
* @constructor
|
||||
*/
|
||||
goog.ds.Expr = function(opt_expr) {
|
||||
if (opt_expr) {
|
||||
this.setSource_(opt_expr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the source expression text & parse
|
||||
*
|
||||
* @param {string} expr The string expression source.
|
||||
* @param {Array=} opt_parts Array of the parts of an expression.
|
||||
* @param {goog.ds.Expr=} opt_childExpr Optional child of this expression,
|
||||
* passed in as a hint for processing.
|
||||
* @param {goog.ds.Expr=} opt_prevExpr Optional preceding expression
|
||||
* (i.e. $A/B/C is previous expression to B/C) passed in as a hint for
|
||||
* processing.
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.setSource_ = function(expr, opt_parts,
|
||||
opt_childExpr, opt_prevExpr) {
|
||||
this.src_ = expr;
|
||||
|
||||
if (!opt_childExpr && !opt_prevExpr) {
|
||||
// Check whether it can be empty
|
||||
if (goog.string.endsWith(expr, goog.ds.Expr.String_.CAN_BE_EMPTY)) {
|
||||
this.canBeEmpty_ = true;
|
||||
expr = expr.substring(0, expr.length - 1);
|
||||
}
|
||||
|
||||
// Check whether this is an node function
|
||||
if (goog.string.endsWith(expr, '()')) {
|
||||
if (goog.string.endsWith(expr, goog.ds.Expr.String_.NAME_EXPR) ||
|
||||
goog.string.endsWith(expr, goog.ds.Expr.String_.COUNT_EXPR) ||
|
||||
goog.string.endsWith(expr, goog.ds.Expr.String_.POSITION_EXPR)) {
|
||||
var lastPos = expr.lastIndexOf(goog.ds.Expr.String_.SEPARATOR);
|
||||
if (lastPos != -1) {
|
||||
this.exprFn_ = expr.substring(lastPos + 1);
|
||||
expr = expr.substring(0, lastPos);
|
||||
} else {
|
||||
this.exprFn_ = expr;
|
||||
expr = goog.ds.Expr.String_.CURRENT_NODE_EXPR;
|
||||
}
|
||||
if (this.exprFn_ == goog.ds.Expr.String_.COUNT_EXPR) {
|
||||
this.isCount_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Split into component parts
|
||||
this.parts_ = opt_parts || expr.split('/');
|
||||
this.size_ = this.parts_.length;
|
||||
this.last_ = this.parts_[this.size_ - 1];
|
||||
this.root_ = this.parts_[0];
|
||||
|
||||
if (this.size_ == 1) {
|
||||
this.rootExpr_ = this;
|
||||
this.isAbsolute_ = goog.string.startsWith(expr, '$');
|
||||
} else {
|
||||
this.rootExpr_ = goog.ds.Expr.createInternal_(this.root_, null,
|
||||
this, null);
|
||||
this.isAbsolute_ = this.rootExpr_.isAbsolute_;
|
||||
this.root_ = this.rootExpr_.root_;
|
||||
}
|
||||
|
||||
if (this.size_ == 1 && !this.isAbsolute_) {
|
||||
// Check whether expression maps to current node, for convenience
|
||||
this.isCurrent_ = (expr == goog.ds.Expr.String_.CURRENT_NODE_EXPR ||
|
||||
expr == goog.ds.Expr.String_.EMPTY_EXPR);
|
||||
|
||||
// Whether this expression is just an attribute (i.e. '@foo')
|
||||
this.isJustAttribute_ =
|
||||
goog.string.startsWith(expr, goog.ds.Expr.String_.ATTRIBUTE_START);
|
||||
|
||||
// Check whether this is a common node expression
|
||||
this.isAllChildNodes_ = expr == goog.ds.Expr.String_.ALL_CHILD_NODES_EXPR;
|
||||
this.isAllAttributes_ = expr == goog.ds.Expr.String_.ALL_ATTRIBUTES_EXPR;
|
||||
this.isAllElements_ = expr == goog.ds.Expr.String_.ALL_ELEMENTS_EXPR;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the source data path for the expression
|
||||
* @return {string} The path.
|
||||
*/
|
||||
goog.ds.Expr.prototype.getSource = function() {
|
||||
return this.src_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the last part of the expression.
|
||||
* @return {?string} Last part of the expression.
|
||||
*/
|
||||
goog.ds.Expr.prototype.getLast = function() {
|
||||
return this.last_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the parent expression of this expression, or null if this is top level
|
||||
* @return {goog.ds.Expr} The parent.
|
||||
*/
|
||||
goog.ds.Expr.prototype.getParent = function() {
|
||||
if (!this.parentExprSet_) {
|
||||
if (this.size_ > 1) {
|
||||
this.parentExpr_ = goog.ds.Expr.createInternal_(null,
|
||||
this.parts_.slice(0, this.parts_.length - 1), this, null);
|
||||
}
|
||||
this.parentExprSet_ = true;
|
||||
}
|
||||
return this.parentExpr_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the parent expression of this expression, or null if this is top level
|
||||
* @return {goog.ds.Expr} The parent.
|
||||
*/
|
||||
goog.ds.Expr.prototype.getNext = function() {
|
||||
if (!this.nextExprSet_) {
|
||||
if (this.size_ > 1) {
|
||||
this.nextExpr_ = goog.ds.Expr.createInternal_(null, this.parts_.slice(1),
|
||||
null, this);
|
||||
}
|
||||
this.nextExprSet_ = true;
|
||||
}
|
||||
return this.nextExpr_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate an expression on a data node, and return a value
|
||||
* Recursively walks through child nodes to evaluate
|
||||
* TODO(user) Support other expression functions
|
||||
*
|
||||
* @param {goog.ds.DataNode=} opt_ds Optional datasource to evaluate against.
|
||||
* If not provided, evaluates against DataManager global root.
|
||||
* @return {*} Value of the node, or null if doesn't exist.
|
||||
*/
|
||||
goog.ds.Expr.prototype.getValue = function(opt_ds) {
|
||||
if (opt_ds == null) {
|
||||
opt_ds = goog.ds.DataManager.getInstance();
|
||||
} else if (this.isAbsolute_) {
|
||||
opt_ds = opt_ds.getDataRoot ? opt_ds.getDataRoot() :
|
||||
goog.ds.DataManager.getInstance();
|
||||
}
|
||||
|
||||
if (this.isCount_) {
|
||||
var nodes = this.getNodes(opt_ds);
|
||||
return nodes.getCount();
|
||||
}
|
||||
|
||||
if (this.size_ == 1) {
|
||||
return opt_ds.getChildNodeValue(this.root_);
|
||||
} else if (this.size_ == 0) {
|
||||
return opt_ds.get();
|
||||
}
|
||||
|
||||
var nextDs = opt_ds.getChildNode(this.root_);
|
||||
|
||||
if (nextDs == null) {
|
||||
return null;
|
||||
} else {
|
||||
return this.getNext().getValue(nextDs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate an expression on a data node, and return matching nodes
|
||||
* Recursively walks through child nodes to evaluate
|
||||
*
|
||||
* @param {goog.ds.DataNode=} opt_ds Optional datasource to evaluate against.
|
||||
* If not provided, evaluates against data root.
|
||||
* @param {boolean=} opt_canCreate If true, will try to create new nodes.
|
||||
* @return {goog.ds.DataNodeList} Matching nodes.
|
||||
*/
|
||||
goog.ds.Expr.prototype.getNodes = function(opt_ds, opt_canCreate) {
|
||||
return /** @type {goog.ds.DataNodeList} */(this.getNodes_(opt_ds,
|
||||
false, opt_canCreate));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate an expression on a data node, and return the first matching node
|
||||
* Recursively walks through child nodes to evaluate
|
||||
*
|
||||
* @param {goog.ds.DataNode=} opt_ds Optional datasource to evaluate against.
|
||||
* If not provided, evaluates against DataManager global root.
|
||||
* @param {boolean=} opt_canCreate If true, will try to create new nodes.
|
||||
* @return {goog.ds.DataNode} Matching nodes, or null if doesn't exist.
|
||||
*/
|
||||
goog.ds.Expr.prototype.getNode = function(opt_ds, opt_canCreate) {
|
||||
return /** @type {goog.ds.DataNode} */(this.getNodes_(opt_ds,
|
||||
true, opt_canCreate));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate an expression on a data node, and return the first matching node
|
||||
* Recursively walks through child nodes to evaluate
|
||||
*
|
||||
* @param {goog.ds.DataNode=} opt_ds Optional datasource to evaluate against.
|
||||
* If not provided, evaluates against DataManager global root.
|
||||
* @param {boolean=} opt_selectOne Whether to return single matching DataNode
|
||||
* or matching nodes in DataNodeList.
|
||||
* @param {boolean=} opt_canCreate If true, will try to create new nodes.
|
||||
* @return {goog.ds.DataNode|goog.ds.DataNodeList} Matching node or nodes,
|
||||
* depending on value of opt_selectOne.
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.getNodes_ = function(opt_ds, opt_selectOne,
|
||||
opt_canCreate) {
|
||||
if (opt_ds == null) {
|
||||
opt_ds = goog.ds.DataManager.getInstance();
|
||||
} else if (this.isAbsolute_) {
|
||||
opt_ds = opt_ds.getDataRoot ? opt_ds.getDataRoot() :
|
||||
goog.ds.DataManager.getInstance();
|
||||
}
|
||||
|
||||
if (this.size_ == 0 && opt_selectOne) {
|
||||
return opt_ds;
|
||||
} else if (this.size_ == 0 && !opt_selectOne) {
|
||||
return new goog.ds.BasicNodeList([opt_ds]);
|
||||
} else if (this.size_ == 1) {
|
||||
if (opt_selectOne) {
|
||||
return opt_ds.getChildNode(this.root_, opt_canCreate);
|
||||
}
|
||||
else {
|
||||
var possibleListChild = opt_ds.getChildNode(this.root_);
|
||||
if (possibleListChild && possibleListChild.isList()) {
|
||||
return possibleListChild.getChildNodes();
|
||||
} else {
|
||||
return opt_ds.getChildNodes(this.root_);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var nextDs = opt_ds.getChildNode(this.root_, opt_canCreate);
|
||||
if (nextDs == null && opt_selectOne) {
|
||||
return null;
|
||||
} else if (nextDs == null && !opt_selectOne) {
|
||||
return new goog.ds.EmptyNodeList();
|
||||
}
|
||||
return this.getNext().getNodes_(nextDs, opt_selectOne, opt_canCreate);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the expression can be null.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.canBeEmpty_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* The parsed paths in the expression
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.parts_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* Number of paths in the expression
|
||||
*
|
||||
* @type {?number}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.size_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* The root node path in the expression
|
||||
*
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.root_;
|
||||
|
||||
|
||||
/**
|
||||
* The last path in the expression
|
||||
*
|
||||
* @type {?string}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.last_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the expression evaluates to current node
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.isCurrent_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the expression is just an attribute
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.isJustAttribute_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* Does this expression select all DOM-style child nodes (element and text)
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.isAllChildNodes_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* Does this expression select all DOM-style attribute nodes (starts with '@')
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.isAllAttributes_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* Does this expression select all DOM-style element child nodes
|
||||
*
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.isAllElements_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* The function used by this expression
|
||||
*
|
||||
* @type {?string}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.exprFn_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Cached value for the parent expression.
|
||||
* @type {goog.ds.Expr?}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.parentExpr_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Cached value for the next expression.
|
||||
* @type {goog.ds.Expr?}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.prototype.nextExpr_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Create an expression from a string, can use cached values
|
||||
*
|
||||
* @param {string} expr The expression string.
|
||||
* @return {goog.ds.Expr} The expression object.
|
||||
*/
|
||||
goog.ds.Expr.create = function(expr) {
|
||||
var result = goog.ds.Expr.cache_[expr];
|
||||
|
||||
if (result == null) {
|
||||
result = new goog.ds.Expr(expr);
|
||||
goog.ds.Expr.cache_[expr] = result;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create an expression from a string, can use cached values
|
||||
* Uses hints from related expressions to help in creation
|
||||
*
|
||||
* @param {?string=} opt_expr The string expression source.
|
||||
* @param {Array=} opt_parts Array of the parts of an expression.
|
||||
* @param {goog.ds.Expr=} opt_childExpr Optional child of this expression,
|
||||
* passed in as a hint for processing.
|
||||
* @param {goog.ds.Expr=} opt_prevExpr Optional preceding expression
|
||||
* (i.e. $A/B/C is previous expression to B/C) passed in as a hint for
|
||||
* processing.
|
||||
* @return {goog.ds.Expr} The expression object.
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.createInternal_ = function(opt_expr, opt_parts, opt_childExpr,
|
||||
opt_prevExpr) {
|
||||
var expr = opt_expr || opt_parts.join('/');
|
||||
var result = goog.ds.Expr.cache_[expr];
|
||||
|
||||
if (result == null) {
|
||||
result = new goog.ds.Expr();
|
||||
result.setSource_(expr, opt_parts, opt_childExpr, opt_prevExpr);
|
||||
goog.ds.Expr.cache_[expr] = result;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cache of pre-parsed expressions
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.cache_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Commonly used strings in expressions.
|
||||
* @enum {string}
|
||||
* @private
|
||||
*/
|
||||
goog.ds.Expr.String_ = {
|
||||
SEPARATOR: '/',
|
||||
CURRENT_NODE_EXPR: '.',
|
||||
EMPTY_EXPR: '',
|
||||
ATTRIBUTE_START: '@',
|
||||
ALL_CHILD_NODES_EXPR: '*|text()',
|
||||
ALL_ATTRIBUTES_EXPR: '@*',
|
||||
ALL_ELEMENTS_EXPR: '*',
|
||||
NAME_EXPR: 'name()',
|
||||
COUNT_EXPR: 'count()',
|
||||
POSITION_EXPR: 'position()',
|
||||
INDEX_START: '[',
|
||||
INDEX_END: ']',
|
||||
CAN_BE_EMPTY: '?'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Standard expressions
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* The current node
|
||||
*/
|
||||
goog.ds.Expr.CURRENT = goog.ds.Expr.create(
|
||||
goog.ds.Expr.String_.CURRENT_NODE_EXPR);
|
||||
|
||||
|
||||
/**
|
||||
* For DOM interop - all DOM child nodes (text + element).
|
||||
* Text nodes have dataName #text
|
||||
*/
|
||||
goog.ds.Expr.ALL_CHILD_NODES =
|
||||
goog.ds.Expr.create(goog.ds.Expr.String_.ALL_CHILD_NODES_EXPR);
|
||||
|
||||
|
||||
/**
|
||||
* For DOM interop - all DOM element child nodes
|
||||
*/
|
||||
goog.ds.Expr.ALL_ELEMENTS =
|
||||
goog.ds.Expr.create(goog.ds.Expr.String_.ALL_ELEMENTS_EXPR);
|
||||
|
||||
|
||||
/**
|
||||
* For DOM interop - all DOM attribute nodes
|
||||
* Attribute nodes have dataName starting with "@"
|
||||
*/
|
||||
goog.ds.Expr.ALL_ATTRIBUTES =
|
||||
goog.ds.Expr.create(goog.ds.Expr.String_.ALL_ATTRIBUTES_EXPR);
|
||||
|
||||
|
||||
/**
|
||||
* Get the dataName of a node
|
||||
*/
|
||||
goog.ds.Expr.NAME = goog.ds.Expr.create(goog.ds.Expr.String_.NAME_EXPR);
|
||||
|
||||
|
||||
/**
|
||||
* Get the count of nodes matching an expression
|
||||
*/
|
||||
goog.ds.Expr.COUNT = goog.ds.Expr.create(goog.ds.Expr.String_.COUNT_EXPR);
|
||||
|
||||
|
||||
/**
|
||||
* Get the position of the "current" node in the current node list
|
||||
* This will only apply for datasources that support the concept of a current
|
||||
* node (none exist yet). This is similar to XPath position() and concept of
|
||||
* current node
|
||||
*/
|
||||
goog.ds.Expr.POSITION = goog.ds.Expr.create(goog.ds.Expr.String_.POSITION_EXPR);
|
||||
Reference in New Issue
Block a user