excel_to_json.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. # -*- coding: utf-8 -*-
  2. '''
  3. 一、支持的表头
  4. 单值Key-Value形式的:【KV】、【MAP】;即第2行是key,第3行是类型,第5行是value
  5. 如:{a=1, b=3, ...}
  6. 单值Key-Value形式的:【K-V】;即第1列是key,第2列是类型,第4列是value
  7. 如:{a=1, b=3, ...}
  8. 对象列表形式的:【V】;即第1列
  9. 如:{1, 2, 3, ...}
  10. 对象Key-Value形式的:【M】;
  11. 如:{[1]={a=1, b=3, ...}, [2]={a=1, b=3, ...}}
  12. 单值列表形式的:【LIST】、【L】。
  13. 如:{{a=1, b=3, ...}, {a=1, b=3, ...}}
  14. 推荐使用:
  15. 单值Key-Value形式的:【K-V】
  16. 对象列表形式的:【V】
  17. 对象Key-Value形式的:【M】
  18. 单值列表形式的:【L】
  19. 二、支持的数据类型:
  20. 整数:int;
  21. 整数字符串:intstring;
  22. 布尔值:bool、boolean。为true的值:"TRUE"、"true"、"T"、"1"、1:
  23. 字符串:text、string;
  24. 浮点型:double、float;
  25. lua表达式:table、lua;
  26. 如:{{id=101,count=2222}}
  27. 其它:直接用文本输出。
  28. '''
  29. import os
  30. import sys
  31. import commands
  32. import json
  33. import shutil
  34. import ConfigParser
  35. import json
  36. import math
  37. from optparse import OptionParser
  38. from xlrd import open_workbook
  39. reload(sys)
  40. sys.setdefaultencoding('utf-8')
  41. class ConfigParserEx(ConfigParser.ConfigParser):
  42. def __init__(self,defaults=None):
  43. ConfigParser.ConfigParser.__init__(self,defaults=None)
  44. def optionxform(self, optionstr):
  45. return optionstr
  46. def load_config(path):
  47. ''' 读取配置表
  48. '''
  49. config = ConfigParserEx()
  50. config.read(path)
  51. return config
  52. kSpace = " "
  53. class ExcaleToLuaClass(object):
  54. def __init__(self):
  55. self.currentPyPath = sys.path[0]
  56. self.configPath = None
  57. self.errorMap = []
  58. def start(self):
  59. print("开始转换...")
  60. print("++++ 检查参数...")
  61. ok = self.check_arguments()
  62. if ok:
  63. print("---- 检查参数正确!!!")
  64. else:
  65. print("---- 检查参数错误!!!")
  66. return
  67. print("++++ 加载配置...")
  68. ok = self.load_arguments_config()
  69. if ok:
  70. print("---- 加载配置正确!!!")
  71. else:
  72. print("---- 加载配置错误!!!")
  73. return
  74. print("++++ 转换...")
  75. ok = self.loop_exchange()
  76. if ok:
  77. print("---- 转换正确!!!")
  78. else:
  79. print("---- 转换错误!!!")
  80. return
  81. for errorName in self.errorMap:
  82. print(json.dumps("\033[31m---- 错误配置:" + errorName + "\033[0m").decode("unicode-escape"))
  83. def check_arguments(self):
  84. ''' 检查参数
  85. '''
  86. parser = OptionParser()
  87. parser.add_option("-s", action="store", type="string", dest="source", help="source path")
  88. parser.add_option("-o", action="store", type ="string", dest="output", help="output path")
  89. parser.add_option("-t", action="store", type ="string", dest="type", help="type")
  90. # 不必输入,固定是输出json格式
  91. # parser.add_option("--json", action="store_true", dest="outputJson", help="output json")
  92. (options, args) = parser.parse_args()
  93. ok = True
  94. sourcePath = options.source
  95. if options.source == None:
  96. ok = False
  97. print("-s config path is not set")
  98. outputPath = options.output
  99. if options.output == None:
  100. #如果输出目录没有写,则在源目录中新建一个output目录作为输出目录
  101. outputPath = os.path.join(cur_path, "out")
  102. onlyClient = False
  103. if options.type == "c":
  104. onlyClient = True
  105. else:
  106. onlyClient = False
  107. onlyServer = False
  108. if options.type == "s":
  109. onlyServer = True
  110. else:
  111. onlyServer = False
  112. outputJson = True # options.outputJson
  113. print "sourcePath", sourcePath
  114. print "outputPath", outputPath
  115. if outputJson:
  116. print "输出 json格式"
  117. else:
  118. print "输出 lua格式"
  119. if not os.path.exists(outputPath):
  120. os.makedirs(outputPath)
  121. self.excelDirList = [""]
  122. self.jsonDirList = [""]
  123. self.configRoot = ""
  124. self.configRoot = ""
  125. self.excelRootPath = sourcePath
  126. self.jsonRootPath = outputPath
  127. if onlyClient:
  128. self.mode = "CLIENT"
  129. elif onlyServer:
  130. self.mode = "SERVER"
  131. else:
  132. self.mode = "ALL"
  133. self.outputJson = outputJson
  134. return True
  135. def load_arguments_config(self):
  136. ''' 加载参数
  137. '''
  138. return True
  139. def loop_exchange(self):
  140. ''' 循环转换
  141. '''
  142. excelDirList = self.excelDirList
  143. jsonDirList = self.jsonDirList
  144. excelRootPath = self.excelRootPath
  145. jsonRootPath = self.jsonRootPath
  146. configRoot = self.configRoot
  147. mode = self.mode
  148. for i in range(0, len(excelDirList)):
  149. excelDir = excelDirList[i]
  150. jsonDir = jsonDirList[i]
  151. sourcePath = os.path.join(excelRootPath, excelDir)
  152. outputPath = os.path.join(jsonRootPath, jsonDir, configRoot)
  153. if not os.path.exists(outputPath):
  154. os.makedirs(outputPath)
  155. dirList = []
  156. # 填充所有目录和文件名称
  157. for dirpath, dirnames, filenames in os.walk(sourcePath):
  158. for filename in filenames:
  159. dirList.append(os.path.join(dirpath, filename))
  160. # 过滤文件
  161. for filePath in dirList:
  162. name, ext = os.path.splitext(filePath)
  163. if ext == ".xlsx":
  164. if name.find("~$") < 0 and name.find(".~") < 0:
  165. # 批量创建
  166. self.excel2lua(filePath, outputPath, mode)
  167. return True
  168. # 生成lua文件
  169. def excel2lua(self, filePath, outputPath, mode):
  170. ''' 转换
  171. '''
  172. excelData = self.openExecl(filePath)
  173. # 遍历所有的sheet
  174. for sheet in excelData.sheets():
  175. name = sheet.name
  176. nrows = sheet.nrows
  177. ncols = sheet.ncols
  178. #print(nrows, ncols)#行列数
  179. #row 1 作为lua表的属性用
  180. row_1 = sheet.row_values(0)
  181. dataMode = row_1[0]
  182. excelMode = row_1[1]
  183. if dataMode == "" or excelMode == "":
  184. # self.errorMap.append(filePath)
  185. continue
  186. if mode != "ALL":
  187. if mode == "CLIENT" and (excelMode != "CLIENT" and excelMode != "ALL"):
  188. # 只需要导出客户端需要的,该表不是客户端需要的,过掉
  189. continue
  190. elif mode == "SERVER" and (excelMode != "SERVER" and excelMode != "ALL"):
  191. # 只需要导出客户端需要的,该表不是客户端需要的,过掉
  192. continue
  193. outputFilePath = os.path.join(outputPath, name + ".lua")
  194. if dataMode == "K-V":
  195. self.outputColKeyValue(sheet, outputFilePath)
  196. elif dataMode == "V":
  197. self.outputList(sheet, outputFilePath)
  198. elif dataMode == "M":
  199. self.outputObjMap(sheet, outputFilePath)
  200. elif dataMode == "L":
  201. self.outputObjList(sheet, outputFilePath)
  202. # 下面是兼容旧版本的标签
  203. elif dataMode == "KV" or dataMode == "MAP":
  204. self.outputKeyValue(sheet, outputFilePath)
  205. elif dataMode == "LIST":
  206. self.outputObjList(sheet, outputFilePath)
  207. else:
  208. continue
  209. if self.outputJson:
  210. self.lua2json(outputPath, name)
  211. # lua转json
  212. def lua2json(self, outputPath, name):
  213. cmdFormat = 'lua -e \" \
  214. local cjson = require([[cjson]]); \
  215. package.path = [[{0}?.lua;]] .. package.path; \
  216. local function updateKey(tab) \
  217. if type(tab) ~= [[table]] then \
  218. return tab; \
  219. end \
  220. local count = 0; \
  221. for key, value in pairs(tab) do \
  222. count = count + 1; \
  223. end \
  224. local ret = {{}}; \
  225. if count == #tab then \
  226. for i, value in ipairs(tab) do \
  227. ret[i] = updateKey(value); \
  228. end \
  229. else \
  230. for key, value in pairs(tab) do \
  231. ret[tostring(key)] = updateKey(value); \
  232. end \
  233. end \
  234. return ret; \
  235. end \
  236. local fileName = [[{1}]]; \
  237. local config = require(fileName); \
  238. config = updateKey(config); \
  239. local jsonStr = cjson.encode(config); \
  240. print(jsonStr); \
  241. \"'
  242. cmd = cmdFormat.format(outputPath, name)
  243. content = commands.getoutput(cmd)
  244. data = json.loads(content)
  245. jsonStr = json.dumps(data, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False)
  246. jsonStr = jsonStr.decode("utf-8")
  247. jsonStr = jsonStr.replace(',\n ', ', ');
  248. jsonStr = jsonStr.replace(',\n ', ', ');
  249. jsonStr = jsonStr.replace(',\n ', ', ');
  250. jsonStr = jsonStr.replace(',\n ', ', ');
  251. jsonStr = jsonStr.replace(',\n ', ', ');
  252. jsonStr = jsonStr.replace('[\n ', '[');
  253. jsonStr = jsonStr.replace('[\n ', '[');
  254. jsonStr = jsonStr.replace('[\n ', '[');
  255. jsonStr = jsonStr.replace('[\n ', '[');
  256. jsonStr = jsonStr.replace('[\n ', '[');
  257. jsonStr = jsonStr.replace('\n ]', ']');
  258. jsonStr = jsonStr.replace('\n ]', ']');
  259. jsonStr = jsonStr.replace('\n ]', ']');
  260. jsonStr = jsonStr.replace('\n ]', ']');
  261. jsonStr = jsonStr.replace('\n ]', ']');
  262. jsonStr = jsonStr.replace('\n ]', ']');
  263. jsonStr = jsonStr.replace('{\n ', '{');
  264. jsonStr = jsonStr.replace('{\n ', '{');
  265. jsonStr = jsonStr.replace('{\n ', '{');
  266. jsonStr = jsonStr.replace('{\n ', '{');
  267. jsonStr = jsonStr.replace('{\n ', '{');
  268. jsonStr = jsonStr.replace('\n }', '}');
  269. jsonStr = jsonStr.replace('\n }', '}');
  270. jsonStr = jsonStr.replace('\n }', '}');
  271. jsonStr = jsonStr.replace('\n }', '}');
  272. jsonStr = jsonStr.replace('\n }', '}');
  273. jsonStr = jsonStr.replace('\n }', '}');
  274. outputFilePath = os.path.join(outputPath, name + ".json")
  275. output = open(outputFilePath , "w")
  276. output.write(jsonStr)
  277. output.close()
  278. luaOutputFilePath = os.path.join(outputPath, name + ".lua")
  279. os.remove(luaOutputFilePath)
  280. # 打开execl
  281. def openExecl(self, filePath):
  282. try:
  283. print("openExecl file name : " + filePath)
  284. data = open_workbook(filePath)
  285. return data
  286. except Exception,e:
  287. print "openExecl error:" + str(e)
  288. def cellValue(self, value, typeStr):
  289. ret = ""
  290. if value == "":
  291. return ""
  292. if value == "无" and typeStr != "text":
  293. return ""
  294. if typeStr == "int":
  295. retInt = float(value)
  296. ret = str(int(math.floor(retInt + 0.5)))
  297. elif typeStr == "intstring":
  298. if type(value) == type(0.1):
  299. retInt = float(value)
  300. ret = "\'" + str(int(math.floor(retInt + 0.5))) + "\'"
  301. else:
  302. ret = "\'" + str(value) + "\'"
  303. elif typeStr == "bool" or typeStr == "boolean":
  304. if value == "TRUE" or value == "true" or value == "T" or value == "1" or value == 1:
  305. ret = "true"
  306. else:
  307. ret = "false"
  308. elif typeStr == "text" or typeStr == "string":
  309. ret = "\'" + str(value) + "\'"
  310. elif typeStr == "double" or typeStr == "float":
  311. ret = str(value)
  312. elif typeStr == "table" or typeStr == "lua":
  313. ret = str(value)
  314. else:
  315. ret = str(value)
  316. return ret
  317. # 以Map形式输出 {a=1, b=3, ...}
  318. def outputColKeyValue(self, sheet, outputFilePath):
  319. name = sheet.name
  320. nrows = sheet.nrows
  321. ncols = sheet.ncols
  322. #print(nrows, ncols)#行列数
  323. output = open(outputFilePath, "w")
  324. output.write("local root = {")
  325. # 从第2行开始读
  326. start_rr = 1
  327. #第一行需要特殊处理
  328. firstLine = True
  329. for x in xrange(start_rr, nrows):
  330. onRow = sheet.row_values(x)
  331. keyStr = onRow[0]
  332. # 忽略key是空的列
  333. if keyStr == "":
  334. continue
  335. valueType = onRow[1]
  336. value = onRow[3]
  337. valueStr = self.cellValue(value, valueType)
  338. # 忽略空值的属性
  339. if valueStr == "":
  340. continue
  341. if firstLine:
  342. output.write("\n" + kSpace + keyStr + " = " + valueStr)
  343. firstLine = False
  344. else:
  345. output.write(",\n" + kSpace + keyStr + " = " + valueStr)
  346. output.write("\n}\nreturn root")
  347. output.close()
  348. # 以List形式输出 {1, 2, 3, ...}
  349. def outputList(self, sheet, outputFilePath):
  350. nrows = sheet.nrows
  351. ncols = sheet.ncols
  352. #print(nrows, ncols)#行列数
  353. # 第3行是数据类型的声明
  354. typeRow = sheet.row_values(2)
  355. # 因为是list,就一个类型
  356. valueType = typeRow[0]
  357. output = open(outputFilePath, "w")
  358. output.write("local root = {")
  359. # 从第5行开始读
  360. start_rr = 4
  361. #第一行需要特殊处理
  362. firstLine = True
  363. for x in xrange(start_rr, nrows):
  364. onRow = sheet.row_values(x)
  365. value = onRow[0]
  366. valueStr = self.cellValue(value, valueType)
  367. if firstLine:
  368. output.write("\n" + kSpace + valueStr)
  369. firstLine = False
  370. else:
  371. output.write(",\n" + kSpace + valueStr)
  372. output.write("\n}\nreturn root")
  373. output.close()
  374. # 以Map形式输出 {[1]={a=1, b=3, ...}, [2]={a=1, b=3, ...}}
  375. def outputObjMap(self, sheet, outputFilePath):
  376. name = sheet.name
  377. nrows = sheet.nrows
  378. ncols = sheet.ncols
  379. #print(nrows, ncols)#行列数
  380. # 支持合并单元格
  381. merge = {}
  382. for (rlow, rhigh, clow, chigh) in sheet.merged_cells:
  383. for r in xrange(rlow, rhigh):
  384. if not merge.get(r):
  385. merge[r] = {}
  386. for c in xrange(clow, chigh):
  387. merge[r][c] = sheet.row_values(rlow)[clow]
  388. #第1行的第3个单元格声明哪个作为key
  389. row_1 = sheet.row_values(0)
  390. key = row_1[2]
  391. # 第2行是key名称
  392. keyRow = sheet.row_values(1)
  393. # 第3行是数据类型的声明
  394. typeRow = sheet.row_values(2)
  395. output = open(outputFilePath, "w")
  396. output.write("local root = {")
  397. # 从第0列开始读
  398. start_cc = 0
  399. # 从第5行开始读
  400. start_rr = 4
  401. #第一行需要特殊处理
  402. firstLine = True
  403. for x in xrange(start_rr, nrows):
  404. objStr = "{"
  405. keyValue = ""
  406. # 读取一行
  407. oneRow = sheet.row_values(x)
  408. mergeRow = merge.get(x)
  409. # 第一个属性需要特殊处理
  410. firstProperty = True
  411. for cc in xrange(start_cc, ncols):
  412. keyStr = keyRow[cc]
  413. # 忽略key是空的列
  414. if keyStr == "":
  415. continue
  416. value = oneRow[cc]
  417. valueType = typeRow[cc]
  418. if mergeRow:
  419. mergeCell = mergeRow.get(cc)
  420. if mergeCell != None:
  421. value = mergeCell
  422. value = self.cellValue(value, valueType)
  423. if value == "":
  424. continue
  425. if firstProperty:
  426. objStr = objStr + "\n" + kSpace + kSpace + keyStr + " = " + value
  427. firstProperty = False
  428. else:
  429. objStr = objStr + ",\n" + kSpace + kSpace + keyStr + " = " + value
  430. if keyStr == key:
  431. keyValue = value
  432. if firstLine:
  433. objStr = "\n" + kSpace + "[" + keyValue + "] = " + objStr + "\n" + kSpace + "}"
  434. firstLine = False
  435. else:
  436. objStr = ",\n" + kSpace + "[" + keyValue + "] = " + objStr + "\n" + kSpace + "}"
  437. output.write(objStr)
  438. output.write("\n}\nreturn root")
  439. output.close()
  440. # 以Map形式输出 {{a=1, b=3, ...}, {a=1, b=3, ...}}
  441. def outputObjList(self, sheet, outputFilePath):
  442. name = sheet.name
  443. nrows = sheet.nrows
  444. ncols = sheet.ncols
  445. #print(nrows, ncols)#行列数
  446. # 支持合并单元格
  447. merge = {}
  448. for (rlow, rhigh, clow, chigh) in sheet.merged_cells:
  449. for r in xrange(rlow, rhigh):
  450. if not merge.get(r):
  451. merge[r] = {}
  452. for c in xrange(clow, chigh):
  453. merge[r][c] = sheet.row_values(rlow)[clow]
  454. # 第2行是key名称
  455. keyRow = sheet.row_values(1)
  456. # 第3行是数据类型的声明
  457. typeRow = sheet.row_values(2)
  458. output = open(outputFilePath, "w")
  459. output.write("local root = {")
  460. # 从第0列开始读
  461. start_cc = 0
  462. # 从第5行开始读
  463. start_rr = 4
  464. #第一行需要特殊处理
  465. firstLine = True
  466. for x in xrange(start_rr, nrows):
  467. if firstLine:
  468. output.write("\n" + kSpace + "{")
  469. firstLine = False
  470. else:
  471. output.write(",\n" + kSpace + "{")
  472. # 读取一行
  473. onRow = sheet.row_values(x)
  474. mergeRow = merge.get(x)
  475. # 第一个属性需要特殊处理
  476. firstProperty = True
  477. for cc in xrange(start_cc, ncols):
  478. keyStr = keyRow[cc]
  479. # 忽略key是空的列
  480. if keyStr == "":
  481. continue
  482. value = onRow[cc]
  483. valueType = typeRow[cc]
  484. if mergeRow:
  485. mergeCell = mergeRow.get(cc)
  486. if mergeCell != None:
  487. value = mergeCell
  488. valueStr = self.cellValue(value, valueType)
  489. # 忽略空值的属性
  490. if valueStr == "":
  491. continue
  492. if firstProperty:
  493. output.write("\n" + kSpace + kSpace + keyStr + " = " + valueStr)
  494. firstProperty = False
  495. else:
  496. output.write(",\n" + kSpace + kSpace + keyStr + " = " + valueStr)
  497. output.write("\n" + kSpace + "}")
  498. output.write("\n}\nreturn root")
  499. output.close()
  500. # 以Map形式输出 {a=1, b=3, ...}
  501. def outputKeyValue(self, sheet, outputFilePath):
  502. name = sheet.name
  503. nrows = sheet.nrows
  504. ncols = sheet.ncols
  505. #print(nrows, ncols)#行列数
  506. # 支持合并单元格
  507. merge = {}
  508. for (rlow, rhigh, clow, chigh) in sheet.merged_cells:
  509. for r in xrange(rlow, rhigh):
  510. if not merge.get(r):
  511. merge[r] = {}
  512. for c in xrange(clow, chigh):
  513. merge[r][c] = sheet.row_values(rlow)[clow]
  514. # 第2行是key名称
  515. keyRow = sheet.row_values(1)
  516. # 第3行是数据类型的声明
  517. typeRow = sheet.row_values(2)
  518. # 第3行是值
  519. valueRow = sheet.row_values(4)
  520. mergeRow = merge.get(4)
  521. output = open(outputFilePath, "w")
  522. output.write("local root = {")
  523. # 从第0列开始读
  524. start_cc = 0
  525. #第一行需要特殊处理
  526. firstLine = True
  527. for cc in xrange(start_cc, ncols):
  528. keyStr = keyRow[cc]
  529. # 忽略key是空的列
  530. if keyStr == "":
  531. continue
  532. value = valueRow[cc]
  533. valueType = typeRow[cc]
  534. if mergeRow:
  535. mergeCell = mergeRow.get(cc)
  536. if mergeCell != None:
  537. value = mergeCell
  538. valueStr = self.cellValue(value, valueType)
  539. # 忽略空值的属性
  540. if valueStr == "":
  541. continue
  542. if firstLine:
  543. output.write("\n" + kSpace + keyStr + " = " + valueStr)
  544. firstLine = False
  545. else:
  546. output.write(",\n" + kSpace + keyStr + " = " + valueStr)
  547. output.write("\n}\nreturn root")
  548. output.close()
  549. def main():
  550. ExcaleToLuaClass().start()
  551. if __name__ == '__main__':
  552. main()