Na občasné zadávání a prohlížení dat je to dobré, ale čas od času potřebuji udělat nějaké hromadné změny, doplnění nebo výpočty a na to je jedinečný tabulkový kalkulátor Calc nebo Excel s funkcemi automatického doplňování, najdi a nahraď a podobně. A proto jsem řešil problém, jak dostat data z Sail Forms do tabulkového kalkulátoru a po úpravě zpět do Sail Forms.
Program sice má export do CSV, ale jen v palcené verzi, což je pro mě problém, když Google obchod nepodporuje PayPal. I kdyby to problém nebyl, obávám se, že by si ten program stejně neporadil s českým CSV, tj. českým kódováním, českým oddělovačem sloupců i českou desetinnou čárkou na místo tečky.
A proto jsem se rozhodl udělat si vlastní konvertor s využitím exportu dat z Sail Forms pro zálohování. Vyexportovaná data jsou uložena v XML souboru, takže konverze z XML do CSV a zpět je poměrně jednoduchá. Konvertor jsem si napsal v Pythonu a ovládá se jednoduše z příkazového řádku.
Zdrojový kód dávám veřejně k dispozici, takže každý kdo umí s Pythonem může tento konvertor používat. Kdyby k tomu někdo chtěl doplnit okenní uživatelské rozhranní, budu jen rád. Zdrojový kód je upraven tak, aby celá aplikace mohla být jen v jednom souboru.
Velkou výhodou tohoto konvertoru je, že používá nestandardní formát CSV souboru, díky čemuž je možno v Excelu používat Unicode kódování a Excel nemá problém s určením hranic sloupců ani čísel.
Velkou výhodou tohoto konvertoru je, že používá nestandardní formát CSV souboru, díky čemuž je možno v Excelu používat Unicode kódování a Excel nemá problém s určením hranic sloupců ani čísel.
Obsah souboru "sfconvert.py":
==============================================================================
# encoding: utf-8
##############################################################################
# Sail Forms Convertor / Python 2.5
# (c) Petr Mach 2012
#
# Convert XML backup data from SailForms to CSV and vice versa.
#
# CSV FORMAT:
# value separator: TAB
# text delimiter: "
# encoding: Unicode (UTF-16 LE)
# decimal point: depending on locale or optional parameter
#
# HOW TO USE:
# python sfconvert MODE FILENAME [DP]
# FILENAME - name of XML backup file, for example data.xml
# MODE - GET or STORE
# [DP] - optional, decimal point in CSV file
#
# EXAMPLES:
# python sfconvert GET data.xml
# - need: data.xml
# - create: data.xml.csv
# python sfconvert STORE data.xml
# - need: data.xml, data.xml.csv
# - create: data.xml.csv.xml
#
# WARNING:
# Do not delete data.xml after creation of data.xml.csv.
# This file is needed to create data.xml.csv.xml.
#
# TESTED WITH:
# Python 2.5 on WindowsXP CZ.
#
import sys, locale
from xml.dom import minidom as md
from xml.dom import Node
class SFConvertor(object):
"""
user methods:
SFConvert.run(mode)
main methods:
SFConvert.makeCsvData() # make CSV data from XML file
SFConvert.writeCsvData(csvData)
SFConvert.readCsvData() # read CSV data from CSV file
SFConvert.makeRecData(csvData) # make XML data from CSV data
SFConvert.writeRacData(recData) # create new XML file from old XML file with new data
other methods:
SFConvert.getColData() # get columns data from XML file
SFConvert.getColFormat() # make index [col name] = data format from colData
SFConvert.getXmlUText(node) # get unicode text from DOM/XML node
"""
def __init__(self, fName, dPoint):
self.sfIFName = fName
self.csvFName = self.sfIFName + '.csv'
self.sfOFName = self.csvFName + '.xml'
self.dPoint = dPoint
try:
self.domData = md.parse(self.sfIFName)
except:
print "ERROR: Parsing XML file '%s' failed!" % self.sfIFName
print makeTextFromException()
sys.exit(1)
self.colData = self.getColData()
self.colFormat = self.getColFormat()
self.csvData = None
self.recData = None
def run(self, mode):
if mode in ('GET', 'LOAD'):
print 'MODE: GET CSV'
print 'decimal="%s"' % self.dPoint
csvData = self.makeCsvData()
self.writeCsvData(csvData)
elif mode in ('STORE', 'SAVE'):
print 'MODE: STORE CSV'
print 'decimal="%s"' % self.dPoint
csvData = self.readCsvData()
if len(csvData) == 0:
print "ERROR: CSV data in file '%s' not found. Empty file?" % self.csvFName
sys.exit(1)
recData = self.makeRecData(csvData)
self.writeRecData(recData)
else:
return 'info'
return 'done'
def getColData(self):
fields = self.domData.getElementsByTagName("fields")[0]
fields = fields.getElementsByTagName("field")
colsData = []
for field in fields:
colData = {}
xmlCols = field.getElementsByTagName("col")
for xmlCol in xmlCols:
xmlColName = xmlCol.getAttribute('name')
xmlColData = xmlCol.firstChild.wholeText
if xmlColName == 'col_order':
xmlColData = int(xmlColData)
colData[xmlColName] = xmlColData
if 'col_order' not in colData:
# this is label, not data column
continue
if colData['format'] == 'picture':
# format picture has 2 data columns
colData1 = colData.copy() # shallow copy
colData2 = colData.copy()
colData1['dbname'] = colData1['dbname'] + '_file'
colData2['dbname'] = colData2['dbname'] + '_data'
colsData.append(colData1)
colsData.append(colData2)
else:
colsData.append(colData)
colsData.sort(cmp = lambda x,y: cmp(x['col_order'], y['col_order']))
return colsData
def getColFormat(self):
data = {}
for item in self.colData:
data[item['dbname']] = item['format']
return data
def getXmlUText(self, node):
data = []
node = node.firstChild;
while(True):
if not node:
break
if node.nodeType == Node.ELEMENT_NODE:
data.append(self.getXmlText(node))
if node.nodeType == Node.TEXT_NODE:
data.append(node.wholeText)
node = node.nextSibling
return u''.join(data)
def makeCsvData(self):
csv = []
#header
row = []
for column in self.colData:
row.append(column['dbname'])
csv.append(row)
#data
xmlRecords = self.domData.getElementsByTagName('rec')
for i, xmlRecord in enumerate(xmlRecords):
xmlFields = xmlRecord.getElementsByTagName('field')
uData = {}
uRow = []
for xmlField in xmlFields:
dbname = xmlField.getAttribute('name')
uText = self.getXmlUText(xmlField).strip() # return unicode text
format = self.colFormat[dbname]
if uText == '' or format in ('text', 'int', 'picture'):
pass
elif format in ('float', 'float_d1', 'float_d2', 'float_d3', 'float_d4'):
uText = uText.replace(' ', '')
uText = uText.replace('.', self.dPoint)
elif format == 'date':
uText = "%s.%s.%s" % (uText[6:8], uText[4:6], uText[0:4])
elif format == 'time':
uText = "%s:%s" % (uText[:2], uText[2:])
else:
print "UNKNOWN FORMAT:", format
uData[dbname] = uText
for column in self.colData:
dbname = column['dbname']
if dbname in uData:
uRow.append(uData[dbname])
else:
uRow.append('')
csv.append(uRow)
return csv
def writeCsvData(self, data, encoding='utf-16', delimiter='\t', **kwds):
try:
fHandler = open(self.csvFName, 'wb')
except:
print "ERROR: open file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
try:
csvWriter = UnicodeCsvWriter(fHandler, encoding=encoding, delimiter=delimiter)
csvWriter.writerows(data)
except:
print "ERROR: write to file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
try:
fHandler.close()
except:
print "ERROR: close file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
def readCsvData(self, encoding='utf-16', delimiter='\t', **kwds):
try:
fHandler = open(self.csvFName, 'rb')
except:
print "ERROR: open file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
try:
csvReader = UnicodeCsvReader(fHandler, encoding=encoding, delimiter=delimiter)
data = []
for row in csvReader:
data.append(row)
except:
print "ERROR: read from file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
try:
fHandler.close()
except:
print "ERROR: close file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
return data
def makeRecData(self, csvData):
#cut header from csv data
header = csvData[0][:]
csvData = csvData[1:]
#make xml records from csv data
recData = []
for row in csvData:
recData.append('')
for i, cell in enumerate(row):
dbname = header[i]
try:
format = self.colFormat[dbname]
except:
print "V SailForms XML souboru neexistuje sloupec '%s'" % dbname
print "V CSV souboru se nesmi menit nazvy sloupcu!"
print "Opravte prosim CSV soubor a provedte konverzi znova."
sys.exit(1)
if format in ('text', 'int', 'picture'):
value = cell.strip()
elif format == 'date':
value = cell.strip()
if len(value) > 0:
tmp = value.split('.')
value = "%s%02d%02d" % (tmp[2], int(tmp[1]), int(tmp[0]))
elif format == 'time':
value = cell.strip()
if len(value) > 0:
tmp = value.split(':')
value = "%02d%02d" % (int(tmp[0]), int(tmp[1]))
elif format == 'float':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%f" % float(value)
elif format == 'float_d1':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%.1f" % float(value)
elif format == 'float_d2':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%.2f" % float(value)
elif format == 'float_d3':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%.3f" % float(value)
elif format == 'float_d4':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%.4f" % float(value)
else:
print "Neznamy format '%s'. Data budou formatovany jako text."
value = cell.strip()
if value != '':
recData.append('%s ' % (dbname, value))
recData.append(' ')
return '\n'.join(recData)
def writeRecData(self, recData):
try:
fi = open(self.sfIFName, 'rt')
except:
print "ERROR: open file failed - '%s'" % self.sfIFName
print makeTextFromException()
sys.exit(1)
try:
fo = open(self.sfOFName, 'wt')
except:
print "ERROR: open file failed - '%s'" % self.sfOFName
print makeTextFromException()
sys.exit(1)
try:
mode = 1
for line in fi:
if mode == 1: # copy header
fo.write(line)
if line.strip() == '': # save new data
fo.write(recData.encode('utf-8'))
mode = 2
elif mode == 2: # skip old data
if line.strip() == ' ':
fo.write(line)
mode = 3
elif mode == 3: # copy footer
fo.write(line)
except:
print "ERROR: Create new XML file '%s' failed!" % self.sfOFName
print makeTextFromException()
sys.exit(1)
try:
fi.close()
except:
print "ERROR: close file failed - '%s'" % self.sfIFName
print makeTextFromException()
sys.exit(1)
try:
fo.close()
except:
print "ERROR: close file failed - '%s'" % self.sfOFName
print makeTextFromException()
sys.exit(1)
#############################################################################
# unicode wrappers for CSV module
# Taken from example in Python 2.5 Documentation / CSV module
#
import csv, codecs, cStringIO
class UTF8Recoder:
def __init__(self, f, encoding):
self.reader = codecs.getreader(encoding)(f)
def __iter__(self):
return self
def next(self):
return self.reader.next().encode("utf-8")
class UnicodeCsvReader:
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
f = UTF8Recoder(f, encoding)
self.reader = csv.reader(f, dialect=dialect, **kwds)
def next(self):
row = self.reader.next()
return [unicode(s, "utf-8") for s in row]
def __iter__(self):
return self
class UnicodeCsvWriter:
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
self.queue = cStringIO.StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, row):
self.writer.writerow([s.encode("utf-8") for s in row])
data = self.queue.getvalue()
data = data.decode("utf-8")
data = self.encoder.encode(data)
self.stream.write(data)
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)
#############################################################################
# universal error handler
# (c) Petr Mach 2012, petr.mach.cz@gmail.com
#
import sys, inspect
def getTextFromCode(code, offset, linenu):
''' Print relevant part source code. '''
code = code[:offset+1]
code.reverse()
shortCode = []
for i, line in enumerate(code):
sLine = line.strip()
if sLine[:3] == 'def':
shortCode.insert(0, line)
break
if sLine[:5] == 'class':
shortCode.insert(0, line)
break
if sLine == '' and i > 10:
break
shortCode.insert(0, line)
offset = len(shortCode)-1
TEXT = []
for i, line in enumerate(shortCode):
number = linenu-offset+i
line = line[:-1]
TEXT.append("%5d %s" % (number, line))
return '\n'.join(TEXT)
def getTextFromDict(d, title=None):
''' Pretty print of dict. '''
TEXT = []
if title:
TEXT.append(title)
keys = d.keys()
keys.sort()
keyMaxLen = 0
for key in keys:
if len(key) > keyMaxLen:
keyMaxLen = len(key)
keyMaxLen += 1
pattern = '%%%ds = %%-17s %%s' % keyMaxLen
for key in keys:
TEXT.append(pattern % (key, type(d[key]), unicode(d[key])[:60].__repr__()))
return '\n'.join(TEXT)
def getTextFromStrerr(strerr):
TEXT = []
TEXT.append('\nERROR:')
TEXT.append(str(strerr))
return ' '.join(TEXT)
def isIter(obj):
try:
iter(obj)
except:
return False
if isinstance(obj, type('')):
return False
return True
def makeTextFromException(size='full'):
''' Print information about exception. '''
TEXT = []
typerr,strerr,c = sys.exc_info()
TEXT.append('\nEXCEPTION: ' + str(typerr))
traceback = inspect.trace(100)
last = len(traceback) - 1
for i, (frame, file, linenu, object, code, offset) in enumerate(traceback):
if code and code[offset]:
example = code[offset].strip()
else:
example = ''
if size == 'full' or i == last:
TEXT.append('%s/%d %s: %s' % (file, linenu, object, example))
if(i == last):
if code and size == 'full':
TEXT.append(getTextFromCode(code, offset, linenu))
TEXT.append(getTextFromStrerr(strerr))
if size == 'full':
TEXT.append(getTextFromDict(frame.f_locals, 'LOCAL VARS:'))
TEXT.append('----------')
return '\n'.join(TEXT)
if __name__ == '__main__':
print sys.argv
prog = sys.argv[0]
info = """SailForms Converter 1.0 / Python 2.5
(c) Petr Mach 2012, petr.mach.cz@gmail.com
Convert XML backup data from SailForms to CSV and vice versa.
CSV FORMAT:
value separator: TAB
text delimiter: "
encoding: Unicode (UTF-16 LE)
decimal point: depending on locale or optional parameter
HOW TO USE:
python %s MODE FILENAME [DP]
FILENAME - name of XML backup file, for example data.xml
MODE - GET or STORE
[DP] - optional, decimal point in CSV file
EXAMPLES:
python %s GET data.xml
- need: data.xml
- create: data.xml.csv
python %s STORE data.xml
- need: data.xml, data.xml.csv
- create: data.xml.csv.xml
WARNING:
Do not delete data.xml after creation of data.xml.csv.
This file is needed to create data.xml.csv.xml."""
info = info % (prog, prog, prog)
if len(sys.argv) < 3:
print info
sys.exit()
mode = sys.argv[1] # GET, STORE
sfIFName = sys.argv[2] # sf_backup.xml
locale.setlocale(locale.LC_ALL, '')
cLocale = locale.localeconv()
dPoint = cLocale['decimal_point']
if len(sys.argv) > 3:
dPoint = sys.argv[3]
convertor = SFConvertor(sfIFName, dPoint)
res = convertor.run(mode)
if res == 'info':
print info
else:
print 'DONE'
##############################################################################
# Sail Forms Convertor / Python 2.5
# (c) Petr Mach 2012
#
# Convert XML backup data from SailForms to CSV and vice versa.
#
# CSV FORMAT:
# value separator: TAB
# text delimiter: "
# encoding: Unicode (UTF-16 LE)
# decimal point: depending on locale or optional parameter
#
# HOW TO USE:
# python sfconvert MODE FILENAME [DP]
# FILENAME - name of XML backup file, for example data.xml
# MODE - GET or STORE
# [DP] - optional, decimal point in CSV file
#
# EXAMPLES:
# python sfconvert GET data.xml
# - need: data.xml
# - create: data.xml.csv
# python sfconvert STORE data.xml
# - need: data.xml, data.xml.csv
# - create: data.xml.csv.xml
#
# WARNING:
# Do not delete data.xml after creation of data.xml.csv.
# This file is needed to create data.xml.csv.xml.
#
# TESTED WITH:
# Python 2.5 on WindowsXP CZ.
#
import sys, locale
from xml.dom import minidom as md
from xml.dom import Node
class SFConvertor(object):
"""
user methods:
SFConvert.run(mode)
main methods:
SFConvert.makeCsvData() # make CSV data from XML file
SFConvert.writeCsvData(csvData)
SFConvert.readCsvData() # read CSV data from CSV file
SFConvert.makeRecData(csvData) # make XML
SFConvert.writeRacData(recData) # create new XML file from old XML file with new
other methods:
SFConvert.getColData() # get columns data from XML file
SFConvert.getColFormat() # make index [col name] = data format from colData
SFConvert.getXmlUText(node) # get unicode text from DOM/XML node
"""
def __init__(self, fName, dPoint):
self.sfIFName = fName
self.csvFName = self.sfIFName + '.csv'
self.sfOFName = self.csvFName + '.xml'
self.dPoint = dPoint
try:
self.domData = md.parse(self.sfIFName)
except:
print "ERROR: Parsing XML file '%s' failed!" % self.sfIFName
print makeTextFromException()
sys.exit(1)
self.colData = self.getColData()
self.colFormat = self.getColFormat()
self.csvData = None
self.recData = None
def run(self, mode):
if mode in ('GET', 'LOAD'):
print 'MODE: GET CSV'
print 'decimal="%s"' % self.dPoint
csvData = self.makeCsvData()
self.writeCsvData(csvData)
elif mode in ('STORE', 'SAVE'):
print 'MODE: STORE CSV'
print 'decimal="%s"' % self.dPoint
csvData = self.readCsvData()
if len(csvData) == 0:
print "ERROR: CSV data in file '%s' not found. Empty file?" % self.csvFName
sys.exit(1)
recData = self.makeRecData(csvData)
self.writeRecData(recData)
else:
return 'info'
return 'done'
def getColData(self):
fields = self.domData.getElementsByTagName("fields")[0]
fields = fields.getElementsByTagName("field")
colsData = []
for field in fields:
colData = {}
xmlCols = field.getElementsByTagName("col")
for xmlCol in xmlCols:
xmlColName = xmlCol.getAttribute('name')
xmlColData = xmlCol.firstChild.wholeText
if xmlColName == 'col_order':
xmlColData = int(xmlColData)
colData[xmlColName] = xmlColData
if 'col_order' not in colData:
# this is label, not data column
continue
if colData['format'] == 'picture':
# format picture has 2 data columns
colData1 = colData.copy() # shallow copy
colData2 = colData.copy()
colData1['dbname'] = colData1['dbname'] + '_file'
colData2['dbname'] = colData2['dbname'] + '_data'
colsData.append(colData1)
colsData.append(colData2)
else:
colsData.append(colData)
colsData.sort(cmp = lambda x,y: cmp(x['col_order'], y['col_order']))
return colsData
def getColFormat(self):
data = {}
for item in self.colData:
data[item['dbname']] = item['format']
return data
def getXmlUText(self, node):
data = []
node = node.firstChild;
while(True):
if not node:
break
if node.nodeType == Node.ELEMENT_NODE:
data.append(self.getXmlText(node))
if node.nodeType == Node.TEXT_NODE:
data.append(node.wholeText)
node = node.nextSibling
return u''.join(data)
def makeCsvData(self):
csv = []
#header
row = []
for column in self.colData:
row.append(column['dbname'])
csv.append(row)
#data
xmlRecords = self.domData.getElementsByTagName('rec')
for i, xmlRecord in enumerate(xmlRecords):
xmlFields = xmlRecord.getElementsByTagName('field')
uData = {}
uRow = []
for xmlField in xmlFields:
dbname = xmlField.getAttribute('name')
uText = self.getXmlUText(xmlField).strip() # return unicode text
format = self.colFormat[dbname]
if uText == '' or format in ('text', 'int', 'picture'):
pass
elif format in ('float', 'float_d1', 'float_d2', 'float_d3', 'float_d4'):
uText = uText.replace(' ', '')
uText = uText.replace('.', self.dPoint)
elif format == 'date':
uText = "%s.%s.%s" % (uText[6:8], uText[4:6], uText[0:4])
elif format == 'time':
uText = "%s:%s" % (uText[:2], uText[2:])
else:
print "UNKNOWN FORMAT:", format
uData[dbname] = uText
for column in self.colData:
dbname = column['dbname']
if dbname in uData:
uRow.append(uData[dbname])
else:
uRow.append('')
csv.append(uRow)
return csv
def writeCsvData(self, data, encoding='utf-16', delimiter='\t', **kwds):
try:
fHandler = open(self.csvFName, 'wb')
except:
print "ERROR: open file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
try:
csvWriter = UnicodeCsvWriter(fHandler, encoding=encoding, delimiter=delimiter)
csvWriter.writerows(data)
except:
print "ERROR: write to file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
try:
fHandler.close()
except:
print "ERROR: close file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
def readCsvData(self, encoding='utf-16', delimiter='\t', **kwds):
try:
fHandler = open(self.csvFName, 'rb')
except:
print "ERROR: open file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
try:
csvReader = UnicodeCsvReader(fHandler, encoding=encoding, delimiter=delimiter)
data = []
for row in csvReader:
data.append(row)
except:
print "ERROR: read from file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
try:
fHandler.close()
except:
print "ERROR: close file failed - '%s'" % self.csvFName
print makeTextFromException()
sys.exit(1)
return data
def makeRecData(self, csvData):
#cut header from csv data
header = csvData[0][:]
csvData = csvData[1:]
#make xml records from csv data
recData = []
for row in csvData:
recData.append('
for i, cell in enumerate(row):
dbname = header[i]
try:
format = self.colFormat[dbname]
except:
print "V SailForms XML souboru neexistuje sloupec '%s'" % dbname
print "V CSV souboru se nesmi menit nazvy sloupcu!"
print "Opravte prosim CSV soubor a provedte konverzi znova."
sys.exit(1)
if format in ('text', 'int', 'picture'):
value = cell.strip()
elif format == 'date':
value = cell.strip()
if len(value) > 0:
tmp = value.split('.')
value = "%s%02d%02d" % (tmp[2], int(tmp[1]), int(tmp[0]))
elif format == 'time':
value = cell.strip()
if len(value) > 0:
tmp = value.split(':')
value = "%02d%02d" % (int(tmp[0]), int(tmp[1]))
elif format == 'float':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%f" % float(value)
elif format == 'float_d1':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%.1f" % float(value)
elif format == 'float_d2':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%.2f" % float(value)
elif format == 'float_d3':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%.3f" % float(value)
elif format == 'float_d4':
value = cell.strip()
if len(value) > 0:
value = value.replace(' ', '')
value = value.replace(self.dPoint, '.')
value = "%.4f" % float(value)
else:
print "Neznamy format '%s'. Data budou formatovany jako text."
value = cell.strip()
if value != '':
recData.append('
recData.append('
return '\n'.join(recData)
def writeRecData(self, recData):
try:
fi = open(self.sfIFName, 'rt')
except:
print "ERROR: open file failed - '%s'" % self.sfIFName
print makeTextFromException()
sys.exit(1)
try:
fo = open(self.sfOFName, 'wt')
except:
print "ERROR: open file failed - '%s'" % self.sfOFName
print makeTextFromException()
sys.exit(1)
try:
mode = 1
for line in fi:
if mode == 1: # copy header
fo.write(line)
if line.strip() == '
fo.write(recData.encode('utf-8'))
mode = 2
elif mode == 2: # skip old data
if line.strip() == '
fo.write(line)
mode = 3
elif mode == 3: # copy footer
fo.write(line)
except:
print "ERROR: Create new XML file '%s' failed!" % self.sfOFName
print makeTextFromException()
sys.exit(1)
try:
fi.close()
except:
print "ERROR: close file failed - '%s'" % self.sfIFName
print makeTextFromException()
sys.exit(1)
try:
fo.close()
except:
print "ERROR: close file failed - '%s'" % self.sfOFName
print makeTextFromException()
sys.exit(1)
#############################################################################
# unicode wrappers for CSV module
# Taken from example in Python 2.5 Documentation / CSV module
#
import csv, codecs, cStringIO
class UTF8Recoder:
def __init__(self, f, encoding):
self.reader = codecs.getreader(encoding)(f)
def __iter__(self):
return self
def next(self):
return self.reader.next().encode("utf-8")
class UnicodeCsvReader:
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
f = UTF8Recoder(f, encoding)
self.reader = csv.reader(f, dialect=dialect, **kwds)
def next(self):
row = self.reader.next()
return [unicode(s, "utf-8") for s in row]
def __iter__(self):
return self
class UnicodeCsvWriter:
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
self.queue = cStringIO.StringIO()
self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
self.stream = f
self.encoder = codecs.getincrementalencoder(encoding)()
def writerow(self, row):
self.writer.writerow([s.encode("utf-8") for s in row])
data = self.queue.getvalue()
data = data.decode("utf-8")
data = self.encoder.encode(data)
self.stream.write(data)
self.queue.truncate(0)
def writerows(self, rows):
for row in rows:
self.writerow(row)
#############################################################################
# universal error handler
# (c) Petr Mach 2012, petr.mach.cz@gmail.com
#
import sys, inspect
def getTextFromCode(code, offset, linenu):
''' Print relevant part source code. '''
code = code[:offset+1]
code.reverse()
shortCode = []
for i, line in enumerate(code):
sLine = line.strip()
if sLine[:3] == 'def':
shortCode.insert(0, line)
break
if sLine[:5] == 'class':
shortCode.insert(0, line)
break
if sLine == '' and i > 10:
break
shortCode.insert(0, line)
offset = len(shortCode)-1
TEXT = []
for i, line in enumerate(shortCode):
number = linenu-offset+i
line = line[:-1]
TEXT.append("%5d %s" % (number, line))
return '\n'.join(TEXT)
def getTextFromDict(d, title=None):
''' Pretty print of dict. '''
TEXT = []
if title:
TEXT.append(title)
keys = d.keys()
keys.sort()
keyMaxLen = 0
for key in keys:
if len(key) > keyMaxLen:
keyMaxLen = len(key)
keyMaxLen += 1
pattern = '%%%ds = %%-17s %%s' % keyMaxLen
for key in keys:
TEXT.append(pattern % (key, type(d[key]), unicode(d[key])[:60].__repr__()))
return '\n'.join(TEXT)
def getTextFromStrerr(strerr):
TEXT = []
TEXT.append('\nERROR:')
TEXT.append(str(strerr))
return ' '.join(TEXT)
def isIter(obj):
try:
iter(obj)
except:
return False
if isinstance(obj, type('')):
return False
return True
def makeTextFromException(size='full'):
''' Print information about exception. '''
TEXT = []
typerr,strerr,c = sys.exc_info()
TEXT.append('\nEXCEPTION: ' + str(typerr))
traceback = inspect.trace(100)
last = len(traceback) - 1
for i, (frame, file, linenu, object, code, offset) in enumerate(traceback):
if code and code[offset]:
example = code[offset].strip()
else:
example = '
if size == 'full' or i == last:
TEXT.append('%s/%d %s: %s' % (file, linenu, object, example))
if(i == last):
if code and size == 'full':
TEXT.append(getTextFromCode(code, offset, linenu))
TEXT.append(getTextFromStrerr(strerr))
if size == 'full':
TEXT.append(getTextFromDict(frame.f_locals, 'LOCAL VARS:'))
TEXT.append('----------')
return '\n'.join(TEXT)
if __name__ == '__main__':
print sys.argv
prog = sys.argv[0]
info = """SailForms Converter 1.0 / Python 2.5
(c) Petr Mach 2012, petr.mach.cz@gmail.com
Convert XML backup data from SailForms to CSV and vice versa.
CSV FORMAT:
value separator: TAB
text delimiter: "
encoding: Unicode (UTF-16 LE)
decimal point: depending on locale or optional parameter
HOW TO USE:
python %s MODE FILENAME [DP]
FILENAME - name of XML backup file, for example data.xml
MODE - GET or STORE
[DP] - optional, decimal point in CSV file
EXAMPLES:
python %s GET data.xml
- need: data.xml
- create: data.xml.csv
python %s STORE data.xml
- need: data.xml, data.xml.csv
- create: data.xml.csv.xml
WARNING:
Do not delete data.xml after creation of data.xml.csv.
This file is needed to create data.xml.csv.xml."""
info = info % (prog, prog, prog)
if len(sys.argv) < 3:
print info
sys.exit()
mode = sys.argv[1] # GET, STORE
sfIFName = sys.argv[2] # sf_backup.xml
locale.setlocale(locale.LC_ALL, '')
cLocale = locale.localeconv()
dPoint = cLocale['decimal_point']
if len(sys.argv) > 3:
dPoint = sys.argv[3]
convertor = SFConvertor(sfIFName, dPoint)
res = convertor.run(mode)
if res == 'info':
print info
else:
print 'DONE'
Žádné komentáře:
Okomentovat