9

Instead of accessing a deep object with a known dot notation, I want to do the opposite: build the dot notation string from the keys of the deep object.

So given the following JSON object:

{
  great:{
    grand:{
      parent:{
        child:1
      },
      parent2:1
    }
  }
}

I'd like to get the following array of paths:

[
  "great.grand.parent.child",
  "great.grand.parent2"
]

Thanks in advance!

talentedmrjones
  • 7,511
  • 1
  • 26
  • 26
  • 2
    Why are people voting this down? There is a valid reason why I want to do this. Just because you don't understand why doesn't mean it's not valid. See my answer below. – talentedmrjones Nov 28 '12 at 18:56
  • As per the downvote `[title]` attribute, "This question does not show any research effort." – zzzzBov Nov 28 '12 at 19:21
  • 1
    @zzzzBov Ah, well, I just didn't post the research. Only the problem. What efforts I tried were convoluted and not working, so I thought it best just to express the problem. – talentedmrjones Nov 28 '12 at 19:24

2 Answers2

7

Try this. But I don't know why you need this.

function path(a) {
  var list = [];
  (function(o, r) {
    r = r || '';
    if (typeof o != 'object') {
      return true;
    }
    for (var c in o) {
      if (arguments.callee(o[c], r + "." + c)) {
        list.push(r.substring(1) + "." + c);
      }
    }
    return false;
  })(a);
  return list;
}
var a = {
  great:{
    grand:{
      parent:{
        child:1
      },
      parent2:1
    }
  }
};
console.log(JSON.stringify(path(a)));
mattn
  • 7,571
  • 30
  • 54
  • I rewrote it to show you what I was ultimately trying to do. After a long day, and with tired eyes and brain, I just couldn't put the pieces together last night and **needed** this code to be ready this morning. So thank you for helping out! I will post the code as an answer but have already chosen yours as the selected answer. – talentedmrjones Nov 28 '12 at 18:48
  • Not sure this outputs a valid response for objects like `{"user-id": 1}` as `obj.user-id` won't work. It should be `obj['user-id']`. – Elliot Williams Jul 09 '13 at 08:38
2
var path = function (a) {
  var list = [];
  (function(o, r) {
    r = r || '';
    if (_.isArray(o)) {
      return true;
    }
    for (var c in o) {
      if (arguments.callee(o[c], r + (r!=""?"[":"") + c + (r!=""?"]":""))) {
        list.push(r + (r!=""?"[":"") + c + (r!=""?"]":""));
      }
    }
    return false;
  })(a);
  return list;
};

With an input of something like this (a deep JSON object of input errors):

{
    "email": [
      "Enter a valid email."
    ],
    "billing": {
      "name": [
        "Enter a billing name."
      ],
      "line1": [
        "Enter a street address or PO box."
      ],
      "city": [
        "Enter a city."
      ],
      "state": [
        "Enter your state abbreviation."
      ],
      "zip": [
        "Enter a valid 5-digit zip."
      ]
    },
    "shipping": {
      "name": [
        "Enter a billing name."
      ],
      "line1": [
        "Enter a street address or PO box."
      ],
      "city": [
        "Enter a city."
      ],
      "state": [
        "Enter your state abbreviation."
      ],
      "zip": [
        "Enter a valid 5-digit zip."
      ]
    },
    "payment": {
      "number": [
        "Enter a valid credit card number."
      ],
      "exp_month": [
        "Enter a valid expiration month."
      ],
      "exp_year": [
        "Enter a valid expiration year."
      ],
      "cvc": [
        "Enter a valid CVC."
      ]
    }
 }

You get an output like this (names of inputs in array notation in which to attach errors via client-side templates)

["email", "billing[name]", "billing[line1]", "billing[city]", "billing[state]", "billing[zip]", "shipping[name]", "shipping[line1]", "shipping[city]", "shipping[state]", "shipping[zip]", "payment[number]", "payment[exp_month]", "payment[exp_year]", "payment[cvc]"]
talentedmrjones
  • 7,511
  • 1
  • 26
  • 26