Changeset 12658
- Timestamp:
- 02/23/08 10:56:13 (11 months ago)
- Location:
- dojox/trunk/jsonPath
- Files:
-
- 3 modified
Legend:
- Unmodified
- Added
- Removed
-
dojox/trunk/jsonPath/query.js
r11516 r12658 1 1 dojo.provide("dojox.jsonPath.query"); 2 2 3 dojox.jsonPath._regularExpressions = { 4 "regA": /[\['](\??\(.*?\))[\]']/g, 5 "regB": /'?\.'?|\['?/g, 6 "regC": /;;;|;;/g, 7 "regD": /;$|'?\]|'$/g, 8 "regE": /#([0-9]+)/g, 9 "regF": /^[0-9*]+$/, 10 "regG": /,/, 11 "regH": /'?,'?/, 12 "regI": /^\(.*?\)$/, 13 "regJ": /^\?\(.*?\)$/, 14 "regK": /^\?\((.*?)\)$/, 15 "regL": /^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/, 16 "regM": /^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, 17 "regN": /@/g, 18 "regO": /\^/g, 19 "regP": /^\$;/ 20 }; 21 22 dojox.jsonPath.query = function(/*Object*/obj, /*String*/expr, /*Object*/arg) { 23 // summay 3 dojox.jsonPath.query = function(/*Object*/obj, /*String*/expr, /*Object*/arg){ 4 // summaRy 24 5 // Perform jsonPath query `expr` on javascript object or json string `obj` 25 6 // obj - object || json string to perform query on 26 7 // expr - jsonPath expression (string) to be evaluated 27 8 // arg - {}special arugments. 28 // resultType: "VALUE"||"PATH"} (defaults to value) 9 // resultType: "VALUE"||"BOTH"||"PATH"} (defaults to value) 10 // evalType: "RESULT"||"ITEM"} (defaults to ?) 29 11 30 12 var re = dojox.jsonPath._regularExpressions; 31 if (!arg){arg={};} ;13 if (!arg){arg={};} 32 14 15 var strs = []; 16 function _str(i){ return strs[i];} 17 var acc; 18 if (arg.resultType == "PATH" && arg.evalType == "RESULT") throw Error("RESULT based evaluation not supported with PATH based results"); 33 19 var P = { 34 20 resultType: arg.resultType || "VALUE", 35 result: [], 36 37 normalize: function(expr) { 21 normalize: function(expr){ 38 22 var subx = []; 39 40 return expr.replace(re.regA, function($0,$1){return "[#"+(subx.push($1)-1)+"]";}) 41 .replace(re.regB, ";") 42 .replace(re.regC, ";..;") 43 .replace(re.regD, "") 44 .replace(re.regE, function($0,$1){return subx[$1];}); 23 expr = expr.replace(/'([^']|'')*'/g, function(t){return "_str("+(strs.push(eval(t))-1)+")";}); 24 var ll = -1; 25 while(ll!=subx.length){ 26 ll=subx.length;//TODO: Do expression syntax checking 27 expr = expr.replace(/(\??\([^\(\)]*\))/g, function($0){return "#"+(subx.push($0)-1);}); 28 } 29 expr = expr.replace(/[\['](#[0-9]+)[\]']/g,'[$1]') 30 .replace(/'?\.'?|\['?/g, ";") 31 .replace(/;;;|;;/g, ";..;") 32 .replace(/;$|'?\]|'$/g, ""); 33 ll = -1; 34 while(ll!=expr){ 35 ll=expr; 36 expr = expr.replace(/#([0-9]+)/g, function($0,$1){return subx[$1];}); 37 } 38 return expr.split(";"); 45 39 }, 46 47 asPath: function(path) { 48 var x = path.split(";"), p = "$"; 49 for (var i=1,n=x.length; i<n; i++){ 50 p += re.regF.test(x[i]) ? ("["+x[i]+"]") : ("['"+x[i]+"']"); 40 asPaths: function(paths){ 41 for (var j=0;j<paths.length;j++){ 42 var p = "$"; 43 var x= paths[j]; 44 for (var i=1,n=x.length; i<n; i++) 45 p += /^[0-9*]+$/.test(x[i]) ? ("["+x[i]+"]") : ("['"+x[i]+"']"); 46 paths[j]=p; 47 } 48 return paths; 49 }, 50 exec: function(locs, val, rb){ 51 var path = ['$']; 52 var result=rb?val:[val]; 53 var paths=[path]; 54 function add(v, p,def){ 55 if (v && v.hasOwnProperty(p) && P.resultType != "VALUE") paths.push(path.concat([p])); 56 if (def) 57 result = v[p]; 58 else if (v && v.hasOwnProperty(p)) 59 result.push(v[p]); 51 60 } 52 return p; 53 }, 54 55 store: function(p, v) { 56 if (p){ 57 switch(P.resultType){ 58 case "PATH": 59 P.result.push(P.asPath(p)); 60 break; 61 case "BOTH": 62 P.result.push({path: P.asPath(p), value: v}); 63 break; 64 case "VALUE": 65 default: 66 P.result.push(v); 67 break; 61 function desc(v){ 62 result.push(v); 63 paths.push(path); 64 P.walk(v,function(i){ 65 if (typeof v[i] ==='object') { 66 var oldPath = path; 67 path = path.concat(i); 68 desc(v[i]); 69 path = oldPath; 70 } 71 }); 72 } 73 function slice(loc, val){ 74 if (val instanceof Array){ 75 var len=val.length, start=0, end=len, step=1; 76 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);}); 77 start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start); 78 end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end); 79 for (var i=start; i<end; i+=step) 80 add(val,i); 68 81 } 69 82 } 70 return !!p; 83 function repStr(str){ 84 var i=loc.match(/^_str\(([0-9]+)\)$/); 85 return i?strs[i[1]]:str; 86 } 87 function oper(val){ 88 if (/^\(.*?\)$/.test(loc)) // [(expr)] 89 add(val, P.eval(loc, val),rb); 90 else if (loc === "*"){ 91 P.walk(val, rb && val instanceof Array ? // if it is result based, there is no point to just return the same array 92 function(i){P.walk(val[i],function(j){ add(val[i],j); })} : 93 function(i){ add(val,i); }); 94 } 95 else if (loc === "..") 96 desc(val); 97 else if (/,/.test(loc)){ // [name1,name2,...] 98 for (var s=loc.split(/'?,'?/),i=0,n=s.length; i<n; i++) 99 add(val,repStr(s[i])); 100 } 101 else if (/^\?\(.*?\)$/.test(loc)) // [?(expr)] 102 P.walk(val, function(i){ if (P.eval(loc.replace(/^\?\((.*?)\)$/,"$1"),val[i])) add(val,i); }); 103 else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) // [start:end:step] python slice syntax 104 slice(loc, val); 105 else { 106 loc=repStr(loc); 107 if (rb && val instanceof Array && !/^[0-9*]+$/.test(loc)) 108 P.walk(val, function(i){ add(val[i], loc)}); 109 else 110 add(val,loc,rb); 111 } 112 113 } 114 while (locs.length){ 115 var loc = locs.shift(); 116 if ((val = result) === null || val===undefined) return val; 117 result = []; 118 var valPaths = paths; 119 paths = []; 120 if (rb) 121 oper(val) 122 else 123 P.walk(val,function(i){path=valPaths[i]||path;oper(val[i])}); 124 } 125 if (P.resultType == "BOTH"){ 126 paths = P.asPaths(paths); 127 var newResult = []; 128 for (var i =0;i <paths.length;i++) 129 newResult.push({path:paths[i],value:result[i]}); 130 return newResult; 131 } 132 return P.resultType == "PATH" ? P.asPaths(paths):result; 71 133 }, 72 73 trace: function(expr, val, path) { 74 if (expr) { 75 var x = expr.split(";"), loc = x.shift(); 76 x = x.join(";"); 77 if (val && val.hasOwnProperty(loc)){ 78 P.trace(x, val[loc], path + ";" + loc); 79 }else if (loc === "*"){ 80 P.walk(loc, x, val, path, function(m,l,x,v,p) { P.trace(m+";"+x,v,p); }); 81 }else if (loc === ".."){ 82 P.trace(x, val, path); 83 P.walk(loc, x, val, path, function(m,l,x,v,p) { typeof v[m] === "object" && P.trace("..;"+x,v[m],p+";"+m); }); 84 }else if (re.regG.test(loc)) { // [name1,name2,...] 85 for (var s=loc.split(re.regH),i=0,n=s.length; i<n; i++){ 86 P.trace(s[i]+";"+x, val, path); 87 } 88 }else if (re.regI.test(loc)){ // [(expr)] 89 P.trace(P.eval(loc, val, path.substr(path.lastIndexOf(";")+1))+";"+x, val, path); 90 }else if (re.regJ.test(loc)){ // [?(expr)] 91 P.walk(loc, x, val, path, function(m,l,x,v,p) { if (P.eval(l.replace(re.regK,"$1"),v[m],m)) P.trace(m+";"+x,v,p); }); 92 }else if (re.regL.test(loc)){ // [start:end:step] phyton slice syntax 93 P.slice(loc, x, val, path); 94 } 95 }else{ 96 P.store(path, val); 134 walk: function(val, f){ 135 if (val instanceof Array){ 136 for (var i=0,n=val.length; i<n; i++) 137 if (i in val) 138 f(i); 139 } 140 else if (typeof val === "object"){ 141 for (var m in val) 142 if (val.hasOwnProperty(m)) 143 f(m); 97 144 } 98 145 }, 99 100 walk: function(loc, expr, val, path, f) { 101 if (val instanceof Array) { 102 for (var i=0,n=val.length; i<n; i++) 103 if (i in val) 104 f(i,loc,expr,val,path); 105 }else if (typeof val === "object"){ 106 for (var m in val) 107 if (val.hasOwnProperty(m)) 108 f(m,loc,expr,val,path); 109 } 110 }, 111 112 slice: function(loc, expr, val, path) { 113 if (val instanceof Array) { 114 var len=val.length, start=0, end=len, step=1; 115 loc.replace(re.regM, function($0,$1,$2,$3){start=parseInt($1||start);end=parseInt($2||end);step=parseInt($3||step);}); 116 start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start); 117 end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end); 118 for (var i=start; i<end; i+=step) 119 P.trace(i+";"+expr, val, path); 120 } 121 }, 122 123 eval: function(x, _v, _vname) { 124 try { 125 return obj && _v && eval(x.replace(re.regN, "_v")); 126 }catch(e){ 127 throw new SyntaxError("dojox.jsonPath: " + e.message + ": " + x.replace(re.regN, "_v").replace(re.regO, "_a")); 128 } 146 eval: function(x, _v){ 147 try { return $ && _v && eval(x.replace(/@/g,'_v')); } 148 catch(e){ throw new SyntaxError("jsonPath: " + e.message + ": " + x.replace(/@/g, "_v").replace(/\^/g, "_a")); } 129 149 } 130 150 }; 131 151 132 if (expr && obj && (P.resultType == "VALUE" || P.resultType == "PATH" || P.resultType=="BOTH")) { 133 P.trace(P.normalize(expr).replace(re.regP,""), obj, "$"); 134 return P.result.length ? P.result : false; 135 } 152 var $ = obj; 153 if (expr && obj){ 154 return P.exec(P.normalize(expr).slice(1), obj, arg.evalType == "RESULT"); 155 } 156 157 return false; 158 136 159 }; -
dojox/trunk/jsonPath/README
r11516 r12658 9 9 Project authors 10 10 Dustin Machi 11 Kris Zyp 11 12 ------------------------------------------------------------------------------- 12 13 Project description -
dojox/trunk/jsonPath/tests/jsonPath.js
r11516 r12658 13 13 "book": [ 14 14 { 15 "category": "reference",16 "author": "Nigel Rees",17 "title": "Sayings of the Century",18 "price": 8.9515 "category":"reference", 16 "author":"Nigel Rees", 17 "title":"Sayings of the Century", 18 "price":8.95 19 19 }, 20 20 { 21 "category": "fiction",22 "author": "Evelyn Waugh",23 "title": "Sword of Honour",24 "price": 12.9921 "category":"fiction", 22 "author":"Evelyn Waugh", 23 "title":"Sword of Honour", 24 "price":12.99 25 25 }, 26 26 { 27 "category": "fiction",28 "author": "Herman Melville",29 "title": "Moby Dick",30 "isbn": "0-553-21311-3",31 "price": 8.9927 "category":"fiction", 28 "author":"Herman Melville", 29 "title":"Moby Dick", 30 "isbn":"0-553-21311-3", 31 "price":8.99 32 32 }, 33 33 { 34 "category": "fiction",35 "author": "J. R. R. Tolkien",36 "title": "The Lord of the Rings",37 "isbn": "0-395-19395-8",38 "price": 22.9934 "category":"fiction", 35 "author":"J. R. R. Tolkien", 36 "title":"The Lord of the Rings", 37 "isbn":"0-395-19395-8", 38 "price":22.99 39 39 } 40 40 ], 41 41 "bicycle": { 42 "color": "red",43 "price": 19.9542 "color":"red", 43 "price":19.95 44 44 } 45 } 45 }, 46 "symbols":{"@.$;":5} 46 47 } 47 48 … … 52 53 runTest: function(t) { 53 54 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 54 var success = '["Nigel Rees", "Evelyn Waugh", "Herman Melville","J. R. R. Tolkien"]';55 var success = '["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]'; 55 56 doh.assertEqual(success,result); 56 57 } … … 60 61 runTest: function(t) { 61 62 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 62 var success = '["Nigel Rees", "Evelyn Waugh", "Herman Melville","J. R. R. Tolkien"]';63 var success = '["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]'; 63 64 doh.assertEqual(success,result); 64 65 … … 69 70 runTest: function(t) { 70 71 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 71 var success = '[[{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99}], {"color": "red", "price":19.95}]';72 var success = '[[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95}]'; 72 73 doh.assertEqual(success,result); 73 74 } … … 77 78 runTest: function(t) { 78 79 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 79 var success = '[8.95, 12.99, 8.99, 22.99,19.95]';80 var success = '[8.95,12.99,8.99,22.99,19.95]'; 80 81 doh.assertEqual(success,result); 81 82 } … … 85 86 runTest: function(t) { 86 87 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 87 var success = '[{"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price":22.99}]';88 var success = '[{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]'; 88 89 doh.assertEqual(success,result); 89 90 } … … 93 94 runTest: function(t) { 94 95 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 95 var success = '[{"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price":22.99}]';96 var success = '[{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]'; 96 97 doh.assertEqual(success,result); 97 98 } … … 101 102 runTest: function(t) { 102 103 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 103 var success = '[{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price":12.99}]';104 var success = '[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]'; 104 105 doh.assertEqual(success,result); 105 106 } … … 109 110 runTest: function(t) { 110 111 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 111 var success = '[{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95}, {"category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price":12.99}]';112 var success = '[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]'; 112 113 doh.assertEqual(success,result); 113 114 } … … 117 118 runTest: function(t) { 118 119 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 119 var success = '[{"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99}, {"category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price":22.99}]';120 var success = '[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]'; 120 121 doh.assertEqual(success,result); 121 122 } … … 125 126 runTest: function(t) { 126 127 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 127 var success = '[{"category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95}, {"category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99}]'; 128 var success = '[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]'; 129 doh.assertEqual(success,result); 130 } 131 }, 132 { 133 name: "$.symbols[*]", 134 runTest: function(t) { 135 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 136 var success = '[5]'; 137 doh.assertEqual(success,result); 138 } 139 }, 140 { 141 name: "$.symbols['@.$;']", 142 runTest: function(t) { 143 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 144 var success = '[5]'; 145 doh.assertEqual(success,result); 146 } 147 }, 148 { 149 name: "$.symbols[(@[('@.$;')]?'@.$;':'@.$;')]", 150 runTest: function(t) { 151 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, this.name)); 152 var success = '[5]'; 128 153 doh.assertEqual(success,result); 129 154 } … … 137 162 } 138 163 }, 164 { 165 name: "evalType: 'RESULT' test $.store.book[?(@.price<15)][1:3]", 166 runTest: function(t) { 167 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, "$.store.book[?(@.price<15)][1:3]",{evalType:"RESULT"})); 168 var success = '[{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]'; 169 doh.assertEqual(success,result); 170 } 171 }, 172 { 173 name: "evalType: 'RESULT' test $.store.book[1].category", 174 runTest: function(t) { 175 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, "$.store.book[1].category",{evalType:"RESULT"})); 176 var success = '"fiction"'; 177 doh.assertEqual(success,result); 178 } 179 }, 180 { 181 name: "evalType: 'RESULT' test $.store.bicycle", 182 runTest: function(t) { 183 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, "$.store.bicycle",{evalType:"RESULT"})); 184 var success = '{"color":"red","price":19.95}'; 185 doh.assertEqual(success,result); 186 } 187 }, 188 { 189 name: "evalType: 'RESULT' test $.store.book[*]", 190 runTest: function(t) { 191 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, "$.store.book[*]",{evalType:"RESULT"})); 192 var success = '["reference","Nigel Rees","Sayings of the Century",8.95,"fiction","Evelyn Waugh","Sword of Honour",12.99,"fiction","Herman Melville","Moby Dick","0-553-21311-3",8.99,"fiction","J. R. R. Tolkien","The Lord of the Rings","0-395-19395-8",22.99]'; 193 doh.assertEqual(success,result); 194 } 195 }, 196 { 197 name: "evalType: 'RESULT' test $.store.book.category", 198 runTest: function(t) { 199 var result = dojo.toJson(dojox.jsonPath.query(dojox.jsonPath.tests.testData, "$.store.book.category",{evalType:"RESULT"})); 200 var success = '["reference","fiction","fiction","fiction"]'; 201