纯Java实现Google地图的KMZ和KML文件的解析

目录

前言

一、关于KMZ和KML

1、KMZ是什么

2、KML是什么

二、Java解析实例

1、POM.xml引用

2、KML 基类定义

3、空间对象的定义

4、Kml解析工具类

三、KML文件的解析

1、KML解析测试

2、KMZ解析测试

四、总结


前言

        今天是六.一儿童节,在这里祝各位大朋友们儿童节快乐,同时祝祖国的所有花朵们更加快乐。童年的欢乐可以治愈一切。不知道各位的儿童节是怎么度过的呀,是在陪孩子呢,还在在享受自己的欢乐时光,只愿大家都欢乐就好。这是写在最前面祝福的话,愿我们都开心快乐。

        最近碰到有朋友咨询,大致的问题是,他在项目中要实现KMZ数据的解析和WebGIS的可视化。刚好他用的技术栈是Java,同时KMZ的解析在各个网站上的相关解析代码不多。有很多代码是解析KML的,但是解析KMZ的相对比较少。一时没有参考的例子,希望能结合JAVA讲一下如何进行KMZ数据的解析。其实话说回来,虽然大致了解KMZ是什么数据,但是在之前的项目过程中,接触的空间数据也基本都是shp、gdb等等,至于google的KMZ还真的是第一回接触。

        本文主要讲解如何用JAVA语言,直接解析KMZ数据。文章首先介绍google地图中的KMZ和KML数据,然后使用代码的方式实现数据的解析,最后展示解析成果以及如何将数据转换成空间WKT数据。关于JAVA解析KML的博客和资料有不少,但是KMZ文件的还是比较稀少的,供各位朋友在工作中解析KMZ文件有一个参考。

一、关于KMZ和KML

        在进行相关文件的解析之前,首先我们来看一下KMZ和KML这两种文件,先了解这两种文件是什么?用来做什么的,具体的文件内容是什么样的。本节主要提供这些基础知识的讲解。

1、KMZ是什么

        KMZ 文件包含主 KML 文件以及0个或多个用 ZIP 格式打包成一个单元的支持文件(称为归档)。然后,KMZ 文件就可以作为单个实体进行存储和通过电子邮件发送。NetworkLink 可从网络服务器提取 KMZ 文件。将 KMZ 文件解压缩后,主 .kml 文件及其支持文件便分离成其各自的原始格式和目录结构,以及原始文件名和扩展名。除了变成归档格式外,ZIP 格式也会受到压缩,因此归档只能包含一个大型 KML 文件。根据 KML 文件的内容,此过程通常会产生10:1的压缩。10千字节的 KML 文件可以用1千字节的 KMZ 文件来提供。

        KMZ是Google Earth默认的输出文件格式,是一个经过ZIP格式压缩过的KML文件,当我们从网站上下载KMZ文件的时候,Windows会把KMZ文件认成ZIP文件,所以另存的时候文件后缀会被改成.ZIP,因此需要手动将文件后缀改成.KMZ。   KMZ文件用ZIP工具软件打开,然后解压缩即可得到原始KML文件。当然,KMZ文件也有自己的好处,就是KMZ文件的自身可以包含影像,这样就可以不依赖引用网络上的截图。   一般情况下,双击KMZ/KML文件即可从Google Earth中打开地标文件,但是需要注意的是,KMZ/KML地标文件名不能包含中文字符,文件存放的路径也不能有中文字符,否则将无法在Google Earth中打开。

        这里我们以漂亮国的全球基地为说明,验证一下上述的内容。把KMZ文件的后缀名修改为zip,然后用压缩文件打开。可以看到以下的文件:

        总结一下,KMZ就是把KML文件,进行了一个打包。这个很重要,在后面的解析过程中,会用到这个知识点。讲完了KMZ,下面介绍一下KML。

2、KML是什么

        KML 代表 钥匙孔标记语言。此 GIS 格式基于 XML,主要用于 Google 地球。KML由Keyhole Inc开发,后来被Google收购.KMZ(KML-Zipped)取代KML成为默认的Google地球地理空间格式,因为它是文件的压缩版本。KML/KMZ于2008年成为开放地理空间联盟的国际标准。经度和纬度分量(十进制度)由 1984 年世界大地测量系统 (WGS84) 定义。垂直分量(高度)以米为单位从 WGS84 EGM96 大地水准面垂直基准面开始测量。

        KML (keyhole markup language)是以XML语言为基础开发的一种文件格式,用来描述和存储地理信息数据(点、线、面、图片等),是纯粹的xml文本格式,可用记事本打开编辑,所以kml文件很小。KML跟XML文件最大的不同就是KML描述的是地理信息数据。最早开发KML的是keyhole公司,2004年Goole收购keyhole并用KML开发GooleEarth。KML是原先的Keyhole客户端进行读写的文件格式,是一种XML描述语言,并且是文本格式,这种格式的文件对于Google Earth程序设计来说有极大的好处,程序员可以通过简单的几行代码读取出地标文件的内部信息,并且还可以通过程序自动生成KML文件,因此,使用KML格式的地标文件非常利于Google Earth应用程序的开发。

        这里我们还是以上面的kml文件为说明,将打开的示例xml文件内容展示如下:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
<Document>
  <!-- Begin Style Definitions -->
  <Folder>
    <name>Point Features</name>
    <description>Point Features</description>
    <Placemark>
      <description>Airport</description>
      <name><![CDATA[CHARLESTON AFB/INTL 查尔斯顿空军基地/国际机场]]></name>
      <Point>
        <coordinates>-80.0408900000,32.8985600000,0</coordinates>
      </Point>
    </Placemark>
    <Placemark>
      <description>Airport</description>
      <name><![CDATA[DAVIS-MONTHAN AFB 戴维斯-蒙森空军基地]]></name>
      <Point>
        <coordinates>-110.8822600000,32.1652200000,0</coordinates>
      </Point>
    </Placemark>
  </Folder>
</Document>
</kml>

        以上就是一个KML文件的示例,其主体内容就是一个XML。它以XML为主体,用来存储地理空间数据。因此对KML数据的解析,其本质就是对XML文件的解析。

二、Java解析实例

        本节主要以代码实战的方式介绍使用Java编程语言实现对KML语言和KMZ语言的解析。由于涉及到xml的解析,这里不采用最原始的dom解析方式。对于KML语言,有成熟的组件de.micromata.jak.JavaAPIforKml对KML的解析。这里对相关的解析组件进行介绍:

序号组件名称作用
1de.micromata.jak.JavaAPIforKmlKML文件解析
2org.apache.commons.commons-compress压缩包解压
3com.vividsolutions.jtsJTS wkt字符串构建

1、POM.xml引用

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.yelang</groupId>
	<artifactId>gdal_demo1</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>gdal_demo1</name>
	<description>试验</description>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
	</properties>
	<dependencies>
		<!-- https://mvnrepository.com/artifact/de.micromata.jak/JavaAPIforKml -->
		<dependency>
			<groupId>de.micromata.jak</groupId>
			<artifactId>JavaAPIforKml</artifactId>
			<version>2.2.1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-compress</artifactId>
			<version>1.21</version>
		</dependency>
		<dependency>
			<groupId>com.vividsolutions</groupId>
			<artifactId>jts</artifactId>
			<version>1.13</version>
		</dependency>
	</dependencies>
</project>

2、KML 基类定义

        这里进行kml 基类定义,将name、description、List<Coordinate>进行统一封装。针对Point、Polygon、Polyline对象,在自己的对象属性中扩展额外的属性。这里采用OOP的实现方式。网上很多的代码没有将父级类抽象出来,同时其代码只解析了name。没有解析description属性。这里我们将描述信息同样解析出来。关键代码如下:

package com.yelang.kmzcase;
import java.util.List;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
/**
 * kml 基类,将name、description、List<Coordinate>进行统一封装
 * @author 夜郎king
 */
public class KmlBaseEntity {
	private List<Coordinate> points;
	private String name;
	private String description;
	public List<Coordinate> getPoints() {
		return points;
	}
	public void setPoints(List<Coordinate> points) {
		this.points = points;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public KmlBaseEntity(List<Coordinate> points, String name, String description) {
		super();
		this.points = points;
		this.name = name;
		this.description = description;
	}
	public KmlBaseEntity() {
		super();
	}
}

3、空间对象的定义

        空间对象常见的类型包括点(Point)、线(Polyline)、面(Polygon)三种类型。这里我们将根据需要定义不同的空间对象。下面分别给出实例代码:

KmlPoint.java

package com.yelang.kmzcase;
import java.util.List;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
public class KmlPoint extends KmlBaseEntity{
	private String color;
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public KmlPoint(List<Coordinate> points,String name,String description,String color){
		super(points, name, description);
		this.color = color;
	}
	public KmlPoint() {
		super();
	}
}

KmlLine.java 

package com.yelang.kmzcase;
public class KmlLine extends KmlBaseEntity {
	private String color;
	private long width;
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public long getWidth() {
		return width;
	}
	public void setWidth(long width) {
		this.width = width;
	}
}

KmlPolygon.java

package com.yelang.kmzcase;
/**
 * @program: 面状实体
 **/
public class KmlPolygon extends KmlBaseEntity {
	private String color;
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
}

4、Kml解析工具类

        这里定义Kml的解析工具类,主要负责解析KML,然后根据不同的图层,将属性和空间坐标点信息赋值给不同的空间数据集合。网上有一些解析的代码,仅解析name属性。这里扩展了其它的属性,包括描述属性。详细代码如下:

package com.yelang.kmzcase;

import de.micromata.opengis.kml.v_2_2_0.*;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
 * @description: KML文件解析
 **/
public class ParsingKmlUtil {
	/**
	 *	 解析kml文件
	 */
	public KmlData parseKmlByFile(File file) {
		Kml kml = Kml.unmarshal(file);
		return getByKml(kml);
	}
	/**
	 * 	解析kml文件流
	 * 
	 * @param inputstream
	 * @return
	 */
	public KmlData parseKmlByInputstream(InputStream inputstream) {
		Kml kml = Kml.unmarshal(inputstream);
		return getByKml(kml);
	}
	/**
	 * Kml对象转自定义存储对象
	 * 
	 * @param kml
	 * @return
	 */
	public KmlData getByKml(Kml kml) {
		KmlData kmlData = new KmlData();
		kmlData.setKmlPoints(new ArrayList<>());
		kmlData.setKmlLines(new ArrayList<>());
		kmlData.setKmlPolygons(new ArrayList<>());
		Feature feature = kml.getFeature();
		parseFeature(feature, kmlData);
		return kmlData;
	}

	/**
	 * 	解析kml节点
	 * @param feature
	 * @param kmlData
	 */
	private void parseFeature(Feature feature, KmlData kmlData) {
		if (feature != null) {
			if (feature instanceof Document) {
				List<Feature> featureList = ((Document) feature).getFeature();
				featureList.forEach(documentFeature -> {
					if (documentFeature instanceof Placemark) {
						getPlaceMark((Placemark) documentFeature, kmlData);
					} else {
						parseFeature(documentFeature, kmlData);
					}
				});
			} else if (feature instanceof Folder) {
				List<Feature> featureList = ((Folder) feature).getFeature();
				featureList.forEach(documentFeature -> {
					if (documentFeature instanceof Placemark) {
						getPlaceMark((Placemark) documentFeature, kmlData);
					} else {
						parseFeature(documentFeature, kmlData);
					}
				});
			}
		}
	}

	private void getPlaceMark(Placemark placemark, KmlData kmlData) {
		Geometry geometry = placemark.getGeometry();
		/*String name = placemark.getName();
		placemark.getDescription();
		System.out.println(placemark.getDescription());
		if (name == null) {
			name = placemark.getDescription();
		}
		parseGeometry(name, geometry, kmlData);*/
		parseGeometry(placemark,geometry,kmlData);
	}
	/**
	 *	 解析点线面形状的数据分别放入存储对象
	 * @param placemark placemark对象
	 * @param geometry 形状类型
	 * @param kmlData  存储对象
	 */
	private void parseGeometry(Placemark placemark, Geometry geometry, KmlData kmlData) {
		if (geometry != null) {
			if (geometry instanceof Polygon) {
				Polygon polygon = (Polygon) geometry;
				Boundary outerBoundaryIs = polygon.getOuterBoundaryIs();
				if (outerBoundaryIs != null) {
					LinearRing linearRing = outerBoundaryIs.getLinearRing();
					if (linearRing != null) {
						List<Coordinate> coordinates = linearRing.getCoordinates();
						if (coordinates != null) {
							outerBoundaryIs = ((Polygon) geometry).getOuterBoundaryIs();
							addPolygonToList(kmlData.getKmlPolygons(), placemark, outerBoundaryIs);
						}
					}
				}
			} else if (geometry instanceof LineString) {
				LineString lineString = (LineString) geometry;
				List<Coordinate> coordinates = lineString.getCoordinates();
				if (coordinates != null) {
					coordinates = ((LineString) geometry).getCoordinates();
					addLineStringToList(kmlData.getKmlLines(), coordinates, placemark);
				}
			} else if (geometry instanceof Point) {
				Point point = (Point) geometry;
				List<Coordinate> coordinates = point.getCoordinates();
				if (coordinates != null) {
					coordinates = ((Point) geometry).getCoordinates();
					addPointToList(kmlData.getKmlPoints(), coordinates, placemark);
				}
			} else if (geometry instanceof MultiGeometry) {
				List<Geometry> geometries = ((MultiGeometry) geometry).getGeometry();
				for (Geometry geometryToMult : geometries) {
					Boundary outerBoundaryIs;
					List<Coordinate> coordinates;
					if (geometryToMult instanceof Point) {
						coordinates = ((Point) geometryToMult).getCoordinates();
						addPointToList(kmlData.getKmlPoints(), coordinates, placemark);
					} else if (geometryToMult instanceof LineString) {
						coordinates = ((LineString) geometryToMult).getCoordinates();
						addLineStringToList(kmlData.getKmlLines(), coordinates, placemark);
					} else if (geometryToMult instanceof Polygon) {
						outerBoundaryIs = ((Polygon) geometryToMult).getOuterBoundaryIs();
						addPolygonToList(kmlData.getKmlPolygons(), placemark, outerBoundaryIs);
					}
				}
			}
		}
	}
	
	/**
	 *	 保存面状数据
	 * 
	 * @param kmlPolygonList  已有面状数据
	 * @param placemark       placemark对象
	 * @param outerBoundaryIs 面状信息
	 */
	private void addPolygonToList(List<KmlPolygon> kmlPolygonList, Placemark placemark, Boundary outerBoundaryIs) {
		LinearRing linearRing = outerBoundaryIs.getLinearRing();// 面
		KmlPolygon kmlPolygon = new KmlPolygon();
		kmlPolygon.setPoints(linearRing.getCoordinates());
		kmlPolygon.setName(placemark.getName());
		kmlPolygon.setDescription(placemark.getDescription());
		kmlPolygonList.add(kmlPolygon);
	}
	/**
	 * 保存线状数据
	 * 
	 * @param kmlLineList 已有线状数据
	 * @param coordinates 线状经纬度数据
	 * @param name        线状名称
	 */
	private void addLineStringToList(List<KmlLine> kmlLineList, List<Coordinate> coordinates, Placemark placemark) {
		KmlLine kmlLine = new KmlLine();
		kmlLine.setPoints(coordinates);
		kmlLine.setName(placemark.getName());
		kmlLine.setDescription(placemark.getDescription());
		kmlLineList.add(kmlLine);
	}
	/**
	 * 保存点状数据
	 * 
	 * @param kmlPointList 已有点状数据
	 * @param coordinates  点状经纬度数据
	 * @param name         点状名称
	 */
	private void addPointToList(List<KmlPoint> kmlPointList, List<Coordinate> coordinates, Placemark placemark) {
		KmlPoint kmlPoint = new KmlPoint();
		kmlPoint.setName(placemark.getName());
		kmlPoint.setDescription(placemark.getDescription());
		kmlPoint.setPoints(coordinates);
		kmlPointList.add(kmlPoint);
	}

}

        在定义了上述的代码之后,基本就可以实现了纯Java对KML文件的解析。下一节将调用上面的代码进行相应文件的解析。

三、KML文件的解析

        本节将重点介绍如何解析KML文件。

1、KML解析测试

package com.yelang.kmzcase;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.io.WKTWriter;
import de.micromata.opengis.kml.v_2_2_0.Coordinate;
import de.micromata.opengis.kml.v_2_2_0.Kml;
import java.io.*;
import com.vividsolutions.jts.geom.*;
public class KMZParser {
	public static void parseKml() throws IOException {
		ParsingKmlUtil parsingKmlUtil = new ParsingKmlUtil();
		File file = new File("C:/BaiduDownload/美军基地-地图数据(kmz)/美空军基地 - 副本/US-AFB.KML"); // 文件地址自己修改
		KmlData kmlData = parsingKmlUtil.parseKmlByFile(file);
		// assert kmlData != null;
		if (kmlData.getKmlPoints().size() > 0) {
			for (KmlPoint k : kmlData.getKmlPoints()) {
				GeometryFactory geoFactory = new GeometryFactory();
				Coordinate coord = k.getPoints().get(0);
				com.vividsolutions.jts.geom.Coordinate jtCoord = new com.vividsolutions.jts.geom.Coordinate(coord.getLongitude(), coord.getLatitude(), coord.getAltitude());
				// 使用GeometryFactory创建一个点
		        Geometry point = geoFactory.createPoint(jtCoord);
				WKTWriter writer = new WKTWriter();
				String wkt = writer.write(point);
				System.out.println(k.getPoints() + "\t"+ wkt  +"\t"+ k.getDescription() + "\t  " + k.getName());
			}
		}
	}
	// 使用示例
	public static void main(String[] args) throws IOException {
		KMZParser.parseKml();
	}
}

        由于在XML中的坐标是一个数组,如果想把这些数据保存到空间数据库中,需要进行格式转换,比如从WKT字符串转为Geometry。当然,保存到空间数据库中,有很多种方法,这里我们介绍一种,基于JTS的方式构建WKT字符串,因为在MyBatis-Plus中,可以直接操作WKT字符串。将坐标转换WKT字符串的方法如下:

com.vividsolutions.jts.geom.Coordinate jtCoord = new com.vividsolutions.jts.geom.Coordinate(coord.getLongitude(), coord.getLatitude(), coord.getAltitude());
// 使用GeometryFactory创建一个点
Geometry point = geoFactory.createPoint(jtCoord);
WKTWriter writer = new WKTWriter();
String wkt = writer.write(point);

        在控制台中执行以上方法可以看到以下信息的输出,说明KML文件解析成功。

[-80.04089,32.89856]	POINT (-80.04089 32.89856)	Airport	  CHARLESTON AFB/INTL 查尔斯顿空军基地/国际机场
[-110.88226,32.16522]	POINT (-110.88226 32.16522)	Airport	  DAVIS-MONTHAN AFB 戴维斯-蒙森空军基地
[-110.34393,31.58844]	POINT (-110.34393 31.58844)	Airport	  LIBBY AAF/SIERRA VISTA MUN 利比空军基地/谢拉维斯塔
[-98.49243,33.98621]	POINT (-98.49243 33.98621)	Airport	  SHEPPARD AFB/WICHITA FALLS MUN 谢泼德空军基地/威奇托福尔斯??
[-72.52899,42.19849]	POINT (-72.52899 42.19849)	Airport	  WESTOVER ARB/METROPOLITAN 韦斯特欧弗空军基地
[-84.04541,39.82544]	POINT (-84.04541 39.82544)	Airport	  WRIGHT-PATTERSON AFB 赖特-帕特森空军基地
[-84.07013,39.80072]	POINT (-84.07013 39.80072)	Airport	  WRIGHT-PATTERSON AFB 赖特-帕特森空军基地

2、KMZ解析测试

        网上很多博客都只讲了如何解析KML,但是对于KMZ的解析介绍比较少,以JAVA为开发语言解析更少了。上面的方法也只实现了KML的解析,如果把文件换成KMZ,肯定会报错的。不信来试试。错误信息如下:

         如果发生了以上的异常,不要急。发生这个异常的原因其实在文章的开头就讲过了。如果看到这里前面没有印象的,可以翻到前面去看一下。还是简单说明一下吧,主要是KMZ是KML的压缩包,而以上代码是KML的解析,没有对KMZ进行解压。这里有两种方法来实现,第一种是将KMZ文件进行解压,然后对解压后的文件解析,肯定没问题。第二种是在压缩包中读取,然后对压缩流信息进行解析。第一种方式会增加不必要的脏文件,第二种则不会,因为原始文件只有一个。 下面我们采用第二种实现方式,首先来定义一个处理接口(必须要):

package com.yelang.kmzcase;
import java.io.IOException;
import java.io.InputStream;
/**
 * kml转换类,用于实现kml的自定义识别与读取
 * @author 夜郎king
 */
public interface IKMLParser {
	/**
	 * @param kmlInputStream
	 * @throws IOException
	 */
	void parseKML(InputStream kmlInputStream) throws IOException;
}

        然后再定义针对KMZ的内容解析代码(基于在线解压的方式),然后已输入流的方式完成内容解析,这个代码网上比较少,如果需要KMZ文件解析,可以作为参考:

public static void parseKMZFile(File kmzFile, IKMLParser kmlParser) throws IOException {
		try (InputStream fileInputStream = new FileInputStream(kmzFile);
				ArchiveInputStream archiveInputStream = new ZipArchiveInputStream(fileInputStream)) {

			ArchiveEntry entry;
			while ((entry = archiveInputStream.getNextEntry()) != null) {
				String name = entry.getName();
				if (name.toLowerCase().endsWith(".kml") || name.toLowerCase().endsWith(".kmz")) {
					// 如果发现.kml或.kmz文件,可以将其内容读取出来并传递给KMLParser处理
					kmlParser.parseKML(archiveInputStream);
				}
			}
		}
	}

	public static void parseKmz() throws IOException {
		File kmzFile = new File("C:/BaiduDownload/美军基地-地图数据(kmz)/美国全球基地.kmz");
		KMZParser.parseKMZFile(kmzFile, new IKMLParser() {
			@Override
			public void parseKML(InputStream kmlInputStream) throws IOException {
				// 在这里实现你的KML解析逻辑
				// 例如,可以将读取的KML内容转换为字符串
				try (BufferedReader reader = new BufferedReader(new InputStreamReader(kmlInputStream))) {
					String line;
					StringBuffer xmlContent = new StringBuffer(1024);
					while ((line = reader.readLine()) != null) {
						// 处理每一行KML数据
						xmlContent.append(line);
					}
					// System.out.println(xmlContent);
					Kml kml = Kml.unmarshal(xmlContent.toString());
					ParsingKmlUtil pku = new ParsingKmlUtil();
					KmlData kmlData = pku.getByKml(kml);
				if (null != kmlData.getKmlPoints()&&kmlData.getKmlPoints().size() > 0) {
						for (KmlPoint kp : kmlData.getKmlPoints()) {
							GeometryFactory geoFactory = new GeometryFactory();
							Coordinate coord = kp.getPoints().get(0);
							com.vividsolutions.jts.geom.Coordinate jtCoord = new com.vividsolutions.jts.geom.Coordinate(coord.getLongitude(), coord.getLatitude(), coord.getAltitude());
							// 使用GeometryFactory创建一个点
					        Geometry point = geoFactory.createPoint(jtCoord);
							WKTWriter writer = new WKTWriter();
							String wkt = writer.write(point);
							System.out.println(kp.getPoints() + "\t"+ wkt  +"\t"+ kp.getDescription() + "\t  " + kp.getName());
						}
						System.out.println("美军全球基地的数据是==>" + kmlData.getKmlPoints().size());
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});
	}

        上述代码的主要逻辑是,使用compress对KMZ文件进行在线解压,然后动态拼接KML内容,最后解析KML文件,然后提取空间信息。经过上述步骤,完成信息的解析。在运行以上的代码,发现KMZ文件已经成功解析。

        至此已经完成KMZ和KML文件的解析。 

四、总结

        以上就是本文的主要内容,本文主要讲解如何用JAVA语言,直接解析KMZ数据。文章首先介绍google地图中的KMZ和KML数据,然后使用代码的方式实现数据的解析,最后展示解析成果以及如何将数据转换成空间WKT数据。关于JAVA解析KML的博客和资料有不少,但是KMZ文件的还是比较稀少的,算是作为网文的一种补充,供各位朋友在工作中解析KMZ文件有一个参考。行文仓促,定有不足之处,欢迎各位朋友在评论区批评指正,不胜感激。

        博文在编写过程中参考了以下博文:

        1、什么是 KMZ 文件?。

        2、从事地信测绘必须知道的GIS常见数据格式类型,以及数据格式和扩展名汇总。

        3、地理信息地图标记KML与KMZ的区别。

        4、java 生成kml 文件。

        5、Java解析kml文件获取点/线段/多边形面状地图经纬度信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/669381.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络运维的重要性

一、介绍 网络运维&#xff0c;英文名为Network Operations (NetOps)&#xff0c;指的是负责维护和管理企业或组织内部网络设备和系统的团队或个人。网络运维的主要目标是确保网络的稳定运行和高效性能&#xff0c;以满足企业或组织的需求。 网络运维工作涵盖了多个方面&…

5.算法讲解之-二分查找(简单易懂)

1.简介 1.二分查找的思路简单易懂&#xff0c;较难的是如何处理查找过程中的边界条件&#xff0c;当较长时间没写二分查找的时候就容易忘记如何处理边界条件。 2.只有多写代码&#xff0c;多做笔记就不易忘记边界条件 2.算法思路 正常查找都是从头到尾查找一个数字是否在数组中…

WIFI 万[néng]钥匙 v5.0.10/v4.9.80 SVIP版!

WiFi Master Key v5.0.10/v4.9.80 WIFI万[Nng]钥匙APP是一款专业的网络连接工具&#xff0c;设计宗旨在于为用户提供方便快捷的WiFi接入方案。本应用集成了覆盖全国的大量免费WiFi热点信息&#xff0c;确保用户能够在不同地区快速而稳定地连接到互联网。此外&#xff0c;该应用…

UMLChina为什么叒要翻译《分析模式》?

UMLChina受机械工业出版社委托&#xff0c;重新翻译《分析模式》。 Martin Fowler的“Analysis Patterns&#xff0c;Reusable Object Models”&#xff0c;原书出版于1997年&#xff0c;至今为止未出第2版。 2004年&#xff0c;机械工业出版社出版该书中译本《分析模式》。 …

Llama 3-V: 比GPT4-V小100倍的SOTA

大模型技术论文不断&#xff0c;每个月总会新增上千篇。本专栏精选论文重点解读&#xff0c;主题还是围绕着行业实践和工程量产。若在某个环节出现卡点&#xff0c;可以回到大模型必备腔调重新阅读。而最新科技&#xff08;Mamba&#xff0c;xLSTM,KAN&#xff09;则提供了大模…

python猜数字游戏

猜数字游戏 计算机随机产生一个1~100的随机数&#xff0c;人输入自己猜的数字&#xff0c; 计算机给出对应的提示“大一点”&#xff0c;”小一点“或”恭喜你猜对了“&#xff0c;直到猜中为止。 如果猜的次数超过7次&#xff0c;计算机温馨提示“智商余额明显不足” import …

K8s(Kubernetes)常用命令

大家好&#xff0c;当谈及容器编排工具时&#xff0c;Kubernetes&#xff08;常简称为K8s&#xff09;无疑是当今最受欢迎和广泛使用的解决方案之一。作为一个开源的容器编排平台&#xff0c;Kubernetes 提供了丰富的功能&#xff0c;可以帮助开发人员和运维团队管理、部署和扩…

能耗监测系统在上海交通大学闵行校区理科实验楼群的设计与应用

引言 建筑能耗系统&#xff0c;除了基本的电力参数监测、配电系统的运行状况&#xff0c;更加关注能耗的去向。除了常规的园区楼层出线电能计量&#xff0c;还会涉及水&#xff0c;气等能耗计量。 针对上海交通大学闵行校区理科实验楼群能耗监测系统的具体要求&#xff0c;以…

小熊家务帮day8-day9 客户管理模块2 (用户定位,地址簿,实名认证,银行卡信息上传等功能)

客户管理模块 0.用户定位功能0.1 需求0.2 接口分析0.3 接口开发Controller层开发Service层开发 1.我的地址簿功能1.1 需求1.2 数据库设计1.3 新增地址簿1.3.1 接口设计1.3.2 接口开发Controller层开发Service层开发测试功能 1.4 地址簿查询1.4.1 接口设计1.4.2 接口开发Control…

游戏主播到底是为游戏宣传还是蹭游戏带来的热度

易采游戏网6月1日最新消息&#xff1a;近日知名游戏主播周淑怡在社交平台上发表了自己对《地下城与勇士》手游(简称DNF手游)的点评。作为一款拥有庞大粉丝基础的端游改编作品&#xff0c;DNF手游自发布以来便受到了广泛关注。而周淑怡的点评不仅聚焦于游戏体验本身&#xff0c;…

visual studis 安装教程

1、下载软件 2、直接安装。根据自己的需求选择需要的模板类型。 如果是.net环境&#xff0c;可以选择.net项目&#xff1b; 如果是c环境&#xff0c;可以选择c项目模板&#xff0c;多个模板可以同时并存。 3、选择C模板&#xff0c;然后重新启动项目。 我是小路&#xff0c;一枚…

Flutter基础 -- Dart 语言 -- 列表集合枚举

目录 1. 列表 List 1.1 初始 1.2 声明 1.2.1 自动 1.2.2 定长 1.2.3 生成数据 1.3 属性 1.4 方法 1.4.1 添加 1.4.2 查询 1.4.3 删除 1.4.4 Range 1.4.5 洗牌 1.4.6 排序 1.4.7 复制子列表 1.4.8 操作符 2. 集合 Map 2.1 初始 2.2 声明 2.2.1 松散 2.2.2 …

7、架构-架构的安全性

即使只限定在“软件架构设计”这个语境下&#xff0c;系统安全仍然是一 个很大的话题。我们谈论的计算机系统安全&#xff0c;不仅仅是指“防御系统 被黑客攻击”这样狭隘的安全&#xff0c;还至少应包括&#xff08;不限于&#xff09;以下这些问 题的具体解决方案。 认证&am…

小白教你搭建测试环境(docker部署版)

如何使用docker创建多数据库端口&#xff08;云服务器版&#xff09; 背景&#xff1a; 需要搭建一个测试环境&#xff0c;同时还需要不同的端口映射mysql端口。那么我采用的docker拉取mysql镜像&#xff0c;通过宿主机和docker容器端口映射完成。 准备一台云服务器服务器安装…

[书生·浦语大模型实战营]——训练自己的小助手认知+应用部署到 OpenXLab+复现多模态微调

1.训练自己的小助手认知 微调后的回答&#xff1a; 微调前的回答&#xff1a; 2.应用部署到 OpenXLab 上传的自我认知模型 应用部署在OpenXLab&#xff08;比上次部署方便不少&#xff0c;文档写的更清楚了&#xff0c;棒棒&#xff09;,链接如下应用链接 3.复现多模态…

SLAM精度评估—evo

evo是一款用于SLAM轨迹精度的评估工具。核心功能是&#xff08;1&#xff09;能够绘制&#xff08;传感器运动&#xff09;轨迹&#xff0c;&#xff08;2&#xff09;评估估计轨迹与真值&#xff08;ground truth&#xff09;的误差。evo支持多种数据集的轨迹格式(TUM、KITT、…

php之文件操作代码审计

1 PHP文件操作函数 1.1 PHP文件操作函数 文件包含 include/require/include_once/require_once 文件读取 file_get_contents/fread/readfile/file 文件写入 file_put_contents/fwrite/mkdir/fputs 文件删除 unlink/rmdir 文件上传 move_uploaded_file/copy/rename 1.2 文…

Error CREATEing SolrCore ‘new_core‘ Unable to create core [new_core]

Error CREATEing SolrCore new_core: Unable to create core [new_core] Caused by: Cant find resource solrconfig.xml in classpath or F:\Document_Solr.apache.org\solr-8.11.3\server\solr\new_core

VHDL/CPLD硬件描述语言:2022年做的万年历实验

之前接触过一些硬件描述语言以及VHDL/CPLD的单片机的设计实验&#xff0c;那时是2022年了 这里补写一篇笔记,以记录一下那十多个小时 万年历实验 研究中的心得体会&#xff1a; 说明解释都是个人理解&#xff0c;与标准描述有较大出入...... 目录 输入输出器件的编写: 分频器…

年中汇报季?——一文教会你如何进行数据分析

一、常见的数据分析报告类型 数据分析报告通常可以分为三类&#xff1a;日常分析报告、专题型分析报告和综合性分析报告。前两者是以数据结论建议的格式去撰写&#xff0c;综合性分析报告则是&#xff1a;行业环境调研&#xff08;竞品类产品数据分析&#xff09;自身产品数据…