skip to Main Content

I have a JSON object, some keys of which have names end in .json, like this:

{
    "a.json": "...",
    ....
}

The "..." can be either a string which fromjson can decode, or something else.

I want a jq filter which will, in the first case, replace the key’s value by its fromjson equivalent, e.g. "{}" would become {}, resulting in:

{
    "a.json": {},
   ....
}

Otherwise, the .json suffix should be removed from the key, so that if for example the value was "shh" the net result would be:

{
    "a": "shh",
    ....
}

All keys ending with .json (like the a.json above) should be processed in this way. Any other key-value pairs should be left unaltered.

When:

with_entries(
        select(.key|test(".json$")) as $root
            | $root.value = $root.value as $sub | ($sub|try fromjson catch $sub)
)

This works for the value, but I cannot find a way to chnge the .key in the catch block.

2

Answers


  1. You can use the error supression operator ? in combination with the alternative operator //:

    with_entries(
      select(.key | endswith(".json")) |= (.value |= fromjson)? // .key |= rtrimstr(".json")
    )
    

    Demo

    Login or Signup to reply.
  2. It’s not pretty but this does what you’re asking

    # {
    #   "a.json": "{"x":42}",
    #   "b.json": "false",
    #   "c.json": "no JSON value",
    #   "d": "key mismatch"
    # }
    
    jq '
    to_entries
    | map( .value as $v | .key as $k
      | if (.key|test("json")) 
        then ( try {key,value: (.value|fromjson)} catch {key:($k|gsub(".json";"")),value:$v} )  
        else . end
      )
    | from_entries'
    

    Output:

    {
      "a.json": {
        "x": 42
      },
      "b.json": false,
      "c": "no JSON value",
      "d": "key mismatch"
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search