I have data in CSV format and want to convert into JSON format using JavaScript.
Following are csv format:
[Test.csv]
id;name;author
integer;string;authors:n
1;To Kill an Angry Bird;1
[authors.csv]
id;name
integer;string
1;Harper Lee
2;JRR Tolkien
3;William Shakespeare
I want to get all the books with their authors. How can I implement it using JavaScript?
-
Use jquery-csv, specifically toArrays() to convert the CSV to convert to in-memory data. Then call JSON.stringify() to convert it to JSON. Here's the link to jquery-csv github.com/evanplaice/jquery-csvEvan Plaice– Evan Plaice2016年01月21日 14:16:39 +00:00Commented Jan 21, 2016 at 14:16
8 Answers 8
The below should work for you.
All credit to Convert CSV to JSON in JavaScript (archived), by iwek:
//var csv is the CSV file with headers function csvJSON(csv){ var lines=csv.split("\n"); var result = []; var headers=lines[0].split(","); for(var i=1;i<lines.length;i++){ var obj = {}; var currentline=lines[i].split(","); for(var j=0;j<headers.length;j++){ obj[headers[j]] = currentline[j]; } result.push(obj); } //return result; //JavaScript object return JSON.stringify(result); //JSON }
If your columns contain commas in their values, you'll need to deal with those before doing the next step (you might convert them to &&& or something, then covert them back later).
5 Comments
I would check out PapaParse. They have a file called papaparse.min.js that you can drop into your project if need be. PapaParse has no dependencies.
I have used it myself and can verify it works, is convenient, and is well-documented.
Comments
Based on the code by iwek re-shared in Wesley Smith's answer, I would add if (!lines[i]) continue so it can ignore any empty line and trailing lines.
function csvJSON(csv) {
const lines = csv.split('\n')
const result = []
const headers = lines[0].split(',')
for (let i = 1; i < lines.length; i++) {
if (!lines[i])
continue
const obj = {}
const currentline = lines[i].split(',')
for (let j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j]
}
result.push(obj)
}
return result
}
2 Comments
[ { '"foo"': '"bar"', '"created"': '"2021年08月09日 13:44:42"', '"price"': '"10.00"', }, ]This solution fixed the comma issue.
function csvJSON(text, quoteChar = '"', delimiter = ',') {
var rows=text.split("\n");
var headers=rows[0].split(",");
const regex = new RegExp(`\\s*(${quoteChar})?(.*?)\1円\\s*(?:${delimiter}|$)`, 'gs');
const match = line => [...line.matchAll(regex)]
.map(m => m[2])
.slice(0, -1);
var lines = text.split('\n');
const heads = headers ?? match(lines.shift());
lines = lines.slice(1);
return lines.map(line => {
return match(line).reduce((acc, cur, i) => {
// replace blank matches with `null`
const val = cur.length <= 0 ? null : Number(cur) || cur;
const key = heads[i] ?? `{i}`;
return { ...acc, [key]: val };
}, {});
});
}
var csvtojson = csvJSON(SOME_CSV_DATA);
console.log(csvtojson)
Comments
This solution has one issue i.e. the values should not contain comma(,):
// convert csv to json
csvJSON(csvText) {
let lines = [];
const linesArray = csvText.split('\n');
// for trimming and deleting extra space
linesArray.forEach((e: any) => {
const row = e.replace(/[\s]+[,]+|[,]+[\s]+/g, ',').trim();
lines.push(row);
});
// for removing empty record
lines.splice(lines.length - 1, 1);
const result = [];
const headers = lines[0].split(",");
for (let i = 1; i < lines.length; i++) {
const obj = {};
const currentline = lines[i].split(",");
for (let j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j];
}
result.push(obj);
}
//return result; //JavaScript object
// return JSON.stringify(result); //JSON
return result;
}
// For Reading CSV File
readCSV(event) {
const reader = new FileReader();
reader.readAsText(event.files[0]);
reader.onload = () => {
const text = reader.result;
const csvToJson = this.csvJSON(text);
console.log(csvToJson);
};
}
2 Comments
Here is my try on your SPECIFIC example. I know it is an old question but I have used current methods
const titlesCsv = `id;name;author
integer;string;authors:n
1;To Kill an Mockingbird;1
2;Lord of the Rings;2
3;Hamlet;3`
const authorsCsv = `id;name
integer;string
1;Harper Lee
2;JRR Tolkien
3;William Shakespeare`
const parseCsv = csv => {
let lines = csv.split("\n");
const header = lines.shift().split(";")
lines.shift(); // get rid of definitions
return lines.map(line => {
const bits = line.split(";")
let obj = {};
header.forEach((h, i) => obj[h] = bits[i]); // or use reduce here
return obj;
})
};
const titles = parseCsv(titlesCsv)
const authors = parseCsv(authorsCsv)
const books = titles.map(title => {
return {
id: title.id,
name: title.name,
author: authors.find(author => author.id === title.author).name
}
})
console.log(books)
Comments
Here is an improved version of Sandeep Sherpur's answer. This version handles:
- comma (,) and double quotes (") inside the value fields
- empty fields
- empty lines and useless spaces
- extra or missing commas
function csvToJson(text, quoteChar = '"', delimiter = ",") {
text = text.trim()
let rows = text.split("\n")
let headers = rows[0].split(",")
const regex = new RegExp(`\\s*(${quoteChar})?(.*?)\1円\\s*(?:${delimiter}|$)`, "gs")
const match = (line) => {
const matches = [...line.matchAll(regex)].map((m) => m[2])
// Ensure matches length matches headers length by padding with null values
const paddedMatches = Array.from({ length: headers.length }, (_, i) => matches[i] ?? null)
return paddedMatches
}
let lines = text.split("\n")
const heads = headers ?? match(lines.shift())
lines = lines.slice(1)
return lines.map((line) => {
return match(line).reduce((acc, cur, i) => {
// replace blank matches with `null`
const val = cur === null || cur.length <= 0 ? null : Number(cur) || cur
const key = heads[i] ?? `{i}`
return { ...acc, [key]: val }
}, {})
})
}
const csvString = `
aa,bb,cc
11,22,33
44,
77,,99
`
const jsonData = csvToJson(csvString)
console.log(jsonData)
Comments
I have a similar answer like the code by iwek re-shared in Wesley Smith's answer, but my code can be used in conjunction with Excel directly (copy and paste from Excel into a textarea).
function csvUpload(csvText){
//Split all the text into seperate lines on new lines and carriage return feeds
var allTextLines = csvText.split(/\r\n|\n/);
//Split per line on tabs and commas
var headers = allTextLines[0].split(/\t|,/);
var lines = [];
var locations = [];
for (var i=1; i<allTextLines.length; i++) {
var data = allTextLines[i].split(/\t|,/);
if (data.length == headers.length) {
var location = {"device_id":data[0], "address":data[1], "city":data[2]};
locations.push(location);
}
}
return locations;
}
This way you can use a CSV that is copied into Excel. Excel will remove the seperators like , and others and will insert newlines etc.
With the my code you can pass everything into a textfield directly from Excel and then use that to create a json.
I have the naming of the fields static here, but you could use iwek's code to set the headers dynamically:
for(var j=0;j<headers.length;j++){
obj[headers[j]] = currentline[j];
}