15

Given a string as dot notation, how would I create an object from that string (checking for already existing properties): eg

var obj = {};
stringToObj('a.b', 'value1', obj);
stringToObj('a.b.c', 'value2', obj);

would produce

{
   "a": {
    "b": {
        "_x": "value1",
        "c": {
            "_x": "value2"
        }
    }
    }
 }

I've looked at this question and this one but neither seems to be sufficient for what Im doing.

Any thoughts?

Community
  • 1
  • 1
stephen mc
  • 751
  • 2
  • 12
  • 22

4 Answers4

20

For those of you who are looking for solution without the _x in the object try this code. A slight modification of the above code (which is brilliant)

stringToObj = function(path,value,obj) {
  var parts = path.split("."), part;
  var last = parts.pop();
  while(part = parts.shift()) {
   if( typeof obj[part] != "object") obj[part] = {};
   obj = obj[part]; // update "pointer"
  }
 obj[last] = value;
}

As bonus the above code will work if you want to update parts of an existing object :)

 var obj = {a:{b:3}};
 stringToObj("a.b",10,obj);
 console.log(obj); //result : {a:{b:10}}
ilikeopensource
  • 355
  • 2
  • 7
15

You can take advantage of references:

function stringToObj(path,value,obj) {
    var parts = path.split("."), part;
    while(part = parts.shift()) {
        if( typeof obj[part] != "object") obj[part] = {};
        obj = obj[part]; // update "pointer"
    }
    obj["_x"] = value;
}
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
2

To expand on both @ilikeopensource and @Niet the Dark Absol answers, I needed to add the support for arrays (multiple instances of the same path) with the possibility for nested objects. My case was more of a hybrid of dot notation and json strings.

function stringToObj(path, value, obj) {
    var objValue = value;
    try {
        objValue = JSON.parse(value);
    } catch (e) { } //eat the error, must not be json so carry on... Hack to do a valid JSON check

    var parts = path.split("."), part;
    var last = parts.pop();
    while (part = parts.shift()) {
        if (typeof obj[part] != "object")
            obj[part] = {};
        obj = obj[part];
    }
    if (obj.hasOwnProperty(last) && obj[last] && obj[last].constructor === Array) {
        obj[last].push(objValue);
    }
    else if (obj.hasOwnProperty(last) && obj[last]) {
        var objArray = [];
        objArray.push(obj[last])
        objArray.push(objValue);
        obj[last] = objArray;
    }
    else {
        obj[last] = objValue;
    }
}

Thanks guys for the help!

S1r-Lanzelot
  • 2,206
  • 3
  • 31
  • 45
  • Can you give example input for what you are supporting? ie. "support for array" And, of course the expected output. – roydukkey Jul 28 '20 at 20:20
1

This may be well answered already, but I would like to share my resolution for those who still looking for a different approach.

If you would like to convert string dot notation to a string JSON, here's my approach.

function dotToJson({ notation, inclusive = true, value = null }) {
  const fragments = notation.split(".").reverse();

  if (!inclusive) {
    fragments.pop();
  }

  console.log(fragments);

  return fragments.reduce((json, fragment) => {
    if (isNaN(fragment)) {
      return `{ "${fragment}": ${json} }`
    }

    let fill = "";

    if (Number(fragment) > 0) {
      for (let i = 0; i < fragment; i++) {
        fill += "null, "
      }
    }

    return `[${fill}${json}]`;
  }, JSON.stringify(value));
};
Attribute Meaning
notation Dot notation string
inclusive Include the root fragment
value Default value for leaf

You can see the results here, I tested it using Quokka.js

Final screenshot

NOTE: Additionally to this, thiss may help to update objects because you can use spread operator with the parsed version of the JSON

kingbeencent
  • 1,151
  • 11
  • 10