I’d like to use jq
to recursively transform arbitrary JSON files:
Input
{
"id": 123456,
"name": "Test",
"more": [1, 2, 3],
"instance": {
"id": 987654,
"name": "Different"
}
}
Output
[
{
"name" : "id",
"type": "number",
"value": 123456
},
{
"name": "name",
"type": "string",
"value": "Test"
},
{
"name":"more",
"type": "array",
"value": [1, 2, 3]
},
{
"name": "instance",
"type": "object",
"value": [
{
"name": "id",
"type": "number",
"value": 987654
},
{
"name": "name",
"type": "string",
"value": "Different"
}
]
}
]
Transformation Explanation
Each key-value pair should be transformed to an object containing the keys name, type, value
. While name
should be the original key. type
should be the type of the original value perceived by jq’s type
operator. Since Key-value pairs are transformed to complex objects, pairs on the same hierarchy become part of the same array.
Is this possible to achieve via jq
?
2
Answers
Your requirement almost fits what
to_entries
is doing. But you need to carry down the type in a top-down recursion (because with a bottom-up approach, like when usingwalk
, the objects beforehand converted to arrays byto_entries
become indistinguishable from proper arrays when determining the type afterwards). So, a recursive function could set up type and value, and in case value is an object, useto_entries
and prepend the name to it recursion results:Demo
A note regarding your comment that arrays should "stay the same": While this clarified that arrays should not be transformed (e.g. using numeric indices as their items’ "names"), it’s still unclear whether you want array items that are again objects themselves also be transformed or not (while staying inside the untransformed array). For example, change
[1, 2, 3]
in your example to[1, {"x":2}, 3]
. The above assumes that this array should be reproduced as is (Demo). If, however, you want the recursion to be propagated down into array items as well, also update arrays (before objects, to not run into the bottom-up issue), e.g. usingarrays |= map(f.value) | objects |= …
(Demo), which would produce[1, [{"name": "x", "type": "number", "value": 2}], 3]
for the altered example.Incase it is useful, here’s a solution that transforms the elements of both arrays and objects to show their types (demo):
For this input:
It will produce this output: