Mercurial > hg > ChinaGisRestApi
comparison RestDbInterface.py @ 16:cbb73d103152
NEW - # 12: create table and upload data
https://it-dev.mpiwg-berlin.mpg.de/tracs/GIS/ticket/12
works now!
author | casties |
---|---|
date | Mon, 16 Aug 2010 21:24:00 +0200 |
parents | 5e3edf980813 |
children | ed997e639cfd |
comparison
equal
deleted
inserted
replaced
15:5e3edf980813 | 16:cbb73d103152 |
---|---|
7 from OFS.Folder import Folder | 7 from OFS.Folder import Folder |
8 from Products.PageTemplates.PageTemplateFile import PageTemplateFile | 8 from Products.PageTemplates.PageTemplateFile import PageTemplateFile |
9 from Products.ZSQLExtend import ZSQLExtend | 9 from Products.ZSQLExtend import ZSQLExtend |
10 import logging | 10 import logging |
11 import re | 11 import re |
12 import psycopg2 | |
12 | 13 |
13 from zope.interface import implements | 14 from zope.interface import implements |
14 from zope.publisher.interfaces import IPublishTraverse | 15 from zope.publisher.interfaces import IPublishTraverse |
15 from ZPublisher.BaseRequest import DefaultPublishTraverse | 16 from ZPublisher.BaseRequest import DefaultPublishTraverse |
16 #from zope.publisher.interfaces import NotFound | 17 #from zope.publisher.interfaces import NotFound |
18 #from zope.component import queryMultiAdapter | 19 #from zope.component import queryMultiAdapter |
19 import Shared.DC.ZRDB.DA | 20 import Shared.DC.ZRDB.DA |
20 from Products.ZSQLMethods.SQL import SQLConnectionIDs | 21 from Products.ZSQLMethods.SQL import SQLConnectionIDs |
21 | 22 |
22 | 23 |
23 def getTextFromNode(nodename): | 24 def getTextFromNode(node): |
24 """get the cdata content of a XML node""" | 25 """get the cdata content of a XML node""" |
25 if nodename is None: | 26 if node is None: |
26 return "" | 27 return "" |
27 nodelist=nodename.childNodes | 28 |
29 if isinstance(node, list): | |
30 nodelist = node | |
31 else: | |
32 nodelist=node.childNodes | |
33 | |
28 rc = "" | 34 rc = "" |
29 for node in nodelist: | 35 for node in nodelist: |
30 if node.nodeType == node.TEXT_NODE: | 36 if node.nodeType == node.TEXT_NODE: |
31 rc = rc + node.data | 37 rc = rc + node.data |
32 return rc | 38 return rc |
33 | 39 |
34 def sqlName(s,lc=False): | 40 def sqlName(s,lc=True): |
35 """returns ASCII-only version of string""" | 41 """returns restricted ASCII-only version of string""" |
36 if s is None: | 42 if s is None: |
37 return "" | 43 return "" |
38 | 44 |
39 # blank -> "-" | |
40 s = re.sub(r' ','-',s) | |
41 # all else -> "_" | 45 # all else -> "_" |
42 s = re.sub(r'[^A-Za-z0-9_-]','_',s) | 46 s = re.sub(r'[^A-Za-z0-9_]','_',s) |
43 if lc: | 47 if lc: |
44 return s.lower() | 48 return s.lower() |
45 | 49 |
46 return s | 50 return s |
47 | 51 |
103 self._v_database_connection = conn | 107 self._v_database_connection = conn |
104 except Exception, e: | 108 except Exception, e: |
105 raise IOError("No database connection! (%s)"%str(e)) | 109 raise IOError("No database connection! (%s)"%str(e)) |
106 | 110 |
107 cursor = conn.getcursor() | 111 cursor = conn.getcursor() |
112 cursor.connection.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT) | |
108 return cursor | 113 return cursor |
109 | 114 |
110 def executeSQL(self, query, *args): | 115 def executeSQL(self, query, *args): |
111 """execute query with args on database and return all results. | 116 """execute query with args on database and return all results. |
112 result format: {"fields":fields, "rows":data}""" | 117 result format: {"fields":fields, "rows":data}""" |
118 logging.debug("executeSQL query=%s args=%s"%(query,args)) | |
113 cur = self.getCursor() | 119 cur = self.getCursor() |
114 cur.execute(query, args) | 120 cur.execute(query, args) |
115 # description of returned fields | 121 # description of returned fields |
116 fields = cur.description | 122 fields = cur.description |
117 # get all data in an array | 123 # get all data in an array |
118 data = cur.fetchall() | 124 data = cur.fetchall() |
119 cur.close() | 125 cur.close() |
120 return {"fields":fields, "rows":data} | 126 return {"fields":fields, "rows":data} |
127 | |
128 def executeOnlySQL(self, query, *args): | |
129 """execute query with args on database that has no results. | |
130 result format: {"fields":fields, "rows":data}""" | |
131 logging.debug("executeOnlySQL query=%s args=%s"%(query,args)) | |
132 cur = self.getCursor() | |
133 cur.execute(query, args) | |
134 cur.close() | |
135 return None | |
121 | 136 |
122 | 137 |
123 def publishTraverse(self,request,name): | 138 def publishTraverse(self,request,name): |
124 """change the traversal""" | 139 """change the traversal""" |
125 # get stored path | 140 # get stored path |
220 | 235 |
221 | 236 |
222 def getTable(self,schema='public',table=None,username='guest'): | 237 def getTable(self,schema='public',table=None,username='guest'): |
223 """return table data""" | 238 """return table data""" |
224 logging.debug("gettable") | 239 logging.debug("gettable") |
225 data = self.executeSQL("select * from %s"%table) | 240 data = self.executeSQL('select * from "%s"."%s"'%(schema,table)) |
226 return data | 241 return data |
227 | 242 |
228 def showListOfTables(self,format='XML',schema='public'): | 243 def showListOfTables(self,format='XML',schema='public'): |
229 """returns PageTemplate with list of tables""" | 244 """returns PageTemplate with list of tables""" |
230 logging.debug("showlistoftables") | 245 logging.debug("showlistoftables") |
282 | 297 |
283 sqlFields.append({'name':name, 'type':type}) | 298 sqlFields.append({'name':name, 'type':type}) |
284 | 299 |
285 # drop table if it exists | 300 # drop table if it exists |
286 try: | 301 try: |
287 res = executeSQL('drop table "%s.%s"'%(schema,table)) | 302 res = self.executeSQL('select * from "%s"."%s" where 1=0'%(schema,table)) |
288 logging.debug("createemptytable: dropped table %s.%s"%(schema,table)) | 303 logging.debug("createemptytable: table %s.%s exists"%(schema,table)) |
304 self.executeOnlySQL('drop table "%s"."%s"'%(schema,table)) | |
289 except: | 305 except: |
290 pass | 306 pass |
291 | 307 |
292 fieldString = ", ".join(['"%s" %s'%(f['name'],f['type']) for f in sqlFields]) | 308 fieldString = ", ".join(['"%s" %s'%(f['name'],f['type']) for f in sqlFields]) |
293 sqlString = 'create table "%s.%s" (%s)'%(schema,table,fieldString) | 309 sqlString = 'create table "%s"."%s" (%s)'%(schema,table,fieldString) |
294 loging.debug("createemptytable: SQL=%s"%sqlString) | 310 logging.debug("createemptytable: SQL=%s"%sqlString) |
295 ret = self.executeSQL(sqlString) | 311 ret = self.executeOnlySQL(sqlString) |
296 | 312 |
297 return sqlFields | 313 return sqlFields |
298 | 314 |
299 | 315 |
300 | 316 |
301 def createTableFromXML(self,schema,table,data): | 317 def createTableFromXML(self,schema,table,data): |
302 """create or replace a table with the given XML data""" | 318 """create or replace a table with the given XML data""" |
303 logging.debug("createTableFromXML schema=%s table=%s data=%s"%(schema,table,data)) | 319 logging.debug("createTableFromXML schema=%s table=%s data=%s"%(schema,table,data)) |
304 self.importExcelXML(schema,table, data) | 320 self.importExcelXML(schema,table, data) |
305 | 321 |
306 def importExcelXML(self,schema,table,data,fieldNamesOnly=False): | 322 def importExcelXML(self,schema,table,xmldata,fieldNamesOnly=False): |
307 ''' | 323 ''' |
308 Import XML file in Excel format into the table | 324 Import XML file in Excel format into the table |
309 @param table: name of the table the xml shall be imported into | 325 @param table: name of the table the xml shall be imported into |
310 @param containerTagName: XML-Tag which describes a dataset | 326 @param containerTagName: XML-Tag which describes a dataset |
311 @param data: data to be imported | 327 @param data: data to be imported |
315 from xml.dom.pulldom import parseString,parse | 331 from xml.dom.pulldom import parseString,parse |
316 | 332 |
317 namespace = "urn:schemas-microsoft-com:office:spreadsheet" | 333 namespace = "urn:schemas-microsoft-com:office:spreadsheet" |
318 containerTagName = "Table" | 334 containerTagName = "Table" |
319 rowTagName = "Row" | 335 rowTagName = "Row" |
336 colTagName = "Cell" | |
320 dataTagName = "Data" | 337 dataTagName = "Data" |
321 fieldNames = [] | 338 fieldNames = [] |
322 sqlFields = [] | 339 sqlFields = [] |
340 numFields = 0 | |
323 sqlInsert = None | 341 sqlInsert = None |
324 | 342 |
325 logging.debug("import excel xml") | 343 logging.debug("import excel xml") |
326 | 344 |
327 ret="" | 345 ret="" |
328 if isinstance(data, str): | 346 if isinstance(xmldata, str): |
329 logging.debug("importXML reading string data") | 347 logging.debug("importXML reading string data") |
330 doc=parseString(data) | 348 doc=parseString(xmldata) |
331 else: | 349 else: |
332 logging.debug("importXML reading file data") | 350 logging.debug("importXML reading file data") |
333 doc=parse(data) | 351 doc=parse(xmldata) |
334 | 352 |
335 cnt = 0 | 353 cnt = 0 |
336 while True: | 354 while True: |
337 node=doc.getEvent() | 355 node=doc.getEvent() |
338 | 356 |
339 if node is None: | 357 if node is None: |
340 break | 358 break |
341 | 359 |
342 else: | 360 else: |
361 #logging.debug("tag=%s"%node[1].localName) | |
343 if node[1].localName is not None: | 362 if node[1].localName is not None: |
344 tagName = node[1].localName.lower() | 363 tagName = node[1].localName.lower() |
345 else: | 364 else: |
346 # ignore non-tag nodes | 365 # ignore non-tag nodes |
347 continue | 366 continue |
348 | 367 |
349 if tagName == containerTagName.lower(): # make everything case insensitive | |
350 # start of container -- do we need this? | |
351 cnt = 0 | |
352 continue | |
353 | |
354 if tagName == rowTagName.lower(): | 368 if tagName == rowTagName.lower(): |
355 # start of row | 369 # start of row |
356 doc.expandNode(node[1]) | 370 doc.expandNode(node[1]) |
357 cnt += 1 | 371 cnt += 1 |
358 if cnt == 1: | 372 if cnt == 1: |
366 # return just field names | 380 # return just field names |
367 return fieldNames | 381 return fieldNames |
368 | 382 |
369 # create table | 383 # create table |
370 sqlFields = self.createEmptyTable(schema, table, fieldNames) | 384 sqlFields = self.createEmptyTable(schema, table, fieldNames) |
385 numFields = len(sqlFields) | |
371 fieldString = ", ".join(['"%s"'%f['name'] for f in sqlFields]) | 386 fieldString = ", ".join(['"%s"'%f['name'] for f in sqlFields]) |
372 valString = ", ".join(["%s" for f in sqlFields]) | 387 valString = ", ".join(["%s" for f in sqlFields]) |
373 sqlInsert = 'insert into "%s.%s" (%s) values (%s)'%(schema,table,fieldString,valString) | 388 sqlInsert = 'insert into "%s"."%s" (%s) values (%s)'%(schema,table,fieldString,valString) |
374 logging.debug("importexcelsql: sqlInsert=%s"%sqlInsert) | 389 logging.debug("importexcelsql: sqlInsert=%s"%sqlInsert) |
375 | 390 |
376 else: | 391 else: |
377 # following rows are data | 392 # following rows are data |
378 dataNodes=node[1].getElementsByTagNameNS(namespace, dataTagName) | 393 colNodes=node[1].getElementsByTagNameNS(namespace, colTagName) |
379 data = [] | 394 data = [] |
380 for dataNode in dataNodes: | 395 hasData = False |
381 val = getTextFromNode(dataNodes) | 396 for colNode in colNodes: |
397 dataNodes=colNode.getElementsByTagNameNS(namespace, dataTagName) | |
398 if len(dataNodes) > 0: | |
399 val = getTextFromNode(dataNodes[0]) | |
400 hasData = True | |
401 else: | |
402 val = None | |
403 | |
382 data.append(val) | 404 data.append(val) |
383 | 405 |
384 self.executeSQL(sqlInsert, data) | 406 if not hasData: |
385 | 407 # ignore empty rows |
386 | 408 continue |
387 continue | 409 |
388 | 410 # fix number of data fields |
389 '''dataSet={} | 411 if len(data) > numFields: |
390 for col in node[1].childNodes: | 412 del data[numFields:] |
391 if col.nodeType is col.ELEMENT_NODE: | 413 elif len(data) < numFields: |
392 data=col.nodeName | 414 missFields = numFields - len(data) |
393 dataSet[data]=getTextFromNode(col) | 415 data.extend(missFields * [None,]) |
394 | 416 |
395 update=False | 417 logging.debug("importexcel sqlinsert=%s data=%s"%(sqlInsert,data)) |
396 | 418 self.executeOnlySQL(sqlInsert, *data) |
397 if identify: | |
398 | |
399 field=dataSet[identify] | |
400 | |
401 searchStr="""select %s from %s where %s = '%s'"""%(identify,table,identify,field) | |
402 logger("import xml",logging.INFO,searchStr) | |
403 search=self.ZSQLSimpleSearch(searchStr) | |
404 if search: | |
405 update=True | |
406 | |
407 if update: | |
408 tmp=[] | |
409 for fieldName in dataSet.keys(): | |
410 tmp.append("""%s = %s"""%(fieldName,self.ZSQLQuote(dataSet[fieldName]))) | |
411 setStr=",".join(tmp) | |
412 | |
413 field=dataSet[identify] | |
414 | |
415 queryStr="""UPDATE %s SET %s WHERE %s = '%s' """%(table,setStr,identify,field) | |
416 logger("update xml",logging.INFO,queryStr) | |
417 self.ZSQLSimpleSearch(queryStr) | |
418 ret+="ud: %s \n"%field | |
419 | |
420 else: | |
421 fields=",".join(dataSet.keys()) | |
422 values=",".join([""" %s """%self.ZSQLQuote(dataSet[x]) for x in dataSet.keys()]) | |
423 | |
424 | |
425 queryStr="""INSERT INTO %s (%s) VALUES (%s)"""%(table,fields,values) | |
426 self.ZSQLSimpleSearch(queryStr) | |
427 logger("update xml",logging.INFO,queryStr) | |
428 ''' | |
429 | 419 |
430 logging.debug("XML import field names: %s"%(fieldNames)) | 420 return cnt |
431 return ret | |
432 | 421 |
433 | 422 |
434 def manage_editRestDbInterface(self, title=None, connection_id=None, | 423 def manage_editRestDbInterface(self, title=None, connection_id=None, |
435 REQUEST=None): | 424 REQUEST=None): |
436 """Change the object""" | 425 """Change the object""" |