Skip to content

Commit

Permalink
Add support for converting geojson to csv. Closes #183.
Browse files Browse the repository at this point in the history
  • Loading branch information
onyxfish committed Aug 23, 2012
1 parent 3810579 commit c13ea6e
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 2 deletions.
7 changes: 5 additions & 2 deletions csvkit/convert/__init__.py
@@ -1,13 +1,14 @@
#!/usr/bin/env python

from csvitself import csv2csv
from dbase import dbf2csv
from fixed import fixed2csv
from geojs import geojson2csv
from js import json2csv
from xls import xls2csv
from xlsx import xlsx2csv
from dbase import dbf2csv

SUPPORTED_FORMATS = ['fixed', 'xls', 'xlsx', 'csv', 'json', 'dbf']
SUPPORTED_FORMATS = ['fixed', 'xls', 'xlsx', 'csv', 'json', 'geojson', 'dbf']

def convert(f, format, schema=None, key=None, **kwargs):
"""
Expand All @@ -30,6 +31,8 @@ def convert(f, format, schema=None, key=None, **kwargs):
return xlsx2csv(f, **kwargs)
elif format == 'json':
return json2csv(f, key, **kwargs)
elif format == 'geojson':
return geojson2csv(f, **kwargs)
elif format == 'csv':
return csv2csv(f, **kwargs)
elif format == 'dbf':
Expand Down
66 changes: 66 additions & 0 deletions csvkit/convert/geojs.py
@@ -0,0 +1,66 @@
#!/usr/bin/env python

from cStringIO import StringIO
import json

from csvkit import CSVKitWriter

def geojson2csv(f, key=None, **kwargs):
"""
Convert a GeoJSON document into CSV format.
"""
document = f.read()
js = json.loads(document)

if not isinstance(js, dict):
raise TypeError('JSON document is not valid GeoJSON: Root element is not an object.')

if 'type' not in js:
raise TypeError('JSON document is not valid GeoJSON: No top-level "type" key.')

if js['type'] != 'FeatureCollection':
raise TypeError('Only GeoJSON with root FeatureCollection type is supported. Not %s' % js['type'])

if 'features' not in js:
raise TypeError('JSON document is not a valid FeatureCollection: No top-level "features" key.')

features = js['features']

features_parsed = [] # tuples in the format (id, properties, geometry)
property_set = set()

for feature in features:
geoid = feature.get('id', None)

properties = feature.get('properties') or {}
property_set.update(properties.keys())

geometry = json.dumps(feature['geometry'])

features_parsed.append((geoid, properties, geometry))

header = ['id']
fields = sorted(list(property_set))
header.extend(fields)
header.append('geojson')

o = StringIO()
writer = CSVKitWriter(o)

writer.writerow(header)

for geoid, properties, geometry in features_parsed:
row = [geoid]

for field in fields:
row.append(properties.get(field, None))

row.append(geometry)

writer.writerow(row)

output = o.getvalue()
o.close()

return output

4 changes: 4 additions & 0 deletions examples/test_geojson.csv
@@ -0,0 +1,4 @@
id,prop0,prop1,geojson
,value0,,"{""type"": ""Point"", ""coordinates"": [102.0, 0.5]}"
,value0,0.0,"{""type"": ""LineString"", ""coordinates"": [[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]]}"
,value0,{u'this': u'that'},"{""type"": ""Polygon"", ""coordinates"": [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]]]}"
49 changes: 49 additions & 0 deletions examples/test_geojson.json
@@ -0,0 +1,49 @@
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [102.0, 0.5]
},
"properties": {
"prop0": "value0"
}
}, {
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[102.0, 0.0],
[103.0, 1.0],
[104.0, 0.0],
[105.0, 1.0]
]
},
"properties": {
"prop0": "value0",
"prop1": 0.0
}
}, {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[100.0, 0.0],
[101.0, 0.0],
[101.0, 1.0],
[100.0, 1.0],
[100.0, 0.0]
]
]
},
"properties": {
"prop0": "value0",
"prop1": {
"this": "that"
}
}
}]
}

10 changes: 10 additions & 0 deletions tests/test_convert/test_convert.py
Expand Up @@ -26,6 +26,16 @@ def test_guess_fixed(self):

def test_guess_xls(self):
self.assertEqual('xls', convert.guess_format('testdata.xls'))

def test_guess_xlsx(self):
self.assertEqual('xlsx', convert.guess_format('testdata.xlsx'))

def test_guess_csv(self):
self.assertEqual('csv', convert.guess_format('testdata.csv'))

def test_guess_dbf(self):
self.assertEqual('dbf', convert.guess_format('testdata.dbf'))

def test_guess_json(self):
self.assertEqual('json', convert.guess_format('testdata.json'))

1 comment on commit c13ea6e

@springmeyer
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

Please sign in to comment.