Skip to content

Instantly share code, notes, and snippets.

@konobi
Created February 22, 2011 19:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save konobi/a31dd7ccb19a317073ae to your computer and use it in GitHub Desktop.
Save konobi/a31dd7ccb19a317073ae to your computer and use it in GitHub Desktop.
diff --git a/json b/json
index 5566714..ace5337 100755
--- a/json
+++ b/json
@@ -31,6 +31,7 @@ function printHelp() {
sys.puts(" -H drop any HTTP header block");
sys.puts(" -i output using node's `sys.inspect`");
sys.puts(" -j output using `JSON.stringfy`, i.e. strict JSON");
+ sys.puts(" --jp search using jsonpath");
sys.puts("");
sys.puts("Examples:");
sys.puts(" curl -s http://search.twitter.com/search.json?q=node.js | json");
@@ -56,7 +57,8 @@ function parseArgv(argv) {
quiet: false,
dropHeaders: false,
outputSysInspect: false,
- outputJSON: false
+ outputJSON: false,
+ jp: false,
};
// Turn '-iH' into '-i -H'.
@@ -93,6 +95,9 @@ function parseArgv(argv) {
case "-j": // output with JSON.stringify
parsed.outputJSON = true;
break;
+ case "--jp": // search using jsonpath
+ parsed.jp = true;
+ break;
default: // arguments
if (parsed.lookup === null) {
parsed.lookup = arg;
@@ -178,7 +183,7 @@ function main(argv) {
return;
}
- if (args.lookup) {
+ if (!args.jp && args.lookup) {
// Parse command line lookup string into separate parts of the lookup.
var split = args.lookup.split(/(\.|\[)/);
var bits = [];
@@ -221,6 +226,8 @@ function main(argv) {
}
data = Script.runInNewContext("(" + JSON.stringify(data) + ")" + lookup);
+ } else if (args.jp && args.lookup) {
+ data = jsonPath(data, args.lookup, { resultType: 'VALUE' });
}
// Print out results.
@@ -247,3 +254,92 @@ if (require.main === module) {
process.exit(retval);
}
}
+
+
+/* JSONPath 0.8.0 - XPath for JSON
+ *
+ * Copyright (c) 2007 Stefan Goessner (goessner.net)
+ * Licensed under the MIT (MIT-LICENSE.txt) licence.
+ */
+function jsonPath(obj, expr, arg) {
+ var P = {
+ resultType: arg && arg.resultType || "VALUE",
+ result: [],
+ normalize: function(expr) {
+ var subx = [];
+ return expr.replace(/[\['](\??\(.*?\))[\]']/g, function($0,$1){return "[#"+(subx.push($1)-1)+"]";})
+ .replace(/'?\.'?|\['?/g, ";")
+ .replace(/;;;|;;/g, ";..;")
+ .replace(/;$|'?\]|'$/g, "")
+ .replace(/#([0-9]+)/g, function($0,$1){return subx[$1];});
+ },
+ asPath: function(path) {
+ var x = path.split(";"), p = "$";
+ for (var i=1,n=x.length; i<n; i++)
+ p += /^[0-9*]+$/.test(x[i]) ? ("["+x[i]+"]") : ("['"+x[i]+"']");
+ return p;
+ },
+ store: function(p, v) {
+ if (p) P.result[P.result.length] = P.resultType == "PATH" ? P.asPath(p) : v;
+ return !!p;
+ },
+ trace: function(expr, val, path) {
+ if (expr) {
+ var x = expr.split(";"), loc = x.shift();
+ x = x.join(";");
+ if (val && val.hasOwnProperty(loc))
+ P.trace(x, val[loc], path + ";" + loc);
+ else if (loc === "*")
+ P.walk(loc, x, val, path, function(m,l,x,v,p) { P.trace(m+";"+x,v,p); });
+ else if (loc === "..") {
+ P.trace(x, val, path);
+ P.walk(loc, x, val, path, function(m,l,x,v,p) { typeof v[m] === "object" && P.trace("..;"+x,v[m],p+";"+m); });
+ }
+ else if (/,/.test(loc)) { // [name1,name2,...]
+ for (var s=loc.split(/'?,'?/),i=0,n=s.length; i<n; i++)
+ P.trace(s[i]+";"+x, val, path);
+ }
+ else if (/^\(.*?\)$/.test(loc)) // [(expr)]
+ P.trace(P.eval(loc, val, path.substr(path.lastIndexOf(";")+1))+";"+x, val, path);
+ else if (/^\?\(.*?\)$/.test(loc)) // [?(expr)]
+ P.walk(loc, x, val, path, function(m,l,x,v,p) { if (P.eval(l.replace(/^\?\((.*?)\)$/,"$1"),v[m],m)) P.trace(m+";"+x,v,p); });
+ else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) // [start:end:step] phyton slice syntax
+ P.slice(loc, x, val, path);
+ }
+ else
+ P.store(path, val);
+ },
+ walk: function(loc, expr, val, path, f) {
+ if (val instanceof Array) {
+ for (var i=0,n=val.length; i<n; i++)
+ if (i in val)
+ f(i,loc,expr,val,path);
+ }
+ else if (typeof val === "object") {
+ for (var m in val)
+ if (val.hasOwnProperty(m))
+ f(m,loc,expr,val,path);
+ }
+ },
+ slice: function(loc, expr, val, path) {
+ 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);end=parseInt($2||end);step=parseInt($3||step);});
+ start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start);
+ end = (end < 0) ? Math.max(0,end+len) : Math.min(len,end);
+ for (var i=start; i<end; i+=step)
+ P.trace(i+";"+expr, val, path);
+ }
+ },
+ eval: function(x, _v, _vname) {
+ try { return $ && _v && eval(x.replace(/@/g, "_v")); }
+ catch(e) { throw new SyntaxError("jsonPath: " + e.message + ": " + x.replace(/@/g, "_v").replace(/\^/g, "_a")); }
+ }
+ };
+
+ var $ = obj;
+ if (expr && obj && (P.resultType == "VALUE" || P.resultType == "PATH")) {
+ P.trace(P.normalize(expr).replace(/^\$;/,""), obj, "$");
+ return P.result.length ? P.result : false;
+ }
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment