Outputting a comma separated txt file as a csv file in javascript

Viewed 137

I have written a function in javascript that identifies a table in a HTML webpage, parses through the data and downloads it as comma separated values that retains the correct structure of the table. I was hoping there would be a simple way to download the tables as a csv file instead, making sure it keeps the correct structure (i.e. blank cells when present etc).

function downloadTableData(){
try{
var file_string = "";

var table_number = window.prompt("Table number:") - 1;
var column_names = document.getElementsByTagName("table")[table_number].children[0].children[0].children;

col_names = "";
for(var i=0; i<column_names.length; i++){
    col_names += column_names[i].innerText+",";
}
file_string += col_names += "\n";


var table_rows = document.getElementsByTagName("table")[table_number].children[1].children;
var extracted_rows = [];

for(var row_i=0; row_i<table_rows.length; row_i++){
    var row_vals = ""
    for(var col_i=0; col_i<table_rows[row_i].children.length; col_i++){
        row_vals += table_rows[row_i].children[col_i].innerText + ",";
        
    }
    file_string += row_vals+"\n";
    
    extracted_rows.push(row_vals);
}

var textInput = file_string;
alert('Table successfully detected');
var filename = window.prompt("Filename:");

var element = document.createElement('a');
element.setAttribute('href','data:text/plain;charset=utf-8, ' + encodeURIComponent(textInput));
element.setAttribute('download', filename);
document.body.appendChild(element);
element.click();
} catch(err){
    alert('No table detected');
}
2 Answers

You can create a blob with type text/csv

let hiddenElement = document.createElement("a");
let csvData = new Blob([textInput], { type: "text/csv" });
let csvUrl = URL.createObjectURL(csvData);
element.href = csvUrl;
element.target = "_blank";
element.download = filename + ".csv";
element.click();

Given this HTML Table sample:

<table id="tableTest">
    <thead>
        <tr>
            <th>Name</th>
            <th>Surname</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>John</td>
            <td>Doe</td>
        </tr>
        <tr>
            <td>Anne</td>
            <td>Mar</td>
        </tr>
    </tbody>
</table>
  • Create some nifty reusable DOM utility functions
  • Create a reusable download() function
  • Create a tableToCSV() function that converts a common HTML Table to CSV
// DOM utility functions:

const
    ELNew = (tag, prop) => Object.assign(document.createElement(tag), prop),
    ELS = (sel, par) => (par || document).querySelectorAll(sel),
    EL = (sel, par) => (par || document).querySelector(sel);


// Task functions:

const
    download = (href, name = "unnamed") => {
        const EL_a = ELNew("a", { href, download: name });
        EL("body").append(EL_a);
        EL_a.click();
        EL_a.remove();
    };

const
    tableToCSV = (El_table, delimiter = ";") =>
        [...ELS("tr", El_table)].map(EL_tr => [...ELS("th,td", EL_tr)].map(EL_cell => EL_cell.textContent).join(delimiter)).join("\n");

to get your Table as CSV String use:

const CSV = tableToCSV(EL("#tableTest"));

Tip: The default delimiter is ";". To change it to i.e a Comma use:

const CSV = tableToCSV(EL("#tableTest"), ",");

finally to download it use your download() function.
Here are two examples:

  1. using URI encoded Base64 data href
download(
    "data:text/csv;charset=utf-8,\uFEFF" + encodeURIComponent(CSV),
    `whatever.csv`
);
  1. using a Blob as ObjectURL
download(
    URL.createObjectURL(new Blob([CSV], { type: "text/csv;charset=utf-8" })),
    `whatever.csv`
);

Final output file:

whatever.csv

Name;Surname
John;Doe
Anne;Mar
Related