[QGIS Commit] r13039 - trunk/qgis/python/plugins/fTools/tools

svn_qgis at osgeo.org svn_qgis at osgeo.org
Wed Mar 10 14:19:59 EST 2010


Author: cfarmer
Date: 2010-03-10 14:19:58 -0500 (Wed, 10 Mar 2010)
New Revision: 13039

Modified:
   trunk/qgis/python/plugins/fTools/tools/doJoinAttributes.py
Log:
Join attributes tool now supports both dbf and csv files. Uses OGR provider to read tabular information (a bit of a hack, but it seems to work).
Should be slightly faster, and more robust to different file encodings and formats...


Modified: trunk/qgis/python/plugins/fTools/tools/doJoinAttributes.py
===================================================================
--- trunk/qgis/python/plugins/fTools/tools/doJoinAttributes.py	2010-03-10 01:21:07 UTC (rev 13038)
+++ trunk/qgis/python/plugins/fTools/tools/doJoinAttributes.py	2010-03-10 19:19:58 UTC (rev 13039)
@@ -120,11 +120,10 @@
     self.outShape.clear()
     fileDialog = QFileDialog()
     fileDialog.setConfirmOverwrite(False)
-    outName = fileDialog.getOpenFileName(self, self.tr("Join Table"), ".", "DBase Files (*.dbf)")
+    outName = fileDialog.getOpenFileName(self, self.tr("Join Table"), ".", "Tables (*.dbf *.csv)")
     fileCheck = QFile(outName)
     if fileCheck.exists():
       filePath = QFileInfo(outName).absoluteFilePath()
-      if filePath.right(4).toLower() != ".dbf": filePath = filePath + ".dbf"
       if not outName.isEmpty():
         self.inTable.clear()
         self.inTable.insert(filePath)
@@ -135,13 +134,18 @@
   def updateTableFields(self):
     if self.inTable.text() != "":
       filePath = self.inTable.text()
-      f = open(unicode(filePath), 'rb')
-      table = list(self.dbfreader(f))
-      f.close()
+      joinInfo = QFileInfo(filePath)
+      joinPath = joinInfo.absoluteFilePath()
+      joinName = joinInfo.completeBaseName()
       self.joinField.clear()
-      for i in table[0]:
-        self.joinField.addItem(unicode(i))
-      table = None
+      changedLayer = QgsVectorLayer(joinPath, joinName, 'ogr')
+      try:
+        changedField = ftools_utils.getFieldList(changedLayer)
+      except:
+        QMessageBox.warning(self, self.tr("Join Attributes"), self.tr("Unable to read input table!"))
+        return
+      for i in changedField:
+        self.joinField.addItem(unicode(changedField[i].name()))
 
   def compute(self, inName, inField, joinName, joinField, outName, keep, useTable, progressBar):
     layer1 = ftools_utils.getVectorLayerByName(inName)
@@ -151,21 +155,18 @@
     fieldList1 = ftools_utils.getFieldList(layer1).values()
     index1 = provider1.fieldNameIndex(inField)
     if useTable:
-      f = open(unicode(joinName), 'rb')
-      table = list(self.dbfreader(f))
-      f.close()
-      (fieldList2, index2) = self.createFieldList(table, joinField)
-      table = table[2:]
-      func = lambda x: (unicode(type(x)) != "<type 'str'>" and QVariant(float(x))) or (QVariant(x))
-      table = map(lambda f: map(func, f), table)
-
+      joinInfo = QFileInfo(joinName)
+      joinPath = joinInfo.absoluteFilePath()
+      joinName = joinInfo.completeBaseName()
+      layer2 = QgsVectorLayer(joinPath, joinName, 'ogr')
+      useTable = False
     else:
       layer2 = ftools_utils.getVectorLayerByName(joinName)
-      provider2 = layer2.dataProvider()
-      allAttrs = provider2.attributeIndexes()
-      provider2.select(allAttrs)
-      fieldList2 = ftools_utils.getFieldList(layer2)
-      index2 = provider2.fieldNameIndex(joinField)
+    provider2 = layer2.dataProvider()
+    allAttrs = provider2.attributeIndexes()
+    provider2.select(allAttrs, QgsRectangle(), False, False)
+    fieldList2 = ftools_utils.getFieldList(layer2)
+    index2 = provider2.fieldNameIndex(joinField)
     fieldList2 = self.testForUniqueness(fieldList1, fieldList2.values())
     seq = range(0, len(fieldList1) + len(fieldList2))
     fieldList1.extend(fieldList2)
@@ -192,21 +193,8 @@
       outFeat.setAttributeMap(atMap1)
       outFeat.setGeometry(inGeom)
       none = True
-      if useTable:
-        for i in table:
-          #sequence = range(0, len(table[0]))
-          #atMap2 = dict(zip(sequence, i))
-          if atMap1[index1].toString().trimmed() == i[index2].toString().trimmed():
-            count = count + 1
-            none = False
-            atMap = atMap1.values()
-            atMap2 = i
-            atMap.extend(atMap2)
-            atMap = dict(zip(seq, atMap))
-            break
-      else:
-        provider2.rewind()
-        while provider2.nextFeature(joinFeat):
+      provider2.select(allAttrs, QgsRectangle(), False, False)
+      while provider2.nextFeature(joinFeat):
           atMap2 = joinFeat.attributeMap()
           if atMap1[index1] == atMap2[index2]:
             none = False
@@ -259,55 +247,3 @@
             j = ftools_utils.createUniqueFieldName(j)
             changed = True
     return fieldList2
-
-  def dbfreader(self, f):
-      """Returns an iterator over records in a Xbase DBF file.
-
-      The first row returned contains the field names.
-      The second row contains field specs: (type, size, decimal places).
-      Subsequent rows contain the data records.
-      If a record is marked as deleted, it is skipped.
-
-      File should be opened for binary reads.
-
-      """
-      numrec, lenheader = struct.unpack('<xxxxLH22x', f.read(32))
-      numfields = (lenheader - 33) // 32
-
-      fields = []
-      for fieldno in xrange(numfields):
-          name, typ, size, deci = struct.unpack('<11sc4xBB14x', f.read(32))
-          name = name.replace('\0', '')       # eliminate NULs from string
-          fields.append((name, typ, size, deci))
-      yield [field[0] for field in fields]
-      yield [tuple(field[1:]) for field in fields]
-
-      terminator = f.read(1)
-      assert terminator == '\r'
-
-      fields.insert(0, ('DeletionFlag', 'C', 1, 0))
-      fmt = ''.join(['%ds' % fieldinfo[2] for fieldinfo in fields])
-      fmtsiz = struct.calcsize(fmt)
-      for i in xrange(numrec):
-          record = struct.unpack(fmt, f.read(fmtsiz))
-          if record[0] != ' ':
-              continue                        # deleted record
-          result = []
-          for (name, typ, size, deci), value in itertools.izip(fields, record):
-              if name == 'DeletionFlag':
-                  continue
-              if typ == "N":
-                  value = value.replace('\0', '').lstrip()
-                  if value == '':
-                      value = 0
-                  elif deci:
-                      value = decimal.Decimal(value)
-                  else:
-                      value = int(value)
-              elif typ == 'D':
-                  y, m, d = int(value[:4]), int(value[4:6]), int(value[6:8])
-                  value = datetime.date(y, m, d)
-              elif typ == 'L':
-                  value = (value in 'YyTt' and 'T') or (value in 'NnFf' and 'F') or '?'
-              result.append(value)
-          yield result



More information about the QGIS-commit mailing list