excel转xml

来源:互联网 发布:java配置文件的作用 编辑:程序博客网 时间:2024/05/17 23:18

python把excel文件转成xml文件。

策划用excel配置各种数据,程序在使用前,用python把该excel文件转换成xml文件,再在程序里面加载读取xml文件。

首先定好规则,我们是这样的,一个excel文件只允许第一个表格存放有效配置数字,列名字以c_开头表示此列只有客户端需要,以s_开头表示此列只有客户端需要,以_开头表示为无效配置数据(策划解释说明用),这样定好规则后,就能更清晰的知道哪些需要写入xml文件中,还有,规定每一个表格的第二行为对每一列名字的说明。 也就是说 第二行的数据是不要写入xml文件的。比如如下表格:

itemId itemNameId c_itemColor s_itemPrice _comment 物品id 物品名字id 物品颜色 物品价格 补充说明 0001 10001 10 钻石道具 0002 10002 red 50 帽子道具 0003 10003 red 50 鞋子道具

其中单元格为空的表示该行数据没有该列的属性,如表格中钻石道具没有颜色这一属性。

我们用python来实现转换,其实用java c c++ 都可以,但是做些小工具嘛,最好是用轻便而简单的语言实现,因为对效率不是那么的高,转换的时候,多花费个几秒钟也是可以接受的。所以就用python来写咯,对了最近node.js很火,也可以用js来写,原理都是一样的。

因为要读取excel文件,那么首先就要导入xlrd模块, 以下是我写的py代码:

# -*- coding: utf-8 -*-import osimport sysimport typesimport xlrdimport inspectimport shutilfrom time import localtime, strftimeEXL_PATH = ''XML_PATH = ''TEMP_EXL_PATH = './xls'TEMP_XML_PATH = './xml'LOG_PATH = './log'reload(sys)   sys.setdefaultencoding('utf8')def getExlList():    exl_list = []    for (dirpath, dirnames, filenames) in os.walk(EXL_PATH):        for filename in filenames:            if os.path.splitext(filename)[1] == '.xls':                exl_list.append(filename)        return exl_listdef isChinese(stringCode):    for ch in stringCode.decode('utf-8'):        if u'\u4e00' <= ch <= u'\u9fff':            return True    return Falsedef makeDir(dirPath):    if not os.path.exists(dirPath):        os.mkdir(dirPath)def copyDir(sourceDir, destDir):    if os.path.exists(destDir):        shutil.rmtree(destDir)    shutil.copytree(sourceDir,destDir)def copyAllFile(sourceDir, destDir):    for(dirpath, dirnames, filenames) in os.walk(sourceDir):        for filename in filenames:            desFileName = destDir + '/' + filename            shutil.copy(sourceDir + '/' + filename,desFileName)class enumColType:    clientOnly = 0           #客户端专用    serverOnly = 1           #服务器专用    cleAndSer  = 2           #cs都用    comment    = 3           #cs都无需用def getColType(sourceString):    if sourceString[0] == '_':        return enumColType.comment    elif sourceString[0:2] == 'c_':        return enumColType.clientOnly    elif sourceString[0:2] == 's_':        return enumColType.serverOnly    else:        return enumColType.cleAndSerdef writeToXml(exlName):    prefixFileName = exlName.split('.')[0]    xmlFileName = prefixFileName + '.xml'    xmlServerFileFullName = TEMP_XML_PATH + '/server/' + xmlFileName    xmlClientFileFullName = TEMP_XML_PATH + '/client/' + xmlFileName    fileClient = open(xmlClientFileFullName,'wb')    fileClient.write('<?xml version="1.0" encoding="utf-8" ?>\n')    fileClient.write('<root>\n')    fileServer = open(xmlServerFileFullName,'wb')    fileServer.write('<?xml version="1.0" encoding="utf-8" ?>\n')    fileServer.write('<root>\n')    exlFileFullName = TEMP_EXL_PATH + '/' + exlName    exlData = xlrd.open_workbook(exlFileFullName,formatting_info = True,encoding_override="utf-8")    table = exlData.sheets()[0]    nrows = table.nrows    ncols = table.ncols    print 'nrows:' + str(nrows) + ' ncols:' + str(ncols)    fileLog.write('xlsName:%s, nrows:%s, ncols:%s\n' %(exlName,str(nrows),str(ncols)))    firstRows = table.row_values(0)    for rownum in range(2,nrows):        stringClient = '<element'        stringServer = '<element'        row = table.row_values(rownum)        for colnum in range(ncols):            if row[colnum] != '' and firstRows[colnum] != '':                 #单元格不为空 且列名不为空                if type(row[colnum]) is types.FloatType:                    row[colnum] = int(row[colnum])                colType = getColType(firstRows[colnum])                if  colType == enumColType.cleAndSer:     #cs 都用                    tempString = ' %s="%s"' %( str(firstRows[colnum]), str(row[colnum]) )                    stringClient += tempString                    stringServer += tempString                elif colType == enumColType.clientOnly:    #只客户端用                    ss = str(firstRows[colnum])[2:]                    tempString = ' %s="%s"' %( ss, str(row[colnum]) )                    stringClient += tempString                elif colType == enumColType.serverOnly:     #服务器专用                    ss = str(firstRows[colnum])[2:]                    tempString = ' %s="%s"' %( ss, str(row[colnum]) )                    stringServer += tempString        stringClient += '/>\n'        fileClient.write(stringClient)        stringServer += '/>\n'        fileServer.write(stringServer)    fileClient.write('</root>')    fileClient.close()    fileServer.write('</root>')    fileServer.close()    fileLog.write('xlsName:%s transform success\n' %(exlName))if __name__ == "__main__":    EXL_PATH =  sys.argv[1]    XML_PATH =  sys.argv[2]    print 'EXL_PATH = ' + EXL_PATH    print 'XML_PATH = ' + XML_PATH    makeDir(LOG_PATH)    copyDir(EXL_PATH,TEMP_EXL_PATH)    makeDir(TEMP_XML_PATH)    makeDir(TEMP_XML_PATH + '/client')    makeDir(TEMP_XML_PATH + '/server')    fileLog = open(LOG_PATH + '/' + strftime("%Y%m%d%H%M%S", localtime()) + '.txt', "wb")    fileLog.write('from %s to %s\n' %(EXL_PATH,XML_PATH))    allExlFiles = getExlList()    for(exlFile) in allExlFiles:        print 'exchange file : ' + exlFile         writeToXml(exlFile)    copyAllFile(TEMP_XML_PATH + '/client',XML_PATH)    fileLog.close()

具体就是 读取excel的第一个表格,然后遍历每一行,分情况,把要写入文件字段累加,最后写入xml文件,代码很简单,但是里面包括了一些和工程涉及的东西,不过很容易看懂,也不影响。
那么上面的表格经过转换之后,就会得到两个文件,一个是给服务器的,一个是给客户端的。其中服务器xml如下:

<?xml version="1.0" encoding="utf-8" ?><root><element itemId="0001" itemNameId="10001" itemPrice="10"/><element itemId="0002" itemNameId="10002" itemPrice="50"/><element itemId="0003" itemNameId="10003" itemPrice="50"/></root>

客服端xml文件如下:

<?xml version="1.0" encoding="utf-8" ?><root><element itemId="0001" itemNameId="10001"/><element itemId="0002" itemNameId="10002" itemColor="red"/><element itemId="0003" itemNameId="10003" itemColor="red"/></root>

注意这两个文件内容的区别 和excel之前的区别。
这样就实现了策划按照规定来填写表格,我们程序负责转化就是了。

改进和优化:有个时候,表格行数很多,就会有一个问题,什么问题,相同的字符串太多,因为每一行的属性名字就是每一列的名字,比如上面的表格,如果有1000行,那么这个xml中就会有1000 个 字符串 “itemId”,并且其余的属性也基本那么多,这样一来就会想到,压缩了,其实zip文件压缩的最基本的原理就是重复多次出现的字符串,用一个标识代替。 我们可以首先给每一列的名字,用较短的字符串来表示,比如第一列用c0代替,如上xml可以这么写:

<?xml version="1.0" encoding="utf-8" ?><root><column c0="itemId" c1="itemNameId" c2="itemPrice" c3="itemColor"/><element c0="0001" c1="10001"/><element c0="0002" c1="10002" c3="red"/><element c0="0003" c1="10003" c3="red"/></root>

如果表格中行数较少,影响不大,但是表格行数多了,效果就显示出来了,无论是xml文件的大小,还有在内存中解析所占的内存,都是一份不小的优化了。 至于具体怎么实现,这里就不贴代码了,首先写入xml的原理无非新建一个列的索引,把第一列名写到column。 再以后写内容的时候,不写列名,而写列的索引。 至于解析也一样,读到某一行数据 再把属性索引对应到colum 得到真正的属性名字,就ok了。

0 0
原创粉丝点击