📄 gdata_condensed.js
字号:
return XMLX_parse(xmlNode, xpath); } } catch (e) { // LOG_XML_PRINT(xmlNode); // this is everyone else LOG_DEBUG("XML_getNodes: catch path - " + e.toString()); return XMLX_parse(xmlNode, xpath); }};/** * helper method to call the javascript parser*/function XMLX_parse(xmlNode, xpath) { LOG_DEBUG("XML_parse: no xpath support, hence i am here"); var expr = xpathParse(xpath); var ctx = new ExprContext(xmlNode); var ret = expr.evaluate(ctx); return ret.nodeSetValue();}/*** @param xmlNode the node to search from* @xpath the xpath to search for* @return the first xmlnode found*/function XMLX_getNode(xmlNode, xpath) { var result = XMLX_getNodes(xmlNode, xpath); if (result) { return result[0]; } return null; }// remove this if you merge if (window.GD_Loader) { // continue loading window.GD_Loader();}// end/* Copyright (c) 2006 Google Inc. * * 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. */// All Rights Reserved//// An XPath parser and evaluator written in JavaScript. The// implementation is complete except for functions handling// namespaces.//// Reference: [XPATH] XPath Specification// <http://www.w3.org/TR/1999/REC-xpath-19991116>.////// The API of the parser has several parts://// 1. The parser function xpathParse() that takes a string and returns// an expession object.//// 2. The expression object that has an evaluate() method to evaluate the// XPath expression it represents. (It is actually a hierarchy of// objects that resembles the parse tree, but an application will call// evaluate() only on the top node of this hierarchy.)//// 3. The context object that is passed as an argument to the evaluate()// method, which represents the DOM context in which the expression is// evaluated.//// 4. The value object that is returned from evaluate() and represents// values of the different types that are defined by XPath (number,// string, boolean, and node-set), and allows to convert between them.//// These parts are near the top of the file, the functions and data// that are used internally follow after them.//function assert(condition) { DBG_ASSERT(condition); }// The entry point for the parser.//// @param expr a string that contains an XPath expression.// @return an expression object that can be evaluated with an// expression context.// right now, only used for safarifunction xpathParse(expr) { LOG_DEBUG('XPath parse ' + expr); xpathParseInit(); var cached = xpathCacheLookup(expr); if (cached) { LOG_DEBUG('XPath ....cached '); return cached; } // Optimize for a few common cases: simple attribute node tests // (@id), simple element node tests (page), variable references // ($address), numbers (4), multi-step path expressions where each // step is a plain element node test // (page/overlay/locations/location). if (expr.match(/^(\$|@)?\w+$/i)) { var ret = makeSimpleExpr(expr); xpathParseCache[expr] = ret; LOG_DEBUG('XPath ... simple'); return ret; } if (expr.match(/^\w+(\/\w+)*$/i)) { ret = makeSimpleExpr2(expr); xpathParseCache[expr] = ret; LOG_DEBUG('XPath ... simple 2 '); return ret; } var cachekey = expr; // expr is modified during parse var stack = []; var ahead = null; var previous = null; var done = false; var parse_count = 0; var lexer_count = 0; var reduce_count = 0; while (!done) { parse_count+=1; expr = expr.replace(/^\s*/, ''); previous = ahead; ahead = null; var rule = null; var match = ''; for (var i = 0; i < xpathTokenRules.length; ++i) { var result = xpathTokenRules[i].re.exec(expr); lexer_count+=1; if (result && result.length > 0 && result[0].length > match.length) { rule = xpathTokenRules[i]; match = result[0]; break; } } // Special case: allow operator keywords to be element and // variable names. // NOTE: The parser resolves conflicts by looking ahead, // and this is the only case where we look back to // disambiguate. So this is indeed something different, and // looking back is usually done in the lexer (via states in the // general case, called "start conditions" in flex(1)). Also,the // conflict resolution in the parser is not as robust as it could // be, so I'd like to keep as much off the parser as possible (all // these precedence values should be computed from the grammar // rules and possibly associativity declarations, as in bison(1), // and not explicitly set. if (rule && (rule == TOK_DIV || rule == TOK_MOD || rule == TOK_AND || rule == TOK_OR) && (!previous || previous.tag == TOK_AT || previous.tag == TOK_DSLASH || previous.tag == TOK_SLASH || previous.tag == TOK_AXIS || previous.tag == TOK_DOLLAR)) { rule = TOK_QNAME; } if (rule) { expr = expr.substr(match.length); LOG_DEBUG('XPath token: parse ' + match + ' -- ' + rule.label); ahead = { tag: rule, match: match, prec: rule.prec ? rule.prec : 0, // || 0 is removed by the compiler expr: makeTokenExpr(match) }; } else { LOG_DEBUG('XPath DONE'); done = true; } while (xpathReduce(stack, ahead)) { reduce_count+=1; LOG_DEBUG('XPATH stack: ' + stackToString(stack)); } } LOG_DEBUG('XPATH stack:' + stackToString(stack)); if (stack.length != 1) { throw 'XPath parse error ' + cachekey + ':\n' + stackToString(stack); } result = stack[0].expr; xpathParseCache[cachekey] = result; LOG_DEBUG('XPath parse: ' + parse_count + ' / ' + lexer_count + ' / ' + reduce_count); return result;}var xpathParseCache = {};function xpathCacheLookup(expr) { return xpathParseCache[expr];}function xpathReduce(stack, ahead) { var cand = null; if (stack.length > 0) { var top = stack[stack.length-1]; var ruleset = xpathRules[top.tag.key]; if (ruleset) { for (var i = 0; i < ruleset.length; ++i) { var rule = ruleset[i]; var match = xpathMatchStack(stack, rule[1]); if (match.length) { cand = { tag: rule[0], rule: rule, match: match }; cand.prec = xpathGrammarPrecedence(cand); break; } } } } var ret; if (cand && (!ahead || cand.prec > ahead.prec || (ahead.tag.left && cand.prec >= ahead.prec))) { for (i = 0; i < cand.match.matchlength; ++i) { stack.pop(); } LOG_DEBUG('reduce ' + cand.tag.label + ' ' + cand.prec + ' ahead ' + (ahead ? ahead.tag.label + ' ' + ahead.prec + (ahead.tag.left ? ' left' : '') : ' none ')); var matchexpr = UTIL_mapExpr(cand.match, function(m) { return m.expr; }); cand.expr = cand.rule[3].apply(null, matchexpr); stack.push(cand); ret = true; } else { if (ahead) { LOG_DEBUG('shift ' + ahead.tag.label + ' ' + ahead.prec + (ahead.tag.left ? ' left' : '') + ' over ' + (cand ? cand.tag.label + ' ' + cand.prec : ' none')); stack.push(ahead); } ret = false; } return ret;}function xpathMatchStack(stack, pattern) { // NOTE: The stack matches for variable cardinality are // greedy but don't do backtracking. This would be an issue only // with rules of the form A* A, i.e. with an element with variable // cardinality followed by the same element. Since that doesn't // occur in the grammar at hand, all matches on the stack are // unambiguous. var S = stack.length; var P = pattern.length; var p, s; var match = []; match.matchlength = 0; var ds = 0; for (p = P - 1, s = S - 1; p >= 0 && s >= 0; --p, s -= ds) { ds = 0; var qmatch = []; if (pattern[p] == Q_MM) { p -= 1; match.push(qmatch); while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) { qmatch.push(stack[s - ds]); ds += 1; match.matchlength += 1; } } else if (pattern[p] == Q_01) { p -= 1; match.push(qmatch); while (s - ds >= 0 && ds < 2 && stack[s - ds].tag == pattern[p]) { qmatch.push(stack[s - ds]); ds += 1; match.matchlength += 1; } } else if (pattern[p] == Q_1M) { p -= 1; match.push(qmatch); if (stack[s].tag == pattern[p]) { while (s - ds >= 0 && stack[s - ds].tag == pattern[p]) { qmatch.push(stack[s - ds]); ds += 1; match.matchlength += 1; } } else { return []; } } else if (stack[s].tag == pattern[p]) { match.push(stack[s]); ds += 1; match.matchlength += 1; } else { return []; } UTIL_reverseInplace(qmatch); qmatch.expr = UTIL_mapExpr(qmatch, function(m) { return m.expr; }); } UTIL_reverseInplace(match); if (p == -1) { return match; } else { return []; }}function xpathTokenPrecedence(tag) { return tag.prec || 2;}function xpathGrammarPrecedence(frame) { var ret = 0; if (frame.rule) { /* normal reduce */ if (frame.rule.length >= 3 && frame.rule[2] >= 0) { ret = frame.rule[2]; } else { for (var i = 0; i < frame.rule[1].length; ++i) { var p = xpathTokenPrecedence(frame.rule[1][i]); ret = Math.max(ret, p); } } } else if (frame.tag) { /* TOKEN match */ ret = xpathTokenPrecedence(frame.tag); } else if (frame.length) { /* Q_ match */ for (var j = 0; j < frame.length; ++j) { var p = xpathGrammarPrecedence(frame[j]); ret = Math.max(ret, p); } } return ret;}function stackToString(stack) { var ret = ''; for (var i = 0; i < stack.length; ++i) { if (ret) { ret += '\n'; } ret += stack[i].tag.label; } return ret;}// XPath expression evaluation context. An XPath context consists of a// DOM node, a list of DOM nodes that contains this node, a number// that represents the position of the single node in the list, and a// current set of variable bindings. (See XPath spec.)//// The interface of the expression context://// Constructor -- gets the node, its position, the node set it// belongs to, and a parent context as arguments. The parent context// is used to implement scoping rules for variables: if a variable// is not found in the current context, it is looked for in the// parent context, recursively. Except for node, all arguments have// default values: default position is 0, default node set is the// set that contains only the node, and the default parent is null.//// Notice that position starts at 0 at the outside interface;// inside XPath expressions this shows up as position()=1.//// clone() -- creates a new context with the current context as// parent. If passed as argument to clone(), the new context has a// different node, position, or node set. What is not passed is// inherited from the cloned context.//// setVariable(name, expr) -- binds given XPath expression to the// name.//// getVariable(name) -- what the name says.//// setNode(node, position) -- sets the context to the new node and// its corresponding position. Needed to implement scoping rules for// variables in XPath. (A variable is visible to all subsequent// siblings, not only to its children.)function ExprContext(node, position, nodelist, parent) { this.node = node; this.position = position || 0; this.nodelist = nodelist || [ node ]; this.variables = {}; this.parent = parent || null; if (parent) { this.root = parent.root; } else if (this.node.nodeType == DOM_DOCUMENT_NODE) { // NOTE: DOM Spec stipulates that the ownerDocument of a // document is null. Our root, however is the document that we are // processing, so the initial context is created from its document // node, which case we must handle here explcitly. this.root = node; } else { this.root = node.ownerDocument; }}ExprContext.prototype.clone = function(node, position, nodelist) { return new ExprContext( node || this.node, typeof position != 'undefined' ? position : this.position, nodelist || this.nodelist, this);};ExprContext.prototype.setVariable = function(name, value) { this.variables[name] = value;};ExprContext.prototype.getVariable = function(name) { if (typeof this.variables[name] != 'undefined') { return this.variables[name]; } else if (this.parent) { return this.parent.getVariable(name); } else { return null; }}ExprContext.prototype.setNode = function(node, position) { this.node = node; this.position = position;}// XPath expression values. They are what XPath expressions evaluate
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -