--- ZSQLExtend/ZSQLExtend.py 2007/03/08 17:00:48 1.106 +++ ZSQLExtend/ZSQLExtend.py 2007/04/02 09:48:13 1.107 @@ -19,7 +19,7 @@ import os.path import os import copy import unicodedata - +import tempfile import logging #ersetzt logging @@ -70,6 +70,9 @@ def sql_quote(v): def showSQLConnectionIDs(self): return SQLConnectionIDs(self) +class Options: + """options class""" + class ZSQLIndex(SimpleItem): """index""" meta_type="ZSQLIndex" @@ -406,149 +409,47 @@ class ZSQLExtendFolder(Folder,Persistent #print "wrote: %s"%fn - def importXMLFileFMP(self,table,data=None,filename=None,update_fields=None,id_field=None,sync_mode=False,RESPONSE=None): + def importXMLFileFMP(self,table,dsn=None,uploadfile=None,update_fields=None,id_field=None,sync_mode=False,replace=False,redirect_url=None,RESPONSE=None): ''' Import FileMaker XML file (FMPXMLRESULT format) into the table. + @param dsn: database connection string @param table: name of the table the xml shall be imported into - @param data: xml data as bz2 string - @param filename: xmlfile filename + @param uploadfile: xmlfile file @param update_fields: (optional) list of fields to update; default is to create all fields @param id_field: (optional) field which uniquely identifies an entry for updating purposes. @param sync_mode: (optional) really synchronise, i.e. delete entries not in XML file @param RESPONSE: (optional) + @param redirect_url: (optional) url for redirecting after the upload is done ''' - from xml.dom.pulldom import parseString,parse - import transaction - - ret = "" - - if data: - data=bz2.decompress(base64.decodestring(data)) - logger("fmpxml",logging.INFO,"received file") - doc=parseString(data) - logger("fmpxml",logging.INFO,"parsed file") - - elif filename: - fh=file(filename) - logger("fmpxml",logging.INFO,"reading file") - doc=parse(fh) - logger("fmpxml",logging.INFO,"parsed file") - - dbIDs = {} - rowcnt = 0 - - if id_field is not None: - # prepare a list of ids for sync mode - qstr="select %s from %s"%(id_field,table) - for id in self.ZSQLSimpleSearch(qstr): - # value 0: not updated - dbIDs[id[0]] = 0; - rowcnt += 1 - - logger("fmpxml",logging.INFO,"%d entries in DB to sync"%rowcnt) - fieldNames = [] - rowcnt = 0 - id_val = '' + tfilehd,filename=tempfile.mkstemp() + tfile=os.fdopen(tfilehd,'w') + logging.error("import %s"%uploadfile) + for c in uploadfile.read(): + tfile.write(c) + tfile.close() + + from importFMPXML import importFMPXML + + if not dsn: + dsn=self.getConnectionObj().connection_string + + options=Options() + options.dsn=dsn + options.table=table + options.filename=filename + options.update_fields=update_fields + options.id_field=id_field + options.sync_mode=sync_mode + options.replace_table=replace + options.lc_names=True + importFMPXML(options) - while 1: - node=doc.getEvent() + os.remove(filename) - if node is None: - break; - - # METADATA tag defines number and names of fields in FMPXMLRESULT - if node[1].nodeName == 'METADATA': - doc.expandNode(node[1]) + if RESPONSE and redirect_url: + RESPONSE.redirect(redirect_url) - names=node[1].getElementsByTagName('FIELD') - - for name in names: - fn = name.getAttribute('NAME') - fieldNames.append(fn) - - if update_fields is None: - # update all fields - update_fields = fieldNames - - logger("fmpxml fieldnames:",logging.INFO,repr(fieldNames)) - # get list of fields in db table - qstr="""select attname from pg_attribute, pg_class where attrelid = pg_class.oid and relname = '%s'""" - columns=[x.attname for x in self.ZSQLSimpleSearch(qstr%table)] - - # adjust db table to fields in XML and fieldlist - for fieldName in fieldNames: - logger("fmpxml fieldname:",logging.INFO,repr(fieldName)) - if (fieldName not in columns) and (fieldName in update_fields): - qstr="""alter table %s add %s %s""" - self.ZSQLSimpleSearch(qstr%(table,fieldName,'text')) - logger("fmpxml add field:",logging.INFO,qstr%(table,fieldName,'text')) - - # ROW tags (in RESULTSET tag) hold data - elif node[1].nodeName == 'ROW': - rowcnt += 1 - - doc.expandNode(node[1]) - cols=node[1].getElementsByTagName('COL') - dataSet={} - i = 0 - # populate with data - for col in cols: - data=col.getElementsByTagName('DATA') - dataSet[fieldNames[i]] = getTextFromNode(data[0]) - i += 1 - - update=False - - # synchronize by id_field - if id_field: - id_val=dataSet[id_field] - if id_val in dbIDs: - dbIDs[id_val] += 1 - update=True - - if update: - # update existing row (by id_field) - setvals=[] - for fieldName in update_fields: - setvals.append("%s = %s"%(fieldName,self.ZSQLQuote(dataSet[fieldName]))) - setStr=string.join(setvals, ',') - id_val=dataSet[id_field] - qstr="""UPDATE %s SET %s WHERE %s = '%s' """%(table,setStr,id_field,id_val) - #logger("fmpxml update:",logging.INFO,queryStr) - self.ZSQLSimpleSearch(qstr) - ret+="up: %s \n"%id_val - else: - # create new row - fields=string.join(update_fields, ',') - values=string.join([" %s "%self.ZSQLQuote(dataSet[x]) for x in update_fields], ',') - qstr="""INSERT INTO %s (%s) VALUES (%s)"""%(table,fields,values) - self.ZSQLSimpleSearch(qstr) - #logger("fmpxml: insert",logging.INFO,queryStr) - ret+="ad: %s \n"%dataSet.get(id_field, rowcnt) - - #logger("fmpxml row:",logging.INFO,"%d (%s)"%(rowcnt,id_val)) - if (rowcnt % 10) == 0: - logger("fmpxml row:",logging.INFO,"%d (%s)"%(rowcnt,id_val)) - transaction.commit() - - transaction.commit() - if sync_mode: - # delete unmatched entries in db - for id in dbIDs.keys(): - # find all not-updated fields - if dbIDs[id] == 0: - logger("fmpxml delete:",logging.INFO,id) - qstr = "DELETE FROM %s WHERE %s = '%s'" - self.ZSQLSimpleSearch(qstr%(table,id_field,id)) - - elif dbIDs[id] > 1: - logger("fmpxml sync:",logging.INFO,"id used more than once?"+id) - - transaction.commit() - - return ret - def generateIndex(self,field,index_name,table,RESPONSE=None): """erzeuge index aus feld""" index={}