Jq: Feature request: function to convert path array representation to path expression

Created on 22 Jul 2019  路  2Comments  路  Source: stedolan/jq

idea: add a function pathexpr to convert a path array representation to a path expression.

Paths, such as returned by path( ... ), would in some cases be more readable and usable after converting to a path expression.

def pathexpr:
    map(
        if type == "number" then
            "[\(tostring)]"
        else
            "."+.
        end
    ) | join("")
;

I'm using this pathexpr and thought it might be a nice addition to jq for general use.

An example
The path( ... ) function is really nice to search through lots of JSON files for a specific value.

For example:

jq 'path(..|select(contains("127.0.0.1")?))' *.json
[
  "other",
  0,
  "data",
  0,
  51,
  "data"
]
[
  "other",
  1,
  "data",
  0,
  6,
  "data"
]
...

The output of this command contains all paths that contain the text "127.0.0.1". Using the pathexpr function I can create very useful outputs. The resulting lines can even be copy-pasted to quickly run another jq to show the actual value in that file at that path:

$ jq -r 'include "funcs"; path(..|select(contains("127.0.0.1")?)) | pathexpr+" "+input_filename' *.json
.other[0].data[0][51].data data_166.json
.other[1].data[0][6].data data_195.json
.other[1].data[0][1207].data data_195.json
.other[1].data[0][186].data data_61.json
.other[1].data[0][921].data data_18.json

$ jq .other[1].data[0][921].data data_18.json
"service running on 127.0.0.1"

Edit: improved readability of pathexpr a little

Most helpful comment

Better idea: define pathexpr so that it produces strings corresponding to jq's "dot" notation, i.e. that can be used in jq programs.

Here (hopefully) is such a def:

def pathexpr:
  reduce .[] as $k ("";
    . + ($k | if type == "number" then  "[\(.)]"
              elif test("[^a-zA-Z0-9_]") then "[\"\(.)\"]"
              else "." + $k
              end))
    | if startswith(".") then . else "." + . end ;

Example:

Since {"a": {"b.c": {"d": 99}}} | .a["b.c"].d we want

["a","b.c","d"] | pathexpr

to emit .a["b.c"].d.

All 2 comments

Better idea: define pathexpr so that it produces strings corresponding to jq's "dot" notation, i.e. that can be used in jq programs.

Here (hopefully) is such a def:

def pathexpr:
  reduce .[] as $k ("";
    . + ($k | if type == "number" then  "[\(.)]"
              elif test("[^a-zA-Z0-9_]") then "[\"\(.)\"]"
              else "." + $k
              end))
    | if startswith(".") then . else "." + . end ;

Example:

Since {"a": {"b.c": {"d": 99}}} | .a["b.c"].d we want

["a","b.c","d"] | pathexpr

to emit .a["b.c"].d.

Hi,

The function doesn't work with non ascii keys.
I use following function for the same purpose in my project jq-front.

def path2pexp($v):
  $v | reduce .[] as $segment (""; . + ($segment 
                                       |if type == "string" then ".\"" + . + "\"" 
                                                            else "[\(.)]" end));
Was this page helpful?
0 / 5 - 0 ratings