This question already has answers here:
Closed 2 years ago.
I have csv files that I am reading using nodeJS. I convert each file to text before reading.
Each line in the file have data delimited with '='.
Each line looks something like
data.location.degree.text=sometexthere
The first portion before the "=" represent an index to a json object in my app. I aim to parse this data and build a json representation of it so that the line above becomes
data:{
location:{
degree:{
text: 'sometexthere'
}
}
}
Using javascript/ node js; How can I convert a string which is supposed to represent a sequence of nested JSON keys, into a json object like above?
You could split the path and make a check if the following element exist. If not assign an object to the new property.
Return then the value of the property.
At the end assign the value.
function setValue(object, path, value) {
path = path.replace(/[\[]/gm, '.').replace(/[\]]/gm, ''); //to accept [index]
var keys = path.split('.'),
last = keys.pop();
keys.reduce(function (o, k) { return o[k] = o[k] || {}; }, object)[last] = value;
}
var data = {};
setValue(data, 'location.degree.text', 'sometexthere');
console.log(data);
// result container
var res = {};
// input data
var inp = [
'data.location.degree.text=sometexthere',
'data.otherLocation.degree.otherText=foo',
'data.location.degree.otherText=bar',
'we.can.do.undefined.values='
];
// recursive function
var pathToObject = function(resultReference, path)
{
// split path on dots
// e.g. data.location.degree.text=sometexthere
// -> ["data", "location", "degree", "text=sometexthere"]
var splitPathParts = path.split('.');
// if there is only one part, we're at the end of our path expression
// e.g. ["text=sometexthere"]
if (splitPathParts.length === 1){
// split "text=sometexthere" into ["text", "sometexthere"]
var keyAndValue = splitPathParts[0].split('=');
// set foo = bar on our result object reference
resultReference[keyAndValue[0]] = keyAndValue[1];
return;
}
// the first element of the split array is our current key
// e.g. for ["data", "location", "degree", "text=sometexthere"],
// the currentKey would be "data";
var currentKey = splitPathParts.shift();
// if our object does not yet contain the current key, set it to an empty object
resultReference[currentKey] || (resultReference[currentKey] = {});
// recursively call ourselves, passing in
// the nested scope and the rest of the path.
// e.g. { data : {} } and 'location.degree.text=sometexthere'
pathToObject(resultReference[currentKey], splitPathParts.join('.'));
}
for (var i = 0; i < inp.length; i++)
{
pathToObject(res, inp[i]);
}
console.log(res);
ES6 syntax makes things slightly more compact:
'use strict';
const pathToObject = (resultReference, path) => {
let [currentKey, ...restOfPath] = path.split('.');
if (restOfPath.length === 0) {
let [k, v] = currentKey.split('=');
resultReference[k] = v;
return;
}
resultReference[currentKey] || (resultReference[currentKey] = {});
pathToObject(resultReference[currentKey], restOfPath.join('.'));
}
let res = {};
[
'data.location.degree.text=sometexthere',
'data.otherLocation.degree.otherText=foo',
'data.location.degree.otherText=bar',
'we.can.do.undefined.values='
].forEach(x => pathToObject(res, x));
console.log(res);