使用python、nodejs、xlsx.full.min.js处理省市区excel数据转成json**
需求描述:通常会拿到excel这样的数据格式,但是我们在代码里使用一般是json类型的数据,因此需要将excel里的数据内容转成json格式的。可通过三种方法实现:python、nodejs+mongodb、xlsx.full.min.js
一、python
Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。
1、特点:
1.易于学习:Python有相对较少的关键字,结构简单,和一个明确定义的语法,学习起来更加简单。
2.易于阅读:Python代码定义的更清晰。
3.易于维护:Python的成功在于它的源代码是相当容易维护的。
4.一个广泛的标准库:Python的最大的优势之一是丰富的库,跨平台的,在UNIX,Windows和Macintosh兼容很好。
5.互动模式:互动模式的支持,您可以从终端输入执行代码并获得结果的语言,互动的测试和调试代码片断。
6.可移植:基于其开放源代码的特性,Python已经被移植(也就是使其工作)到许多平台。
7.可扩展:如果你需要一段运行很快的关键代码,或者是想要编写一些不愿开放的算法,你可以使用C或C++完成那部分程序,然后从你的Python程序中调用。
8.数据库:Python提供所有主要的商业数据库的接口。
9.GUI编程:Python支持GUI可以创建和移植到许多系统调用。
10.可嵌入: 你可以将Python嵌入到C/C++程序,让你的程序的用户获得"脚本化"的能力。
2、python环境搭建
3、运行python文件
// aa.py
print('hello');
//运行
python a.py
4、运行代码
import json
import pandas as pd
class BookTree:
def __init__(self, excel_path, out_file):
self.excel_path = excel_path
self.fp = open(out_file, 'w')
def get_name(self, lt):
lt1 = []
for i in lt:
if str(i).strip() and i not in lt1:
lt1.append(i)
return lt1
def parse_data(self, df, num):
code_ = '行政区域代码' + str(num)
name_ = '行政区域名称' + str(num)
if num == 3:
codes = self.get_name(df[code_].tolist())
lt = []
for code in codes:
dic = {}
dic['code'] = str(code).strip()
name = df[df[code_] == code][name_].tolist()[0].strip()
dic['name'] = name
lt.append(dic)
return lt
else:
codes = self.get_name(df[code_].tolist())
lt = []
for code in codes:
dic = {}
dic['code'] = str(code).strip()
name_lt = df[df[code_] == code][name_].tolist()
dic['name'] = name_lt[0].strip()
chil = self.parse_data(df[df[code_] == code], num + 1)
if chil:
dic['children'] = chil
lt.append(dic)
return lt
def get_df(self):
df = pd.read_excel(self.excel_path, dtype=object)
df = df.dropna(how='all').fillna('')
city = self.parse_data(df, 1)
print(json.dumps({'city': city}, ensure_ascii=False, indent=4), file=self.fp)
def process(self):
self.get_df()
def main():
excel_path = 'test.xlsx'
out_file = 'test.json'
book_tree = BookTree(excel_path, out_file)
book_tree.process()
if __name__ == '__main__':
main()
5、代码解析
二、js实现
1、xlsx.full.min.js
是一个前端上传excel解析工具,将excel表格额数据解析为json形式。
支持xls、xlsx、cds等格式
2、代码实现
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Excel Analysis</title>
<style>
h1 {
text-align: center;
}
#input {
white-space: pre;
margin: 20px 0;
}
#drop {
border: 2px dashed #bbb;
border-radius: 5px;
padding: 25px;
text-align: center;
font: 20pt bold;
color: #bbb;
}
#xlf {
float: left;
}
#output {
resize: vertical;
white-space: pre-wrap;
box-sizing: border-box;
width: 100%;
height: 200px;
padding: 10px;
font-size: 12px;
line-height: 18px;
}
</style>
</head>
<body>
<h1>Excel Analysis</h1>
<div id="input">
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
<div>Or click here to select a file:</div>
<input type="file" id="xlf">
</div>
<textarea id="output"></textarea>
<script src="https://cdn.bootcdn.net/ajax/libs/xlsx/0.16.9/xlsx.full.min.js"></script>
<!-- <script src="//oss.sheetjs.com/js-xlsx/xlsx.full.min.js"></script> -->
<script>
/* eslint-disable */
let processWb = (function () {
let out = document.getElementById('output');
let toJson = function (workbook) {
let result = {};
workbook.SheetNames.forEach(function (sheetName) {
let roa = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {
header: 1
});
if (roa.length) {
result[sheetName] = roa;
}
});
return JSON.stringify(result, 2, 2);
};
let processCode = function (code) {
let result = [];
let k = 0;
for (let i = 0; i <= code.length - 1; i++) {
if (i > 0 && (code[i][0] !== code[i - 1][0])) {
k++;
}
result[k] = result[k] || {};
result[k]['code'] = String(code[i][0]);
result[k]['name'] = code[i][1];
let rr = recursive(code[i].slice(2, code[i].length));
result[k]['children'] = combine(result[k]['children'], rr);
}
let json = {
resultCode: '000000',
resultMsg: '成功',
resultData: result
};
return JSON.stringify(json);
};
let recursive = function (data) {
let result = {code: String(data[0]), name: data[1]};
if (data.length <= 2) {
return result;
} else {
result['children'] = [recursive(data.slice(2, data.length))];
return result;
}
};
let combine = function (node = [], data) {
let cNode = node.filter((n) => n.code === data.code);
console.log(cNode,data)
if (!cNode || !cNode.length) {
node.push(data);
return node;
} else {
cNode = cNode[0];
cNode.children = combine(cNode.children, data.children[0]);
return node;
}
};
return function (wb) {
let output = toJson(wb);
output = JSON.parse(output);
let code = Reflect.get(output, Reflect.ownKeys(output)[0]);
out.innerText = processCode(code);
};
})();
let doFile = (function () {
return function (files) {
let f = files[0];
let reader = new FileReader();
reader.onload = function (e) {
let data = e.target.result;
processWb(XLSX.read(data, {
type: 'array'
}));
};
reader.readAsArrayBuffer(f);
};
})();
(function () {
let drop = document.getElementById('drop');
if (!drop.addEventListener) {
return;
}
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
doFile(e.dataTransfer.files);
}
function handleDragover(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
}
drop.addEventListener('dragenter', handleDragover, false);
drop.addEventListener('dragover', handleDragover, false);
drop.addEventListener('drop', handleDrop, false);
})();
(function () {
let xlf = document.getElementById('xlf');
if (!xlf.addEventListener) {
return;
}
function handleFile(e) {
doFile(e.target.files);
}
xlf.addEventListener('change', handleFile, false);
})();
</script>
</body>
</html>
3、代码解析
①读取excel
读取excel主要是通过XLSX.read(data, {type: type})
;方法来实现,返回一个叫WorkBook的对象,type主要取值如下:
base64: 以base64方式读取;
binary: BinaryString格式(byte n is data.charCodeAt(n))
string: UTF8编码的字符串;
buffer: nodejs Buffer;
array: Uint8Array,8位无符号数组;
file: 文件的路径(仅nodejs下支持);
②读取本地文件
// 示例
let doFile = (function () {
return function (files) {
let f = files[0];
let reader = new FileReader();
reader.onload = function (e) {
let data = e.target.result;
processWb(XLSX.read(data, {
type: 'array'
}));
// XLSX.read()会返回一个workback对象
};
reader.readAsArrayBuffer(f);
};
})();
workbook打印
可以看到,SheetNames
里面保存了所有的sheet名字,然后Sheets则保存了每个sheet的具体内容(我们称之为Sheet Object)。每一个sheet是通过类似A1这样的键值保存每个单元格的内容,我们称之为单元格对象(Cell Object),也就是excel表格的数据:
每一个Sheet Object
表示一张表格,只要不是!开头的都表示普通cell,否则,表示一些特殊含义,具体如下:
sheet['!ref']
:表示所有单元格的范围,例如从A1到F8则记录为A1:F8;sheet[!merges]
:存放一些单元格合并信息,是一个数组,每个数组由包含s和e构成的对象组成,s表示开始,e表示结束,r表示行,c表示列;
等等;
每一个单元格是一个对象(Cell Object),主要有t、v、r、h、w等字段(详见这里):
t:表示内容类型,s表示string类型,n表示number类型,b表示boolean类型,d表示date类型,等等
v:表示原始值;
f:表示公式,如B2+B3;
h:HTML内容
w:格式化后的内容
r:富文本内容rich text
等等
③读取workbook
let toJson = function (workbook) {
let result = {};
// workbook.SheetNames 工作表名称集合
workbook.SheetNames.forEach(function (sheetName) {
// workbook.Sheets[sheetName] 只能通过工作表名称来获取指定工作表
let roa = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], {
header: 1
});
if (roa.length) {
result[sheetName] = roa;
}
});
return JSON.stringify(result, 2, 2);
};
插件自身已经有写好的工具栏XLSX.utils,我们使用的是输出json格式的数据。
XLSX.utils.sheet_to_csv
:生成CSV格式XLSX.utils.sheet_to_txt
:生成纯文本格式XLSX.utils.sheet_to_html
:生成HTML格式XLSX.utils.sheet_to_json
:输出JSON格式
输出结果:
输出一个对象,返回每一行单元格的数据合成一个数组
④读取数据
使用Reflect.get
和Reflect.ownKeys
处理数据
return function (wb) {
let output = toJson(wb);
output = JSON.parse(output);
let code = Reflect.get(output, Reflect.ownKeys(output)[0]);
console.log(code)
out.innerText = processCode(code);
};
code的打印数据:
然后可根据返回的数据进行处理,转成json格式的数据
最后的打印结果:
四、补充
Reflect
是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。Reflect不是一个函数对象,因此它是不可构造的。
1、Reflect.getReflect.get(target, propertyKey[, receiver])
参数:
target
需要取值的目标对象
propertyKey
需要获取的值的键值
receiver
如果target对象中指定了getter,receiver则为getter调用时的this值。
// Object
var obj = { x: 1, y: 2 };
Reflect.get(obj, "x"); // 1
// Array
Reflect.get(["zero", "one"], 1); // "one"
// Proxy with a get handler
var x = {p: 1};
var obj = new Proxy(x, {
get(t, k, r) { return k + "bar"; }
});
Reflect.get(obj, "foo"); // "foobar"
2、Reflect.ownKeys
Reflect.ownKeys:返回一个由目标对象自身的属性键组成的数组。
const object1 = {
property1: 42,
property2: 13
};
const array1 = [];
console.log(Reflect.ownKeys(object1));
// expected output: Array ["property1", "property2"]
console.log(Reflect.ownKeys(array1));
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。