Skip to content

Commit 2033db1

Browse files
author
cfarmer
committedMar 10, 2010
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... git-svn-id: http://svn.osgeo.org/qgis/trunk@13039 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 19e7b9f commit 2033db1

File tree

1 file changed

+24
-88
lines changed

1 file changed

+24
-88
lines changed
 

‎python/plugins/fTools/tools/doJoinAttributes.py

Lines changed: 24 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,10 @@ def inFile(self):
120120
self.outShape.clear()
121121
fileDialog = QFileDialog()
122122
fileDialog.setConfirmOverwrite(False)
123-
outName = fileDialog.getOpenFileName(self, self.tr("Join Table"), ".", "DBase Files (*.dbf)")
123+
outName = fileDialog.getOpenFileName(self, self.tr("Join Table"), ".", "Tables (*.dbf *.csv)")
124124
fileCheck = QFile(outName)
125125
if fileCheck.exists():
126126
filePath = QFileInfo(outName).absoluteFilePath()
127-
if filePath.right(4).toLower() != ".dbf": filePath = filePath + ".dbf"
128127
if not outName.isEmpty():
129128
self.inTable.clear()
130129
self.inTable.insert(filePath)
@@ -135,13 +134,18 @@ def inFile(self):
135134
def updateTableFields(self):
136135
if self.inTable.text() != "":
137136
filePath = self.inTable.text()
138-
f = open(unicode(filePath), 'rb')
139-
table = list(self.dbfreader(f))
140-
f.close()
137+
joinInfo = QFileInfo(filePath)
138+
joinPath = joinInfo.absoluteFilePath()
139+
joinName = joinInfo.completeBaseName()
141140
self.joinField.clear()
142-
for i in table[0]:
143-
self.joinField.addItem(unicode(i))
144-
table = None
141+
changedLayer = QgsVectorLayer(joinPath, joinName, 'ogr')
142+
try:
143+
changedField = ftools_utils.getFieldList(changedLayer)
144+
except:
145+
QMessageBox.warning(self, self.tr("Join Attributes"), self.tr("Unable to read input table!"))
146+
return
147+
for i in changedField:
148+
self.joinField.addItem(unicode(changedField[i].name()))
145149

146150
def compute(self, inName, inField, joinName, joinField, outName, keep, useTable, progressBar):
147151
layer1 = ftools_utils.getVectorLayerByName(inName)
@@ -151,21 +155,18 @@ def compute(self, inName, inField, joinName, joinField, outName, keep, useTable,
151155
fieldList1 = ftools_utils.getFieldList(layer1).values()
152156
index1 = provider1.fieldNameIndex(inField)
153157
if useTable:
154-
f = open(unicode(joinName), 'rb')
155-
table = list(self.dbfreader(f))
156-
f.close()
157-
(fieldList2, index2) = self.createFieldList(table, joinField)
158-
table = table[2:]
159-
func = lambda x: (unicode(type(x)) != "<type 'str'>" and QVariant(float(x))) or (QVariant(x))
160-
table = map(lambda f: map(func, f), table)
161-
158+
joinInfo = QFileInfo(joinName)
159+
joinPath = joinInfo.absoluteFilePath()
160+
joinName = joinInfo.completeBaseName()
161+
layer2 = QgsVectorLayer(joinPath, joinName, 'ogr')
162+
useTable = False
162163
else:
163164
layer2 = ftools_utils.getVectorLayerByName(joinName)
164-
provider2 = layer2.dataProvider()
165-
allAttrs = provider2.attributeIndexes()
166-
provider2.select(allAttrs)
167-
fieldList2 = ftools_utils.getFieldList(layer2)
168-
index2 = provider2.fieldNameIndex(joinField)
165+
provider2 = layer2.dataProvider()
166+
allAttrs = provider2.attributeIndexes()
167+
provider2.select(allAttrs, QgsRectangle(), False, False)
168+
fieldList2 = ftools_utils.getFieldList(layer2)
169+
index2 = provider2.fieldNameIndex(joinField)
169170
fieldList2 = self.testForUniqueness(fieldList1, fieldList2.values())
170171
seq = range(0, len(fieldList1) + len(fieldList2))
171172
fieldList1.extend(fieldList2)
@@ -192,21 +193,8 @@ def compute(self, inName, inField, joinName, joinField, outName, keep, useTable,
192193
outFeat.setAttributeMap(atMap1)
193194
outFeat.setGeometry(inGeom)
194195
none = True
195-
if useTable:
196-
for i in table:
197-
#sequence = range(0, len(table[0]))
198-
#atMap2 = dict(zip(sequence, i))
199-
if atMap1[index1].toString().trimmed() == i[index2].toString().trimmed():
200-
count = count + 1
201-
none = False
202-
atMap = atMap1.values()
203-
atMap2 = i
204-
atMap.extend(atMap2)
205-
atMap = dict(zip(seq, atMap))
206-
break
207-
else:
208-
provider2.rewind()
209-
while provider2.nextFeature(joinFeat):
196+
provider2.select(allAttrs, QgsRectangle(), False, False)
197+
while provider2.nextFeature(joinFeat):
210198
atMap2 = joinFeat.attributeMap()
211199
if atMap1[index1] == atMap2[index2]:
212200
none = False
@@ -259,55 +247,3 @@ def testForUniqueness(self, fieldList1, fieldList2):
259247
j = ftools_utils.createUniqueFieldName(j)
260248
changed = True
261249
return fieldList2
262-
263-
def dbfreader(self, f):
264-
"""Returns an iterator over records in a Xbase DBF file.
265-
266-
The first row returned contains the field names.
267-
The second row contains field specs: (type, size, decimal places).
268-
Subsequent rows contain the data records.
269-
If a record is marked as deleted, it is skipped.
270-
271-
File should be opened for binary reads.
272-
273-
"""
274-
numrec, lenheader = struct.unpack('<xxxxLH22x', f.read(32))
275-
numfields = (lenheader - 33) // 32
276-
277-
fields = []
278-
for fieldno in xrange(numfields):
279-
name, typ, size, deci = struct.unpack('<11sc4xBB14x', f.read(32))
280-
name = name.replace('\0', '') # eliminate NULs from string
281-
fields.append((name, typ, size, deci))
282-
yield [field[0] for field in fields]
283-
yield [tuple(field[1:]) for field in fields]
284-
285-
terminator = f.read(1)
286-
assert terminator == '\r'
287-
288-
fields.insert(0, ('DeletionFlag', 'C', 1, 0))
289-
fmt = ''.join(['%ds' % fieldinfo[2] for fieldinfo in fields])
290-
fmtsiz = struct.calcsize(fmt)
291-
for i in xrange(numrec):
292-
record = struct.unpack(fmt, f.read(fmtsiz))
293-
if record[0] != ' ':
294-
continue # deleted record
295-
result = []
296-
for (name, typ, size, deci), value in itertools.izip(fields, record):
297-
if name == 'DeletionFlag':
298-
continue
299-
if typ == "N":
300-
value = value.replace('\0', '').lstrip()
301-
if value == '':
302-
value = 0
303-
elif deci:
304-
value = decimal.Decimal(value)
305-
else:
306-
value = int(value)
307-
elif typ == 'D':
308-
y, m, d = int(value[:4]), int(value[4:6]), int(value[6:8])
309-
value = datetime.date(y, m, d)
310-
elif typ == 'L':
311-
value = (value in 'YyTt' and 'T') or (value in 'NnFf' and 'F') or '?'
312-
result.append(value)
313-
yield result

0 commit comments

Comments
 (0)
Please sign in to comment.