使用Java實(shí)現(xiàn)KMZ和KML數(shù)據(jù)的直接解析
引言
最近碰到有朋友咨詢,大致的問(wèn)題是,他在項(xiàng)目中要實(shí)現(xiàn)KMZ數(shù)據(jù)的解析和WebGIS的可視化。剛好他用的技術(shù)棧是Java,同時(shí)KMZ的解析在各個(gè)網(wǎng)站上的相關(guān)解析代碼不多。有很多代碼是解析KML的,但是解析KMZ的相對(duì)比較少。一時(shí)沒(méi)有參考的例子,希望能結(jié)合JAVA講一下如何進(jìn)行KMZ數(shù)據(jù)的解析。其實(shí)話說(shuō)回來(lái),雖然大致了解KMZ是什么數(shù)據(jù),但是在之前的項(xiàng)目過(guò)程中,接觸的空間數(shù)據(jù)也基本都是shp、gdb等等,至于google的KMZ還真的是第一回接觸。
本文主要講解如何用JAVA語(yǔ)言,直接解析KMZ數(shù)據(jù)。文章首先介紹google地圖中的KMZ和KML數(shù)據(jù),然后使用代碼的方式實(shí)現(xiàn)數(shù)據(jù)的解析,最后展示解析成果以及如何將數(shù)據(jù)轉(zhuǎn)換成空間WKT數(shù)據(jù)。關(guān)于JAVA解析KML的博客和資料有不少,但是KMZ文件的還是比較稀少的,供各位朋友在工作中解析KMZ文件有一個(gè)參考。
一、關(guān)于KMZ和KML
在進(jìn)行相關(guān)文件的解析之前,首先我們來(lái)看一下KMZ和KML這兩種文件,先了解這兩種文件是什么?用來(lái)做什么的,具體的文件內(nèi)容是什么樣的。本節(jié)主要提供這些基礎(chǔ)知識(shí)的講解。
1、KMZ是什么
KMZ 文件包含主 KML 文件以及0個(gè)或多個(gè)用 ZIP 格式打包成一個(gè)單元的支持文件(稱為歸檔)。然后,KMZ 文件就可以作為單個(gè)實(shí)體進(jìn)行存儲(chǔ)和通過(guò)電子郵件發(fā)送。NetworkLink 可從網(wǎng)絡(luò)服務(wù)器提取 KMZ 文件。將 KMZ 文件解壓縮后,主 .kml 文件及其支持文件便分離成其各自的原始格式和目錄結(jié)構(gòu),以及原始文件名和擴(kuò)展名。除了變成歸檔格式外,ZIP 格式也會(huì)受到壓縮,因此歸檔只能包含一個(gè)大型 KML 文件。根據(jù) KML 文件的內(nèi)容,此過(guò)程通常會(huì)產(chǎn)生10:1的壓縮。10千字節(jié)的 KML 文件可以用1千字節(jié)的 KMZ 文件來(lái)提供。
KMZ是Google Earth默認(rèn)的輸出文件格式,是一個(gè)經(jīng)過(guò)ZIP格式壓縮過(guò)的KML文件,當(dāng)我們從網(wǎng)站上下載KMZ文件的時(shí)候,Windows會(huì)把KMZ文件認(rèn)成ZIP文件,所以另存的時(shí)候文件后綴會(huì)被改成.ZIP,因此需要手動(dòng)將文件后綴改成.KMZ。 KMZ文件用ZIP工具軟件打開(kāi),然后解壓縮即可得到原始KML文件。當(dāng)然,KMZ文件也有自己的好處,就是KMZ文件的自身可以包含影像,這樣就可以不依賴引用網(wǎng)絡(luò)上的截圖。 一般情況下,雙擊KMZ/KML文件即可從Google Earth中打開(kāi)地標(biāo)文件,但是需要注意的是,KMZ/KML地標(biāo)文件名不能包含中文字符,文件存放的路徑也不能有中文字符,否則將無(wú)法在Google Earth中打開(kāi)。
這里我們以漂亮國(guó)的全球基地為說(shuō)明,驗(yàn)證一下上述的內(nèi)容。把KMZ文件的后綴名修改為zip,然后用壓縮文件打開(kāi)。可以看到以下的文件:
總結(jié)一下,KMZ就是把KML文件,進(jìn)行了一個(gè)打包。這個(gè)很重要,在后面的解析過(guò)程中,會(huì)用到這個(gè)知識(shí)點(diǎn)。講完了KMZ,下面介紹一下KML。
2、KML是什么
KML 代表 鑰匙孔標(biāo)記語(yǔ)言。此 GIS 格式基于 XML,主要用于 Google 地球。KML由Keyhole Inc開(kāi)發(fā),后來(lái)被Google收購(gòu).KMZ(KML-Zipped)取代KML成為默認(rèn)的Google地球地理空間格式,因?yàn)樗俏募膲嚎s版本。KML/KMZ于2008年成為開(kāi)放地理空間聯(lián)盟的國(guó)際標(biāo)準(zhǔn)。經(jīng)度和緯度分量(十進(jìn)制度)由 1984 年世界大地測(cè)量系統(tǒng) (WGS84) 定義。垂直分量(高度)以米為單位從 WGS84 EGM96 大地水準(zhǔn)面垂直基準(zhǔn)面開(kāi)始測(cè)量。
KML (keyhole markup language)是以XML語(yǔ)言為基礎(chǔ)開(kāi)發(fā)的一種文件格式,用來(lái)描述和存儲(chǔ)地理信息數(shù)據(jù)(點(diǎn)、線、面、圖片等),是純粹的xml文本格式,可用記事本打開(kāi)編輯,所以kml文件很小。KML跟XML文件最大的不同就是KML描述的是地理信息數(shù)據(jù)。最早開(kāi)發(fā)KML的是keyhole公司,2004年Goole收購(gòu)keyhole并用KML開(kāi)發(fā)GooleEarth。KML是原先的Keyhole客戶端進(jìn)行讀寫(xiě)的文件格式,是一種XML描述語(yǔ)言,并且是文本格式,這種格式的文件對(duì)于Google Earth程序設(shè)計(jì)來(lái)說(shuō)有極大的好處,程序員可以通過(guò)簡(jiǎn)單的幾行代碼讀取出地標(biāo)文件的內(nèi)部信息,并且還可以通過(guò)程序自動(dòng)生成KML文件,因此,使用KML格式的地標(biāo)文件非常利于Google Earth應(yīng)用程序的開(kāi)發(fā)。
這里我們還是以上面的kml文件為說(shuō)明,將打開(kāi)的示例xml文件內(nèi)容展示如下:
<?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 查爾斯頓空軍基地/國(guó)際機(jī)場(chǎng)]]></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>
以上就是一個(gè)KML文件的示例,其主體內(nèi)容就是一個(gè)XML。它以XML為主體,用來(lái)存儲(chǔ)地理空間數(shù)據(jù)。因此對(duì)KML數(shù)據(jù)的解析,其本質(zhì)就是對(duì)XML文件的解析。
二、Java解析實(shí)例
本節(jié)主要以代碼實(shí)戰(zhàn)的方式介紹使用Java編程語(yǔ)言實(shí)現(xiàn)對(duì)KML語(yǔ)言和KMZ語(yǔ)言的解析。由于涉及到xml的解析,這里不采用最原始的dom解析方式。對(duì)于KML語(yǔ)言,有成熟的組件de.micromata.jak.JavaAPIforKml對(duì)KML的解析。這里對(duì)相關(guān)的解析組件進(jìn)行介紹:
序號(hào) | 組件名稱 | 作用 |
1 | de.micromata.jak.JavaAPIforKml | KML文件解析 |
2 | org.apache.commons.commons-compress | 壓縮包解壓 |
3 | com.vividsolutions.jts | JTS wkt字符串構(gòu)建 |
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>試驗(yàn)</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 基類定義
這里進(jìn)行kml 基類定義,將name、description、List<Coordinate>進(jìn)行統(tǒng)一封裝。針對(duì)Point、Polygon、Polyline對(duì)象,在自己的對(duì)象屬性中擴(kuò)展額外的屬性。這里采用OOP的實(shí)現(xiàn)方式。網(wǎng)上很多的代碼沒(méi)有將父級(jí)類抽象出來(lái),同時(shí)其代碼只解析了name。沒(méi)有解析description屬性。這里我們將描述信息同樣解析出來(lái)。關(guān)鍵代碼如下:
package com.yelang.kmzcase; import java.util.List; import de.micromata.opengis.kml.v_2_2_0.Coordinate; /** * kml 基類,將name、description、List<Coordinate>進(jìn)行統(tǒng)一封裝 * @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、空間對(duì)象的定義
空間對(duì)象常見(jiàn)的類型包括點(diǎn)(Point)、線(Polyline)、面(Polygon)三種類型。這里我們將根據(jù)需要定義不同的空間對(duì)象。下面分別給出實(shí)例代碼:
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: 面狀實(shí)體 **/ public class KmlPolygon extends KmlBaseEntity { private String color; public String getColor() { return color; } public void setColor(String color) { this.color = color; } }
4、Kml解析工具類
這里定義Kml的解析工具類,主要負(fù)責(zé)解析KML,然后根據(jù)不同的圖層,將屬性和空間坐標(biāo)點(diǎn)信息賦值給不同的空間數(shù)據(jù)集合。網(wǎng)上有一些解析的代碼,僅解析name屬性。這里擴(kuò)展了其它的屬性,包括描述屬性。詳細(xì)代碼如下:
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對(duì)象轉(zhuǎn)自定義存儲(chǔ)對(duì)象 * * @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節(jié)點(diǎn) * @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); } /** * 解析點(diǎn)線面形狀的數(shù)據(jù)分別放入存儲(chǔ)對(duì)象 * @param placemark placemark對(duì)象 * @param geometry 形狀類型 * @param kmlData 存儲(chǔ)對(duì)象 */ 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); } } } } } /** * 保存面狀數(shù)據(jù) * * @param kmlPolygonList 已有面狀數(shù)據(jù) * @param placemark placemark對(duì)象 * @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); } /** * 保存線狀數(shù)據(jù) * * @param kmlLineList 已有線狀數(shù)據(jù) * @param coordinates 線狀經(jīng)緯度數(shù)據(jù) * @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); } /** * 保存點(diǎn)狀數(shù)據(jù) * * @param kmlPointList 已有點(diǎn)狀數(shù)據(jù) * @param coordinates 點(diǎn)狀經(jīng)緯度數(shù)據(jù) * @param name 點(diǎn)狀名稱 */ 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); } }
在定義了上述的代碼之后,基本就可以實(shí)現(xiàn)了純Java對(duì)KML文件的解析。下一節(jié)將調(diào)用上面的代碼進(jìn)行相應(yīng)文件的解析。
三、KML文件的解析
本節(jié)將重點(diǎn)介紹如何解析KML文件。
1、KML解析測(cè)試
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/美軍基地-地圖數(shù)據(jù)(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創(chuàng)建一個(gè)點(diǎn) 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中的坐標(biāo)是一個(gè)數(shù)組,如果想把這些數(shù)據(jù)保存到空間數(shù)據(jù)庫(kù)中,需要進(jìn)行格式轉(zhuǎn)換,比如從WKT字符串轉(zhuǎn)為Geometry。當(dāng)然,保存到空間數(shù)據(jù)庫(kù)中,有很多種方法,這里我們介紹一種,基于JTS的方式構(gòu)建WKT字符串,因?yàn)樵贛yBatis-Plus中,可以直接操作WKT字符串。將坐標(biāo)轉(zhuǎn)換WKT字符串的方法如下:
com.vividsolutions.jts.geom.Coordinate jtCoord = new com.vividsolutions.jts.geom.Coordinate(coord.getLongitude(), coord.getLatitude(), coord.getAltitude()); // 使用GeometryFactory創(chuàng)建一個(gè)點(diǎn) Geometry point = geoFactory.createPoint(jtCoord); WKTWriter writer = new WKTWriter(); String wkt = writer.write(point);
在控制臺(tái)中執(zhí)行以上方法可以看到以下信息的輸出,說(shuō)明KML文件解析成功
[-80.04089,32.89856] POINT (-80.04089 32.89856) Airport CHARLESTON AFB/INTL 查爾斯頓空軍基地/國(guó)際機(jī)場(chǎng) [-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解析測(cè)試
網(wǎng)上很多博客都只講了如何解析KML,但是對(duì)于KMZ的解析介紹比較少,以JAVA為開(kāi)發(fā)語(yǔ)言解析更少了。上面的方法也只實(shí)現(xiàn)了KML的解析,如果把文件換成KMZ,肯定會(huì)報(bào)錯(cuò)的。不信來(lái)試試。錯(cuò)誤信息如下:
如果發(fā)生了以上的異常,不要急。發(fā)生這個(gè)異常的原因其實(shí)在文章的開(kāi)頭就講過(guò)了。如果看到這里前面沒(méi)有印象的,可以翻到前面去看一下。還是簡(jiǎn)單說(shuō)明一下吧,主要是KMZ是KML的壓縮包,而以上代碼是KML的解析,沒(méi)有對(duì)KMZ進(jìn)行解壓。這里有兩種方法來(lái)實(shí)現(xiàn),第一種是將KMZ文件進(jìn)行解壓,然后對(duì)解壓后的文件解析,肯定沒(méi)問(wèn)題。第二種是在壓縮包中讀取,然后對(duì)壓縮流信息進(jìn)行解析。第一種方式會(huì)增加不必要的臟文件,第二種則不會(huì),因?yàn)樵嘉募挥幸粋€(gè)。 下面我們采用第二種實(shí)現(xiàn)方式,首先來(lái)定義一個(gè)處理接口(必須要):
package com.yelang.kmzcase; import java.io.IOException; import java.io.InputStream; /** * kml轉(zhuǎn)換類,用于實(shí)現(xiàn)kml的自定義識(shí)別與讀取 * @author 夜郎king */ public interface IKMLParser { /** * @param kmlInputStream * @throws IOException */ void parseKML(InputStream kmlInputStream) throws IOException; }
然后再定義針對(duì)KMZ的內(nèi)容解析代碼(基于在線解壓的方式),然后已輸入流的方式完成內(nèi)容解析,這個(gè)代碼網(wǎng)上比較少,如果需要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")) { // 如果發(fā)現(xiàn).kml或.kmz文件,可以將其內(nèi)容讀取出來(lái)并傳遞給KMLParser處理 kmlParser.parseKML(archiveInputStream); } } } } public static void parseKmz() throws IOException { File kmzFile = new File("C:/BaiduDownload/美軍基地-地圖數(shù)據(jù)(kmz)/美國(guó)全球基地.kmz"); KMZParser.parseKMZFile(kmzFile, new IKMLParser() { @Override public void parseKML(InputStream kmlInputStream) throws IOException { // 在這里實(shí)現(xiàn)你的KML解析邏輯 // 例如,可以將讀取的KML內(nèi)容轉(zhuǎn)換為字符串 try (BufferedReader reader = new BufferedReader(new InputStreamReader(kmlInputStream))) { String line; StringBuffer xmlContent = new StringBuffer(1024); while ((line = reader.readLine()) != null) { // 處理每一行KML數(shù)據(jù) 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創(chuàng)建一個(gè)點(diǎn) 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("美軍全球基地的數(shù)據(jù)是==>" + kmlData.getKmlPoints().size()); } } catch (IOException e) { e.printStackTrace(); } } }); }
上述代碼的主要邏輯是,使用compress對(duì)KMZ文件進(jìn)行在線解壓,然后動(dòng)態(tài)拼接KML內(nèi)容,最后解析KML文件,然后提取空間信息。經(jīng)過(guò)上述步驟,完成信息的解析。在運(yùn)行以上的代碼,發(fā)現(xiàn)KMZ文件已經(jīng)成功解析。
至此已經(jīng)完成KMZ和KML文件的解析。
四、總結(jié)
以上就是本文的主要內(nèi)容,本文主要講解如何用JAVA語(yǔ)言,直接解析KMZ數(shù)據(jù)。文章首先介紹google地圖中的KMZ和KML數(shù)據(jù),然后使用代碼的方式實(shí)現(xiàn)數(shù)據(jù)的解析,最后展示解析成果以及如何將數(shù)據(jù)轉(zhuǎn)換成空間WKT數(shù)據(jù)。
到此這篇關(guān)于使用Java實(shí)現(xiàn)KMZ和KML數(shù)據(jù)的直接解析的文章就介紹到這了,更多相關(guān)Java解析KMZ和KML內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IDEA maven compile報(bào)錯(cuò)OutOfMemoryError(內(nèi)存溢出)解決及jvm分析
遇到Maven編譯時(shí)報(bào)OutOfMemoryError錯(cuò)誤通常因?yàn)槟J(rèn)的堆內(nèi)存大小不足,本文就來(lái)介紹一下OutOfMemoryError(內(nèi)存溢出)解決,具有一定的參考價(jià)值,感興趣的可以了解一下2024-10-10Java?SpringBoot集成文件之如何使用POI導(dǎo)出Word文檔
這篇文章主要介紹了Java?SpringBoot集成文件之如何使用POI導(dǎo)出Word文檔,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-08-08mybatis-plus查詢無(wú)數(shù)據(jù)問(wèn)題及解決
這篇文章主要介紹了mybatis-plus查詢無(wú)數(shù)據(jù)問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12Java利用Guava?Retry實(shí)現(xiàn)重處理
guava-retrying是谷歌的Guava庫(kù)的一個(gè)小擴(kuò)展,允許為任意函數(shù)調(diào)用創(chuàng)建可配置的重試策略,比如與正常運(yùn)行時(shí)間不穩(wěn)定的遠(yuǎn)程服務(wù)對(duì)話的函數(shù)調(diào)用。本文將利用其實(shí)現(xiàn)重處理,感興趣的可以了解一下2022-08-08spring boot實(shí)現(xiàn)阿里云視頻點(diǎn)播上傳視頻功能(復(fù)制粘貼即可)
這篇文章主要介紹了spring boot實(shí)現(xiàn)阿里云視頻點(diǎn)播上傳視頻功能(復(fù)制粘貼即可),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12使用springboot整合mybatis-plus實(shí)現(xiàn)數(shù)據(jù)庫(kù)的增刪查改示例
這篇文章主要介紹了使用springboot整合mybatis-plus實(shí)現(xiàn)數(shù)據(jù)庫(kù)的增刪查改示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04