将KML文件读入R吗?


41

我正在处理巨大的.kml文件(最大10 Gb),并且需要一种有效的方法将它们读入R。到目前为止,我一直在通过QGIS将它们转换为shapefile,然后使用readShapePoly和readOGR(后者,顺便说一下,比前者快1000左右)。理想情况下,我想取消QGIS的中间阶段,因为它既麻烦又缓慢。

如何直接读取.kml文件?

看到这也可以使用readOGR完成。不幸的是,我看不到如何实现该示例(经过漫长的.kml文件准备:)xx <- readOGR(paste(td, "cities.kml", sep="/"), "cities")。这里的“城市”似乎是空间物体的名称。

罗杰·比万德(Roger Bivand)承认:“人们如何发现这个名字并不明显,因为OGR中的KML驱动程序需要它来访问文件。一种可能性是:

system(paste("ogrinfo", paste(td, "cities.kml", sep="/")), intern=TRUE)

但这对我也不起作用。这是一个测试的.kml文件,可以尝试使用。在我的工作目录中,readOGR("x.kml", "id")生成以下错误消息:

Error in ogrInfo(dsn = dsn, layer = layer, encoding = encoding, use_iconv = use_iconv) : 
  Cannot open layer . 

system(paste("ogrinfo", "x.kml"), intern=TRUE)生成:

[1] "Had to open data source read-only."   "INFO: Open of `x.kml'"               
[3] "      using driver `KML' successful." "1: x (3D Polygon)"  

,我根本不理解。

getKMLcoordinates{} maptools是一个有效的替代方案?

我也尝试过这个:

tkml <- getKMLcoordinates(kmlfile="x.kml", ignoreAltitude=T)
head(tkml[[1]])
tkml <- SpatialPolygons(tkml, 
                        proj4string=CRS("+init=epsg:3857"))

坐标正确生成,但是我尝试将其转换回多边形对象的尝试失败,并显示以下消息:

Error in SpatialPolygons(tkml, proj4string = CRS("+init=epsg:3857")) : 
  cannot get a slot ("area") from an object of type "double"

1
您可以使用rgdal的功能ogrListLayers在kml中获取图层。
马里奥·贝塞拉

Answers:


36

要使用OGR驱动程序读取KML,请为其提供文件名和层名。

Roger的评论是,层名称隐藏在KML文件中,除非您知道KML的创建方式,否则无法从KML文件名推断层名称。

查看您的示例KML,我可以看到:

<?xml version="1.0" encoding="utf-8" ?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document><Folder><name>x</name>
<Schema name="x" id="x">

这告诉我图层名称是x,不是id,所以:

> foo = readOGR("/tmp/x.kml", "x")
OGR data source with driver: KML 
Source: "/tmp/x.kml", layer: "x"
with 1 features and 2 fields
Feature type: wkbPolygon with 2 dimensions

效果很好。

现在,你可以尝试通过使用R XML解析器解析KML作为XML得到了名,也可以或许试着读它在R作为一个文本文件,直到找到名称标签。

另一种方法是运行命令行ogrinfo程序,该程序会吐出KML文件的层名称:

$ ogrinfo /tmp/x.kml 
Had to open data source read-only.
INFO: Open of `/tmp/x.kml'
      using driver `KML' successful.
1: x (Polygon)

这里显示有一个称为的多边形层x


谢谢您的回答。空格-立即解决问题。如此清晰的解释使我喜欢堆栈交换!一个“加分点”问题:我是否可以使用同一命令读取数据的子集(例如前100万个多边形)?否则,将寻求通过外部程序拆分庞大的kmls。
RobinLovelace

2
作为XML的KML并不是真正为随机访问而设计的。真正的解决方案是将空间数据放入空间数据库,并具有一些空间索引以提高速度。查看PostGIS。
Spacedman

好的好计划-我已经告诉客户,PostGIS是处理如此大数据的前进之路,并且坚信这是他想要做的事情的正确选择。好借口,让我正确学习它!
RobinLovelace

sqlite是基于文件的数据库的空间扩展,与PostGIS相比,它不需要安装服务并且需要的配置更少。
弗兰克,

奇怪的是systemR中需要path.expand~ogrinfo工作,即使它在命令行中运行良好,未膨胀路径上(MacOS的; Sys.which('ogrinfo')以及which ogrinfo返回相同的路径)
MichaelChirico

5

如果您想使用maptool做另一种方法,这应该可以工作:

tkml <- getKMLcoordinates(kmlfile="yourkml.kml", ignoreAltitude=T)
#make polygon
p1 = Polygon(tkml)
#make Polygon class
p2 = Polygons(list(p1), ID = "drivetime")
#make spatial polygons class
p3= SpatialPolygons(list(p2),proj4string=CRS("+init=epsg:4326"))

这里的关键是您需要经历几个步骤才能制作空间多边形类。


嗨@Seen,我尝试过您的方法,但似乎不起作用?我有一个错误:Polygon(tkml)中的错误:坐标必须是两列矩阵> head(tkml)[[1]] [1] -87.88141 30.49800 adn我有它的列表。.您认为它可以转换吗矩阵坐标列表?谢谢!
maycca '16

1

不知道这对其他人是否仍然是一个问题,但是与此同时,我在圈子里跑了一段时间。最终对我有用的是下面。它使用该XML程序包到达xmlValue正确的节点。我必须将layer参数设置readOGR为kml文件中的文件夹之一的名称。当我将layer参数设置为kml文件的时,我将得到与上述RobinLovelace相同的错误。

下面显示的是许多代码行,仅显示如何查看kml文档的各个节点级别。我认为这取决于kml的来源。但是您应该能够使用相同的逻辑来确定正确的参数值。

另外,我创建的KML文件列表,以便它可以很容易地制作成可以放在一个功能lapply- do.call对。然后,这可以从一长串的kml文件中提取数据。或者,单个kml文件中的许多子文件夹似乎readOGR无法处理kml文件中的多个子文件夹。

library(rgdal); library(XML)

# SET WORKING DIRECTORY FIRST!!
dir <- getwd()

kmlfilelist <- list.files(dir, pattern =".kml$", full.names=TRUE, recursive=FALSE)

doc0 <- xmlTreeParse(kmlfilelist[2], useInternal = TRUE)
rootNode0 <- xmlRoot(doc0)
rootName0 <- xmlName(rootNode0)
element1Name0 <- names(rootNode0)

nodeNames <- names(rootNode0[1][[1]])

# entire rootNode - kml Document level
rootNode0[[1]]

# 1st element of rootNode - kml file name
rootNode0[[1]][[1]] 

# 2nd element of rootNode - kml Style Map 
rootNode0[[1]][[2]] 

# 3rd element of rootNode - Style
rootNode0[[1]][[3]]

# 4th element of rootNode - Style
rootNode0[[1]][[4]] 

# 5th element of rootNode - kml Folder with data in it.
rootNode0[[1]][[5]] 

# 5th element 1st subelement of rootNode - kml Folder name with data in it. 
#  What to set readOGR() layer parameter to.
rootNode0[[1]][[5]][[1]] 

kmlfoldername <- xmlValue(rootNode0[[1]][[5]][[1]]) # Folder name to set = layer.

readOGR(dsn=kmlfilelist[2], layer =  kmlfoldername)

0

不知道我是否应该修改以前的答案。也许,但这涵盖了此答案中未涵盖的某些内容,因此我决定将其保留。

无论如何,下面的代码对我来说效果很好。它在kml文件中查找所有名为“文件夹”的xmlNode,然后将的layer参数设置readOGRxmlValue。在大约6个单独的kml文件的工作目录上进行了测试。输出是导入的SpatialDataFrames对象的列表。每个SpatialDataFrame可以轻松地成为列表的子集。

仍然不能解决具有多个“文件夹”节点的kml文件的问题。但是该功能可以很容易地与另一个嵌套apply函数一起添加。

library(rgdal); library(XML)

# SET WORKING DIRECTORY FIRST!!
dir <- getwd()

kmlfilelist <- list.files(dir, pattern =".kml$", full.names=TRUE, recursive=FALSE)

ImportKml <- function (kmlfile) {
  doc0 <- xmlTreeParse(kmlfile, useInternal = TRUE)
  rootNode0 <- xmlRoot(doc0)
  rootName0 <- xmlName(rootNode0)
  element1Name0 <- names(rootNode0)

  kmlNodeNames <- unname(names(rootNode0[1][[1]]))
  kmlFolderNodeNum <- which(kmlNodeNames == "Folder")
  kmlFolderNodeName <- xmlValue(rootNode0[[1]][[kmlFolderNodeNum]][[1]])

  kmlIn <- readOGR(dsn=kmlfile, layer = kmlFolderNodeName)
}
ImportedKmls <- lapply(kmlfilelist, ImportKml)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.