Restructure Nested JSON Data And Removing Some Keys - javascript

I need to restructure a nested JSON data.
Here is how it looks like:
{
"MainKey1": [
{
"Section1": {
"ParentTag1 Mapped Label": {
"ParentTag1": {
"Tag1 Mapped Label": {
"Tag1": "1234567890"
}
}
}
}
},
{
"Section2": {
"ParentTag1 Mapped Label": {
"ParentTag1": {
"Tag1 Label": {
"Tag1": "111222333444"
},
"Tag2 Label": {
"Tag2": "121212"
},
"Tag3 Label": {
"Tag3": "0987654321"
}
}
}
}
}
],
"MainKey2": [
{
"Section1": {
"ParentTag1 Mapped Label": {
"ParentTag1": {
"Tag1 Mapped Label": {
"Tag1": "1234567890"
}
}
}
}
}
]
}
And this is a sample of the converted JSON:
{
MainKey: [
{
Section1: [
{
ParentTag1: [
{ Tag1: "1234567890" }
]
}
]
},
{
Section2: [
{
ParentTag1: [
{ Tag1: "111222333444" },
{ Tag2: "121212" },
{ Tag3: "0987654321" }
]
}
]
}
],
MainKey2: [
{
Section1: [
{
ParentTag1 : [
{ Tag1: "1234567890" }
]
}
]
}
]
}
Rules:
Everything inside a MainKey (outermost keys, could be any name) should be an array
All labels should be stripped (as the label could be any name, without the actual word "Label", we can determine if it is a label based on the depth level. Since the JSON will have the label as the parent and the actual "tag" as a child.
Here is what I currently have (it is a mess, sorry!)
function convertJson (jsonObj) {
const mainKeys = Object.keys(jsonObj)
let output = {}
for (let i = 0; i < mainKeys.length; i++) {
const mainKey = mainKeys[i]
let result = []
output[mainKey] = result
for (let j = 0; j < jsonObj[mainKey].length; j++) {
const innerObj = {...jsonObj[mainKey][j]}
const sectionName = Object.keys(innerObj)[0]
const sectionObj = {}
sectionObj[sectionName] = []
const index = result.push(sectionObj) - 1
parseObj(innerObj[sectionName], result[index], 0) // if I change 2nd param to: result, it generates incorrect output
}
}
console.log(output)
}
function parseObj (innerObj, result, depthCount) {
for (var key in innerObj) {
if (typeof innerObj[key] === "object") {
if (depthCount % 2 === 1) {
const parentObj = {}
parentObj[key] = []
result.push(parentObj)
depthCount++
parseObj(innerObj[key], parentObj[key], depthCount)
} else {
depthCount++
parseObj(innerObj[key], result, depthCount)
}
} else {
const keyValuePairObj = {}
keyValuePairObj[key] = innerObj[key]
result.push(keyValuePairObj)
}
}
return result
}
convertJson(json)
But it generates an error:
Uncaught TypeError: result.push is not a function
Now if I change line 90 from:
parseObj(innerObj[sectionName], result[index], 0)
to:
parseObj(innerObj[sectionName], result, 0)
Here is incorrect output:
{
"MainKey1": [
{
"Section1": []
},
{
"ParentTag1": [
{
"Tag1": "1234567890"
}
]
},
{
"Section2": []
},
{
"ParentTag1": [
{
"Tag1": "111222333444"
},
{
"Tag2 Label": [
{
"Tag2": "121212"
}
]
},
{
"Tag3": "0987654321"
}
]
}
],
"MainKey2": [
{
"Section1": []
},
{
"Tag1": "1234567890"
}
]
}
And here is my fiddle:
https://jsfiddle.net/kzaiwo/L4avxmyd/36/
Thanks a lot! Appreciate any help!

Related

frame array of recursive json object from an another array of objects

i have an array of objects of the below format
each with a unique 'sub-task' entry, each of this sub-task is to be embedded as a children element of each unique 'task' from the 'tasks' array
[
{
"sub-task":"abc",
"task":"alpha1"},
{
"sub-task":"def",
"task":"alpha1"},
{
"sub-task":"ijkl",
"task":"proto"},
{
"sub-task":"mno",
"task":"def"},
{
"sub-task":"qrs",
"task":"proto"},
{
"sub-task":"asdf",
"task":"mno"},
]
i was trying to frame an another array of below format
[
{
"name":"alpha1",
"children":[
{
"name":"abc"
},
{
"name":"def",
"children":[
{
"name":"mno"
}
]
}
]
},
{
"name":"proto",
"children":[
{
"name":"ijkl"
},
{
"name":"qrs",
"children":[
{
"name":"asdf"
}
]
}
]
}
]
i was trying of below logic, but ended up with no solution...
var treeData = [];
for( var ele of tasks){
recurOn(treeData,ele);
}
function recurOn(arr,obj){
if(arr.length == 0){
treeData.push({name:obj.parentGroup,children:[{name:obj.groupName}]})
//console.log(treeData);
return 1;
}else {
for(var item of treeData){
if(item.name == obj.parentGroup){
//console.log('item: ', item);
item.children.push({name:obj.groupName});
break;
}
else {
treeData.push(recurOn([],obj))
}
}
return 1;
}
}
//console.log(treeData);
//console.log(result);
Since the no of levels an elements holds is not known i was unable to fix for a logic
Use a map to store object reference.
let input = [
{ "sub-task": "abc", "task": "alpha1" },
{ "sub-task": "def", "task": "alpha1" },
{ "sub-task": "ijkl", "task": "proto" },
{ "sub-task": "mno", "task": "def" },
{ "sub-task": "qrs", "task": "proto" },
{ "sub-task": "asdf", "task": "mno" },
];
let map = new Map, result = [];
input.forEach(({ ["sub-task"]: name, task }) => {
let node = map.get(task), child = { name, children: [] };
if (!node) {
map.set(task, node = { name: task, children: [] });
result.push(node);
}
map.set(name, child);
node.children.push(child);
})
console.log(result);

how to improve this function that converts a flat array into a tree?

I have this function that converts a flat array to a tree based on a path property.
This is my data :
const input = [
{"name":"brussels_district_north","path":"Brussels/Brussels CBD/North"},
{"name":"brussels_district_louise","path":"Brussels/Brussels CBD/Louise"},
{"name":"brussels_district_west","path":"Brussels/Brussels Decentralised/West"},
{"name":"brussels_district_léopold","path":"Brussels/Brussels CBD/Léopold"},
{"name":"brussels_district_airport","path":"Brussels/Brussels Periphery/Airport"},
{"name":"brussels_district_ring","path":"Brussels/Brussels Periphery/Ring"},
{"name":"brussels_district_walloon-brabant","path":"Brussels/Brussels Decentralised/Walloon Brabant"},
{"name":"brussels_district_centrum","path":"Brussels/Brussels CBD/Centre"},
{"name":"brussels_district_midi","path":"Brussels/Brussels CBD/Midi"},
{"name":"brussels_district_south","path":"Brussels/Brussels Decentralised/South"},
{"name":"brussels_district_ north_east","path":"Brussels/Brussels Decentralised/North East"},
]
Then the "transform" function :
const output = [];
//make a tree out of this data
input.reduce((r, item) => {
item.path.split(/(?=\/)/).reduce((o, _, i, p) => {
o.children = o.children || [];
var path = p.slice(0, i + 1).join('');
var pathLast = path.match(/([^\/]*)\/*$/)[1] //list item of path splitted with '/'
var temp = o.children.find(o => o.path === path);
if (!temp) {
o.children.push(temp = { path });
}
return temp;
}, r);
return r;
}, { children: output });
console.log(output);
Which give me this :
[
{
"path":"Brussels",
"children":[
{
"path":"Brussels/Brussels CBD",
"children":[
{
"path":"Brussels/Brussels CBD/North"
},
{
"path":"Brussels/Brussels CBD/Louise"
},
{
"path":"Brussels/Brussels CBD/Léopold"
},
{
"path":"Brussels/Brussels CBD/Centre"
},
{
"path":"Brussels/Brussels CBD/Midi"
}
]
},
{
"path":"Brussels/Brussels Decentralised",
"children":
[
{
"path":"Brussels/Brussels Decentralised/West"
},
{
"path":"Brussels/Brussels Decentralised/Walloon Brabant"
},
{
"path":"Brussels/Brussels Decentralised/South"
},
{
"path":"Brussels/Brussels Decentralised/North East"
}
]
},
{
"path":"Brussels/Brussels Periphery",
"children":
[
{
"path":"Brussels/Brussels Periphery/Airport"
},
{
"path":"Brussels/Brussels Periphery/Ring"
}
]
}
]
}
]
That is nice !
But the output only has the path attribute, while I would like to keep the other ones (actually, there is only another name attribute here but I will have more), so I rather want this :
[
{
"path":"Brussels",
"children":[
{
"path":"Brussels/Brussels CBD",
"children":[
{
"path":"Brussels/Brussels CBD/North",
"name":"brussels_district_north"
},
{
"path":"Brussels/Brussels CBD/Louise",
"name":"brussels_district_louise"
},
{
"path":"Brussels/Brussels CBD/Léopold",
"name":"brussels_district_léopold"
},
{
"path":"Brussels/Brussels CBD/Centre",
"name":"brussels_district_centrum"
},
{
"path":"Brussels/Brussels CBD/Midi",
"name":"brussels_district_midi"
}
]
},
{
"path":"Brussels/Brussels Decentralised",
"children":
[
{
"path":"Brussels/Brussels Decentralised/West",
"name":"brussels_district_west"
},
{
"path":"Brussels/Brussels Decentralised/Walloon Brabant",
"name":"brussels_district_walloon-brabant"
},
{
"path":"Brussels/Brussels Decentralised/South",
"name":"brussels_district_south"
},
{
"path":"Brussels/Brussels Decentralised/North East",
"name":"brussels_district_ north_east"
}
]
},
{
"path":"Brussels/Brussels Periphery",
"children":
[
{
"path":"Brussels/Brussels Periphery/Airport",
"name":"brussels_district_airport"
},
{
"path":"Brussels/Brussels Periphery/Ring",
"name":"brussels_district_ring"
}
]
}
]
}
]
How could I edit my function to achieve this ?
Thanks
You could check if the index plus one is equal to the length of the splitted path and add name.
const
input = [{ name: "brussels_district_north", path: "Brussels/Brussels CBD/North" }, { name: "brussels_district_louise", path: "Brussels/Brussels CBD/Louise" }, { name: "brussels_district_west", path: "Brussels/Brussels Decentralised/West" }, { name: "brussels_district_léopold", path: "Brussels/Brussels CBD/Léopold" }, { name: "brussels_district_airport", path: "Brussels/Brussels Periphery/Airport" }, { name: "brussels_district_ring", path: "Brussels/Brussels Periphery/Ring" }, { name: "brussels_district_walloon-brabant", path: "Brussels/Brussels Decentralised/Walloon Brabant" }, { name: "brussels_district_centrum", path: "Brussels/Brussels CBD/Centre" }, { name: "brussels_district_midi", path: "Brussels/Brussels CBD/Midi" }, { name: "brussels_district_south", path: "Brussels/Brussels Decentralised/South" }, { name: "brussels_district_ north_east", path: "Brussels/Brussels Decentralised/North East" }],
output = [];
input.reduce((r, item) => {
item.path.split(/(?=\/)/).reduce((o, _, i, p) => {
o.children = o.children || [];
var path = p.slice(0, i + 1).join('');
var temp = o.children.find(o => o.path === path);
if (!temp) {
o.children.push(temp = { path });
if (i + 1 === p.length) temp.name = item.name;
}
return temp;
}, r);
return r;
}, { children: output });
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to put all values into an array from a JSON object with specific key, Deep keys

I am trying to parse a large json object with mostly useless information. I'm trying to access all '_text' keys and their values and put them in an array.
EX:
const myObj = {
"_declaration": {
"_attributes": {
"version": "1.0",
"encoding": "UTF-8",
"standalone": "yes"
}
},
"w:document": {
"_attributes": {
"xmlns:wpc": "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
"xmlns:cx": "http://schemas.microsoft.com/office/drawing/2014/chartex",
"xmlns:cx1": "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
"xmlns:cx2": "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
"xmlns:cx3": "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
"xmlns:cx4": "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
"xmlns:cx5": "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
"xmlns:cx6": "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
"xmlns:cx7": "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
"xmlns:cx8": "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
"xmlns:aink": "http://schemas.microsoft.com/office/drawing/2016/ink",
"xmlns:am3d": "http://schemas.microsoft.com/office/drawing/2017/model3d",
"xmlns:o": "urn:schemas-microsoft-com:office:office",
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
"xmlns:m": "http://schemas.openxmlformats.org/officeDocument/2006/math",
"xmlns:v": "urn:schemas-microsoft-com:vml",
"xmlns:wp14": "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
"xmlns:wp": "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
"xmlns:w10": "urn:schemas-microsoft-com:office:word",
"xmlns:w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
"xmlns:w14": "http://schemas.microsoft.com/office/word/2010/wordml",
"xmlns:w15": "http://schemas.microsoft.com/office/word/2012/wordml",
"xmlns:w16cid": "http://schemas.microsoft.com/office/word/2016/wordml/cid",
"xmlns:w16se": "http://schemas.microsoft.com/office/word/2015/wordml/symex",
"xmlns:wpg": "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
"xmlns:wpi": "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
"xmlns:wne": "http://schemas.microsoft.com/office/word/2006/wordml",
"xmlns:wps": "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
"mc:Ignorable": "w14 w15 w16se w16cid wp14"
},
"w:body": {
"w:p": [
{
"_attributes": {
"w14:paraId": "53160B82",
"w14:textId": "77777777",
"w:rsidR": "00484DC0",
"w:rsidRDefault": "00484DC0",
"w:rsidP": "00264A78"
},
"w:pPr": {
"w:spacing": {
"_attributes": {
"w:after": "0",
"w:line": "240",
"w:lineRule": "auto"
}
},
"w:rPr": {
"w:sz": {
"_attributes": {
"w:val": "36"
}
},
"w:szCs": {
"_attributes": {
"w:val": "36"
}
}
}
}
},
{
"_attributes": {
"w14:paraId": "0FC460F5",
"w14:textId": "77777777",
"w:rsidR": "00880E84",
"w:rsidRDefault": "00880E84",
"w:rsidP": "00264A78"
},
"w:pPr": {
"w:spacing": {
"_attributes": {
"w:after": "0",
"w:line": "240",
"w:lineRule": "auto"
}
},
"w:rPr": {
"w:sz": {
"_attributes": {
"w:val": "36"
}
},
"w:szCs": {
"_attributes": {
"w:val": "36"
}
}
}
},
"w:r": {
"w:rPr": {
"w:sz": {
"_attributes": {
"w:val": "36"
}
},
"w:szCs": {
"_attributes": {
"w:val": "36"
}
}
},
"w:t": {
"_text": "Teaching Guide/Lesson Template"
}
}
}
...More of the object, this is the JSON format that I
then parse using JSON.parse in my code to read
const myArray = /*An array*/
//myArray should be ["Some text", "that I want", "in an array"]
The order does matter I tried this with a recursive function but the object is too large and I'm exceeding the maximum call stack. Is there any function or library out there that I can use for this functionality?
Make a recursive function with Object.keys like so:
function getText(obj) {
let text = [];
Object.keys(obj).forEach(key => {
if (key == "_text") {
text.push(obj[key]);
}
if (typeof obj[key] == "object") {
text.push(getText(obj[key]));
}
});
const flatten = function(arr, result = []) {
for (let i = 0, length = arr.length; i < length; i++) {
const value = arr[i];
if (Array.isArray(value)) {
flatten(value, result);
} else {
result.push(value);
}
}
return result;
};
return flatten(text);
}
const myObj = {
object1: {
deeperLevel: {
_text: "Some text"
}
},
object2: {
_text: "that I want"
},
object3: {
deeperLevel: {
EvenDeeper: {
_text: "in an array"
}
}
}
};
const myArr = getText(myObj);
console.log(myArr);
Flattening algorithm from this answer.

javascript : copying data from one array of objects to another which has existing data gives incorrect result

Copying data does not return correct results. This code looks fine, but it isn't giving me the results which are correct. Am I missing something? Looks as though it's using the same instance to copy the data into the object.
let sidList = [
{ taskTargetHosts: [['host1'], ['host1']] },
{ taskTargetHosts: [['host3'], ['host3']] },
];
let jobData = [
{ config: { tasks: [{ targetHosts: [] }, { targetHosts: [] }] } },
{
config: {
tasks: [{ targetHosts: [] }, { targetHosts: [] }],
},
},
];
let dataIndx = 0;
for (let sidRow of sidList) {
for (
let taskIndx = 0;
taskIndx < jobData[dataIndx].config.tasks.length;
taskIndx++
) {
jobData[dataIndx].config.tasks[taskIndx].targetHosts =
sidRow.taskTargetHosts[taskIndx];
}
dataIndx++;
}
output expected for jobData:
[{"config": {"tasks": [{"targetHosts": ["host1"]},{"targetHosts": ["host1"]}]}},{"config": {"tasks": [{"targetHosts": ["host3"]},{"targetHosts": ["host3"]}]}}]
What I'm getting:
[{"config": {"tasks": [{"targetHosts": ["host1"]},{"targetHosts": ["host1"]}]}},{"config": {"tasks": [{"targetHosts": ["host1"]},{"targetHosts":["host1"]}]}}]
it seems to work for me your problem may be elsewhere
let sidList = [
{ taskTargetHosts: [['host1'], ['host1']] },
{ taskTargetHosts: [['host3'], ['host3']] },
];
let jobData = [
{ config: { tasks: [{ targetHosts: [] }, { targetHosts: [] }] } },
{ config: { tasks: [{ targetHosts: [] }, { targetHosts: [] }] } },
];
let dataIndx = 0;
for (let sidRow of sidList) {
for ( let taskIndx = 0; taskIndx < jobData[dataIndx].config.tasks.length; taskIndx++ ) {
jobData[dataIndx].config.tasks[taskIndx].targetHosts = sidRow.taskTargetHosts[dataIndx];
}
dataIndx++;
}
console.log (jobData[0].config.tasks[0]); //{ targetHosts: [ 'host1' ] }
console.log (jobData[0].config.tasks[1]); //{ targetHosts: [ 'host1' ] }
console.log (jobData[1].config.tasks[0]); //{ targetHosts: [ 'host3' ] }
console.log (jobData[1].config.tasks[1]); //{ targetHosts: [ 'host3' ] }

Convert JSON from one format to other

I'm trying to convert the below JSON to another format wherein the reultant JSON dosen't contain valueChainEntity object name and also I want to delete the inputs and outputs array.Note that the structure is a parent child relation and the inputs and outputs array can be present inside the items array at any level.Even in the all levels(but only inside items array)
var inputJSON = [
{
"valueChainEntity":{
"id":308,
"valueChainEntityId":48,
"items":[
{
"valueChainEntity":{
"id":309,
"valueChainEntityId":49,
"items":[
{
"valueChainEntity":{
"id":312,
"valueChainEntityId":50,
"items":[
]
},
"inputs":[
{
"id":312,
"valueChainEntityId":50,
"items":[
]
}
],
"outputs":[
{
"id":313,
"valueChainEntityId":50
}
]
}
]
}
}
]
}
}
]
var outputJSON= [
{
"id":308,
"valueChainEntityId":48,
"items":[
{
"id":309,
"valueChainEntityId":49,
"items":[
{
"id":312,
"valueChainEntityId":50,
"items":[
]
}
]
}
]
}
]
My code:
inputJSON.forEach((item) => {
return item.valueChainEntity;
});
//which will traverse only through the first level and will not delete the **inputs** and **outputs** array..
See if following works:
function parseInputJSON(inp) {
return inp.map(function (item) {
return getValueChainEntity(item);
});
}
function getValueChainEntity(item) {
if (item['valueChainEntity'] != undefined) {
var valueChainEntity = item.valueChainEntity;
valueChainEntity.items = parseInputJSON(valueChainEntity.items);
return valueChainEntity;
}
return item;
}
var inputJSON=[
{
"valueChainEntity": {
"id": 308,
"valueChainEntityId": 48,
"items": [
{
"valueChainEntity": {
"id": 309,
"valueChainEntityId": 49,
"items": [
{
"valueChainEntity": {
"id": 312,
"valueChainEntityId": 50,
"items": []
},
"inputs": [
{
"id": 312,
"valueChainEntityId": 50,
"items": []
}
],
"outputs": [
{
"id": 313,
"valueChainEntityId": 50
}
]
}
]
}
}
]
}
}];
var newInput = parseInputJSON(inputJSON);
document.getElementById("json").innerHTML = JSON.stringify(newInput, undefined, 4);
<pre id="json"></pre>
Here's another way that is working..
Sample code
function populateChildrenRecursively(outputTypeId, valueChainEntities, parentValueChainEntity) {
for (var i = 0; i < valueChainEntities.length; i++) {
if (valueChainEntities[i].valueChainEntity.valueChainEntityId != parentValueChainEntity.valueChainEntity.valueChainEntityId && hasInput(outputTypeId, valueChainEntities[i].inputs)) {
parentValueChainEntity.valueChainEntity.items.push(valueChainEntities[i]);
if (valueChainEntities[i].outputs.length > 0) {
valueChainEntities[i].valueChainEntity.items = [];
for (var j = 0; j < valueChainEntities[i].outputs.length; j++) {
populateChildrenRecursively(valueChainEntities[i].outputs[j].outputTypeId, valueChainEntities, valueChainEntities[i]);
}
}
}
}
}
https://plnkr.co/edit/d2wtXcaU37quthBjgrCu?p=preview

Categories