bademeister
bademeister

Reputation: 107

Traverse JSON object to build JSTree

I have a JSON object and want to traverse it so that it matches the structure of JSTree:

Original JSON:

{
	"analogBasebandProcessorBoardType": "Test_BOARD",
	"tuners": {
		"tuner1": "RFE_MAIN",
		"tuner2": "MAX93"
	},
	"allowedSoftConfigs": ["30-16", "30-29", "10-22"]
}

It should look like this:

{
    'core': {
      'data': [
      {
          'text': 'analogBasebandProcessorBoardType',
          'children': 
                      [
                        {
                          'text': 'Test_BOARD'
                        }
                      ]
      }, 
      {
          'text': 'tuners',
          'children': 
                      [{
                        'text': 'Tuner1',
                        'children': 
                        [{
                          'text': 'RFE_MAIN'
                        }]
                      },
                       {
                         'text': 'Tuner2',
                         'children': 
                         [{
                           'text': 'MAX93'
                         }]
                       }
                      ]
       },

       {
          'text': 'allowedSoftConfigs',
          'children': 
          						[
                        {
                            'text': '30-16'
                         }, 
                         {
                            'text': '30-29'
                         },
                         {
                            'text': '10-22'
                         }
							         ]
        },

      ]
    }
  }

I think the only way to solve this is traversing. I have tried it but it is not exactly what I want, but I think I am not very far away from the solution.

This is the JSON that is being generated:

{
	"core": {
		"data": {
			"analogBasebandProcessorBoardType": {
				"text": "analogBasebandProcessorBoardType",
				"children": [{
					"text": "Test_BOARD"
				}],
				"tuners": {
					"tuner1": {
						"text": "tuner1",
						"children": [{
							"text": "RFE_MAIN"
						}],
						"tuner2": {
							"text": "tuner2",
							"children": [{
								"text": "MAX93"
							}],
							"allowedSoftConfigs": {
								"0": {
									"1": {
										"2": {
											"text": "2",
											"children": [{
												"text": "10-22"
											}]
										},
										"text": "1",
										"children": [{
											"text": "30-29"
										}]
									},
									"text": "0",
									"children": [{
										"text": "30-16"
									}]
								}
							}
						}
					}
				}
			}
		}
	}
}

My code alway uses the "name" as the key for the data-array. It would be correct if there is no key. But I am not sure where this behavior is caused.

It would be great if someone could take a look on it as I don't know how to solve it. Here is the complete code but it is easier to view in jsfiddle i think:

//function to add something to objects with a string path
function assign(obj, prop, value) {
    if (typeof prop === "string")
        prop = prop.split(".");

    if (prop.length > 1) {
        var e = prop.shift();
        assign(obj[e] =
                 Object.prototype.toString.call(obj[e]) === "[object Object]"
                 ? obj[e]
                 : {},
               prop,
               value);
    } else
        obj[prop[0]] = value;
}



$(function() {
  // 6 create an instance when the DOM is ready

var tbjsonstring = '{	"analogBasebandProcessorBoardType": "Test_BOARD",	"tuners": {		"tuner1": "RFE_MAIN","tuner2": "MAX93"	},	"allowedSoftConfigs": ["30-16", "30-29", "10-22"]}';

var tbjson = JSON.parse(tbjsonstring);

var computedJSON = {
    'core': {
      'data': [
      ]
    }
  }
var path = "core.data";

console.log(tbjson);
(function traverse(o) {
var z = 0;
    for (var i in o) {
      data0 = {
                  'text': i,
             }
       data1 = {
                  'text': o[i],
             }      
      if(traversed == 1){
      console.log("traversed" + o[i]);
      //	assign(computedJSON,path,data1);
        traversed = 0;
      }else{
     //   assign(computedJSON,path,data0);
      }       
     
      console.log('key : ' + i + ', value: ' + o[i]);

			//console.log(path);
			path = path+"."+i;
      z++;
      if (o[i] !== null && typeof(o[i])=="object") {
        //going on step down in the object tree!!
        var traversed = "1";
        traverse(o[i]);
      }else{
      //key value pair, no children
      data = {};
      data = {
          'text': i,
          'children': [{
            'text': o[i]
          }]
      }
      assign(computedJSON,path,data);
      }  
    }
  })
  (tbjson);

//print to the console
console.log(JSON.stringify(computedJSON));





//This is the working json, computedJSON should looke like this:
  var jstreejson = {
    'core': {
      'data': [
      {
          'text': 'analogBasebandProcessorBoardType',
          'children': 
                      [
                        {
                          'text': 'Test_BOARD'
                        }
                      ]
      }, 
      {
          'text': 'tuners',
          'children': 
                      [{
                        'text': 'Tuner1',
                        'children': 
                        [{
                          'text': 'RFE_MAIN'
                        }]
                      },
                       {
                         'text': 'Tuner2',
                         'children': 
                         [{
                           'text': 'MAX93'
                         }]
                       }
                      ]
       },

       {
          'text': 'allowedSoftConfigs',
          'children': 
          						[
                        {
                            'text': '30-16'
                         }, 
                         {
                            'text': '30-29'
                         },
                         {
                            'text': '10-22'
                         }
							         ]
        },

      ]
    }
  }


//jstree initialization
  $('#jstree').jstree(jstreejson);
  $('#tbjstree').jstree(computedJSON);
  // 7 bind to events triggered on the tree
  $('#jstree').on("changed.jstree", function(e, data) {
    console.log(data.selected);
  });

});
The won't run in the stackoverflow-snippet-editor (even with loaded js/css files) so please visit jsfiddle for a working demo:
<a href='https://jsfiddle.net/dnffx4g8/6/' target='_blank'>JSFiddle Demo</a>

jsfiddle-link: https://jsfiddle.net/dnffx4g8/6/

Upvotes: 0

Views: 181

Answers (2)

Nina Scholz
Nina Scholz

Reputation: 386766

You could use an iterative an recursive approach for it, with a function who checks for array and object and iterates accordingly.

function buildObject(source) {
    if (Array.isArray(source)) {
        return source.reduce(function (r, a) {
            if (a !== null && typeof a === 'object') {
                return r.concat(buildObject(a));
            }
            r.push({ text: a });
            return r;
        }, []);
    }
    if (source !== null && typeof source === 'object') {
        return Object.keys(source).map(function (k) {
            return {
                text: k,
                children: buildObject(source[k])
            };
        });
    }
    return [{ text: source }];
}

var data = { "analogBasebandProcessorBoardType": "Test_BOARD", "tuners": { "tuner1": "RFE_MAIN", "tuner2": "MAX93" }, "allowedSoftConfigs": ["30-16", "30-29", "10-22"], "PathValue": [{ "links": ["in1->GSES_1.in1", "GSES_1.out1->GSES_1.in1", "GSES_1.out1->out1_1"], "ParamFile": "IN1_OUT12.txt" }, { "links": ["in1->GSES_1.in1", "GSES_1.out2->GSES_2.in1", "GSES_2.out1->out1_2"], "ParamFile": "IN1_OUT52.txt" }] },
    result = { core: { data: buildObject(data) } };

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

ES6

function buildObject(source) {
    if (Array.isArray(source)) {
        return source.map(text => ({ text }));
    }
    if (source !== null && typeof source === 'object') {
        return Object.keys(source).map(text => ({ text, children: buildObject(source[text])}));
    }
    return [{ text: source }];
}

var object = { analogBasebandProcessorBoardType: "Test_BOARD", tuners: { tuner1: "RFE_MAIN", tuner2: "MAX93" }, allowedSoftConfigs: ["30-16", "30-29", "10-22"] },
    result = { core: { data: buildObject(object) } };
    
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

trincot
trincot

Reputation: 351084

Given an object named data, you could use this ES6 function:

var result = {
  core: {
    data: (function treeify(data) {
        return Array.isArray(data) ? data.map ( value => treeify(value) )
            : typeof data !== 'object' || data == null ? { text: data }
            : Object.keys(data).map(key => ({ text:key, children: [treeify(data[key])] }));
    })(data)
  }
};

Here is a snippet with your sample data:

var data = {
	"analogBasebandProcessorBoardType": "Test_BOARD",
	"tuners": {
		"tuner1": "RFE_MAIN",
		"tuner2": "MAX93"
	},
	"allowedSoftConfigs": ["30-16", "30-29", "10-22"]
};

var result = {
  core: {
    data: (function treeify(data) {
        return Array.isArray(data) ? data.map ( value => treeify(value) )
            : typeof data !== 'object' || data == null ? { text: data }
            : Object.keys(data).map ( key => ({ text: key, children: [treeify(data[key])] }) );
    })(data)
  }
};

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

NB: I would not name your objects tbjson or computedJson, to avoid confusion with plain JavaScript objects. The term JSON is better reserved for the text notation.

Explanation of the Code

treeify is a recursive function. The value it returns depends on the data type of the argument that is passed to it:

  • When it is an array (Array.isArray()) then the function is called recursively for each element (treeify(value)), and these results are assembled in a new array (the return value of data.map()) that is returned to the caller.

  • When it is a non-object (as null is considered an object a separate test is needed for that), then the value is given to the text property of a new object which is returned to the caller ({ text: data }).

  • When it is an object, the keys of that object are iterated (Object.keys(data).map()) and for each corresponding value the function is called recursively (treeify(data[key])). That result is put in an array and assigned to the children property of a new object, while the key is assigned to the text property of that same object. This is returned to the caller.

The result variable will start the calling chain for initialising the value of the data property.

Upvotes: 0

Related Questions