Bash: convert lower level JSON to escaped string

Viewed 1368

I am struggling to use jq to massage the input data so that the first level keys are preserved, while the lower level JSON gets converted to escaped strings.

Input JSON:

{
  "a": "1",
  "b": {
    "c": "2",
    "d": {
      "e": "3"
    }
  },
  "f": "4"
}

Desired output:

{
  "a": "1",
  "b": "{ \"c\": \"2\", \"d\": { \"e\": \"3\"} }",
  "f": "4"
}

Is there a "pure" jq solution to this?

3 Answers

with_entries and tostring seem to do the trick:

$ jq 'with_entries(.value |= tostring )' example.json                                               
{
  "a": "1",
  "b": "{\"c\":\"2\",\"d\":{\"e\":\"3\"}}",
  "f": "4"
}

You can use jq with map_values and tojson:

jq 'map_values(if type == "object" then tojson else . end)' file

This is potentially a safer choice than doing tostring on all the values, since it won't affect any numbers, booleans, etc.

$ cat file
{
  "a": 1,
  "b": {
    "c": "2",
    "d": {
      "e": "3"
    }
  },
  "f": "4",
  "h": [1]
}
$ jq 'with_entries(.value |= tostring )' file
{
  "a": "1",
  "b": "{\"c\":\"2\",\"d\":{\"e\":\"3\"}}",
  "f": "4",
  "h": "[1]"
}
$ jq 'map_values(if type == "object" then tojson else . end)' file
{
  "a": 1,
  "b": "{\"c\":\"2\",\"d\":{\"e\":\"3\"}}",
  "f": "4",
  "h": [
    1
  ]
}

Of course, you can JSON-encode arrays or other types by adding to the if condition.

Try this
jq "{a: .a, b: .b | tostring, f: .f}" input.json
Output:

{
  "a": "1",
  "b": "{\"c\":\"2\",\"d\":{\"e\":\"3\"}}",
  "f": "4"
}
Related