我正在处理巨大的.kml文件(最大10 Gb),并且需要一种有效的方式将它们读入R。到目前为止,我一直在通过QGIS将它们转换为shapefile,然后通过readShapePoly和readOGR(后者,顺便说一下,比前者快1000左右)。理想的情况是,我希望省去QGIS的中间阶段,因为它既麻烦又缓慢。也可以使用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"


评论

您可以使用rgdal的功能ogrListLayers获取kml中的图层。

#1 楼

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

罗格的注释是,图层名称隐藏在KML文件中,除非您知道KML的用法创建的文件无法从KML文件名推断出图层名称。

以您的示例KML为例,我可以看到:这告诉我层名称是x,而不是id,因此:

<?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">


工作正常。通过使用R XML解析器将KML解析为XML来获取名称,或者您可以尝试将R作为文本文件读取到R中,直到找到名称标签为止。

另一种方法是运行命令行ogrinfo程序,用于输出KML文件的层名称:

> 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


此处显示了一个名为x的多边形层。

评论


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

–RobinLovelace
13年4月16日在14:10

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

– Spacedman
13年4月16日在14:33

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

–RobinLovelace
13年4月16日在14:53

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

–坦率
16年2月10日在8:32

奇怪的是R中的系统需要在〜上进行path.expand才能使ogrinfo正常工作,即使它在命令行上的未扩展路径上也可以正常工作(macOS; Sys.which('ogrinfo')和哪个ogrinfo返回相同的路径)

– MichaelChirico
18年8月31日在3:30

#2 楼

如果要使用maptool做替代方法,这应该可以工作:

评论


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

– Maycca
16-4-22在21:16



这是一个非常老的帖子,所以我想检查问题是否比这里介绍的解决方案更好。如果不是,则Polygon(tkml)给我一个错误:选择函数'coordinates'的方法时评估参数'obj'时出错:参数表示行数不同:364、171、191、115、312、441 ,350、167、326、275、261、240 ...

–user30994
20-09-17在18:02

#3 楼

不知道这对其他人是否仍然是一个问题,但是与此同时,我在圈子里跑了一段时间。最终对我有用的是下面。它使用XML软件包获取右侧节点的xmlValue。我必须将layerreadOGR参数设置为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)


#4 楼

不知道我是否应该修改以前的答案。也许可以,但这涵盖了此答案中未涵盖的某些内容,因此我决定将其保留。它在kml文件中查找所有名为“文件夹”的xmlNode,然后将layerreadOGR参数设置为该xmlValue。在大约6个单独的kml文件的工作目录上进行了测试。输出是导入的SpatialDataFrames对象的列表。每个SpatialDataFrame都可以轻松地成为列表的子集。

仍然不能处理具有多个Folder节点的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)