xls2ddl/xlsxData.py

288 lines
5.9 KiB
Python
Raw Permalink Normal View History

2024-03-21 17:12:54 +08:00
import os
import sys
from openpyxl import load_workbook
from appPublic.myjson import loadf,dumpf,dumps
from appPublic.dictObject import DictObject
class TypeConvert:
def conv(self,typ,v):
if typ is None:
return v
f = getattr(self,'to_'+typ,None)
if f is None:
return v
return f(v)
def to_int(self,v):
try:
return int(v)
except:
return 0
def to_float(self,v):
try:
return float(v)
except:
return 0.0
def to_str(self,v):
try:
return str(v)
except:
return ''
def to_json(self,v):
if v == '':
return v
try:
return loads(v)
except:
return v
def to_date(self,v):
return v
def to_time(self,v):
return v
def to_timestamp(self,v):
return v
def to_cruddata(self,v):
vs = v.split('"',3)
if vs < 3:
return v
fn = vs[1]
d = CRUDData(fn)
try:
data = d.read()
except Exception as e:
return v
if vs[2] is None:
return data
cmd = "d%s" % vs[2]
ret=eval(cmd,{'d':data})
return ret
def to_xlsxdata(self,v):
vs = v.split('"',3)
if vs < 3:
return v
fn = vs[1]
d = XLSXData(fn)
try:
data = d.read()
except Exception as e:
return v
if vs[2] is None:
return data
cmd = "d%s" % vs[2]
ret=eval(cmd,{'d':data})
return ret
class CRUDException(Exception):
def __init__(self,xlsfile,errmsg,*args,**argv):
Exception.__init__(self,*args,**argv)
self.xlsfile = xlsfile
self.errmsg = errmsg
def __str__(self):
return 'filename:' + self.xlsfile+' error:' + self.errmsg
class XLSXData(object):
def __init__(self,xlsxfile):
atype = type(xlsxfile)
if atype == type('') or atype == type(u''):
self.xlsxfile = xlsxfile
self.book = load_workbook(filename=xlsxfile)
else:
self.book = xlsxfile # is from Factory
def readRecords(self,name,sheet):
i = 1
recs = []
fields = []
tc = TypeConvert()
for i,row in enumerate(sheet.values):
if i==0:
fields = self.getFieldNames(row)
continue
rec = {}
for j, a in enumerate(row):
if a is None:
continue
k = fields[j][0]
v = tc.conv(fields[j][1],a)
rec[k] = v
if rec == {}:
continue
o = DictObject(**rec)
recs.append(o)
return {name:recs}
def read(self):
ret = {}
for i,s in enumerate(self.book.worksheets):
ret.update(self.readRecords(self.book.sheetnames[i], s))
return DictObject(**ret)
def getFieldNames(self,row):
fs = []
for i,f in enumerate(row):
if f is None:
f = 'F_' + str(i)
else:
if type(f) != type(u""):
f = 'F_' + str(f)
"""
else:
f = f.encode('utf-8')
"""
b=f.split(':')
if len(b) < 2:
b.append(None)
fs.append(b)
i+= 1
return fs
class CRUDData(XLSXData):
@classmethod
def isMe(self,book):
names = book.sheetnames
if 'summary' not in names:
return False
if 'fields' not in names:
return False
if 'validation' not in names:
return False
return True
def read(self):
d = XLSXData.read(self)
if not 'summary' in d.keys():
raise CRUDException(self.xlsxfile,'summary sheet missing')
if not 'fields' in d.keys():
raise CRUDException(self.xlsxfile,'fields sheet missing')
if not 'validation' in d.keys():
raise CRUDException(self.xlsxfile,'validation sheet missing')
v = d['summary'][0]['primary']
v = v.split(',')
d['summary'][0]['primary'] = v
d = self.convForeignkey(d)
d = self.convIndex(d)
return d
def convForeignkey(self,data):
vs = data['validation']
nvs = []
for v in vs:
if v['oper'] == 'fk':
m = v['value']
des= m.split(':')
if len(des) != 3:
raise CRUDException(self.xlsxfile,'fk value error:%s' % m)
v['value'] = {'table':des[0],'value':des[1],'title':des[2]}
nvs.append(v)
data['validation'] = nvs
return data
def getFieldByNmae(self,fields,name):
for f in fields:
if f['name'] == name:
return f
def getFKs(self,validation):
fks = []
for v in validation:
if v['oepr'] == 'fk':
fks.append(v)
return fks
def getIDXs(self,validation):
idxs = []
for v in validation:
if v['oper'] == 'idx':
idxs.append(v)
return idxs
def isFieldExist(self,fields,name):
for f in fields:
if f['name'] == name:
return True
return False
def convIndex(self,data):
vs = data['validation']
nvs = []
for v in vs:
if v['oper'] == 'idx':
idx = {}
idx['name'] = v['name']
m = v['value']
des= m.split(':')
if len(des) != 2:
raise CRUDException(self.xlsxfile,'idx value format:idx_type:keylist:%s' % m)
idx['idxtype'] = des[0]
idx['idxfields'] = des[1].split(',')
nvs.append(idx)
data['indexes'] = nvs
return data
def xlsxFactory(xlsxfilename):
def findSubclass(name,klass):
for k in klass.__subclasses__():
if k.isMe(name):
return k
k1 = findSubclass(name,k)
if k1 is not None:
return k1
return None
try:
book = load_workbook(filename=xlsxfilename)
k = findSubclass(book,XLSXData)
if k is not None:
xlsx = k(book)
xlsx.xlsxfile = xlsxfilename
return xlsx
return XLSXData(book)
except Exception as e:
# print(xlsxfilename, 'load failed\n%s' % str(e))
return None
def ValueConvert(s):
if s[:9] == 'xlsfile::':
d = xlsxFactory(s[9:])
return d.read()
if s[:10] == 'jsonfile::':
return loadf(s[10:])
return s
def paramentHandle(ns):
for k,v in ns.items():
ns[k] = ValueConvert(v)
return ns
if __name__ == '__main__':
retData = {}
ns = {}
datafiles = []
for a in sys.argv[1:]:
m = a.split('=',1)
if len(m)>1:
ns[m[0]] = m[1]
else:
datafiles.append(a)
ns = paramentHandle(ns)
for f in datafiles:
ext = os.path.splitext(f)[-1]
if ext in ['.xlsx','.xls' ]:
d = xlsxFactory(f)
data = d.read()
retData.update(data)
retData.update(ns)
print( dumps(retData))