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)));
}
}
}