Adadev

Converting JSON to shapefile using Gdal in C#

May 27, 2017

In this article I explain how to convert a JSON file to shapefile using Gdal library in C#. The following is an example of a valid JSON file (you can also download the complete file):

{
	"features": [{
		"geometry": {
			"coordinates": [-37.2726631195437,
			-9.91254751352393],
			"type": "Point"
		},
		"properties": {
			"identifier": "12",
			"serial_number": "29213220",
			"name": "POINT-10",
			"length": 3.0
		},
		"type": "Feature"
	},
	{
		"geometry": {
			"coordinates": [-37.2726722686872,
			-9.91252509027536],
			"type": "Point"
		},
		"properties": {
			"identifier": "11",
			"serial_number": "29213220",
			"name": "POINT-10",
			"length": 4.0,
		},
		"type": "Feature"
	}
}

Let's go to the steps:

Importing Gdal from Visual Studio

Firstly, we have to import Gdal to the project: in Visual Studio, right click on project, go to "Manage NuGet packages", type "Gdal" on search field, select Gdal (1.11.1 is the last version available at the time of writing) and install it. Also select and install Gdal.Native (the project compile without it but it does not execute correctly). The "GdalConfiguration.cs" class is created automatically. It is used before start the conversion method.

To zip the generated shapefile files, we need the library "DotNetZip". Install it too by "Manage NuGet packages". If you do not want to zip the files, you do not need to install it.

To import Gdal in your class, use:

using OSGeo.OGR;
using OSGeo.OSR;

Configuring Gdal

Before use the Gdal classes, we need to configure it. You just need to call ConfigureGdal e ConfigureOgr methods of the class GdalConfiguration.cs. You can call them, for example, in class constructor.

public GdalUtilities() {
    GdalConfiguration.ConfigureGdal();
    GdalConfiguration.ConfigureOgr();
}

Opening Json file with Gdal

The following is the code to open the JSON file with Gdal and get its layer:

Driver jsonFileDriver = Ogr.GetDriverByName("GeoJSON");
DataSource jsonFile = Ogr.Open(jsonFilePath, 0);
if(jsonFile == null) {
    return false;
}
Layer jsonLayer = jsonFile.GetLayerByIndex(0);

Create shapefile

The following is the code to create the shapefile with Gdal. If the file already exists, it is removed.

string filesPathName = shapeFilePath.Substring(0, shapeFilePath.Length - 4);
removeShapeFileIfExists(filesPathName);

Driver esriShapeFileDriver = Ogr.GetDriverByName("ESRI Shapefile");
DataSource shapeFile = esriShapeFileDriver.CreateDataSource(shapeFilePath, new string[] { });
Layer shplayer = shapeFile.CreateLayer(jsonLayer.GetName(), jsonLayer.GetSpatialRef(), jsonLayer.GetGeomType(), new string[] { });

Copying data and properties of JSON to shapefile

The following is the code to create and copy the properties e values of each element of JSON file to new shapefile:

// create fields (properties) in new layer
Feature jsonFeature = jsonLayer.GetNextFeature();
for(int i = 0; i < jsonFeature.GetFieldCount(); i++) {
	FieldDefn fieldDefn = new FieldDefn(getValidFieldName(jsonFeature.GetFieldDefnRef(i)), jsonFeature.GetFieldDefnRef(i).GetFieldType());
	shplayer.CreateField(fieldDefn, 1);
}

while(jsonFeature != null) {
	Geometry geometry = jsonFeature.GetGeometryRef();
	Feature shpFeature = createGeometryFromGeometry(geometry, shplayer, jsonLayer.GetSpatialRef());

	// copy values for each field
	for(int i = 0; i < jsonFeature.GetFieldCount(); i++) {
		if(FieldType.OFTInteger == jsonFeature.GetFieldDefnRef(i).GetFieldType()) {
			shpFeature.SetField(getValidFieldName(jsonFeature.GetFieldDefnRef(i)), jsonFeature.GetFieldAsInteger(i));
		} else if(FieldType.OFTReal == jsonFeature.GetFieldDefnRef(i).GetFieldType()) {
			shpFeature.SetField(getValidFieldName(jsonFeature.GetFieldDefnRef(i)), jsonFeature.GetFieldAsDouble(i));
		} else {
			shpFeature.SetField(getValidFieldName(jsonFeature.GetFieldDefnRef(i)), jsonFeature.GetFieldAsString(i));
		}
	}
	shplayer.SetFeature(shpFeature);

	jsonFeature = jsonLayer.GetNextFeature();
}

Close the shapefile and save it as zipfile

The following is the code to close the created shapefile and to zip all generated files:

shapeFile.Dispose();

// if you want to generate zip of generated files
string zipName = filesPathName + ".zip";
CompressToZipFile(new List<string>() { 
	shapeFilePath, filesPathName + ".dbf", filesPathName + ".prj", filesPathName + ".shx" }, zipName);

Converting JSON to shapefile - complete code

new GdalUtilities().convertJsonToShapeFile(@"C:\development\example-data.json", @"C:\development\shapefile-out.shp");
using OSGeo.OGR;
using OSGeo.OSR;
using System.Collections.Generic;
using Ionic.Zip;
using System.IO;

namespace Adadev.GdalModule {

    public class GdalUtilities {

        public GdalUtilities() {
            GdalConfiguration.ConfigureGdal();
            GdalConfiguration.ConfigureOgr();
        }

        public bool convertJsonToShapeFile(string jsonFilePath, string shapeFilePath) {

            Driver jsonFileDriver = Ogr.GetDriverByName("GeoJSON");
            DataSource jsonFile = Ogr.Open(jsonFilePath, 0);
            if(jsonFile == null) {
                return false;
            }

            string filesPathName = shapeFilePath.Substring(0, shapeFilePath.Length - 4);
            removeShapeFileIfExists(filesPathName);

            Layer jsonLayer = jsonFile.GetLayerByIndex(0);

            Driver esriShapeFileDriver = Ogr.GetDriverByName("ESRI Shapefile");
            DataSource shapeFile = Ogr.Open(shapeFilePath, 0);

            shapeFile = esriShapeFileDriver.CreateDataSource(shapeFilePath, new string[] { });
            Layer shplayer = shapeFile.CreateLayer(jsonLayer.GetName(), jsonLayer.GetSpatialRef(), jsonLayer.GetGeomType(), new string[] { });

            // create fields (properties) in new layer
            Feature jsonFeature = jsonLayer.GetNextFeature();
            for(int i = 0; i < jsonFeature.GetFieldCount(); i++) {
                FieldDefn fieldDefn = new FieldDefn(getValidFieldName(jsonFeature.GetFieldDefnRef(i)), jsonFeature.GetFieldDefnRef(i).GetFieldType());
                shplayer.CreateField(fieldDefn, 1);
            }

            while(jsonFeature != null) {
                Geometry geometry = jsonFeature.GetGeometryRef();
                Feature shpFeature = createGeometryFromGeometry(geometry, shplayer, jsonLayer.GetSpatialRef());

                // copy values for each field
                for(int i = 0; i < jsonFeature.GetFieldCount(); i++) {
                    if(FieldType.OFTInteger == jsonFeature.GetFieldDefnRef(i).GetFieldType()) {
                        shpFeature.SetField(getValidFieldName(jsonFeature.GetFieldDefnRef(i)), jsonFeature.GetFieldAsInteger(i));
                    } else if(FieldType.OFTReal == jsonFeature.GetFieldDefnRef(i).GetFieldType()) {
                        shpFeature.SetField(getValidFieldName(jsonFeature.GetFieldDefnRef(i)), jsonFeature.GetFieldAsDouble(i));
                    } else {
                        shpFeature.SetField(getValidFieldName(jsonFeature.GetFieldDefnRef(i)), jsonFeature.GetFieldAsString(i));
                    }
                }
                shplayer.SetFeature(shpFeature);

                jsonFeature = jsonLayer.GetNextFeature();
            }
            shapeFile.Dispose();

            // if you want to generate zip of generated files
            string zipName = filesPathName + ".zip";
            CompressToZipFile(new List<string>() { shapeFilePath, filesPathName + ".dbf", filesPathName + ".prj", filesPathName + ".shx" }, zipName);

            return true;
        }

        private void removeShapeFileIfExists(string filesPathName) {
            removeFileIfExists(filesPathName + ".shp");
            removeFileIfExists(filesPathName + ".shx");
            removeFileIfExists(filesPathName + ".prj");
            removeFileIfExists(filesPathName + ".zip");
        }

        public static bool removeFileIfExists(string filePath) {
            if(File.Exists(filePath)) {
                File.Delete(filePath);
                return true;
            }
            return false;
        }

        // the field names in shapefile have limit of 10 characteres
        private string getValidFieldName(FieldDefn fieldDefn) {
            string fieldName = fieldDefn.GetName();
            return fieldName.Length > 10 ? fieldName.Substring(0, 10) : fieldName;
        }

        private Feature createGeometryFromGeometry(Geometry geometry, Layer layer, SpatialReference reference) {
            Feature feature = new Feature(layer.GetLayerDefn());

            string wktgeometry = "";
            geometry.ExportToWkt(out wktgeometry);
            Geometry newGeometry = Geometry.CreateFromWkt(wktgeometry);
            newGeometry.AssignSpatialReference(reference);

            feature.SetGeometry(newGeometry);
            layer.CreateFeature(feature);

            return feature;
        }

        public static void CompressToZipFile(List<string> files, string zipPath) {
            using(ZipFile zip = new ZipFile()) {
                foreach(string file in files) {
                    zip.AddFile(file, "");
                }
                zip.Save(zipPath);
            }
        }
    }
}

You can download the complete code and example files in our repository on Github.

Related Content:

Read and Write Images with Gdal in C#

White Balance Algorithm with Gdal in C#

See more:

Code Examples

Gdal

[back to the top]