目录
1.需求分析
在测绘和地理信息系统(GIS)项目中,数据来源多样,包括野外采集的数据以及来自第三方的数据。这些数据有时以表格形式提供,例如 Excel 表格或 CSV 文件。然而,为了进行空间分析、制图和其他 GIS 操作,通常需要将这些表格数据转换为矢量数据格式(如Shapefile或KML)。这种转换不仅使数据能够更好地集成到现有的地理信息系统中,还便于进一步的空间处理和可视化,从而支持各类项目的顺利实施。
GDAL(Geospatial Data Abstraction Library)是强大的开源GIS程序库,广泛用于处理和转换各种地理空间数据格式,其支持读或者写的矢量数据格式就达到了80多种。本文主要讲述利用GDAL/OGR工具将Excel表格(xlsx)转换为矢量数据(kml,shp)的方法,中间会穿插讲述怎么将CSV表格转换为矢量数据的方法。
本文对于没有信息技术工作经验者来说,阅读起来可能有点费力。本文的矢量数据文件均为点状矢量文件,面状、线状的数据的转换更加复杂,这里暂时不介绍。
如果时间有限,无法详细阅读整个过程,可以直接跳至第4节获取转换方法的最佳实践。
2.为什么要用命令行
市面上有许多成熟的GIS软件(如ArcGIS、QGIS等)能够实现表格转矢量文件的功能,但使用GDAL/OGR工具进行此类操作仍有其独特的优势和应用场景。比如以下场景:
(1)批量处理时,gdal/ogr命令行程序有较大优势。
(2)服务器执行定时任务时,gdal/ogr命令行程序比较方便。
(3)桌面GIS软件的启动速度往往较慢,gdal/ogr命令行程序启动很快。
(4)在对计算机处理数据性能要求较高的情况下,gdal/ogr命令行程序有优势。
(5)命令行程序的参数可以用配置文件输入,桌面GIS软件有类似功能,设置起来较麻烦。
(6)适合开发者使用。
以上仅仅是作者的经验之谈。 在处理少量简单数据时,各类桌面GIS软件也很好用。
3.转换方法
转换主要用到了ogrinfo和ogr2ogr两个命令。这里主要介绍转换为kml的方法,最后会给出转换为Shapefile的方法。这两种格式的数据在GIS领域有着广泛的应用,这里不再赘述。值得注意的是,不论是那种数据格式的转换,都应该认真阅读gdal的官方文档,因为转换不同格式的数据执行的参数有较大的差异。
下面的命令行代码是基于windows系统的cmd写的,gdal的版本是3.2。如果是linux或者mac平台,代码略有差异。
3.1读取文件信息
已知我们有一个名叫部分世界著名景点.xlsx的Excel表格,它是由WPS Office编辑录入的,以下是数据的预览:
工作簿有2个工作表(sheet),分别是西欧和北美,里面存放的是世界知名景点的信息及经纬度。
因为后续数据转换涉及到指定空间数据字段和属性字段,所以我们要使用ogrinfo程序读取这个表格,观察其在OGR中是的表现形式。windows系统的简体中文版默认字符集一般是GBK。为了能用ogr程序处理中文,我们在运行时需要切换到UTF-8的字符集。
切换字符集为UTF-8,需要在cmd窗口执行以下代码。
chcp 65001
然后切换到表格所在父目录(这一步省略),指定读取Excel文档的代码,-where "fid <=2 "的作用是只读取前3行,避免数据过多的显示在屏幕上。
ogrinfo -al -where "fid <=2 " 部分世界著名景点.xlsx
以下是部分截图:


从上述信息中,我们可以发现:
Layer Name指的是Excel工作表中的不同表格,在这个例子中有两个图层,分别是“西欧”和“北美”。OGR将Excel的工作表作为图层来读取处理。由于这些Excel工作表不包含任何空间信息,因此Geometry显示为“None”,相应的Layer SRS WKT(图层空间参考系统WKT)也为空。
接下来的部分列出了6个属性字段及其数据类型,这里就不详细展开解释了。每条OGRFeature对应于工作表中的一行记录;如果某行记录的某个属性值为空,则该属性不会出现在对应的要素属性列表中。
根据GDAL文档关于xlsx驱动打开参数的描述,直接通过打开参数将xlsx格式的数据转换成OGR支持的空间数据格式是不行的。然而,对于CSV驱动,文档中记录了X_POSSIBLE_NAMES、Y_POSSIBLE_NAMES和Z_POSSIBLE_NAMES等参数选项,这意味着可以通过先将xlsx文件转换为CSV文件,然后再利用ogr2ogr工具,将CSV文件转换为KML或ESRI Shapefile等空间数据格式。
3.2通过CSV格式中转
首先将xlsx转为cvs格式,由于ogr中所有的csv文件都被默认为UTF-8编码的文件来处理,这里用到了-lco WRITE_BOM=YES是使用UTF-8 BOM编码,是为了和Excel办公软件兼容。如果要用Excel编辑保存csv文档,则需要另存为UTF-8格式的csv文档。
ogr2ogr -f "CSV" 西欧.csv 部分世界著名景点.xlsx 西欧 -lco WRITE_BOM=YES
ogr2ogr -f "CSV" 北美.csv 部分世界著名景点.xlsx 北美 -lco WRITE_BOM=YES
利用csv的打开时的参数,将经纬度转换为图层中空间属性(Geometry)。这里没有指定Z坐标,如果需要,可以加上Z_POSSIBLE_NAMES参数。
ogr2ogr -f 输出格式的驱动名称 输出文件的路径 输入文件的路径 -oo X_POSSIBLE_NAMES=x坐标字段名称 -oo Y_POSSIBLE_NAMES=y坐标字段名称 -dsco NameField=kml图层Name的字段 -dsco DescriptionField=kml图层Description的字段
ogr2ogr -f "KML" 部分世界著名景点(西欧).kml 西欧.csv -oo X_POSSIBLE_NAMES=经度 -oo Y_POSSIBLE_NAMES=纬度 -dsco NameField=名称 -dsco DescriptionField=英文名称
上述命令会将CSV所有的属性都添加到目标图层,如果需要过滤部分字段,比较简单的情况可以用select来过滤,如果过滤行可以用-where参数。更复杂的情况,如需要拼接字段,可以通过执行SQL语句来实现。
ogr2ogr -f "KML" 部分世界著名景点(西欧).kml 西欧.csv -oo X_POSSIBLE_NAMES=经度 -oo Y_POSSIBLE_NAMES=纬度 -dsco NameField=名称 -dsco DescriptionField=英文名称 -select "名称,英文名称,坐落"
这里,会将源文件图层的“名称”,“英文名称”,“坐落”列输出,且将“名称”,“英文名称”分别映射到Name和Description。
在命令窗口写SQL比较麻烦,因为SQL中很多保留字和系统命令冲突,这会需要大量的转义字符,降低了可维护性。更加复杂的情况可以通过虚拟格式(VRT)文件来实现将配置数据都写在xml里面,这样会使得命令行很简单,比较容易维护。
我们编写一个vrt为后缀名的xml文档如下
<OGRVRTDataSource>
<OGRVRTLayer name="西欧">
<SrcDataSource>西欧.csv</SrcDataSource>
<GeometryType>wkbPoint</GeometryType>
<LayerSRS>EPSG:4490</LayerSRS>
<GeometryField encoding="PointFromColumns" x="经度" y="纬度"/>
<Field name="Name" src="名称" type="String"/>
<Field name="Description" src="英文名称" type="String"/>
<Field name="坐落" src="坐落" type="String"/>
<Field name="lon" src="经度" type="String"/>
<Field name="lat" src="纬度" type="String"/>
</OGRVRTLayer>
</OGRVRTDataSource>
执行下列命令,就可以实现转换。虽然在vrt中指定了图层坐标系为EPSG4490,但输出的KML文件坐标系还EPSG4326,这是ogr写KML文件的默认行为,3.2版本没有参数可以调整这个行为。
ogr2ogr -f "KML" 部分世界著名景点(西欧).kml 西欧.csv.vrt
以下是在vrt文件使用SQL语句来实现转换的例子,这里不需要转义SQL。
<OGRVRTDataSource>
<OGRVRTLayer name="西欧">
<SrcDataSource>西欧.csv</SrcDataSource>
<GeometryType>wkbPoint</GeometryType>
<LayerSRS>EPSG:4490</LayerSRS>
<GeometryField encoding="PointFromColumns" x="lon" y="lat"/>
<SrcSQL dialect="SQLite">
SELECT (名称 || ' ' || 英文名称) AS Name,
坐落 AS Description,经度 AS lon,纬度 AS lat FROM 西欧
</SrcSQL>
</OGRVRTLayer>
</OGRVRTDataSource>
以下是多个图层写入目标文件的例子
ogr2ogr -f "KML" 部分世界著名景点.kml 西欧.csv.vrt
ogr2ogr -f "KML" 部分世界著名景点.kml -append 北美.csv.vrt
3.3直接用Excel转换
虽然直接通过打开参数将xlsx格式的数据转换成OGR支持的空间数据格式是不行的,但是可以通过SQL语句实现,或者在vrt文件的<GeometryField>标签中指定x、y、z属性实现。
ogr2ogr -f "KML" 部分世界著名景点(西欧)-x.kml.kml 部分世界著名景点.xlsx -dialect sqlite -sql "SELECT \"名称\" AS Name, \"英文名称\" AS Description,ST_GeomFromText(wktStr) as geom FROM (SELECT 'POINT('||\"经度\" ||' '||\"纬度\"||')' AS wktStr,* FROM \"西欧\")" -nln 西欧
这个是在cmd中执行SQL语句转换Excel为kml的方式,用到了SQLitef方言和ST_GeomFromText函数,由于有大量的转义字符,可维护性不好,不建议使用。
以下是推荐使用的方式,它可以实现在一个vrt中指定配置数据后,通过一行简洁的代码转换Excel到kml文件。值得注意的是使用SQL语句时,GeometryField中的x、y属性必须是SQL语句的查询结果中的字段。
<OGRVRTDataSource>
<OGRVRTLayer name="西欧">
<SrcDataSource>部分世界著名景点.xlsx</SrcDataSource>
<GeometryType>wkbPoint</GeometryType>
<LayerSRS>EPSG:4490</LayerSRS>
<GeometryField encoding="PointFromColumns" x="lon" y="lat"/>
<SrcSQL dialect="SQLite">
SELECT 名称 AS Name,坐落 AS Description,经度 AS lon,纬度 AS lat FROM 西欧
</SrcSQL>
</OGRVRTLayer>
<OGRVRTLayer name="北美">
<SrcDataSource>部分世界著名景点.xlsx</SrcDataSource>
<GeometryType>wkbPoint</GeometryType>
<LayerSRS>EPSG:4490</LayerSRS>
<GeometryField encoding="PointFromColumns" x="经线" y="纬线"/>
<Field name="Name" src="名称" type="String"/>
<Field name="Description" src="英文名称" type="String"/>
</OGRVRTLayer>
</OGRVRTDataSource>
ogr2ogr -f "KML" 部分世界著名景点.kml 部分世界著名景点.xlsx.vrt
部分世界著名景点.xlsx.vrt是上述xml的文件名称,也是相对路径。这是一个多图层的例子,删除一个OGRVRTLayer,就是单个图层的例子。
3.4关于ShapeFile的转换
前面讲述了怎么用表格文件转换为KML文件,是因为作者个人觉得写kml数据对于理解ogr写矢量文件更有帮助。因为ShapeFile在ogr中是单图层的,且属性长度有限制。但是日常项目中有大量的ShapeFile数据,所以有必要写一下它的转换方法。
首先介绍一下CSV转换ShapeFile,这里介绍的方法基本与转为kml一样。所不同的是,ogr写ESRI ShapeFile时,默认字符集是LDID/87,为了兼容中文,建议设置为UTF-8;还有一点是,需要通过-a_srs 参数指定坐标系,否则输出的ShapeFile不带坐标系。
ogr2ogr -f "ESRI Shapefile" 部分世界著名景点(西欧).shp 西欧.csv -oo X_POSSIBLE_NAMES=经度 -oo Y_POSSIBLE_NAMES=纬度 -lco ENCODING=UTF-8 -a_srs EPSG:4490
接下来是Excel转换ShapeFile,编写如下vrt文件
<OGRVRTDataSource>
<OGRVRTLayer name="西欧">
<SrcDataSource>部分世界著名景点.xlsx</SrcDataSource>
<GeometryType>wkbPoint</GeometryType>
<LayerSRS>EPSG:4490</LayerSRS>
<GeometryField encoding="PointFromColumns" x="lon" y="lat"/>
<SrcSQL dialect="SQLite">
SELECT 名称 AS Name,坐落 AS Description,经度 AS lon,纬度 AS lat FROM 西欧
</SrcSQL>
</OGRVRTLayer>
</OGRVRTDataSource>
也可以是这样的vrt文件:
<OGRVRTDataSource>
<OGRVRTLayer name="北美">
<SrcDataSource>部分世界著名景点.xlsx</SrcDataSource>
<GeometryType>wkbPoint</GeometryType>
<LayerSRS>EPSG:4490</LayerSRS>
<GeometryField encoding="PointFromColumns" x="经线" y="纬线"/>
<Field name="Name" src="名称" type="String"/>
<Field name="Description" src="英文名称" type="String"/>
</OGRVRTLayer>
</OGRVRTDataSource>
执行的转换代码中需要带上字符集设置、坐标系设置的有关参数。
ogr2ogr -f "ESRI Shapefile" 部分世界著名景点(西欧).shp 部分世界著名景点.xlsx.vrt -lco ENCODING=UTF-8 -a_srs EPSG:4490
由于“Description”超过了10个字节,作为字段名时,会被ogr截断。使用中文字段名也会面临这个情况,在UTF-8编码中,最多只能写3个汉字作为字段名。
4.总结
在利用GDAL/OGR命令行工具进行表格数据到矢量文件的转换时,存在多种方法,具体操作细节也较多。其中最佳实践是将字段映射及其他配置信息写入一个虚拟格式(VRT)文件中,然后再通过ogr2ogr命令行工具进行转换。这种方法特别适用于处理复杂的转换需求,在文档的3.3节和3.4节中有详细描述。然而,在转换任务相对简单的情况下,可以直接在命令行中输入必要的参数完成转换。例如,直接指定源文件路径、目标格式和其他基本选项即可。
在实际生产环境中,选择哪种方法应根据具体需求进行分析。对于复杂的数据转换任务,使用VRT文件能够提高效率并减少错误;而对于简单的转换任务,直接在命令行中指定参数则更加便捷。总之,结合实际需求选择最合适的方法,可以确保数据转换过程高效准确。

附件:本文实验数据