JSON To CSV conversion (JavaScript) : How to properly format CSV conversion

前端 未结 1 1719
余生分开走
余生分开走 2021-01-25 13:14

I want to convert JSON responses to CSV format. I was able to figure out how to properly generate the headers in a way where parents of a key are appended together to generate a

1条回答
  •  孤城傲影
    2021-01-25 14:01

    Is that it (have to run the snippet to see results as HTML table demo - do not know how to put it here directly) ?

    function readDown(headName, arr, outRows) {
        var under = [headName];
        while (arr.toString().indexOf("[object") == 0
            || Array.isArray(arr)) {
            var hasArray = false;
            for (var i in arr) {
                if (arr[i].toString().indexOf("[object") == 0
                    || Array.isArray(arr[i])) hasArray = true;
            }
            if (hasArray) {
                for (var i in arr)
                    if (arr[i].toString().indexOf("[object") == 0
                        || Array.isArray(arr[i])) {
                        if (isNaN(i)) under[0] += '_' + i;
                        readDown(under[0], arr[i], outRows);
                        if (arr.length === undefined)
                            return; // empty associative (skills)
                        delete arr[i++];
                        var next = false; // are there following arrays to be groupped ?
                        while (i && arr[i - 1] === undefined && i < arr.length && (arr[i].toString().indexOf("[object") == 0
                            || Array.isArray(arr[i]))) { // group whole lowest array
                            next = true;
                            var idx = outRows.length - 1
                            if (!Array.isArray(outRows[idx][1])) {
                                outRows[idx][1] = [outRows[idx][1], arr[i++]];
                            } else outRows[idx][1].push(arr[i++]);
                            delete arr[i - 1];
                        }
                        if (next && i == arr.length) {
                            arr.length = 0; // array full of undefined members, fix length in case
                            return null; // and return - we are done here
                        }
                    } else { // funny never get there now
                        if (hasArray && isNaN(i)) under[0] += '_' + i;
                        under.push(arr[i]);
                        break;
                    }
            } else {
                if (arr.length === undefined) { // Work_skills[0], friends[0]
                    under.push(arr);
                    outRows.push(under);
                } else { // tags, greetings
                    if(!arr.length) return; // do not keep empty greetings
                    for (var i in arr) under.push(arr[i]);
                    outRows.push(under);
                }
                return null; // all arrays return here
            }
            // unreachable next
        }
    }
    function JSON2CSV(arr, inRows, outRows) {
        var row = [];
        var hasArray = false;
        for (var a in arr) {
            try {
                if (arr[a] == null) { // Change null's to string
                    arr[a] = "null";
                }
                if (Array.isArray(arr[a]) || arr[a].toString().indexOf("[object") == 0) {
                    readDown(a, arr[a], outRows);
                    continue;
                } else {
                    if (isNaN(a)) {
                        outRows.push([a, arr[a]]);
                    } else {
                        outRows.push(['#', arr[a]]);
                    }
                }
            } catch (e) {
                return e;
            }
        }
    }
    function convert(json) {
        var JSONtxt;
        try {
            JSONtxt = JSON.parse(json);
        } catch (e) {
            console.log(e);
            return;
        }
        var columnsArray = [];
        JSON2CSV(JSONtxt, [], columnsArray);
        var maxDepth = 1; // find longest lowest array size
        for (var i in columnsArray)
            if (Array.isArray(columnsArray[i][1])
                && maxDepth < columnsArray[i][1].length)
                maxDepth = columnsArray[i][1].length;
        maxDepth++;
        var csv = [];
        for (var c in columnsArray) {
            if (Array.isArray(columnsArray[c][1])) {
                var r = 0;
                for (var nd in columnsArray[c][1][r]) {
                    csv.push([columnsArray[c][0] + '_' + nd]); // top header
                    var col = csv.length - 1;
                    for (; r < columnsArray[c][1].length; r++) {
                        csv[col].push(columnsArray[c][1][r][nd]); // key's value
                        delete columnsArray[c][1][r][nd];
                    }
                    r = 0;
                }
    
            } else {
                csv.push(columnsArray[c]);
            }
            while (csv[c].length < maxDepth) csv[c].push(null);
        }
        var csvTxt = ""; // tab separated values (copy/paste 2 XL ?)
        var htmlTab = "";
        for (var r = 0; r < maxDepth; r++) {
            htmlTab += "";
            for (var c in csv) {
                htmlTab += r==0?"":"";
        }
        htmlTab += "
    "; return htmlTab; } var json = '{"_id": "5cfe7d3c6deeeef08ce0444b","name": "Debra Milligain","phone": "+1 (906) 432-2182","address": "676 Merit Court, Steinhatchee, Oregon, 5491","tags": ["consequat","reprehenderit","amet"],"Work": {"skills": [{"id": 0,"name": "Programming"},{"id": 1,"name": "Business"}]},"friends": [{"id": 0,"name": "Stafford Hernandez"},{"id": 1,"name": "Colleen Christensen"},{"id": 2,"name": "Barker Keith"}],"greeting": [],"favoriteFruit": "banana"}';
    table {
      border-spacing: 0px; /* small tricks 2 make rounded table simply or */
    }
    th {
      text-align:left; /* centered looks ugly */
    }
    td.empty {
      background-color:lightgray; /* mark null cells */
    }

    Original code without tidy modifications for the snippet:

    function readDown(headName, arr, outRows) {
        var under = [headName];
        while (arr.toString().indexOf("[object") == 0
            || Array.isArray(arr)) {
            var hasArray = false;
            for (var i in arr) {
                if (arr[i].toString().indexOf("[object") == 0
                    || Array.isArray(arr[i])) hasArray = true;
            }
            if (hasArray) {
                for (var i in arr)
                    if (arr[i].toString().indexOf("[object") == 0
                        || Array.isArray(arr[i])) {
                        if (isNaN(i)) under[0] += '_' + i;
                        readDown(under[0], arr[i], outRows);
                        if (arr.length === undefined)
                            return; // empty associative (skills)
                        delete arr[i++];
                        var next = false; // are there following arrays to be groupped ?
                        while (i && arr[i - 1] === undefined && i < arr.length && (arr[i].toString().indexOf("[object") == 0
                            || Array.isArray(arr[i]))) { // group whole lowest array
                            next = true;
                            var idx = outRows.length - 1
                            if (!Array.isArray(outRows[idx][1])) {
                                outRows[idx][1] = [outRows[idx][1], arr[i++]];
                            } else outRows[idx][1].push(arr[i++]);
                            delete arr[i - 1];
                        }
                        if (next && i == arr.length) {
                            arr.length = 0; // array full of undefined members, fix length in case
                            return null; // and return - we are done here
                        }
                    } else { // funny never get there now
                        if (hasArray && isNaN(i)) under[0] += '_' + i;
                        under.push(arr[i]);
                        break;
                    }
            } else {
                if (arr.length === undefined) { // Work_skills[0], friends[0]
                    under.push(arr);
                    outRows.push(under);
                } else { // tags, greetings
                    if(!arr.length) return; // do not keep empty greetings
                    for (var i in arr) under.push(arr[i]);
                    outRows.push(under);
                }
                return null; // all arrays return here
            }
            // unreachable next
        }
    }
    function JSON2CSV(arr, inRows, outRows) {
        var row = [];
        var hasArray = false;
        for (var a in arr) {
            try {
                if (arr[a] == null) { // Change null's to string
                    arr[a] = "null";
                }
                if (Array.isArray(arr[a]) || arr[a].toString().indexOf("[object") == 0) {
                    readDown(a, arr[a], outRows);
                    continue;
                } else {
                    if (isNaN(a)) {
                        outRows.push([a, arr[a]]);
                    } else {
                        outRows.push(['#', arr[a]]);
                    }
                }
            } catch (e) {
                return e;
            }
        }
    }
    function convert(json) {
        var JSONtxt;
        try {
            JSONtxt = JSON.parse(json);
        } catch (e) {
            console.log(e);
            return;
        }
        var columnsArray = [];
        JSON2CSV(JSONtxt, [], columnsArray);
        var maxDepth = 1; // find longest lowest array size
        for (var i in columnsArray)
            if (Array.isArray(columnsArray[i][1])
                && maxDepth < columnsArray[i][1].length)
                maxDepth = columnsArray[i][1].length;
        maxDepth++;
        var csv = [];
        for (var c in columnsArray) {
            if (Array.isArray(columnsArray[c][1])) {
                var r = 0;
                for (var nd in columnsArray[c][1][r]) {
                    csv.push([columnsArray[c][0] + '_' + nd]); // top header
                    var col = csv.length - 1;
                    for (; r < columnsArray[c][1].length; r++) {
                        csv[col].push(columnsArray[c][1][r][nd]); // key's value
                        delete columnsArray[c][1][r][nd];
                    }
                    r = 0;
                }
    
            } else {
                csv.push(columnsArray[c]);
            }
            while (csv[c].length < maxDepth) csv[c].push(null);
        }
        var csvTxt = ""; // tab separated values (copy/paste 2 XL ?)
        var htmlTab = "";
        for (var r = 0; r < maxDepth; r++) {
            htmlTab += "";
            for (var c in csv) {
                htmlTab += "";
            }
            csvTxt += '\r\n';
            htmlTab += "";
        }
        htmlTab += "
    "; if (c != 0) csvTxt += '\t'; if (csv[c][r] != null) { csvTxt += csv[c][r]; htmlTab += csv[c][r]; } htmlTab += "
    "; console.log(csvTxt); console.log(htmlTab); } var json = '{"_id": "5cfe7d3c6deeeef08ce0444b","name": "Debra Milligain","phone": "+1 (906) 432-2182","address": "676 Merit Court, Steinhatchee, Oregon, 5491","tags": ["consequat","reprehenderit","amet"],"Work": {"skills": [{"id": 0,"name": "Programming"},{"id": 1,"name": "Business"}]},"friends": [{"id": 0,"name": "Stafford Hernandez"},{"id": 1,"name": "Colleen Christensen"},{"id": 2,"name": "Barker Keith"}],"greeting": [],"favoriteFruit": "banana"}'; convert(json);

    And even my original JSONoperations.hta CSV export does not look so bad, but a bit rotated and includes useless 1-level numbering, anyway if I would start here ;-)

    table { border-spacing: 0px; }
    th { text-align:left; }
    td.empty { background-color:lightgray;}
    tags012
    consequatreprehenderitamet
    Workskills#idname
    10Programming
    21Business
    friends#idname
    10Stafford Hernandez
    21Colleen Christensen
    32Barker Keith
    _idnamephoneaddressfavoriteFruit
    5cfe7d3c6deeeef08ce0444bDebra Milligain+1 (906) 432-2182676 Merit Court, Steinhatchee, Oregon, 5491banana

    0 讨论(0)
提交回复
热议问题