UNPKG

dojox

Version:

Dojo eXtensions, a rollup of many useful sub-projects and varying states of maturity – from very stable and robust, to alpha and experimental. See individual projects contain README files for details.

236 lines (220 loc) 5.87 kB
define(["dojo/_base/kernel", "dojo/_base/lang" ], function(kernel, lang){ var query = function( /*Object*/ obj, /*String*/ expr, /*Object*/ arg){ // summary: // Perform jsonPath query `expr` on javascript object or json string `obj` // obj: // object || json string to perform query on // expr: // jsonPath expression (string) to be evaluated // arg: // {} special arguments. // // - resultType: "VALUE"||"BOTH"||"PATH"} (defaults to value) // - evalType: "RESULT"||"ITEM"} (defaults to ?) if(!arg){ arg = {}; } var strs = []; function _str(i){ return strs[i]; } var _strName = _str.name; if(arg.resultType == "PATH" && arg.evalType == "RESULT"){ throw Error("RESULT based evaluation not supported with PATH based results"); } var P = { resultType: arg.resultType || "VALUE", normalize: function(expr){ var subx = []; expr = expr.replace(/'([^']|'')*'/g, function(t){ return _strName + "(" + (strs.push(eval(t)) - 1) + ")"; }); var ll = -1; while(ll != subx.length){ ll = subx.length; //TODO: Do expression syntax checking expr = expr.replace(/(\??\([^\(\)]*\))/g, function($0){ return "#" + (subx.push($0) - 1); }); } expr = expr.replace(/[\['](#[0-9]+)[\]']/g, '[$1]') .replace(/'?\.'?|\['?/g, ";") .replace(/;;;|;;/g, ";..;") .replace(/;$|'?\]|'$/g, ""); ll = -1; while(ll != expr){ ll = expr; expr = expr.replace(/#([0-9]+)/g, function($0, $1){ return subx[$1]; }); } return expr.split(";"); }, asPaths: function(paths){ var i, j, p, x, n; for(j = 0; j < paths.length; j++){ p = "$"; x = paths[j]; for(i = 1, n = x.length; i < n; i++){ p += /^[0-9*]+$/.test(x[i]) ? ("[" + x[i] + "]") : ("['" + x[i] + "']"); } paths[j] = p; } return paths; }, exec: function(locs, val, rb){ var path = ['$']; var result = rb ? val : [val]; var paths = [path]; function add(v, p, def){ if(v && v.hasOwnProperty(p) && P.resultType != "VALUE"){ paths.push(path.concat([p])); } if(def){ result = v[p]; }else if(v && v.hasOwnProperty(p)){ result.push(v[p]); } } function desc(v){ result.push(v); paths.push(path); P.walk(v, function(i){ if(typeof v[i] === "object"){ var oldPath = path; path = path.concat(i); desc(v[i]); path = oldPath; } }); } function slice(loc, val){ if(val instanceof Array){ var len = val.length, start = 0, end = len, step = 1; loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, function($0, $1, $2, $3){ start = parseInt($1 || start, 10); end = parseInt($2 || end, 10); step = parseInt($3 || step, 10); }); start = (start < 0) ? Math.max(0, start + len) : Math.min(len, start); end = (end < 0) ? Math.max(0, end + len) : Math.min(len, end); var i; for(i = start; i < end; i += step){ add(val, i); } } } function repStr(str, loc){ var i = loc.match(/^_str\(([0-9]+)\)$/); return i ? strs[i[1]] : str; } function oper(val, loc){ if(/^\(.*?\)$/.test(loc)){ // [(expr)] add(val, P.eval(loc, val), rb); }else if(loc === "*"){ P.walk(val, rb && val instanceof Array ? // if it is result based, there is no point to just return the same array function(i){ P.walk(val[i], function(j){ add(val[i], j); }); } : function(i){ add(val, i); }); }else if(loc === ".."){ desc(val); }else if(/,/.test(loc)){ // [name1,name2,...] var s, n, i; for(s = loc.split(/'?,'?/), i = 0, n = s.length; i < n; i++){ add(val, repStr(s[i], loc)); } }else if(/^\?\(.*?\)$/.test(loc)){ // [?(expr)] P.walk(val, function(i){ if(P.eval(loc.replace(/^\?\((.*?)\)$/, "$1"), val[i])){ add(val, i); } }); }else if(/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)){ // [start:end:step] python slice syntax slice(loc, val); }else{ loc = repStr(loc, loc); if(rb && val instanceof Array && !/^[0-9*]+$/.test(loc)){ P.walk(val, function(i){ add(val[i], loc); }); }else{ add(val, loc, rb); } } } var loc, valPaths; while(locs.length){ loc = locs.shift(); if((val = result) === null || val === undefined){ return val; } result = []; valPaths = paths; paths = []; if(rb){ oper(val, loc); }else{ P.walk(val, function(i){ path = valPaths[i] || path; oper(val[i], loc); }); } } if(P.resultType == "BOTH"){ paths = P.asPaths(paths); var newResult = []; var i; for(i = 0; i < paths.length; i++){ newResult.push({ path: paths[i], value: result[i] }); } return newResult; } return P.resultType == "PATH" ? P.asPaths(paths) : result; }, walk: function(val, f){ var i, n, m; if(val instanceof Array){ for(i = 0, n = val.length; i < n; i++){ if(i in val){ f(i); } } }else if(typeof val === "object"){ for(m in val){ if(val.hasOwnProperty(m)){ f(m); } } } }, "eval": function(x, v){ try { return obj && v && eval(x.replace(/@/g, "v")); } catch (e){ throw new SyntaxError("jsonPath: " + e.message + ": " + x.replace(/@/g, "v").replace(/\^/g, "_a")); } } }; if(expr && obj){ return P.exec(P.normalize(expr).slice(1), obj, arg.evalType == "RESULT"); } return false; }; if(!kernel.isAsync){ var obj = lang.getObject("dojox.jsonPath", true); obj.query = query; } return query; });