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

前端 未结 1 1718
余生分开走
余生分开走 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 = "<TABLE border=\"1\" width=\"1500\">";
        for (var r = 0; r < maxDepth; r++) {
            htmlTab += "<TR>";
            for (var c in csv) {
                htmlTab += r==0?"<TH":"<TD"; // mind 1st header row too
                if (c != 0) csvTxt += '\t';
                if (csv[c][r] != null) {
                    csvTxt += csv[c][r];
                    htmlTab += ">" + csv[c][r];
                } else htmlTab += " class=empty>"
                htmlTab += "</TD>";
            }
            csvTxt += '\r\n';
            htmlTab += r==0?"</TH>":"</TR>";
        }
        htmlTab += "</TABLE>";
        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 */
    }
    <body onload="document.body.innerHTML=convert(json)"></body>

    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 = "<TABLE border=\"1\">";
        for (var r = 0; r < maxDepth; r++) {
            htmlTab += "<TR>";
            for (var c in csv) {
                htmlTab += "<TD>";
                if (c != 0) csvTxt += '\t';
                if (csv[c][r] != null) {
                    csvTxt += csv[c][r];
                    htmlTab += csv[c][r];
                }
                htmlTab += "</TD>";
            }
            csvTxt += '\r\n';
            htmlTab += "</TR>";
        }
        htmlTab += "</TABLE>";
        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;}
    <TABLE border="1" width="900"><TR><TD>tags</TD><TD>0</TD><TD>1</TD><TD>2</TD></TR><TR><TD class="empty"></TD><TD>consequat</TD><TD>reprehenderit</TD><TD>amet</TD></TR><TR><TD>Work</TD><TD>skills</TD><TD>#</TD><TD>id</TD><TD>name</TD></TR><TR><TD class="empty"></TD><TD class="empty"></TD><TD>1</TD><TD>0</TD><TD>Programming</TD></TR><TR><TD class="empty"></TD><TD class="empty"></TD><TD>2</TD><TD>1</TD><TD>Business</TD></TR><TR><TD>friends</TD><TD>#</TD><TD>id</TD><TD>name</TD></TR><TR><TD class="empty"></TD><TD>1</TD><TD>0</TD><TD>Stafford Hernandez</TD></TR><TR><TD class="empty"></TD><TD>2</TD><TD>1</TD><TD>Colleen Christensen</TD></TR><TR><TD class="empty"></TD><TD>3</TD><TD>2</TD><TD>Barker Keith</TD></TR><TR><TD>_id</TD><TD>name</TD><TD>phone</TD><TD>address</TD><TD>favoriteFruit</TD></TR><TR><TD>5cfe7d3c6deeeef08ce0444b</TD><TD>Debra Milligain</TD><TD>+1 (906) 432-2182</TD><TD>676 Merit Court, Steinhatchee, Oregon, 5491</TD><TD>banana</TD></TR></TABLE>

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