query.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.jsonPath.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.jsonPath.query"] = true;
  8. dojo.provide("dojox.jsonPath.query");
  9. dojox.jsonPath.query = function(/*Object*/obj, /*String*/expr, /*Object*/arg){
  10. // summaRy
  11. // Perform jsonPath query `expr` on javascript object or json string `obj`
  12. // obj - object || json string to perform query on
  13. // expr - jsonPath expression (string) to be evaluated
  14. // arg - {}special arugments.
  15. // resultType: "VALUE"||"BOTH"||"PATH"} (defaults to value)
  16. // evalType: "RESULT"||"ITEM"} (defaults to ?)
  17. var re = dojox.jsonPath._regularExpressions;
  18. if (!arg){arg={};}
  19. var strs = [];
  20. function _str(i){ return strs[i];}
  21. var acc;
  22. if (arg.resultType == "PATH" && arg.evalType == "RESULT") throw Error("RESULT based evaluation not supported with PATH based results");
  23. var P = {
  24. resultType: arg.resultType || "VALUE",
  25. normalize: function(expr){
  26. var subx = [];
  27. expr = expr.replace(/'([^']|'')*'/g, function(t){return "_str("+(strs.push(eval(t))-1)+")";});
  28. var ll = -1;
  29. while(ll!=subx.length){
  30. ll=subx.length;//TODO: Do expression syntax checking
  31. expr = expr.replace(/(\??\([^\(\)]*\))/g, function($0){return "#"+(subx.push($0)-1);});
  32. }
  33. expr = expr.replace(/[\['](#[0-9]+)[\]']/g,'[$1]')
  34. .replace(/'?\.'?|\['?/g, ";")
  35. .replace(/;;;|;;/g, ";..;")
  36. .replace(/;$|'?\]|'$/g, "");
  37. ll = -1;
  38. while(ll!=expr){
  39. ll=expr;
  40. expr = expr.replace(/#([0-9]+)/g, function($0,$1){return subx[$1];});
  41. }
  42. return expr.split(";");
  43. },
  44. asPaths: function(paths){
  45. for (var j=0;j<paths.length;j++){
  46. var p = "$";
  47. var x= paths[j];
  48. for (var i=1,n=x.length; i<n; i++)
  49. p += /^[0-9*]+$/.test(x[i]) ? ("["+x[i]+"]") : ("['"+x[i]+"']");
  50. paths[j]=p;
  51. }
  52. return paths;
  53. },
  54. exec: function(locs, val, rb){
  55. var path = ['$'];
  56. var result=rb?val:[val];
  57. var paths=[path];
  58. function add(v, p,def){
  59. if (v && v.hasOwnProperty(p) && P.resultType != "VALUE") paths.push(path.concat([p]));
  60. if (def)
  61. result = v[p];
  62. else if (v && v.hasOwnProperty(p))
  63. result.push(v[p]);
  64. }
  65. function desc(v){
  66. result.push(v);
  67. paths.push(path);
  68. P.walk(v,function(i){
  69. if (typeof v[i] ==='object') {
  70. var oldPath = path;
  71. path = path.concat(i);
  72. desc(v[i]);
  73. path = oldPath;
  74. }
  75. });
  76. }
  77. function slice(loc, val){
  78. if (val instanceof Array){
  79. var len=val.length, start=0, end=len, step=1;
  80. loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, function($0,$1,$2,$3){start=parseInt($1||start);end=parseInt($2||end);step=parseInt($3||step);});
  81. start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start);
  82. end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end);
  83. for (var i=start; i<end; i+=step)
  84. add(val,i);
  85. }
  86. }
  87. function repStr(str){
  88. var i=loc.match(/^_str\(([0-9]+)\)$/);
  89. return i?strs[i[1]]:str;
  90. }
  91. function oper(val){
  92. if (/^\(.*?\)$/.test(loc)) // [(expr)]
  93. add(val, P.eval(loc, val),rb);
  94. else if (loc === "*"){
  95. P.walk(val, rb && val instanceof Array ? // if it is result based, there is no point to just return the same array
  96. function(i){P.walk(val[i],function(j){ add(val[i],j); })} :
  97. function(i){ add(val,i); });
  98. }
  99. else if (loc === "..")
  100. desc(val);
  101. else if (/,/.test(loc)){ // [name1,name2,...]
  102. for (var s=loc.split(/'?,'?/),i=0,n=s.length; i<n; i++)
  103. add(val,repStr(s[i]));
  104. }
  105. else if (/^\?\(.*?\)$/.test(loc)) // [?(expr)]
  106. P.walk(val, function(i){ if (P.eval(loc.replace(/^\?\((.*?)\)$/,"$1"),val[i])) add(val,i); });
  107. else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) // [start:end:step] python slice syntax
  108. slice(loc, val);
  109. else {
  110. loc=repStr(loc);
  111. if (rb && val instanceof Array && !/^[0-9*]+$/.test(loc))
  112. P.walk(val, function(i){ add(val[i], loc)});
  113. else
  114. add(val,loc,rb);
  115. }
  116. }
  117. while (locs.length){
  118. var loc = locs.shift();
  119. if ((val = result) === null || val===undefined) return val;
  120. result = [];
  121. var valPaths = paths;
  122. paths = [];
  123. if (rb)
  124. oper(val)
  125. else
  126. P.walk(val,function(i){path=valPaths[i]||path;oper(val[i])});
  127. }
  128. if (P.resultType == "BOTH"){
  129. paths = P.asPaths(paths);
  130. var newResult = [];
  131. for (var i =0;i <paths.length;i++)
  132. newResult.push({path:paths[i],value:result[i]});
  133. return newResult;
  134. }
  135. return P.resultType == "PATH" ? P.asPaths(paths):result;
  136. },
  137. walk: function(val, f){
  138. if (val instanceof Array){
  139. for (var i=0,n=val.length; i<n; i++)
  140. if (i in val)
  141. f(i);
  142. }
  143. else if (typeof val === "object"){
  144. for (var m in val)
  145. if (val.hasOwnProperty(m))
  146. f(m);
  147. }
  148. },
  149. eval: function(x, _v){
  150. try { return $ && _v && eval(x.replace(/@/g,'_v')); }
  151. catch(e){ throw new SyntaxError("jsonPath: " + e.message + ": " + x.replace(/@/g, "_v").replace(/\^/g, "_a")); }
  152. }
  153. };
  154. var $ = obj;
  155. if (expr && obj){
  156. return P.exec(P.normalize(expr).slice(1), obj, arg.evalType == "RESULT");
  157. }
  158. return false;
  159. };
  160. }