9

Using JQ I would like to take a complex JSON object that includes JSON embedded as strings and then turn it all into a valid string I can easily embed in other JSON objects.

For example, lets say I have this json object:

{
  "region": "CA",
  "waf_rule_tags": "{\"RULEID:942100\":[\"application-multi\",\"language-multi\",\"platform-multi\",\"attack-sqli\",\"OWASP_CRS/WEB_ATTACK/SQL_INJECTION\",\"WASCTC/WASC-19\",\"OWASP_TOP_10/A1\",\"OWASP_AppSensor/CIE1\",\"PCI/6.5.2\"]}"
}

I need to turn this all into the following string:

"{\"region\": \"CA\",\"waf_rule_tags\": \"{\\\"RULEID:942100\\\":[\\\"application-multi\\\",\\\"language-multi\\\",\\\"platform-multi\\\",\\\"attack-sqli\\\",\\\"OWASP_CRS/WEB_ATTACK/SQL_INJECTION\\\",\\\"WASCTC/WASC-19\\\",\\\"OWASP_TOP_10/A1\\\",\\\"OWASP_AppSensor/CIE1\\\",\\\"PCI/6.5.2\\\"]}\"}"

That way I can take this string and insert it exactly under the text field of another JSON object to create the following.

{
      "title": "12345-accesslogs",
      "text": "{\"region\": \"CA\",\"waf_rule_tags\": \"{\\\"RULEID:942100\\\":[\\\"application-multi\\\",\\\"language-multi\\\",\\\"platform-multi\\\",\\\"attack-sqli\\\",\\\"OWASP_CRS/WEB_ATTACK/SQL_INJECTION\\\",\\\"WASCTC/WASC-19\\\",\\\"OWASP_TOP_10/A1\\\",\\\"OWASP_AppSensor/CIE1\\\",\\\"PCI/6.5.2\\\"]}\"}",
      "priority": "normal",
      "tags": ["environment:test"],
      "alert_type": "info"
}
Alex Cohen
  • 5,596
  • 16
  • 54
  • 104

4 Answers4

12

In brief, tostring is your friend.

Assuming that your original JSON object is in a file named object.json, and that the template is in template.json, you could write:

jq --argfile object object.json '.text = ($object | tostring)' template.json

Needless to say, there are numerous variations on this theme, e.g.

jq -n 'input | input + {text: tostring}' \
   object.json template.json

or more compactly if slightly more obscurely:

jq 'input + {text: tostring}' object.json template.json
peak
  • 105,803
  • 17
  • 152
  • 177
8

I found @peak's comment in their own answer so useful I wanted to make it an answer on its own:

$ echo '{ "foo": [ "bar", "baz" ] }' | jq -r tostring
{\"foo\":[\"bar\",\"baz\"]}
marverix
  • 7,184
  • 6
  • 38
  • 50
Jon Lauridsen
  • 2,521
  • 5
  • 31
  • 38
3

JQ provides tojson and fromjson filters for that.

Note about the answers proposing tostring: The JQ manual says about tojson:

The tojson builtin differs from tostring in that tostring returns strings unmodified, while tojson encodes strings as JSON strings.

So I think tojson is always correct but tostring is only correct as long as you only use complex objects.

A.H.
  • 63,967
  • 15
  • 92
  • 126
1

A variation on this is to stringify a given key within a JSON structure using tostring something like this:

echo '{"a":1,"b":{"c":{"d":2},"e":3}}' | jq '.b.c=(.b.c|tostring)'

...which targets path b.c to give:

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

(As per A.H.'s answer, tojson might be useful instead of tostring if you want strings to be json-string-encoded as well)

phhu
  • 1,462
  • 13
  • 33