traversing through JSON string to inner levels using recursive function

I have a JSON input which can go to any number of levels.

I'm giving an input sample of

var d=getEntities( {"Categories": 
{
"Facets": 
    [
    {
    "count": 1,
    "entity": "Company",
    "Company": 
            [
            {

            "entity": "Ford Motor Co",

            "Ford_Motor_Co": 
                [
                    {
                    "count": 1,
                    "entity": "Ford"
                    }
                ]
            }
            ]
    },
        {
            "count": 4,
            "entity": "Country",
              "Country": [
                    {

                        "entity": "Germany",
                         "Germany": [
                                {
                                    "count": 1,
                                    "entity": "Germany"
                                }
                          ],
                        "currency": "Euro (EUR)"
                    },
                    {

                         "entity": "Italy",
                        "Italy": [
                                {
                                     "count": 1,
                                     "entity": "Italy"
                                }
                          ],
                        "currency": "Euro (EUR)"
                    },
                    {

                        "entity": "Japan",
                          "Japan": [
                             {
                                    "count": 1,
                                    "entity": "Japan"
                             }
                          ],
                        "currency": "Yen (JPY)"
                    },
                    {

                        "entity": "South Korea",
                          "South_Korea": [
                              {
                                    "count": 1,
                                    "entity": "South Korea"
                                }
                          ],
                      "currency": "Won (KRW)"
                    }
              ]
        },
        {"count": 5,
              "entity": "Persons",
              "Persons": [
                    {
                         "count": 2,
                        "entity": "Dodge"
                    },
                    {
                        "count": 1,
                        "entity": "Dodge Avenger"
                    },
                    {
                        "count": 1,
                        "entity": "Major League"
                    },
                    {
                        "count": 1,
                        "entity": "Sterling Heights"
                    }
              ]
        }
  ]

}});

I want to add the key value "Entity" in all levels to an array using recursion,

I'm able to collect the data from first level using the string

<html>
<head>
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript" src="dataDumper.js"></script>


<script type="text/javascript">

var testJSON = {"Categories": 
{
"Facets": 
    [
    {
    "count": 1,
    "entity": "Company",
    "Company": 
            [
            {

            "entity": "Ford Motor Co",

            "Ford_Motor_Co": 
                [
                    {
                    "count": 1,
                    "entity": "Ford"
                    }
                ]
            }
            ]
    },
        {
            "count": 4,
            "entity": "Country",
              "Country": [
                    {

                        "entity": "Germany",
                         "Germany": [
                                {
                                    "count": 1,
                                    "entity": "Germany"
                                }
                          ],
                        "currency": "Euro (EUR)"
                    },
                    {

                         "entity": "Italy",
                        "Italy": [
                                {
                                     "count": 1,
                                     "entity": "Italy"
                                }
                          ],
                        "currency": "Euro (EUR)"
                    },
                    {

                        "entity": "Japan",
                          "Japan": [
                             {
                                    "count": 1,
                                    "entity": "Japan"
                             }
                          ],
                        "currency": "Yen (JPY)"
                    },
                    {

                        "entity": "South Korea",
                          "South_Korea": [
                              {
                                    "count": 1,
                                    "entity": "South Korea"
                                }
                          ],
                      "currency": "Won (KRW)"
                    }
              ]
        },
        {"count": 5,
              "entity": "Persons",
              "Persons": [
                    {
                         "count": 2,
                        "entity": "Dodge"
                    },
                    {
                        "count": 1,
                        "entity": "Dodge Avenger"
                    },
                    {
                        "count": 1,
                        "entity": "Major League"
                    },
                    {
                        "count": 1,
                        "entity": "Sterling Heights"
                    }
              ]
        }
  ]

}};

function scan(obj)
{
    var k;
    if (obj.hasOwnProperty('entity')) {



        for (k in obj){
           if (obj.hasOwnProperty(k)){


                scan( obj[k] );  


            }                
          }
    } 


    else{
        if(k=='entity')
        {
        alert(obj.entity);
   }
    }


};

scan(testJSON);



</script>
</head>

<body>

</body>

</html>

How do I get in to the inner levels for JSON string using recursive functions?


Solution 1:

I have made a jsfiddle which traverses every object,array and value in the JS object like so...

function scan(obj) {
    var k;
    if (obj instanceof Object) {
        for (k in obj){
            if (obj.hasOwnProperty(k)){
                //recursive call to scan property
                scan( obj[k] );  
            }                
        }
    } else {
        //obj is not an instance of Object so obj here is a value
    };

};

I get no recursion error (in Chrome). Can you use this to do what you want?

If you need to test if an object is an array use if (obj instanceof Array)

To test if an object has an "entity" property use if (obj.hasOwnProperty('entity'))

To add (or modify an existing) "entity" property use obj.entity = value or obj['entity'] = value

Solution 2:

(function recur( obj ) {
    Object.keys( obj ).forEach( function( prop ) {
        // Check if the property is an object
        if ( ({}).toString.apply( prop ) === '[object Object]' ) {
            // If it is, recall this function
            recur( prop );
        }
    } );
} () );

I haven't added your logic, but you get the idea of how to recursively traverse your object.

Solution 3:

Say I have a structure like the following:

var aObject = {
    items: [],
    children: {}
}

Children is an associative array that contains more aObjects. So it could look like this:

var aObject = {
    items: [],
    children: {
        "subgroup1": {
            items: [],
            children: {}
        },
        "subgroup2": {
            items: [],
            children: {}
        }
    }
}

I have an item that contains an array of subgroups:

["subgroup1", "subgroup1a"]

Each subgroup is a 'location'. The item needs to be placed at:

aObject.children[array[0]].children[array[1]].items

At each level, we have to check if children[array[i]] exists, and if not, create it. You can't simply write aObject.children[array[0]].children[array[1]].items.push(item) because children[array[0]] might not already exist and we will get an error.

This can be solved using recursion! (AngularJS)

function recursive(aLevel, aItem, aArray, aIndex){
    var lLevel = aLevel;

    // If we have reached the end of the array
    if (aIndex === aArray.length){
        // Insert
        aLevel.items.push(aItem);
    } else {

        // If the subgroup doesn't exist, create it
        if (typeof aLevel.children[aArray[aIndex]] === 'undefined'){
            aLevel.children[aArray[aIndex]] = {
              items: [],
              children: {}
            };
        }

        // Move into
        recursive(aLevel.children[aArray[aIndex]], aItem, aArray, aIndex+1);
    }
}

aObject = {
    items: [],
    children: {},
}

angular.forEach(items, function(item, i){
    var location = item.location;

    if (location.length == 0){
        aObject.items.push(item);
    } else {
        recursive(aObject, item, location, 0);
    }
});

The final aObject would look like this:

var aObject = {
     items: [],
     children: {
        "subgroup1": {
            items: [],
            children: {
                "subgroup1a": {
                    items: [item],
                    children: {}
                }
            }
        },
        "subgroup2": {
            items: [],
            children: {}
        }
    }
}

Solution 4:

Here is a function that i use often. It's easily modifiable to do many recursive tasks. For example if you add a bail flag you can quickly get the stack or add a callback function that makes it even more general. Anyway that's my 2 cents

var recursiveObjMap = (function(){
  var stack = [];
  var result = [];
  // var bail = false;
  return function map(data, key){
    if (!$.isArray(data) && !$.isPlainObject(data) ) { 
      result.push(data);
      return false 
    }

    $.each(data, function(i, v){
      if (key) stack.push(key);
      map(v, i);
      stack.pop();
    });
    return result;
  };
})();

recursiveObjMap({a:'b',c:{d:{e:"f"}}}) // ['b', 'f']