First... May I please mention how awful it is working with JSON strings? This is horrendous to have to wade through this string manipulation work.
Okay. Can someone please step in here and provide a fresh set of eyes because mine are entirely crossed attempting to untangle this mess. I suppose this has to do with the fact that the calling application is not necessarily "GIS" based and I am having to work with a non-GEO/ESRI JSON formatted string as an input then attempt to make sense out of it.
Anyway...
I need to take the input JSON and setup a FeatureCollection so that I can process individual polygons.
The input:
input ="""[ { "rings" : [ [[-117,34],[-116,34],[-117,33],[-117,34]], [[-115,44],[-114,43],[-115,43],[-115,44]] ] }, { "rings" : [ [[32,17],[31,17],[30,17],[30,16],[32,17]] ] } ]"""
I need it to read as such:
main_json_string = """{"type":"FeatureCollection","features":[ {"type":"Feature","geometry":{"type":"Polygon","coordinates":[ [[-117,34],[-116,34],[-117,33],[-117,34]]] } }, {"type":"Feature","geometry":{"type":"Polygon","coordinates":[ [[32,17],[31,17],[30,17],[30,16],[32,17]]] } }]}"""
I am unable to pick out from the squiglies how to get it correct. I started with some replace methods and finding it difficult to get it all converted correctly. Any help is appreciated.
Solved! Go to Solution.
I find manipulating JSON strings as strings to be challenging. I recommend using the Python JSON library to convert JSON to Python and back again.
See if the following works for you:
def geo_convert(ring_string): from json import loads, dumps rings = loads(ring_string) feat_coll = {'type': 'FeatureCollection', 'features':[]} for ring in rings: feat_coll['features'].append( {'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [ring['rings'][0]] }}) return dumps(feat_coll)
Pass your input to the function to get main_json_string back.
A couple of comments:
UPDATE: Changed line #13 to include correction from James Crandall.
I find manipulating JSON strings as strings to be challenging. I recommend using the Python JSON library to convert JSON to Python and back again.
See if the following works for you:
def geo_convert(ring_string): from json import loads, dumps rings = loads(ring_string) feat_coll = {'type': 'FeatureCollection', 'features':[]} for ring in rings: feat_coll['features'].append( {'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [ring['rings'][0]] }}) return dumps(feat_coll)
Pass your input to the function to get main_json_string back.
A couple of comments:
UPDATE: Changed line #13 to include correction from James Crandall.
Hi
The AsShape function can take GeoJSON or EsriJSON to geometry.
Geometry objects have a __geo_interface__ attribute, which is GeoJSON.
Geometry objects have a JSON method, which is EsriJSON.
Like:
geom
<Polyline object at 0x3bba81d0[0x225fbad0]>
geom.JSON
'{"paths":[[[2692041.740699999,-18926.525499999523],[2692042.5719999969,-18916.945300001651],[2692034.5209999979,-18810.606699999422],[2692022.3840999976,-18663.190900001675],[2692007.4103000015,-18499.441799998283]]],"spatialReference":{"wkid":102242,"latestWkid":2767}}'
geom.__geo_interface__
{'type': 'MultiLineString', 'coordinates': [[(2692041.740699999, -18926.525499999523), (2692042.571999997, -18916.94530000165), (2692034.520999998, -18810.606699999422), (2692022.3840999976, -18663.190900001675), (2692007.4103000015, -18499.441799998283)]]}
That was my initial thought, but the OP's JSON string doesn't work directly with arcpy.AsShape, it generates an AssertionError. Since the original string needs to be manipulated, I figured just go straight to using the native JSON library to restructure the input.
That's correct. I have to add the necessary attributes to make it geo_JSON "ready"!
Hi Bruce,
Yes that is exactly what I am doing! However the JSON I am getting from the client/application is not formatted for GEO/ESRI JSON and this is what my OP is about: getting it into those formats.
I appreciate the example Joshua! I'll see about implementing it asap.
Joshua,
Thanks again for that geo_convert def() --- very helpful! I'm marking your reply as the answer with the updates below.
One minor syntax thingie that caused it some heartburn was a missing set of "[]" around the "ring" attribute. Seems to work if I wrap 'coordinates': values with them as below:
def geo_convert(ring_string): from json import loads, dumps rings = loads(ring_string) feat_coll = {'type': 'FeatureCollection', 'features':[]} for ring in rings: feat_coll['features'].append( {'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [ring['rings'][0]] }}) return dumps(feat_coll)
I was wondering about that extra nested list. I will update my original code with your modification so the correct answer works correctly.