flatten example does not flatten arrays
Hi, I noticed the flatten-objects function here doesnt flatten nested arrays. I understand that flattening can have different meaning & expectations depending on each use case but my expectation when I want to flatten a json that it should cover everything. Of course considering arrays can get very complex given what arrays can hold. Part of learning jslt I wanted to take on this challenge to see if it can be done. I hope I was successful but part of doing this I found myself using some other helpful functions (see comments on each function) that I thought it might be nice to have not just for flattening but for other things and maybe have them as built function. Without further due , here is the code:
// This is different way of zipping where the key is the index itself. I found that provide more direct way if you need to access the index
// vs storing the index in another key.
def zip-by-index(json)
let res = if(is-array($json)) [for(zip-with-index($json)) {string(.index):.value}] else []
$res
//This is to make an array as complex object to create uniformity on how complex types in json can be processed. Im not sure there are
// many use cases for this but its nice to have as an option
def objectify-array(array)
let res = if($array==[] or $array==null) {}
else if(size($array)==1) $array[0]
else $array[-1]+objectify-array($array[0 : -1])
$res
def flatten_json(prefix,json)
let simple= {for($json) $prefix+.key:.value if(.key!=null and not(is-object(.value)) and not(is-array(.value)))}
let complex= [for($json) flatten_json($prefix+.key+".",.value) if(is-object(.value))]
let array= [for($json) flatten_json($prefix+.key+".",objectify-array(zip-by-index(.value))) if(is-array(.value))]
objectify-array($array)+objectify-array($complex)+$simple
flatten_json("",.)
Example:
{
"x": "x1",
"y": "y2",
"z": {
"z1": "z11",
"z2": null,
"z3": [
1,
{
"zzz": "skid",
"zzz1": null
},
2
]
}
}
Output:
{
"x" : "x1",
"y" : "y2",
"z.z1" : "z11",
"z.z3.0" : 1,
"z.z3.2" : 2,
"z.z3.1.zzz" : "skid"
}
I appreciate any well explained feedback. Thanks S
This is not my original code, I stole it from here.
I changed it very lightly, it is not exactly what you want, because it does not process arrays, yet.
See the unchanged z3 array below.
At any rate, here it is:
// JSLT transform which flattens nested objects into flat objects
// { "a": { "b": 1 } } => { "a.b": 1 }
def flatten-object (obj)
let flat = { for ($obj) .key : .value if (not (is-object (.value))) }
let nested = [
for ($obj)
let outerkey = (.key)
[for (flatten-object (array (.value))) {
"key": $outerkey + "." + .key,
"value": if (is-object (.value)) flatten-object (.value) else .value
}]
if (is-object (.value))
]
let flattened = (flatten ($nested))
{ for ($flattened) .key : .value } + $flat
flatten-object (.)
This transformation produces for the input above this result:
{
"x" : "x1",
"y" : "y2",
"z.z1" : "z11",
"z.z3" : [ 1, {
"zzz" : "skid",
"zzz1" : null
}, 2 ]
}