📄 xpath.js
字号:
return new NumberValue(Math.round(num)); }, // TODO(mesch): The following functions are custom. There is a // standard that defines how to add functions, which should be // applied here. 'ext-join': function(ctx) { assert(this.args.length == 2); var nodes = this.args[0].evaluate(ctx).nodeSetValue(); var delim = this.args[1].evaluate(ctx).stringValue(); var ret = ''; for (var i = 0; i < nodes.length; ++i) { if (ret) { ret += delim; } ret += xmlValue(nodes[i]); } return new StringValue(ret); }, // ext-if() evaluates and returns its second argument, if the // boolean value of its first argument is true, otherwise it // evaluates and returns its third argument. 'ext-if': function(ctx) { assert(this.args.length == 3); if (this.args[0].evaluate(ctx).booleanValue()) { return this.args[1].evaluate(ctx); } else { return this.args[2].evaluate(ctx); } }, 'ext-sprintf': function(ctx) { assert(this.args.length >= 1); var args = []; for (var i = 0; i < this.args.length; ++i) { args.push(this.args[i].evaluate(ctx).stringValue()); } return new StringValue(sprintf.apply(null, args)); }, // ext-cardinal() evaluates its single argument as a number, and // returns the current node that many times. It can be used in the // select attribute to iterate over an integer range. 'ext-cardinal': function(ctx) { assert(this.args.length >= 1); var c = this.args[0].evaluate(ctx).numberValue(); var ret = []; for (var i = 0; i < c; ++i) { ret.push(ctx.node); } return new NodeSetValue(ret); }};function UnionExpr(expr1, expr2) { this.expr1 = expr1; this.expr2 = expr2;}UnionExpr.prototype.evaluate = function(ctx) { var nodes1 = this.expr1.evaluate(ctx).nodeSetValue(); var nodes2 = this.expr2.evaluate(ctx).nodeSetValue(); var I1 = nodes1.length; for (var i2 = 0; i2 < nodes2.length; ++i2) { for (var i1 = 0; i1 < I1; ++i1) { if (nodes1[i1] == nodes2[i2]) { // break inner loop and continue outer loop, labels confuse // the js compiler, so we don't use them here. i1 = I1; } } nodes1.push(nodes2[i2]); } return new NodeSetValue(nodes2);};function PathExpr(filter, rel) { this.filter = filter; this.rel = rel;}PathExpr.prototype.evaluate = function(ctx) { var nodes = this.filter.evaluate(ctx).nodeSetValue(); var nodes1 = []; for (var i = 0; i < nodes.length; ++i) { var nodes0 = this.rel.evaluate(ctx.clone(nodes[i], i, nodes)).nodeSetValue(); for (var ii = 0; ii < nodes0.length; ++ii) { nodes1.push(nodes0[ii]); } } return new NodeSetValue(nodes1);};function FilterExpr(expr, predicate) { this.expr = expr; this.predicate = predicate;}FilterExpr.prototype.evaluate = function(ctx) { var nodes = this.expr.evaluate(ctx).nodeSetValue(); for (var i = 0; i < this.predicate.length; ++i) { var nodes0 = nodes; nodes = []; for (var j = 0; j < nodes0.length; ++j) { var n = nodes0[j]; if (this.predicate[i].evaluate(ctx.clone(n, j, nodes0)).booleanValue()) { nodes.push(n); } } } return new NodeSetValue(nodes);}function UnaryMinusExpr(expr) { this.expr = expr;}UnaryMinusExpr.prototype.evaluate = function(ctx) { return new NumberValue(-this.expr.evaluate(ctx).numberValue());};function BinaryExpr(expr1, op, expr2) { this.expr1 = expr1; this.expr2 = expr2; this.op = op;}BinaryExpr.prototype.evaluate = function(ctx) { var ret; switch (this.op.value) { case 'or': ret = new BooleanValue(this.expr1.evaluate(ctx).booleanValue() || this.expr2.evaluate(ctx).booleanValue()); break; case 'and': ret = new BooleanValue(this.expr1.evaluate(ctx).booleanValue() && this.expr2.evaluate(ctx).booleanValue()); break; case '+': ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() + this.expr2.evaluate(ctx).numberValue()); break; case '-': ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() - this.expr2.evaluate(ctx).numberValue()); break; case '*': ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() * this.expr2.evaluate(ctx).numberValue()); break; case 'mod': ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() % this.expr2.evaluate(ctx).numberValue()); break; case 'div': ret = new NumberValue(this.expr1.evaluate(ctx).numberValue() / this.expr2.evaluate(ctx).numberValue()); break; case '=': ret = this.compare(ctx, function(x1, x2) { return x1 == x2; }); break; case '!=': ret = this.compare(ctx, function(x1, x2) { return x1 != x2; }); break; case '<': ret = this.compare(ctx, function(x1, x2) { return x1 < x2; }); break; case '<=': ret = this.compare(ctx, function(x1, x2) { return x1 <= x2; }); break; case '>': ret = this.compare(ctx, function(x1, x2) { return x1 > x2; }); break; case '>=': ret = this.compare(ctx, function(x1, x2) { return x1 >= x2; }); break; default: alert('BinaryExpr.evaluate: ' + this.op.value); } return ret;};BinaryExpr.prototype.compare = function(ctx, cmp) { var v1 = this.expr1.evaluate(ctx); var v2 = this.expr2.evaluate(ctx); var ret; if (v1.type == 'node-set' && v2.type == 'node-set') { var n1 = v1.nodeSetValue(); var n2 = v2.nodeSetValue(); ret = false; for (var i1 = 0; i1 < n1.length; ++i1) { for (var i2 = 0; i2 < n2.length; ++i2) { if (cmp(xmlValue(n1[i1]), xmlValue(n2[i2]))) { ret = true; // Break outer loop. Labels confuse the jscompiler and we // don't use them. i2 = n2.length; i1 = n1.length; } } } } else if (v1.type == 'node-set' || v2.type == 'node-set') { if (v1.type == 'number') { var s = v1.numberValue(); var n = v2.nodeSetValue(); ret = false; for (var i = 0; i < n.length; ++i) { var nn = xmlValue(n[i]) - 0; if (cmp(s, nn)) { ret = true; break; } } } else if (v2.type == 'number') { var n = v1.nodeSetValue(); var s = v2.numberValue(); ret = false; for (var i = 0; i < n.length; ++i) { var nn = xmlValue(n[i]) - 0; if (cmp(nn, s)) { ret = true; break; } } } else if (v1.type == 'string') { var s = v1.stringValue(); var n = v2.nodeSetValue(); ret = false; for (var i = 0; i < n.length; ++i) { var nn = xmlValue(n[i]); if (cmp(s, nn)) { ret = true; break; } } } else if (v2.type == 'string') { var n = v1.nodeSetValue(); var s = v2.stringValue(); ret = false; for (var i = 0; i < n.length; ++i) { var nn = xmlValue(n[i]); if (cmp(nn, s)) { ret = true; break; } } } else { ret = cmp(v1.booleanValue(), v2.booleanValue()); } } else if (v1.type == 'boolean' || v2.type == 'boolean') { ret = cmp(v1.booleanValue(), v2.booleanValue()); } else if (v1.type == 'number' || v2.type == 'number') { ret = cmp(v1.numberValue(), v2.numberValue()); } else { ret = cmp(v1.stringValue(), v2.stringValue()); } return new BooleanValue(ret);}function LiteralExpr(value) { this.value = value;}LiteralExpr.prototype.evaluate = function(ctx) { return new StringValue(this.value);};function NumberExpr(value) { this.value = value;}NumberExpr.prototype.evaluate = function(ctx) { return new NumberValue(this.value);};function VariableExpr(name) { this.name = name;}VariableExpr.prototype.evaluate = function(ctx) { return ctx.getVariable(this.name);}// Factory functions for semantic values (i.e. Expressions) of the// productions in the grammar. When a production is matched to reduce// the current parse state stack, the function is called with the// semantic values of the matched elements as arguments, and returns// another semantic value. The semantic value is a node of the parse// tree, an expression object with an evaluate() method that evaluates the// expression in an actual context. These factory functions are used// in the specification of the grammar rules, below.function makeTokenExpr(m) { return new TokenExpr(m);}function passExpr(e) { return e;}function makeLocationExpr1(slash, rel) { rel.absolute = true; return rel;}function makeLocationExpr2(dslash, rel) { rel.absolute = true; rel.prependStep(makeAbbrevStep(dslash.value)); return rel;}function makeLocationExpr3(slash) { var ret = new LocationExpr(); ret.appendStep(makeAbbrevStep('.')); ret.absolute = true; return ret;}function makeLocationExpr4(dslash) { var ret = new LocationExpr(); ret.absolute = true; ret.appendStep(makeAbbrevStep(dslash.value)); return ret;}function makeLocationExpr5(step) { var ret = new LocationExpr(); ret.appendStep(step); return ret;}function makeLocationExpr6(rel, slash, step) { rel.appendStep(step); return rel;}function makeLocationExpr7(rel, dslash, step) { rel.appendStep(makeAbbrevStep(dslash.value)); return rel;}function makeStepExpr1(dot) { return makeAbbrevStep(dot.value);}function makeStepExpr2(ddot) { return makeAbbrevStep(ddot.value);}function makeStepExpr3(axisname, axis, nodetest) { return new StepExpr(axisname.value, nodetest);}function makeStepExpr4(at, nodetest) { return new StepExpr('attribute', nodetest);}function makeStepExpr5(nodetest) { return new StepExpr('child', nodetest);}function makeStepExpr6(step, predicate) { step.appendPredicate(predicate); return step;}function makeAbbrevStep(abbrev) { switch (abbrev) { case '//': return new StepExpr('descendant-or-self', new NodeTestAny); case '.': return new StepExpr('self', new NodeTestAny); case '..': return new StepExpr('parent', new NodeTestAny); }}function makeNodeTestExpr1(asterisk) { return new NodeTestElement;}function makeNodeTestExpr2(ncname, colon, asterisk) { return new NodeTestNC(ncname.value);}function makeNodeTestExpr3(qname) { return new NodeTestName(qname.value);}function makeNodeTestExpr4(typeo, parenc) { var type = typeo.value.replace(/\s*\($/, ''); switch(type) { case 'node': return new NodeTestAny; case 'text': return new NodeTestText; case 'comment': return new NodeTestComment; case 'processing-instruction': return new NodeTestPI; }}function makeNodeTestExpr5(typeo, target, parenc) { var type = typeo.replace(/\s*\($/, ''); if (type != 'processing-instruction') { throw type + ' ' + Error().stack; } return new NodeTestPI(target.value);}function makePredicateExpr(pareno, expr, parenc) { return new PredicateExpr(expr);}function makePrimaryExpr(pareno, expr, parenc) { return expr;}function makeFunctionCallExpr1(name, pareno, parenc) { return new FunctionCallExpr(name);}function makeFunctionCallExpr2(name, pareno, arg1, args, parenc) { var ret = new FunctionCallExpr(name); ret.appendArg(arg1); for (var i = 0; i < args.length; ++i) { ret.appendArg(args[i]); } return ret;}function makeArgumentExpr(comma, expr) { return expr;}function makeUnionExpr(expr1, pipe, expr2) { return new UnionExpr(expr1, expr2);}function makePathExpr1(filter, slash, rel) { return new PathExpr(filter, rel);}function makePathExpr2(filter, dslash, rel) { rel.prependStep(makeAbbrevStep(dslash.value)); return new PathExpr(filter, rel);}function makeFilterExpr(expr, predicates) { if (predicates.length > 0) { return new FilterExpr(expr, predicates); } else { return expr; }}function makeUnaryMinusExpr(minus, expr) { return new UnaryMinusExpr(expr);}function makeBinaryExpr(expr1, op, expr2) { return new BinaryExpr(expr1, op, expr2);}function makeLiteralExpr(token) { // remove quotes from the parsed value: var value = token.value.substring(1, token.value.length - 1); return new LiteralExpr(value);}function makeNumberExpr(token) { return new NumberExpr(token.value);}function makeVariableReference(dollar, name) { return new VariableExpr(name.value);}// Used before parsing for optimization of common simple cases. See// the begin of xpathParse() for which they are.function makeSimpleExpr(expr) { if (expr.charAt(0) == '$') { return new VariableExpr(expr.substr(1)); } else if (expr.charAt(0) == '@') { var a = new NodeTestName(expr.substr(1)); var b = new StepExpr('attribute', a); var c = new LocationExpr(); c.appendStep(b); return c; } else if (expr.match(/^[0-9]+$/)) { return new NumberExpr(expr); } else { var a = new NodeTestName(expr); var b = new StepExpr('child', a); var c = new LocationExpr(); c.appendStep(b); return c; }}function makeSimpleExpr2(expr) { var steps = expr.split('/'); var c = new LocationExpr(); for (var i in steps) { var a = new NodeTestName(steps[i]); var b = new StepExpr('child', a); c.appendStep(b);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -