2

I'm pulling in data from ArcGIS using ArcGIS.PCL which provides the geometries as GeoJson. I'd like to convert this GeoJson to KML. Does anyone know of any .NET libraries that provides this functionality? I've had a good search but nothing has popped up on my radar.

I guess a couple of libraries may be required if there's no catch all for this problem. One that can convert GeoJson to WKT then another that can convert WKT to KML.

2

I couldn't find a library, but I coded up a solution that fit my requirements to handle polygons only. The code is provided below for anyone else who might find it useful. ConvertGeoJsonToKml generates complete KML and ConvertGeoJsonToKmlGeometryOnly generates a cut down KML output suitable for use in Google Fusion Tables.

using ArcGIS.ServiceModel.Common;
using ArcGIS.ServiceModel.GeoJson;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Xml.Linq;

namespace MyKickassProject.Utilities
{
    public static class GeometryUtils
    {
        public static string ConvertGeoJsonToKml(string geoJson)
        {
            SharpKml.Dom.Document kmlDocument = new SharpKml.Dom.Document();
            SharpKml.Dom.Placemark kmlPlacemark = new SharpKml.Dom.Placemark();

            kmlPlacemark.Geometry = GeneratePolygon(geoJson);

            kmlDocument.AddFeature(kmlPlacemark);

            SharpKml.Dom.Kml kml = new SharpKml.Dom.Kml();
            kml.Feature = kmlDocument;

            var serializer = new SharpKml.Base.Serializer();
            serializer.Serialize(kml);

            return serializer.Xml;
        }

        public static string ConvertGeoJsonToKmlGeometryOnly(string geoJson)
        {
            SharpKml.Dom.Polygon kmlPolygon = GeneratePolygon(geoJson);

            var serializer = new SharpKml.Base.Serializer();
            serializer.SerializeRaw(kmlPolygon);

            return RemoveAllNamespaces(serializer.Xml);
        }

        private static SharpKml.Dom.Polygon GeneratePolygon(string geoJson)
        {
            var polygon = JsonConvert.DeserializeObject<GeoJsonPolygon>(geoJson);

            if (polygon.Coordinates.Count > 0)
            {
                SharpKml.Dom.Polygon kmlPolygon = new SharpKml.Dom.Polygon();

                SharpKml.Dom.OuterBoundary kmlOuterBoundary = new SharpKml.Dom.OuterBoundary();
                kmlOuterBoundary.LinearRing = PointCollectionToLinearRing(polygon.Coordinates[0]);
                kmlPolygon.OuterBoundary = kmlOuterBoundary;

                if (polygon.Coordinates.Count > 1)
                {
                    for (int i = 1; i < polygon.Coordinates.Count; i++)
                    {
                        SharpKml.Dom.InnerBoundary kmlInnerBoundary = new SharpKml.Dom.InnerBoundary();
                        kmlInnerBoundary.LinearRing = PointCollectionToLinearRing(polygon.Coordinates[i]);
                        kmlPolygon.AddInnerBoundary(kmlInnerBoundary);
                    }
                }

                return kmlPolygon;
            }

            throw new Exception("GeoJSON type is unhandled.");
        }

        private static SharpKml.Dom.LinearRing PointCollectionToLinearRing(PointCollection coordinates)
        {
            var linearRing = new SharpKml.Dom.LinearRing();
            linearRing.Coordinates = new SharpKml.Dom.CoordinateCollection();
            var points = coordinates.AsEnumerable();
            foreach (var point in points)
            {
                linearRing.Coordinates.Add(new SharpKml.Base.Vector(point[1], point[0]));
            }
            return linearRing;
        }

        private static string RemoveAllNamespaces(string xmlDocument)
        {
            XElement xmlDocumentWithoutNs = RemoveAllNamespaces(XElement.Parse(xmlDocument));

            return xmlDocumentWithoutNs.ToString();
        }

        private static XElement RemoveAllNamespaces(XElement xmlDocument)
        {
            if (!xmlDocument.HasElements)
            {
                XElement xElement = new XElement(xmlDocument.Name.LocalName);
                xElement.Value = xmlDocument.Value;

                foreach (XAttribute attribute in xmlDocument.Attributes())
                    xElement.Add(attribute);

                return xElement;
            }
            return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
        }
    }
}
  • Hey mate, looks promising for my use but where did the GeoJsonPolygon class come from, described in var polygon = JsonConvert.DeserializeObject<GeoJsonPolygon>(geoJson);? thanks – Sam Mar 14 '17 at 10:10
  • 1
    @Sam - You'll find GeoJsonPolygon in ArcGIS.ServiceModel.GeoJson from the ArcGIS.PCL nuget package. – Gavin Mar 14 '17 at 20:27
  • That'll get me on the right track again, much obliged @Gavin! – Sam Mar 15 '17 at 8:45
0

Perhaps you could use a GDAL based approach? It looks like someone has written some GDAL bindings for C# which may help althouhg I can't say I've used the library myself...

Goodluck

  • Thanks for the suggestion, much appreciated, but unfortunately I'm working in an environment where I can't install GDAL. Seems quite a heavy solution solution for what is really a light weight problem at heart. Best suggestion so far though! I'm quite surprised there doesn't seem to be a nice .NET library already out there for this sort of conversion as I'm sure it must be a pretty common problem. – Gavin Dec 1 '15 at 6:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.