我有一个CSV文件需要转换为Javascript对象/ JSON文件。因为我无论如何要处理JS中的数据并且其中任何一个都没问题,这并不重要。
例如:
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
应该成为这个:
[
{
"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
}
}
]
这就是我想出的:
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;
}
我的代码有效,但是它有一个明显的缺陷:对于每个层,它都会进入(例如house/address/street
),我必须手动编写重复的if / else
语句。
有没有更好的方法来写它?我知道这涉及某种递归或迭代,但我似乎无法弄清楚如何。
我已经搜索过,但大多数问题似乎都是用Python代替JS。
我希望尽可能在没有任何其他库的vanilla JS中完成此操作。
答案 0 :(得分:3)
您可以通过递归创建Object来实现预期的结果 请看下面的代码:
var csv = [
"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"
];
var attrs = csv.splice(0,1);
var result = csv.map(function(row) {
var obj = {};
var rowData = row.split(',');
attrs[0].split(',').forEach(function(val, idx) {
obj = constructObj(val, obj, rowData[idx]);
});
return obj;
})
function constructObj(str, parentObj, data) {
if(str.split('/').length === 1) {
parentObj[str] = data;
return parentObj;
}
var curKey = str.split('/')[0];
if(!parentObj[curKey])
parentObj[curKey] = {};
parentObj[curKey] = constructObj(str.split('/').slice(1).join('/'), parentObj[curKey], data);
return parentObj;
}
console.log(result);
.as-console-wrapper{max-height: 100% !important; top:0}
constructObj()
函数基本上通过查看列名来递归地构造结果对象,因此如果列名包含像/
中的house/address/street
,它将在对象中创建一个键名称house
然后以字符串address/street/
递归调用其余剩余键的自身。当字符串中不再有/
时,递归结束,然后它只是分配该键中的值并返回结果对象。
答案 1 :(得分:1)
您可以映射您的记录并动态创建对象:
let records = ['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']
let output = records.map( record => {
let arr = record.split(',')
return {
"name": arr[0],
"birthday": {
"day": parseInt(arr[1]),
"month": parseInt(arr[2]),
"year": parseInt(arr[3])
},
"house": {
"type": arr[4],
"address": {
"street": arr[5],
"city": arr[6],
"state": arr[7]
},
"occupants": parseInt(arr[8])
}
}
})
console.log(output)
&#13;