diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2024-06-19 01:55:08 +0200 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2024-06-19 03:32:29 +0200 |
commit | bc58a552b1be29d0f11d6856da60282034339e96 (patch) | |
tree | 9b252bae0ec31cd75f9b542446466f4bec624729 /webmap-import | |
parent | 35635ebf16aebfe3113806acca0de274679118fe (diff) |
Add logic to replace field value literals.
And set them to NULL.
Diffstat (limited to 'webmap-import')
-rwxr-xr-x | webmap-import | 99 |
1 files changed, 92 insertions, 7 deletions
diff --git a/webmap-import b/webmap-import index e9ae302..e978f34 100755 --- a/webmap-import +++ b/webmap-import @@ -730,8 +730,9 @@ def setOutputFieldMap(defn, sources): fieldMap[fldName] = i for source in sources: - src = source['source']['path'] - fieldMap2 = source['import'].get('field-map', None) + source_import = source['import'] + + fieldMap2 = source_import.get('field-map', None) if fieldMap2 is None: fieldMap2 = fieldMap else: @@ -744,10 +745,22 @@ def setOutputFieldMap(defn, sources): if i is None: raise Exception(f'Ouput layer has no field named "{ofld}"') fieldMap2[ifld] = i - - source['import']['field-map'] = fieldMap2 - - return fieldMap + source_import['field-map'] = fieldMap2 + + # validate field value mapping + valueMap = source_import.get('value-map', None) + if valueMap is not None: + for fldName, rules in valueMap.items(): + if rules is None: + continue + if not isinstance(rules, list): + rules = [rules] + for idx, rule in enumerate(rules): + if rule is None or not isinstance(rule, dict): + raise Exception(f'Field "{fldName}" has invalid rule #{idx}: {rule}') + if 'from' not in rule or 'to' not in rule or len(rule) != 2: + raise Exception(f'Field "{fldName}" has invalid rule #{idx}: {rule}') + rules[idx] = ( rule['from'], rule['to'] ) # Escape the given identifier, cf. # swig/python/gdal-utils/osgeo_utils/samples/validate_gpkg.py:_esc_id() @@ -856,6 +869,31 @@ def importSource(lyr, path=None, unar=None, args={}, cachedir=None, extent=None) return importSource2(lyr, ds_srcpath, args=args, basedir=Path(tmpdir), extent=extent) +# Validate field value mapping +def setFieldMapValue(fld, idx, val): + if val is None: + if not fld.IsNullable(): + logging.warning('Field "%s" is not NULLable but remaps NULL', fld.GetName()) + return None + + fldType = fld.GetType() + if fldType == ogr.OFTInteger or fldType == ogr.OFTInteger64: + if isinstance(val, int): + return val + elif fldType == ogr.OFTString: + if isinstance(val, str): + return val + elif fldType == ogr.OFTBinary: + if isinstance(val, bytes): + return val + elif fldType == ogr.OFTReal: + if isinstance(val, int): + return float(val) + elif isinstance(val, float): + return val + + raise Exception(f'Field "{fld.GetName()}" mapping #{idx} has incompatible type for {ogr.GetFieldTypeName(fldType)}') + # Import a source layer (already extracted) # This is more or less like ogr2ogr/GDALVectorTranslate() but we roll # out our own (slower) version because GDALVectorTranslate() insists in @@ -927,7 +965,6 @@ def importSource2(lyr_dst, path, args={}, basedir=None, extent=None): # call SetIgnored() on unwanted source fields logging.debug('Set Ignored=True on output field "%s"', fldName) fld.SetIgnored(True) - defn = None count0 = -1 if lyr.TestCapability(ogr.OLCFastFeatureCount): @@ -965,6 +1002,32 @@ def importSource2(lyr_dst, path, args={}, basedir=None, extent=None): else: logging.info('Source layer "%s" has %d features', layername, count0) + # build a list of pairs (field index, mapping_dict) + valueMapLiteral = [] + for fldName, rules in args.get('value-map', {}).items(): + i = defn.GetFieldIndex(fldName) + if i < 0: + raise Exception(f'Source layer "{layername}" has no field named "{fldName}"') + if fieldMap[i] < 0: + logging.warning('Ignored source field "%s" has value map', fldName) + continue + + h = {} + fld = defn.GetFieldDefn(i) + for idx, (rFrom, rTo) in enumerate(rules): + # use fld for both from and to (the types must match, + # casting is not allowed in the mapping) + rFrom = setFieldMapValue(fld, idx, rFrom) + rTo = setFieldMapValue(fld, idx, rTo) + h[rFrom] = rTo + + if len(h) > 0: + valueMapLiteral.append((i, h)) + + bValueMapLiteral = len(valueMapLiteral) > 0 + + defn = None + defn_dst = lyr_dst.GetLayerDefn() eGType_dst = defn_dst.GetGeomType() eGType_dst_HasZ = ogr.GT_HasZ(eGType_dst) @@ -975,6 +1038,28 @@ def importSource2(lyr_dst, path, args={}, basedir=None, extent=None): mismatch = {} feature = lyr.GetNextFeature() while feature is not None: + if bValueMapLiteral: + for i, h in valueMapLiteral: + if not feature.IsFieldSet(i): + continue + elif feature.IsFieldNull(i): + if None in h: + v = h[None] + if v is not None: + # replace NULL with non-NULL value + feature.SetField(i, v) + continue + + v = feature.GetField(i) + if v in h: + v2 = h[v] + if v2 is None: + # replace non-NULL value with NULL + feature.SetFieldNull(i) + else: + # replace non-NULL value with non-NULL value + feature.SetField(i, v2) + feature2 = ogr.Feature(defn_dst) feature2.SetFromWithMap(feature, False, fieldMap) |