Jetson John
Jetson John

Reputation: 3829

Creating a nested JSON object dynamically?

I am almost there with this but cannot seem to get this functionality going as planned.

I have json 'jsonData' it contains formula of different terms

"jsonData":{
            "a" : "b + c",
            "b" : "d + e",
            "d" : "h + i",
            "c" : "f + g"
        }

What I am trying to do is to have a function pass one arguments 'mainItem'(ie. one of the key in 'jsonData' for example a in 'jsonData'). Within this function it will get the formula from the json data(for example a is the 'mainitem' and b + c is the formula) and check the dependency of child component of the formula i.e it will check whether b and c have any dependency down the line in json data. If it has any dependency it will be added as a child component to the parent for example if b have a formula in json data. b will be added as the 'mainitem' in the child component of the parent 'mainitem' a. At the end of the code, this is what I would like to get.

{
mainitem : "a",
formula : "b+c",
childComponent: {
                 mainitem: "b",
                 formula : "d+e",
                 childcomponent: {
                                  mainitem: "d",
                                  formula : "h+i"
                                  }
                 },
                 {
                 mainitem: "c",
                 formula : "f+g"
                 },
}

The issue is that I am able to create the parent object. But I have no idea how to create the child component for the parent and If the child component have sub child it will also embedded as the child of the child component and so on. It is like a parent child hierarchy series

function getJson(mainItem) {
  var json = {};
  json['mainitem'] = mainItem;
  $.each(jsonData, function(key, value){
    if(mainitem == key){
      json['formula'] = value;
    }
  })
}

Any insight into this would highly be appreciated. Thank you.

Upvotes: 2

Views: 7890

Answers (4)

mqchen
mqchen

Reputation: 4193

You need/could to write a recursive function that splits up the "formula" into each composing component/item and then check each component/item for their dependencies.

Here is a solution for you: http://jsfiddle.net/mqchen/4x7cD/

function getJson(item, data) {

    if(!data["jsonData"].hasOwnProperty(item)) return null;

    var out = {
        mainItem: item, 
        formula: data["jsonData"][item]
    };

    // Break up formula
    var components = out.formula.split(" ");

    for(var i = 0; i < components.length; i++) {
        var child = getJson(components[i], data); // Recursive call to get childComponents
        if(child !== null) {
            out["childComponent"] = out["childComponent"] == undefined ? [] : out["childComponent"];
            out["childComponent"].push(child);
        }
    }

    return out;
}

// Call it
getJson("a", data)

Note: It does not consider circular dependencies, i.e. if you have a: "b + c", b: "d + a".

Upvotes: 2

Ivan
Ivan

Reputation: 2262

There is approved answer already but here are my 5 cents.

as @Mahesha999 said you need to build "Syntax Tree as in classic parser/compiler". For some theory + examples look at those videos

They are focused on antlr but also contains a lot theory about parsers. Also antlr have javascript plugin that can be used.

I think it's better than any expression evaluation.

Upvotes: 0

Mahesha999
Mahesha999

Reputation: 24931

Yeah this is some sort of building Syntax Tree as in classic parser/compiler problem.

Any ways I have written this simple recursive function that does what you want. Though if your goal is to build some sort of parser then you must think of following parser / compiler building principles since that will keep things manageable and graspable once functions start growing.

    function getJson(mainitem,outjson)
    {
        formula = jsonData[mainitem]; 
        outjson.mainitem = mainitem;

        if (formula != null)
        {
            outjson.formula = formula;
            var firstItem = formula.toString().charAt(0);
            var secondItem = formula.charAt(formula.length - 1);                
            outjson.firstchild = {};
            outjson.secondchild = {};
            getJson(firstItem, outjson.firstchild);
            getJson(secondItem, outjson.secondchild);
        }
    }

What all you have to do is to create an empty object and pass it to getJson() along with the operand in problem i.e. mainitem:

    var outjson = {};
    getJson("a", outjson);

I have used JSON library to convert outjson object to JSON text.

Also I have logged this outjson so that you can examine it in the embedded firebug lites' Console window.

Find it at JSFiddle.

Upvotes: 1

Vinay
Vinay

Reputation: 6342

This is a dependency problem. I can already tell you ahead of time that you will need to figure out a way to handle circular dependencies (you don't want to get thrown into an infinite loop/recursion when trying to generate the output). Let's go through the basic algorithm. What are some things we need?

  1. We need a way to parse the formulas so that they're meaningful. For this example, I'm gonna assume that we'll get an input that's of the form a + b + c, where I only expect the item and + to delimit each item.
  2. We need a way to recurse down an item's dependencies to create nested childcomponents.

    // assuming jsonData is available in this scope
    
    function getStructure (elem) {
        elem = $.trim(elem);
    
        // handling an element that doesn't exist in jsonData
        if (!jsonData[elem]) {
            return {
                'mainitem': elem,
                'formula': 'none' // or whatever you want to put
            };
        }
    
        var result = {},
            formula = jsonData[elem],
            children = formula.split('+'),
            i;
    
        result['mainitem'] = elem;
        result['formula'] = formula;
    
        // or however you want to store the child components
        result['childComponent'] = [];
    
        for (i = 0; i < children.length; i += 1) {
            result['childComponent'].push(getStructure(children[i]));
        }
    
        return result;
    }
    

Upvotes: 1

Related Questions