0

My goal is to remove placemarks in a kml file read with sharpkml and save the xml as new kml.

What I tried

  • RemoveChildren -> Not found
  • AddUpdate with DeleteCollection -> Not working

And

using SharpKml.Base;
using SharpKml.Dom;
using SharpKml.Engine;

           
TextReader i_test = File.OpenText(@"test.kml");
KmlFile k_test = KmlFile.Load(i_test);
Kml l_test = k_test.Root as Kml;
var serializer = new Serializer();
if (l_test != null)
{
    foreach (var ort_u in l_test.Flatten().OfType<Placemark>())
    {
        Placemark p_u = ort_u;
        foreach(var einh in ort_u.ExtendedData.Data)
        {
            if (einh.Name == "teststring")
            {
                    var update = new Update();
                    update.AddUpdate(new DeleteCollection(){ p_u });
                    serializer.Serialize(l_test);
                    Console.WriteLine(serializer.Xml.Length);
            }
        }
    }
}

None of them works.

How do I delete a Placemark using SharpKml and save the whole kml minus the placemark in a new file?

Aurelius Schnitzler
  • 511
  • 2
  • 8
  • 18

1 Answers1

0

Ok... A Placemark is a Feature, and Features go in Containers... And in Containers there is an aptly named .RemoveFeature()... Sadly the method uses the .Id to find the Feature, but not all Features have an Id... But this we can solve. We set a temporary Id (Guid.NewGuid().ToString()) that is more or less guaranteed to be unique (Guid are more or less guaranteed to be unique), and we use this Id to remove the Feature.

Note that I had to add a .ToArray() in the foreach, because you can't modify a collection that you are going through, but with the .ToArray() we go through a "copy" of the collection, while we remove the elements from the original.

foreach (var placemark in kml.Flatten().OfType<Placemark>().ToArray())
{
    if (placemark.Name == "Simple placemark")
    {
        placemark.Id = Guid.NewGuid().ToString();
        ((Container)placemark.Parent).RemoveFeature(placemark.Id);
    }

    Console.WriteLine(placemark.Name);
}

I've opened a bug on the github of SharpKml about this thing.

For saving:

using (var stream = File.Create("output.kml"))
{
    var ser = new Serializer();
    ser.Serialize(kml, stream);
}
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • Okay, that works. Yet my maps won't accept the file. Possible reasons? – Aurelius Schnitzler Jan 02 '21 at 16:23
  • @AureliusSchnitzler The serializer changes the file. I suggest you download Winmerge and compare the before-and-after. For example I've used the official google sample file, and `1` is changed to `true` and so on. – xanatos Jan 02 '21 at 16:24
  • Use `File.Create` instead of `File.Write` to save the file. Bad examples in the github. The `File.Write` won't delete the file, it will simply overwrite starting from the first byte, so if there is already a bigger file, you'll overwrite the first part and leave the last part. – xanatos Jan 02 '21 at 16:28