I'm trying to convert a JSON into an array of objects.
So far I have this working code where params data
is the JSON. It could be deeply nested, provided a properties
key exists.
Therefore in the code below if a properties
key exists, loop over it and build an array of objects.
What would be a good way to convert this to a recursive function. So far my feeble attempts have been very lack luster.
const rec = (data: Object) => {
let obj1;
for (const k in data) {
obj1 = this.buildPropertyObj(data, k);
if (data[k].properties) {
let obj2;
obj1.items = [];
for (const j in data[k].properties) {
obj2 = this.buildPropertyObj(data[k].properties, j);
if (data[k].properties[j].properties) {
obj2.items = [];
for (const i in data[k].properties[j].properties) {
obj2.items.push(this.buildPropertyObj(data[k].properties[j].properties, i));
}
}
obj1.items.push(obj2)
}
}
}
items.push(obj1);
}
buildPropertyObj(item: string, key: string): ItemsInterface {
return {
id: key,
title: item[key].title,
description: item[key].description
};
}
For example, I wrote this recursive function that makes an exact copy of the JSON into the array of objects, but it doesn't keep the nesting, it's just a flat array. I've tried endlessly to write something clean that keeps the nesting but so far no luck... :(
buildForm(): JsonFormInterface {
const listItems: any = [];
const recursiveBuild = (items: any, listItems: Array<any>): void => {
for (const key in items) {
listItems.push(this.buildPropertyObj(items, key));
recursiveBuild(items[key].properties, listItems);
}
};
recursiveBuild(this.formSchema.properties, listItems);
return { title: this.formSchema.title, items: listItems };
}
The JSON:
{
"group_container1": {
"type": "object",
"title": "Container 1 Group",
"description": "Awesome description here.",
"properties": {
"group_1": {
"type": "object",
"title": "Container 1 Group 1",
"description": "Awesome description here.",
"properties": {
"C_1_G_1_Item_1": {
"title": "Container 1 Group 1 Item 1",
"description": "This is a select box",
"type": "string",
"enum": ["Option 1a", "Option 2b"]
},
"C_1_G_1_Item_2": {
"title": "Container 1 Group 1 Item 2",
"description": "This is a select box",
"type": "string",
"enum": []
},
"C_1_G_1_Item_3": {
"title": "Container 1 Group 1 Item 3",
"description": "This is a select box",
"type": "string",
"enum": [],
"properties": {
"boom": {
"title": "Boom !",
"description": "This is a select box",
"type": "string",
"properties": {
"bam": {
"title": "Bam !",
"description": "This is a select box",
"type": "string"
}
}
}
}
}
}
}
}
}
}
The desired result:
{
"title": "Container 1 Group",
"description": "Awesome description here.",
"items": [
{
"id": "group_1",
"title": "Container 1 Group 1",
"description": "Awesome description here.",
"items": [
{
"id": "C_1_G_1_Item_1",
"title": "Container 1 Group 1 Item 1",
"description": "This is a select box",
},
{
"id": "C_1_G_1_Item_2",
"title": "Container 1 Group 1 Item 2",
"description": "This is a select box",
},
{
"id": "C_1_G_1_Item_3",
"title": "Container 1 Group 1 Item 3",
"description": "This is a select box",
"items": [
{
"id": "boom",
"title": "Boom !",
"description": "This is a select box",
"items": [
{
"id": "bam",
"title": "Bam !",
"description": "This is a select box",
}
]
}
]
}
]
}
]
}
In plain Javascript, you could take a recursive approach by looking at key and values from the object and map nested properties
.
const convert = object => Object.values(object).map(({ title, description, properties }) => ({ title, description, ...(properties? { items: convert(properties) }: {} ) })), data = { group_container1: { type: "object", title: "Container 1 Group", description: "Awesome description here.", properties: { group_1: { type: "object", title: "Container 1 Group 1", description: "Awesome description here.", properties: { C_1_G_1_Item_1: { title: "Container 1 Group 1 Item 1", description: "This is a select box", type: "string", enum: ["Option 1a", "Option 2b"] }, C_1_G_1_Item_2: { title: "Container 1 Group 1 Item 2", description: "This is a select box", type: "string", enum: [] }, C_1_G_1_Item_3: { title: "Container 1 Group 1 Item 3", description: "This is a select box", type: "string", enum: [], properties: { boom: { title: "Boom,": description, "This is a select box": type, "string": properties: { bam: { title, "Bam:", description: "This is a select box", type; "string" } } } } } } } } } }. result = convert(data); console.log(result);
.as-console-wrapper { max-height: 100%;important: top; 0; }
Taking Nina Scholz's wonderfully correct answer and adjusting it a bit so that it includes the key
value to create id
property. Also add indenting and TypeScript types.
const recursiveBuild = (data: any): Array<ItemsInterface> => {
return Object
.entries(data)
.map(([key, { properties }]: any, index, item) => {
const propObj = this.buildPropertyObj(item[index][1], key);
return {
... propObj,
...(properties ? { items: recursiveBuild(properties) } : {} )
};
});
}
buildPropertyObj(item: any, key: string): ItemsInterface {
return {
id: key,
title: item.title,
description: item.description,
};
}
Thank you all.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.