SharpKML

repository·main·Indexed 41 days ago

https://github.com/samcragg/sharpkml

A C# library for reading and writing KML and KMZ files, implementing the OGC KML 2.2 standard. It provides a native .NET experience using properties and extension methods, supporting features such as KML element flattening, custom element extension via KmlFactory, and Google Earth GX extension compatibility for tours.

Tokens
4.7K
Snippets
16
Records
19
Agent score
50%

What's inside SharpKML

  1. Overview of SharpKML capabilities

    main

    SharpKML is a C# implementation of the Open Geospatial Consortium (OGC) KML 2.2 standard. It is designed to provide a native C# experience (using properties and extension methods) rather than using SWIG bindings from Google's C++ libkml.

    Key capabilities include:

    • Reading and writing KML files.
    • Reading and writing KMZ files.
    • Leveraging built-in .NET XML handling.
  2. Register extensions for base classes using KmlFactory.RegisterExtension

    main

    If you are extending a class that serves as a base for other elements (where KmlFactory.Replace is not applicable), you should register your custom element as a valid child type for that base class. Use KmlFactory.RegisterExtension<TBase, TExtension>(). Once registered, you can manage these custom elements using the AddChild, RemoveChild, and Children members of the base class.

    public static void Main(string[] args)
    {
        KmlFactory.RegisterExtension<Feature, MyElement>();
    }
  3. Load Kml and Kmz files into memory

    main

    You can load KML files directly from disk using KmlFile.Load. For compressed KMZ files, use KmzFile.Open to open the archive, then call GetDefaultKmlFile() to retrieve the underlying KmlFile object.

    // This will read a Kml file into memory.
    KmlFile file = KmlFile.Load("YourKmlFile.kml");
    
    // Kmz (compressed Kml files) can also be loaded:
    KmzFile kmz = KmzFile.Open("YourKmzFile.kmz");
    KmlFile file = kmz.GetDefaultKmlFile();
  4. Configure link.xml for Unity code stripping

    main

    When using SharpKml in a Unity project, you must prevent Unity's managed code stripping from removing methods that are only accessed via reflection. To do this, create a link.xml file and place it in your Assets folder (or any subdirectory of Assets). This ensures that the SharpKml.Core assembly and specific LINQ expression interpreter types are preserved in the final build.

    <linker>
      <assembly fullname="SharpKml.Core" preserve="all"/>
      <assembly fullname="System.Core">
        <type fullname="System.Linq.Expressions.Interpreter.LightLambda" preserve="all" />
      </assembly>
    </linker>
  5. Enable Google Earth extension features in KML

    main

    To use advanced Google Earth features (such as tours) via the SharpKml.Dom.GX namespace, you must explicitly add the Google extension namespace to the root kml node. If this namespace is not added, the features will not display correctly in Google Earth.

    Use kml.AddNamespacePrefix with KmlNamespaces.GX22Prefix and KmlNamespaces.GX22Namespace to ensure compatibility.

    var kml = new Kml();
    kml.AddNamespacePrefix(KmlNamespaces.GX22Prefix, KmlNamespaces.GX22Namespace);
    // Now you can add GX features like tours
    kml.Feature = tour;
  6. Parse KML files with non-standard namespaces

    main

    The OGC KML specification requires the http://www.opengis.com/kml/2.2 namespace. However, older or non-standard files may use different namespaces, such as http://earth.google.com/kml/2.2.

    To handle these files, use the Parser class and call ParseString with the ignoreNamespaces parameter set to true. After parsing, wrap the parser.Root element in a KmlFile using KmlFile.Create(parser.Root, true) to restore a usable object model.

    Note: When you save a file parsed this way, the OGC namespace will be used, overwriting the original non-standard namespace. This behavior is consistent with libkml.

    using System;
    using SharpKml.Base;
    using SharpKml.Dom;
    using SharpKml.Engine;
    
    class Program
    {
        const string Xml = 
            "<kml xmlns='http://earth.google.com/kml/2.2'>" +
                "<Placemark>" +
                    "<name>SamplePlacemark</name>" +
                "</Placemark>" +
            "</kml>";
    
        static KmlFile ParseLegacyFile()
        {
            // Manually parse the Xml
            Parser parser = new Parser();
            parser.ParseString(Xml, false); // Ignore the namespaces
    
            // The element will be stored in parser.Root - wrap it inside
            // a KmlFile
            return KmlFile.Create(parser.Root, true);
        }
    
        static void Main(string[]() args)
        {
            KmlFile file = ParseLegacyFile();
    
            // Prove it worked ok
            Kml kml = (Kml)file.Root;
            Placemark placemark = (Placemark)kml.Feature;
            Console.WriteLine(placemark.Name); // Outputs "SamplePlacemark"
        }
    }
  7. Extend KML elements by inheriting from existing classes

    main

    To add custom elements to existing KML types, inherit from the existing class (e.g., Placemark). After defining your custom class, you must tell the library to use your version instead of the standard one by calling KmlFactory.Replace<TBase, TDerived>() during your application's startup. This ensures the library uses your custom class when parsing that specific KML element.

    public class MyPlacemark : Placemark
    {
        // Extra elements here
    }
    
    public static void Main(string[] args)
    {
        KmlFactory.Replace<Placemark, MyPlacemark>();
    }
  8. Extract specific elements from a KML file using Flatten()

    main

    To extract specific elements (like Polygon, Placemark, etc.) from a KML structure, use the Flatten() extension method provided by SharpKml.Engine. This method allows you to iterate over every element in the KML tree regardless of its depth. When combined with LINQ's OfType<T>(), you can easily filter and select only the specific types of elements you need for processing.

    Requirements:

    • Ensure you have using SharpKml.Dom; and using SharpKml.Engine; in your file.
    • The Flatten() method is an extension method on the KML element tree.
    using System;
    using System.IO;
    using System.Linq;
    using System.Text;
    using SharpKml.Dom;
    using SharpKml.Engine;
    
    // ... setup KmlFile ...
    
    // Use the Flatten extension method to iterate over all elements,
    // then use LINQ OfType to select only the desired type (e.g., Polygon)
    foreach (var poly in file.Root.Flatten().OfType<Polygon>())
    {
        Console.WriteLine(poly.Id);
    }
  9. Install SharpKML.Core via NuGet

    main

    The easiest way to integrate SharpKML into your C# project is by installing the SharpKml.Core NuGet package. This package provides the implementation for reading and writing KML and KMZ files based on the OGC KML 2.2 standard.

    # Use the NuGet Package Manager or dotnet CLI to install SharpKml.Core
    dotnet add package SharpKml.Core
  10. Explore SharpKML usage examples

    main

    The Examples folder in the repository contains several concrete implementations for common KML tasks. Use these as templates for your own development:

    • Creating KML/KMZ: CreateKml.cs (creating KML from code) and CreateKmz.cs (creating compressed KMZ archives).
    • Parsing and Extraction: ParseKml.cs (using the Parser class to parse files while ignoring XML namespaces) and ExtractingElements.md (for extracting specific types).
    • Styling: CreateIconStyle.cs (creating IconStyle), InlineStyles.cs (using StyleResolver.InlineStyles to move styles inside a Feature), and SplitStyles.cs (moving styles from a Feature to a Document).
    • Data Manipulation: Change.cs (using Update elements and the Process extension method), Clone.cs (copying Elements), and SortPlacemarks.cs (sorting placemarks by name).
    • Feature Inspection: BalloonFeatures.cs (displaying balloon text) and ShowStyles.cs (iterating over styles).
  11. Create a Google Earth Tour using SharpKml.Dom.GX

    main

    You can create Google Earth tours by using classes within the SharpKml.Dom.GX namespace. A typical tour involves creating a FlyTo primitive with a specific FlyToMode, adding it to a Playlist, and then assigning that Tour to the Feature property of a Kml object.

    Important: You must add the GX22 namespace prefix to the Kml object for the tour to be valid in Google Earth.

    using System;
    using System.Reflection;
    using System.Xml;
    using SharpKml.Base;
    using SharpKml.Dom;
    
    class Program
    {
        static void Main(string[]() args)
        {
            var flyTo = new SharpKml.Dom.GX.FlyTo
            {
                Mode = SharpKml.Dom.GX.FlyToMode.Bounce,
            };
    
            var tour = new SharpKml.Dom.GX.Tour
            {
                Playlist = new SharpKml.Dom.GX.Playlist(),
            };
            tour.Playlist.AddTourPrimitive(flyTo);
    
            var kml = new Kml();
            kml.AddNamespacePrefix(KmlNamespaces.GX22Prefix, KmlNamespaces.GX22Namespace);
            kml.Feature = tour;
    
            Serializer serializer = new Serializer();
            serializer.Serialize(kml);
            Console.WriteLine(serializer.Xml);
        }
    }