Python GeoJSON Error – AttributeError When Converting to WKB Format

geojsonpythonshapelywell-known-binary

I am parsing through a GeoJSON and picking out elements using Python.

{
    "type": "FeatureCollection",
    "features": [{
        "type": "Feature",
        "properties": {
            "uuid": "68F15C01-20CD-4D77-954B-9483BA1D4D33",
            "name": "ABC",
            "len": "529",
        },
        "geometry": {
            "type": "LineString",
            "coordinates": [
                [-360909.60698310119, 7600968.922204642, 0.0],
                [-361357.344715965, 7600811.951385159, 0.0],
                [-361805.08159795138, 7600654.939420643, 0.0]
            ]
        }
    }]
}

I am trying to write Python code which reads in a GeoJSON file from an S3 bucket and parses it accordingly.

I have written the below code to obtain the geometries:

import json
from botocore.exceptions import ClientError
from urllib.parse import unquote_plus
import json
from datetime import datetime
from pyproj import Proj, transform
from shapely import wkb, wkt
from shapely.geometry import Point, LineString, Polygon

    def process_incoming_file(self, bucket, key, event):
        
        bulk_data = []
        
        try:
            obj = s3.get_object(Bucket=bucket, Key=key)
            decoded_content = json.loads(obj['Body'].read().decode('utf-8'))
            print(decoded_content)
            
            if decoded_content.get('type') == "FeatureCollection":
                
                for (idx, obj) in enumerate(decoded_content.get('features')):
                    bulk_item = {}
                    
                    props = obj.get('properties')
                    
                    bulk_item['geometry'] = json.dumps(obj.get('geometry'))
                    print(bulk_item['geometry'])
                    


        except Exception as e:
            print(f'Exception: {e.__class__.__name__}({e})')

This gives me the result (which is expected):

{"type": "LineString", "coordinates": [[-356568.3924294889, 7599139.873836036, 0.0], [-356548.76854016265, 7599100.11754137, 0.0], etc

I now want to convert the above results into WKB format, so I tried:

 if decoded_content.get('type') == "FeatureCollection":
                
                for (idx, obj) in enumerate(decoded_content.get('features')):
                    bulk_item = {}
                    
                    props = obj.get('properties')
                    
                    bulk_item['geometry'] = json.dumps(obj.get('geometry'))
                    print(bulk_item['geometry'])
                    
                    geom = wkb.dumps(bulk_item['geometry'], hex=True, srid=3857)
                    print(geom)

But I get the error:
Exception: AttributeError('str' object has no attribute '_geom')

As I can't be sure the geometries in the GeoJSON will always be LineString like above, I want to be able to write code to recognise the feature type and convert accordingly.

E.g.

bulk_item['geometry'] = json.dumps(obj.get('geometry'))
geom = ['geometry']['type']['value'].(bulk_item['geometry'])
g = geom = wkb.dumps(geom, hex=True, srid=3857) # geometry in WKB format

Best Answer

You convert the geometry dict to string using json.dumps and pass the string to wkb.dumps() method. But it requires a shapely geometry. Therefore, you get 'str' object has no attribute '_geom' error. Leave it as is.

And to get the geom_wkb for different type of geometry, you need to check geometry type, make a geometry from coordinates, then pass the geometry to wkb.dumps() method.

Use the following if statement instead of yours:

if decoded_content['type'] == "FeatureCollection":
    
    for (idx, obj) in enumerate(decoded_content['features']):
        
        geom_type = obj['geometry']['type']
        coords = obj['geometry']['coordinates']
        
        if geom_type == 'Point':
            geom = Point(coords)
        elif geom_type == 'LineString':
            geom = LineString(coords)
        elif geom_type == 'Polygon':
            geom = Polygon(coords)
        elif geom_type == 'MultiPoint':
            geom = MultiPoint(coords)
        elif geom_type == 'MultiLineString':
            geom = MultiLineString(coords)
        elif geom_type == 'MultiPolygon':
            geom = MultiPolygon(coords)
        else:
            raise Exception("unidentified flying geometry detected")
             
        geom_wkb = wkb.dumps(geom, hex=True, srid=3857)
        print(geom_wkb)

# OUT
# 01020000A0110F00000300000063FA8C6D360716C19E66053BD2FE5C410000000000000000D038FD60350E16C1947EE3FCAAFE5C410000000000000000D2698E53341516C1C3771FBC83FE5C410000000000000000

Add from shapely.geometry import * to imports.