Java使用GDAL来解析KMZ及KML实战

devtools/2024/12/23 4:27:30/

目录

前言

一、在GQIS中浏览数据

1、关于空间参考

 2、属性表格

二、GDAL的相关驱动及解析实战

1、GDAL中的KMZ驱动

2、GDAL实际解析

三、数据解析成果

1、KML解析结果

2、KMZ文件入库

四、总结


前言

        在前面的博客中讲过纯Java实现Google地图的KMZ和KML文件的解析,不知道有没有小伙伴在工作中实用了。如果有了实战的朋友一定会发现,虽然在前面的博客中,能解决我们对KMZ和KML文件的解析,也能正确的构造WKT数据,也就是意味着我们可以将数据插入到数据库中或者是转为其它的数据格式。但是,使用纯Java解析的方式还是存在一些问题的。

        下面我们首先来看看使用纯Java的解析模式会存在什么问题。这里我们先说结论,然后再使用针对性的解决办法。其实使用纯Java解析模式主要的问题是:1、没有完全识别出KMZ文件的属性值,有一些属性值丢失(当然,这里是通过桌面软件来进行属性的查看),如果想其实是可以解析到。但确实从之前的解析包中没有发现其它属性的获取方法。2、获取不到空间参考。3、对于KMZ文件,首先需要进行解压缩,然后再读取KML文件,解析代码比较繁琐。

        针对上面的这些问题,本文主要采用GDAL组件来进行KMZ和KML文件的解析,在C站或者其它的技术博客中查找相关知识点会发现,使用JAVA和GDAL实现数据解析的相关介绍内容比较少,很多都是C++或者其它语言的示例,因此这里分享如何使用JAVA语言来进行开发。博文首先使用Qgis软件展示KMZ或者KML文件的全部属性和空间参考,然后介绍GDAL中对于读取KMZ和KML的驱动的讲解,基于GDAL的统一解析模式来实现对KMZ和KML文件的统一解析,避免了过多的代码,最后将KMZ数据进行了数据库插入的操作,从而实现从数据解析、转换、存储的一个完整过程。通过本文您可以掌握使用Java语言通过GDAL实现对KMZ和KML文件的统一处理和存储操作,如果您当前也有这样的需求,欢迎进行交流。

一、在GQIS中浏览数据

        既然KMZ和KML也是一种空间矢量数据,那么QGIS也是一定提供了支持的。为了展示在空间矢量数据中的所有属性数据,这里我们采用QGIS来展示。当然您也可以采用Arcgis或者SuperMap等桌面端软件同样也是可以的。

1、关于空间参考

        首先打开QGIS这款软件,在左边的菜单中选择需要展示的KMZ数据,如下图所示:

        然后将所有的图层都加载到地图中,点击全选。然后点击OK,所有的图层就会自动添加到地图中。 在图层窗口中就可以看到这些子图层的数据和具体的信息。

        使用鼠标右键,点击图层的属性,可以看到这个图层的属性信息,比如基础信息、属性信息等。 这里以空间参考信息为例:

序号参数信息参数值
1存储

LIBKML

2编码

UTF-8

3几何图形

Point (PointZ)

4空间参考CRS

EPSG:4326 - WGS 84 - 地理的

5单位

6要素数目

457

 2、属性表格

        矢量数据中,属性表格是很重要的数据,因此十分有必要介绍一下属性信息。在QGIS中,可以查看空间数据的属性表格,同样的属性查看选项中。点击字段即可查看。

序号参数名字段类型说明
1NameString名称
2descriptionString说明
3timestampDateTime时间戳
4beginDateTime
5endDateTime
6altitudeModeString
7tessellateint
8extrudeint
9visibilityint
10drawOrderint
11iconString

        在QGIS中查看属性信息如下所示:

        我们来实际看一下表中的数据大概是什么,打开数据属性表,如下所示:

        如果您看过之前的文章,就会发现之前的数据解析,其实只解析到了description字段 ,其它字段基本上都是空值,哪怕实际上是有值的。

二、GDAL的相关驱动及解析实战

        在使用Qgis软件对上述数据进行了深度解析之后,我们基本对数据有了一个大概的任务。接下来我们来看看GDAL中对于KMZ和KML文件解析驱动的说明相关的知识。为实际的文件解析提供坚实的基础。

1、GDAL中的KMZ驱动

        既然KML和KMZ文件也是矢量文件的一种,那么首先我们来看看GDAL是否支持这两种文件。首先打开GDAL的矢量驱动连接GDAL矢量驱动器。界面如下图所示:

        其实GDAL支持的矢量文件是非常多的,这里仅将我们关注的KMZ和KML文件进行展示,其它的文件格式在后续的博文中我们慢慢讲解。

JML

JML:OpenJUMP JML格式

Yes

Yes

(读取支持需要libexpat)

KML

锁眼标记语言

Yes

Yes

(读取支持需要libexpat)

LIBKML

LIBKML驱动程序(.kml.kmz)

Yes

Yes

libkml语言

LVBAG

荷兰卡达斯特LV包2.0提取物

libexpat公司

MapML

地图管理语言

Yes

Yes

默认内置

Memory

Memory

Yes

Yes

默认内置

MITAB

MapInfo TAB和MIF/MID

Yes

Yes

默认内置

MongoDBv3

MongoDBv3

Yes

Yes

Mongo CXX>=3.4.0客户端库

MSSQLSpatial

Microsoft SQL Server空间数据库

Yes

Yes

ODBC库

MVT

MVT:地图框矢量平铺

Yes

Yes

(需要SQLite和GEOS提供写支持)

        其中我们发现LIBKML,这个驱动是支持对应的KMZ和KML文件的读写的。关于这个驱动的说明,可以在GDAL的官网看得到。它的描述如下:

        LIBKML驱动程序是 Libkml ,的参考实现 KML 阅读和写作,以跨平台C++的形式出现。必须生成并安装Libkml才能使用此OGR驱动程序。注意:您需要构建libkml 1.3或master。 注意,如果您构建并包含这个LIBKML驱动程序,它将成为ogr的KML的默认读取器,覆盖前面的 KML driver . 仍然可以通过命令行指定KML或LIBKML作为输出驱动程序 来自Google的Libkml为任何有效的KML文件提供读取服务。但是,请注意,一些KML设施并没有映射到OGR用作其内部结构的简单功能规范中。因此,驱动程序将尽最大努力理解libkml读入ogr的KML文件的内容,但是您的里程数可能会有所不同。请尝试一些KML文件作为示例,以了解理解的内容。特别是,多个深度的特征集嵌套将被展平以支持ogr的内部格式。

        它的数据来源如下:

        其它更多的属性信息,请大家及时的去GDAL的官网进行查询。有了上述的知识后,我们就可以采用GDAL来进行数据的解析。

2、GDAL实际解析

        本小节将重点以代码的形式对GDAL如何解析KMZ和KML文件进行深入说明。在上面一个小节中我们已经完成了驱动包说明,GDAL是一个支持很多种格式的数据解析程序包,在程序运行的时候,它通过驱动的桥接口实现了不同的数据解析,然后给予统一的数据格式返回对应的属性数据。为我们下一步进行数据的存储和分析提供基础。

        下面以KML文件为例,给出具体的针对KML的解析代码。

@Testpublic void testReadKml() {//指定文件的名字和路径String strVectorFile ="C:/BaiduDownload/基地-地图数据(kmz)/usa.kml";// 注册所有的驱动ogr.RegisterAll();// 为了支持中文路径,请添加下面这句代码gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8","YES");// 为了使属性表字段支持中文,请添加下面这句gdal.SetConfigOption("SHAPE_ENCODING","CP936");//读取数据,这里以ESRI的shp文件为例String strDriverName = "LIBKML";//创建一个文件,根据strDriverName扩展名自动判断驱动类型org.gdal.ogr.Driver oDriver =ogr.GetDriverByName(strDriverName);if (oDriver == null) {System.out.println(strDriverName+ " 驱动不可用!\n");return;}DataSource dataSource = oDriver.Open(strVectorFile);System.out.println("图层总数=="+dataSource.GetLayerCount());//System.out.println(data);for(int w =0;w<dataSource.GetLayerCount();w++) {//Layer layer = dataSource.GetLayer("test");Layer layer = dataSource.GetLayer(w);String layerName = layer.GetName();System.out.println("图层名称:"+layerName);SpatialReference spatialReference = layer.GetSpatialRef();FeatureDefn featureDefn = layer.GetLayerDefn();int fieldCount = featureDefn.GetFieldCount();Map<String,Object> fieldMap = new HashMap<String,Object>();List<String> filedList = new ArrayList<String>(fieldCount);for(int i=0; i<fieldCount; i++){FieldDefn fieldDefn = featureDefn.GetFieldDefn(i);//得到属性字段类型int fieldType = fieldDefn.GetFieldType();String fieldTypeName = fieldDefn.GetFieldTypeName(fieldType);//得到属性字段名称String fieldName = fieldDefn.GetName();//fieldMap.put(fieldTypeName,fieldName);filedList.add(fieldName);}System.out.println(filedList);System.out.println("**************************************");long featureCount = layer.GetFeatureCount();System.out.println("图层要素个数:"+featureCount);for(int i=0; i<featureCount; i++){Feature feature = layer.GetFeature(i);if(null == feature) continue;for(int k=0; k<filedList.size(); k++){String fvalue = feature.GetFieldAsString(filedList.get(k));System.out.print(filedList.get(k) + ":"+fvalue + "\t");}System.out.println();}}}

        如果看过我之前的博客的话,对于GDAL如何实现空间矢量数据的解析应该比较了解。这里需要注意的只有一点,就是解析驱动。对于KML文件,一定要设置对应的驱动,如String strDriverName = "LIBKML";

三、数据解析成果

        以上的代码重点演示了如何使用GDAL来解析KML数据,本节将把上面小节的程序运行起来,然后把运行结果反馈给用户。对于KML数据,仅将数据在控制台进行输出打印,而对于KMZ数据,我们需要将数据保存的空间数据库中。

1、KML解析结果

        在程序IDE中运行上面的代码,在控制台中可以看到以下输出。

Name:NAS Keflavik IC	description:	timestamp:	begin:	end:	altitudeMode:	tessellate:-1	extrude:0	visibility:-1	drawOrder:	icon:	
Name:Campbell Barracks	description:	timestamp:	begin:	end:	altitudeMode:	tessellate:-1	extrude:0	visibility:-1	drawOrder:	icon:	
Name:Giebelstadt Army Airfield	description:	timestamp:	begin:	end:	altitudeMode:	tessellate:-1	extrude:0	visibility:-1	drawOrder:	icon:	
Name:NAF Atsugi JA	description:	timestamp:	begin:	end:	altitudeMode:	tessellate:-1	extrude:0	visibility:-1	drawOrder:	icon:	
Name:Leighton Barracks	description:	timestamp:	begin:	end:	altitudeMode:	tessellate:-1	extrude:0	visibility:-1	drawOrder:	icon:	

        如果能看到以上的信息,说明已经正确的解析了KML文件。

2、KMZ文件入库

        使用GDAL来解析KMZ文件,因为驱动类型是一样的,因此不需要更换驱动,值需要把文件名给修改下,关键代码如下(重复代码已删除):

 String strVectorFile ="C:/BaiduDownload/基地-地图数据(kmz)/全球基地.kmz";

        为了实现对Kmz保存到数据库中,因此这里我们需要创建对应的数据表,同时要基于MP新建业务处理实现类。首先将数据库的表结构分享给大家,需要的同学可以在这里复制。

CREATE TABLE "public"."biz_usa_military_base" ("id" int8 NOT NULL,"en_name" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,"en_desc" varchar(1024) COLLATE "pg_catalog"."default","cn_name" varchar(255) COLLATE "pg_catalog"."default","remark" varchar(255) COLLATE "pg_catalog"."default","geom" "public"."geometry","create_by" varchar(64) COLLATE "pg_catalog"."default","create_time" timestamp(6),"update_by" varchar(64) COLLATE "pg_catalog"."default","update_time" timestamp(6),CONSTRAINT "pk_biz_usa_military_topics" PRIMARY KEY ("id")
);
ALTER TABLE "public"."biz_usa_military_base" OWNER TO "ghy01";
CREATE INDEX "idx_biz_usa_military_base_geom" ON "public"."biz_usa_military_base" USING gist ("geom" "public"."gist_geometry_ops_2d"
);
COMMENT ON COLUMN "public"."biz_usa_military_base"."id" IS '主键';
COMMENT ON COLUMN "public"."biz_usa_military_base"."en_name" IS '英文名称';
COMMENT ON COLUMN "public"."biz_usa_military_base"."en_desc" IS '英文描述';
COMMENT ON COLUMN "public"."biz_usa_military_base"."cn_name" IS '英文名称';
COMMENT ON COLUMN "public"."biz_usa_military_base"."remark" IS '备注';
COMMENT ON COLUMN "public"."biz_usa_military_base"."geom" IS '空间信息';
COMMENT ON COLUMN "public"."biz_usa_military_base"."create_by" IS '创建人';
COMMENT ON COLUMN "public"."biz_usa_military_base"."create_time" IS '创建时间';
COMMENT ON COLUMN "public"."biz_usa_military_base"."update_by" IS '更新人';
COMMENT ON COLUMN "public"."biz_usa_military_base"."update_time" IS '更新时间';
COMMENT ON TABLE "public"."biz_usa_military_base" IS '基地信息表';

根据数据的表结构,我们需要定义Mapper和实体类来进行对应。

package com.yelang.project.extend.militarytopics.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yelang.framework.handler.PgGeometryTypeHandler;
import com.yelang.framework.web.domain.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/*** 基地实体类* @author 夜郎king*/
@TableName(value ="biz_usa_military_base",autoResultMap = true)
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class UsaMilitaryBase extends BaseEntity{private static final long serialVersionUID = 9052078556566456025L;@TableIdprivate Long id;//主键@TableField(value = "en_name")private String enName;@TableField(value = "en_desc")private String enDesc;@TableField(value = "cn_name")private String cnName;private String remark;@TableField(typeHandler = PgGeometryTypeHandler.class)private String geom;@TableField(exist=false)private String geomJson;
}

        其它的业务类代码比较简单,只是将批量提交的集合进行保存,这里不赘述。重点介绍一下就是GDAL解析完数据后,我们需要将属性信息保存到对象中,然后把每个对象添加到集合中,最后把集合保存到数据库中。获取信息后将数据设置到对象中的关键代码如下:

for(int i=0; i<featureCount; i++){Feature feature = layer.GetFeature(i);if(null == feature) continue;String enName = feature.GetFieldAsString("Name");String enDesc = feature.GetFieldAsString("description");UsaMilitaryBase base = new UsaMilitaryBase();base.setEnName(enName);base.setEnDesc(enDesc);base.setCreateTime(now);Geometry geom = feature.GetGeometryRef();//step 1、生成原始wktString wkt = geom.ExportToWkt();wkt = "SRID=" + srid +";" + wkt;//拼接srid,实现动态写入base.setGeom(wkt);dataList.add(base);
}

        最后调用Service的批量更新功能进行数据的插入。

if(dataList.size() >0) {usaMilitaryBaseService.saveBatch(dataList, 300);

        在测试用例中执行以上代码,在数据库中查询这张表的数据,可以看到以下信息。

        到此就完成了KML数据的解析以及KMZ数据的解析及入库。这里没有复杂的业务逻辑,因此实现起来并不是很复杂。

四、总结

        以上就是本文的主要内容,本文主要采用GDAL组件来进行KMZ和KML文件的解析,在C站或者其它的技术博客中查找相关知识点会发现,使用JAVA和GDAL实现数据解析的相关介绍内容比较少,很多都是C++或者其它语言的示例,因此这里分享如何使用JAVA语言来进行开发。博文首先使用Qgis软件展示KMZ或者KML文件的全部属性和空间参考,然后介绍GDAL中对于读取KMZ和KML的驱动的讲解,基于GDAL的统一解析模式来实现对KMZ和KML文件的统一解析,避免了过多的代码,最后将KMZ数据进行了数据库插入的操作,从而实现从数据解析、转换、存储的一个完整过程。通过本文您可以掌握使用Java语言通过GDAL实现对KMZ和KML文件的统一处理和存储操作,如果您当前也有这样的需求,欢迎进行交流。行文仓促,难免有不足之处,欢迎专家朋友们在评论区留言批评指正,不慎感激。


http://www.ppmy.cn/devtools/47036.html

相关文章

深入理解Linux文件系统与日志分析

1、Linux文件系统 1.1概念 文件是存储在硬盘上的&#xff0c;硬盘上最小的存储单位是扇区&#xff0c;每个扇区的大小是512字节 inode&#xff1a;存储元信息&#xff08;文件的属性&#xff1a;权限、创建者、创建日期等&#xff09;&#xff0c;元信息inode一般是128或者2…

Docker以挂载方式安装RocketMQ

Docker 挂载安装RocketMQ Docker 挂载安装RocketMQ安装 Docker安装NameServer1.拉取容器2.创建NameServer容器3.查看容器状态4.补充配置4.1交互模式启动Docker容器4.2编辑broker.config4.2插入brokerIP1配置 安装Broker安装RocketMQ-console构建镜像启动容器开通安全组策略访问…

IO进程线程(十)进程间通信 消息队列 共享内存 信号灯集

文章目录 一、IPC(Inter-Process Communication)进程间通信相关命令 &#xff1a;&#xff08;一&#xff09;ipcs --- 查看IPC对象&#xff08;二&#xff09;获取IPC键值&#xff08;三&#xff09;删除IPC对象的命令&#xff08;四&#xff09;获取IPC键值的函数1. 函数定义…

二轴机器人大米装箱机:技术创新引领智能包装新潮流

在科技日新月异的今天&#xff0c;自动化和智能化已成为各行各业追求高效、精准生产的关键。作为粮食加工行业的重要一环&#xff0c;大米装箱机的技术创新与应用价值日益凸显。其中&#xff0c;二轴机器人大米装箱机以其高效、稳定、智能的特点&#xff0c;成为市场的新宠。星…

python---正则表达式

本章目标: 1:能够知道在Python中使用正则要导入的模块; [了解] re模块 2:能够使用re模块匹配单个字符; [重点] \d \w 正则表达式的概述: 基本介绍 正则表达式,也叫做规则表达式,通常会说成[正则] 实际上正则表达式就是指符合一定规则的字符串,同时他能用于检查一段…

Qt Graphics View Framework 使用教程

欢迎来到 Qt Graphics View Framework 的世界&#xff01;本教程将引导您了解这一强大工具的基础知识&#xff0c;并教您如何开始使用它来创建丰富的 2D 图形界面。无论您是编程新手还是经验丰富的开发者&#xff0c;本教程都将帮助您快速上手。 基本概念 Qt Graphics View F…

[word] word大括号怎么打两行 #其他#其他#微信

word大括号怎么打两行 Word给用户提供了用于创建专业而优雅的文档工具&#xff0c;帮助用户节省时间&#xff0c;并得到优雅美观的结果。 一直以来&#xff0c;Microsoft Office Word 都是最流行的文字处理程序。 作为 Office 套件的核心程序&#xff0c; Word 提供了许多易…

计算机网络期末知识点(第六章)

目录 ♦️应用层的作用 ♦️应用层中常见的协议 &#x1f421;域名系统DNS 域名结构: DNS协议的作用&#xff1a; &#x1f421;文件传输协议FTP FTP的作用&#xff1a; &#x1f421;远程终端协议Telent Telent的作用&#xff1a; &#x1f421;万维网和HTTP协议 H…