2

I read lots of information on the net and forums but cannot get a solution to my problem. I have the following JSON file:

var data = 
{ "AA" :[{"a1":[{"ab1": [
                     {"ab1a": 10 },
                     {"ab1b": 20 },
                     {"ab1c": 30 },
                     {"ab1d": 40 }
                     ]
            },
            {"ab2":[
                     {"ab1a": 10 },
                     {"ab1b": 20 },
                     {"ab1c": 30 },
                     {"ab1d": 40 }
                    ]
            }
            ]
     }
     ,{"a2":[{"ab3": [
                     {"ab3a": 10 },
                     {"ab3b": 20 },
                     {"ab3c": 30 },
                     {"ab3d": 40 }
                     ]
             },
            {"ab4":[
                     {"ab4a": 10 },
                     {"ab4b": 20 },
                     {"ab4c": 30 },
                     {"ab4d": 40 }
                    ]
            } 
            ]
     }    
    ]
}

I have validated the JSON file. I want to get the keys first for "AA" then "a1" and "a2" and then for "ab1", "ab2" and etc. There are questions and information about values but not the keys. Most probably jQuery might help but I am confused about how to get all the keys.

Any ideas? any hope...!

istos
  • 2,654
  • 1
  • 17
  • 19
shakAttack
  • 185
  • 1
  • 8
  • Have a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in – Marvin Smit Oct 25 '14 at 08:11
  • you probably want to use some kind of recursive function http://stackoverflow.com/questions/2203958/jquery-recursive-iteration-over-objects, optionally for loops will do fine if you know how many levels of objects you have – jyrkim Oct 25 '14 at 08:39

1 Answers1

0

The key to getting all the keys from an object of unknown size is recursion. Here I have 2 solutions; one Functional and one Object Oriented. Also I created some other data to test with in addition to yours.

Here is the repo with the complete code: https://github.com/vasilionjea/json-keys


The Data:

var data = {
  continents: {
    europe: {
      countries: [
        {
          'country-name': 'italy',
          cities: [
            { 'city-name': 'Rome', title: 'Roma Dolor', population:873, gdb: 301 },
            { 'city-name': 'Venice', title: 'Venice Veggies.', population:456, gdb: 244 }
          ]
        },

        {
          'country-name': 'france',
          cities: [
            { 'city-name': 'Paris', title: 'De Ipsum', population:7123, gdb: 77 },
            { 'city-name': 'Marseille', title: 'La Mipsum', population:73, gdb: 7 }
          ]
        }
      ]
    },

    'north-america': {
      countries: [
        {
          'country-name': 'canada',
          cities: [
            { 'city-name': 'Montreal', title: 'The city of lorem ipsum!', population:99, gdb: 011 },
            { 'city-name': 'Quebec', title: 'Veggie Ipsum.', population:123, gdb: 101 }
          ]
        },
        {
          'country-name': 'usa',
          cities: [
            { 'city-name': 'New York', title: 'Empire State', population:1001001, gdb: 1010 },
            { 'city-name': 'San Francisco', title: 'SF Bridge', population:20123, gdb: 202 }
          ]
        }
      ]
    }
  }
}


The functional way:

/*
 * Functional example.
 * Retrieves all keys from an object of unknown size using recursion.
 */
function _isObject(obj) {
  return Object.prototype.toString.call(obj) === "[object Object]";
}

function _eachKey(obj, callback) {
  Object.keys(obj).forEach(callback);
}

var _container = [];

function collectKeys(data) {
  _eachKey(data, function(key) {
    _container.push(key);

    if (_isObject(data[key])) {
      collectKeys(data[key]);
    }

    if (Array.isArray(data[key])) {
      // Because we're looping through an array and each array's item is an object, 
      // the `collectKeys` function is receiving each object of the array as an argument.
      data[key].forEach(collectKeys);
    }
  });

  return _container;
}

// Execute the function
var myKeys = collectKeys(data);


The Object Oriented way:

/*
 * Object Oriented example.
 * Retrieves all keys from an object of unknown size using recursion.
 */
function JSONKeys(obj) {
  this._container = [];

  if (this._isObject(obj)) {
    // Just a normal object literal.
    this._data = obj;
  } else if (typeof obj === 'string') {
    // Just in case the data was passed in as a valid JSON string.
    this._data = JSON.parse(obj);
  } else {
    throw new Error('The provided argument must be an object literal or a JSON string.');
  }
}

JSONKeys.prototype = {
  constructor: JSONKeys,

  _isObject: function(obj) {
    return Object.prototype.toString.call(obj) === "[object Object]";
  },

  _eachKey: function(obj, callback) {
   // Using `bind(this)` makes sure that the `this` value in the `_collect` method 
   // isn't set to the global object (window).
    Object.keys(obj).forEach(callback.bind(this));
  },

  _recur: function(key, data) {
      // If this key's value is also an object go deeper.
      if (this._isObject(data[key])) {
        this._collect(data[key]);
      }

      if (Array.isArray(data[key])) {
        // * Because we're looping through an array and each array's item is an object, 
        //   the `_collect` method is receiving each object of the array as an argument.
        // * Using `bind(this)` makes sure that the `this` value in the `_collect` method 
        //   isn't set to the global object (window).
        data[key].forEach(this._collect.bind(this));
      }
  },

  _collect: function(data) {
    this._eachKey(data, function(key) {
      this._container.push(key);

      // Continue collecting
      this._recur(key, data);
    });
  },

  getAll: function() {
    this._collect(this._data);
    return this._container;
  }
};

// Create a new instance passing the data.
var keysObject = new JSONKeys(data);
allKeys = keysObject.getAll();
istos
  • 2,654
  • 1
  • 17
  • 19
  • var keys = $AA[a2][ab3].keys .Is it possible to get onliner with javascript to obtain keys out of ab3. – shakAttack Oct 28 '14 at 22:30
  • Yes there is. For example if I have the following data: `var person = { addresses: [ {street: '123 main st.', number: 7, city: 'New York'}, {street: '123 first st.', number: 99, city: 'San Francisco', state: 'CA'} ] }`, and want to get the keys of the second address in the array, then I can do this: `Object.keys(person['addresses'][1]);` – istos Oct 28 '14 at 22:42
  • I am getting somewhere..! I need to study more about Accessing Object in the Objects. when i tried "Object.keys(data['AA']['a2'][0]);" i get error data['AA']['a2'] is undefined. – shakAttack Oct 28 '14 at 23:11
  • That's because `data['AA']` is an array and array items can be queried by an integer (this index): `data['AA'][0]` gives you the first object in the array. So to get **a2** you would do `data['AA'][0]['a2']`. But **a2** is also an array, so getting an object in that array you would follow the same pattern. I'm confident you can figure out the rest. :) – istos Oct 28 '14 at 23:13