1

I'm trying to create a KML file containing two layers to display in Google Earth.

Here's a small example of what I've tried:

library(sf)

poly <- st_as_sf(st_as_sfc(
  "POLYGON ((-59.6354 5.0372, -59.3598 5.0372, -59.3598 5.3175, -59.6354 5.3175, -59.6354 5.0372))"
  , crs = 4326
))
pt <- st_as_sf(st_as_sfc(
  "POINT (-59.6354 5.0372)"
  , crs = 4326
))

# Using GeoPackage, it works as expected
st_write(poly, "test.gpkg", layer = "outlines")
st_write(pt, "test.gpkg", layer = "points", append = TRUE)

# Using KML produces an error
st_write(poly, "test.kml", layer = "outlines")
st_write(pt, "test.kml", layer = "points", append = TRUE)
# Error in CPL_write_ogr(obj, dsn, layer, driver, as.character(dataset_options),  :
#   Cannot append to existing dataset.

I still hope that it is possible to achieve a two-layer KML with R, though, since it's also possible to just piece one together using a text editor:

desired_output.kml:

<?xml version="1.0" encoding="utf-8" ?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document id="root_doc">
<Folder><name>outlines</name>
  <Placemark>
<Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style>
      <Polygon><outerBoundaryIs><LinearRing><coordinates>-59.6354,5.0372 -59.3598,5.0372 -59.3598,5.3175 -59.6354,5.3175 -59.6354,5.0372</coordinates></LinearRing></outerBoundaryIs></Polygon>
  </Placemark>
</Folder>
<Folder><name>points</name>
  <Placemark>
      <Point><coordinates>-59.6354,5.0372</coordinates></Point>
  </Placemark>
</Folder>
</Document></kml>

This is compatible with Google Earth and does exactly what I want. Is there any way to achieve this using R?

1
  • 1
    Note the append option to st_write controls the appending of data to existing layers, not the adding of extra layers to existing data source.
    – Spacedman
    Dec 5, 2022 at 17:56

1 Answer 1

2

Write one, then write the other, but make sure you specify the "LIBKML" driver (which needs compiling into your GDAL, and should be the default for kml but I need to specify it...):

> st_write(poly, dsn="test22.kml", driver="LIBKML", layer="poly")
Writing layer `poly' to data source `test22.kml' using driver `LIBKML'
Writing 1 features with 0 fields and geometry type Polygon.
> st_write(pt, dsn="test22.kml", driver="LIBKML", layer="pt")
Writing layer `pt' to data source `test22.kml' using driver `LIBKML'
Writing 1 features with 0 fields and geometry type Point.

Then the resulting KML has two layers:

> ogrinfo("test22.kml")
[1] "INFO: Open of `test22.kml'"             
[2] "      using driver `LIBKML' successful."
[3] "1: poly"                                
[4] "2: pt"                                  

It separates the layers into two <Document> elements and doesn't use <Folder> elements like you have in your sample output, but I'm not sure if that will affect your use case adversely...

If it uses the KML driver I only get the most recent layer written:

> st_write(poly, dsn="testfail.kml", layer="poly")
Writing layer `poly' to data source `testfail.kml' using driver `KML'
Writing 1 features with 0 fields and geometry type Polygon.
> st_write(pt, dsn="testfail.kml", layer="pt")
Writing layer `pt' to data source `testfail.kml' using driver `KML'
Writing 1 features with 0 fields and geometry type Point.
> ogrinfo("testfail.kml")
[1] "INFO: Open of `testfail.kml'"           
[2] "      using driver `LIBKML' successful."
[3] "1: pt"                                  
>

So, use driver="LIBKML" if you can...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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