Add option to QgsVectorFileWriter to prefer using field aliases as output field name

This commit is contained in:
Nyall Dawson 2020-12-05 15:37:06 +10:00
parent f972425342
commit 94522cf844
4 changed files with 102 additions and 11 deletions

View File

@ -143,6 +143,11 @@ Constructor for MetaData
SymbolLayerSymbology
};
enum FieldNameSource
{
Original,
PreferAlias,
};
enum VectorFormatOption
{
@ -384,6 +389,8 @@ Constructor
QgsVectorFileWriter::FieldValueConverter *fieldValueConverter;
QgsFeedback *feedback;
FieldNameSource fieldNameSource;
};

View File

@ -107,7 +107,8 @@ QgsVectorFileWriter::QgsVectorFileWriter(
SymbologyExport symbologyExport,
QgsFeatureSink::SinkFlags sinkFlags,
QString *newLayer,
QgsCoordinateTransformContext transformContext
QgsCoordinateTransformContext transformContext,
FieldNameSource fieldNameSouce
)
: mError( NoError )
, mWkbType( geometryType )
@ -116,7 +117,7 @@ QgsVectorFileWriter::QgsVectorFileWriter(
{
init( vectorFileName, fileEncoding, fields, geometryType,
srs, driverName, datasourceOptions, layerOptions, newFilename, nullptr,
QString(), CreateOrOverwriteFile, newLayer, sinkFlags, transformContext );
QString(), CreateOrOverwriteFile, newLayer, sinkFlags, transformContext, fieldNameSouce );
}
QgsVectorFileWriter::QgsVectorFileWriter(
@ -135,7 +136,8 @@ QgsVectorFileWriter::QgsVectorFileWriter(
ActionOnExistingFile action,
QString *newLayer,
QgsCoordinateTransformContext transformContext,
QgsFeatureSink::SinkFlags sinkFlags
QgsFeatureSink::SinkFlags sinkFlags,
FieldNameSource fieldNameSource
)
: mError( NoError )
, mWkbType( geometryType )
@ -144,7 +146,7 @@ QgsVectorFileWriter::QgsVectorFileWriter(
{
init( vectorFileName, fileEncoding, fields, geometryType, srs, driverName,
datasourceOptions, layerOptions, newFilename, fieldValueConverter,
layerName, action, newLayer, sinkFlags, transformContext );
layerName, action, newLayer, sinkFlags, transformContext, fieldNameSource );
}
QgsVectorFileWriter *QgsVectorFileWriter::create(
@ -163,7 +165,7 @@ QgsVectorFileWriter *QgsVectorFileWriter::create(
return new QgsVectorFileWriter( fileName, options.fileEncoding, fields, geometryType, srs,
options.driverName, options.datasourceOptions, options.layerOptions,
newFilename, options.symbologyExport, options.fieldValueConverter, options.layerName,
options.actionOnExistingFile, newLayer, transformContext, sinkFlags );
options.actionOnExistingFile, newLayer, transformContext, sinkFlags, options.fieldNameSource );
Q_NOWARN_DEPRECATED_POP
}
@ -201,7 +203,7 @@ void QgsVectorFileWriter::init( QString vectorFileName,
const QString &layerNameIn,
ActionOnExistingFile action,
QString *newLayer, SinkFlags sinkFlags,
const QgsCoordinateTransformContext &transformContext )
const QgsCoordinateTransformContext &transformContext, FieldNameSource fieldNameSource )
{
mRenderContext.setRendererScale( mSymbologyScale );
@ -604,10 +606,9 @@ void QgsVectorFileWriter::init( QString vectorFileName,
attrField = fieldValueConverter->fieldDefinition( fields.at( fldIdx ) );
}
QString name( attrField.name() );
if ( action == AppendToLayerAddFields )
{
int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( name ) );
int ogrIdx = OGR_FD_GetFieldIndex( defn, mCodec->fromUnicode( attrField.name() ) );
if ( ogrIdx >= 0 )
{
mAttrIdxToOgrIdx.insert( fldIdx, ogrIdx );
@ -615,6 +616,18 @@ void QgsVectorFileWriter::init( QString vectorFileName,
}
}
QString name;
switch ( fieldNameSource )
{
case Original:
name = attrField.name();
break;
case PreferAlias:
name = !attrField.alias().isEmpty() ? attrField.alias() : attrField.name();
break;
}
OGRFieldType ogrType = OFTString; //default to string
int ogrWidth = attrField.length();
int ogrPrecision = attrField.precision();

View File

@ -185,6 +185,16 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
SymbolLayerSymbology //Exports one feature per symbol layer (considering symbol levels)
};
/**
* Source for exported field names.
*
* \since QGIS 3.18
*/
enum FieldNameSource
{
Original = 0, //!< Use original field names
PreferAlias, //!< Use the original field alias as the exported field name, wherever one is set. Otherwise use the original field names.
};
/**
* Options for sorting and filtering vector formats.
@ -514,6 +524,13 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
//! Optional feedback object allowing cancellation of layer save
QgsFeedback *feedback = nullptr;
/**
* Source for exported field names.
*
* \since QGIS 3.18
*/
FieldNameSource fieldNameSource = Original;
};
#ifndef SIP_RUN
@ -570,7 +587,8 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags()
#ifndef SIP_RUN
, QString *newLayer = nullptr,
QgsCoordinateTransformContext transformContext = QgsCoordinateTransformContext()
QgsCoordinateTransformContext transformContext = QgsCoordinateTransformContext(),
FieldNameSource fieldNameSource = Original
#endif
) SIP_DEPRECATED;
@ -592,6 +610,7 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
* \param newLayer potentially modified layer name (output parameter) (added in QGIS 3.4)
* \param transformContext transform context, needed if the output file srs is forced to specific crs (added in QGIS 3.10.3)
* \param sinkFlags feature sink flags (added in QGIS 3.10.3)
* \param fieldNameSource source for field names (since QGIS 3.18)
* \note not available in Python bindings
* \deprecated Use create() instead.
*/
@ -610,7 +629,8 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
QgsVectorFileWriter::ActionOnExistingFile action,
QString *newLayer = nullptr,
QgsCoordinateTransformContext transformContext = QgsCoordinateTransformContext(),
QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags()
QgsFeatureSink::SinkFlags sinkFlags = QgsFeatureSink::SinkFlags(),
FieldNameSource fieldNameSource = Original
) SIP_SKIP;
//! QgsVectorFileWriter cannot be copied.
@ -967,7 +987,8 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
QgsVectorFileWriter::FieldValueConverter *fieldValueConverter,
const QString &layerName,
QgsVectorFileWriter::ActionOnExistingFile action, QString *newLayer, QgsFeatureSink::SinkFlags sinkFlags,
const QgsCoordinateTransformContext &transformContext );
const QgsCoordinateTransformContext &transformContext,
FieldNameSource fieldNameSource );
void resetMap( const QgsAttributeList &attributes );
std::unique_ptr< QgsFeatureRenderer > mRenderer;

View File

@ -99,6 +99,56 @@ class TestQgsVectorFileWriter(unittest.TestCase):
writeShape(self.mMemoryLayer, 'writetest.shp')
def testWritePreferAlias(self):
"""Test prefering field alias."""
layer = QgsVectorLayer(
('Point?crs=epsg:4326&field=name:string(20)&'
'field=age:integer&field=size:double&index=yes'),
'test',
'memory')
self.assertTrue(layer.isValid())
myProvider = layer.dataProvider()
layer.setFieldAlias(0, 'My Name')
layer.setFieldAlias(2, 'My Size')
ft = QgsFeature()
ft.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10, 10)))
ft.setAttributes(['Johny', 20, 0.3])
myResult, myFeatures = myProvider.addFeatures([ft])
self.assertTrue(myResult)
self.assertTrue(myFeatures)
options = QgsVectorFileWriter.SaveVectorOptions()
options.driverName = 'ESRI Shapefile'
options.fieldNameSource = QgsVectorFileWriter.Original
dest = os.path.join(str(QDir.tempPath()), 'alias.shp')
result, err = QgsVectorFileWriter.writeAsVectorFormatV2(
layer,
dest,
QgsProject.instance().transformContext(),
options)
self.assertEqual(result, QgsVectorFileWriter.NoError)
res = QgsVectorLayer(dest, 'result')
self.assertTrue(res.isValid())
self.assertEqual([f.name() for f in res.fields()], ['name', 'age', 'size'])
options.fieldNameSource = QgsVectorFileWriter.PreferAlias
dest = os.path.join(str(QDir.tempPath()), 'alias2.shp')
result, err = QgsVectorFileWriter.writeAsVectorFormatV2(
layer,
dest,
QgsProject.instance().transformContext(),
options)
self.assertEqual(result, QgsVectorFileWriter.NoError)
res = QgsVectorLayer(dest, 'result')
self.assertTrue(res.isValid())
self.assertEqual([f.name() for f in res.fields()], ['My Name', 'age', 'My Size'])
def testWriteWithLongLongField(self):
ml = QgsVectorLayer('NoGeometry?crs=epsg:4326&field=fldlonglong:long',
'test2', 'memory')