Converting CSV to nested JSON in Javascript

Viewed 4337

I have a CSV file which needs to be converted into a Javascript object / JSON file. Doesn't really matter which since I'll be be handling the data in JS anyway and either is fine.

So for instance this:

name,birthday/day,birthday/month,birthday/year,house/type,house/address/street,house/address/city,house/address/state,house/occupants
Lily Haywood,27,3,1995,Igloo,768 Pocket Walk,Honolulu,HI,7
Stan Marsh,19,10,1987,Treehouse,2001 Bonanza Street,South Park,CO,2

should become this:

[
    {
        "name": "Lily Haywood",
        "birthday": {
            "day": 27,
            "month": 3,
            "year": 1995
        },
        "house": {
            "type": "Igloo",
            "address": {
                "street": "768 Pocket Walk",
                "city": "Honolulu",
                "state": "HI"
            },
            "occupants": 7
        }
    },
    {
        "name": "Stan Marsh",
        "birthday": {
            "day": 19,
            "month": 10,
            "year": 1987
        },
        "house": {
            "type": "Treehouse",
            "address": {
                "street": "2001 Bonanza Street",
                "city": "South Park",
                "state": "CO"
            },
            "occupants": 2
        }
    }
]

This is what I have came up with:

function parse(csv){
    function createEntry(header){
        return function (record){
            let keys = header.split(",");
            let values = record.split(",");
            if (values.length !== keys.length){
                console.error("Invalid CSV file");
                return;
            }
            for (let i=0; i<keys.length; i++){
                let key = keys[i].split("/");
                let value = values[i] || null;
                /////
                if (key.length === 1){
                    this[key] = value;
                }
                else {
                    let newKey = key.shift();
                    this[newKey] = this[newKey] || {};
                    //this[newKey][key[0]] = value;
                    if (key.length === 1){
                        this[newKey][key[0]] = value;
                    }
                    else {
                        let newKey2 = key.shift();
                        this[newKey][newKey2] = this[newKey][newKey2] || {};
                        this[newKey][newKey2][key[0]] = value;
                        //if (key.length === 1){}
                        //...
                    }
                }
                /////
                }
        };
    }
    let lines = csv.split("\n");
    let Entry = createEntry(lines.shift());
    let output = [];
    for (let line of lines){
        entry = new Entry(line);
        output.push(entry);
    }
    return output;
}

My code works, however there is an obvious flaw to it: for each layer it goes down into (e.g. house/address/street), I have to manually write repeated if / else statements.

Is there a better way to write it? I know this involves recursion or iteration of some kind but I just can't seem to figure out how.

I've searched around SO but most questions seem to be on doing it in Python instead of JS.

As far as possible I wish to have this done in vanilla JS without any other libraries.

2 Answers
Related