8 changed files with 439 additions and 59 deletions
@ -0,0 +1,25 @@ |
|||
package org.dromara.system.domain.kmz; |
|||
|
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.Map; |
|||
|
|||
@Data |
|||
public class KmzResult { |
|||
|
|||
private String name; |
|||
|
|||
private Map<String, String> attributes; |
|||
|
|||
private String wkt; |
|||
|
|||
public KmzResult(String name, Map<String, String> attributes, String wkt) { |
|||
this.name = name; |
|||
this.attributes = attributes; |
|||
this.wkt = wkt; |
|||
} |
|||
|
|||
public KmzResult() { |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
package org.dromara.system.domain.kmz; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.Map; |
|||
|
|||
|
|||
@Data |
|||
public class Placemark { |
|||
|
|||
private String name; |
|||
private String coordinates; |
|||
private Map<String, String> attributes; |
|||
|
|||
} |
@ -0,0 +1,240 @@ |
|||
package org.dromara.system.utils; |
|||
|
|||
import org.dromara.system.domain.kmz.KmzResult; |
|||
import org.dromara.system.domain.kmz.Placemark; |
|||
|
|||
import java.io.*; |
|||
import java.nio.file.*; |
|||
import java.util.*; |
|||
import java.util.zip.ZipEntry; |
|||
import java.util.zip.ZipInputStream; |
|||
|
|||
/** |
|||
* KMZ文件解析器 |
|||
* KMZ是Google Earth使用的压缩格式,包含KML文件和其他资源 |
|||
*/ |
|||
public class KmzParserUtil { |
|||
|
|||
/** |
|||
* 解析KMZ文件的主方法 |
|||
* |
|||
* @param inputStream KMZ文件的路径 |
|||
* @return 解析结果列表 |
|||
* @throws IOException 如果文件读取或处理过程中发生错误 |
|||
*/ |
|||
public static List<KmzResult> parseKmz(InputStream inputStream) throws IOException { |
|||
// 存储解析出的地标信息
|
|||
List<Placemark> placemarks = new ArrayList<>(); |
|||
// 存储最终结果
|
|||
List<KmzResult> results = new ArrayList<>(); |
|||
|
|||
// 创建临时目录用于解压KMZ文件
|
|||
Path tempDir = Files.createTempDirectory("kmz_parser_"); |
|||
try { |
|||
// 将KMZ文件解压到临时目录
|
|||
extractKmz(inputStream, tempDir.toString()); |
|||
|
|||
// 遍历临时目录,查找并解析所有KML文件
|
|||
Files.walk(tempDir) |
|||
.filter(path -> path.toString().endsWith(".kml")) |
|||
.forEach(path -> { |
|||
try { |
|||
String kmlContent = new String(Files.readAllBytes(path)); |
|||
parseKmlContent(kmlContent, placemarks); |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
}); |
|||
|
|||
// 将解析出的地标信息转换为最终结果格式
|
|||
for (Placemark placemark : placemarks) { |
|||
String wkt = convertToWKT(placemark.getCoordinates()); |
|||
results.add(new KmzResult(placemark.getName(), placemark.getAttributes(), wkt)); |
|||
} |
|||
|
|||
} finally { |
|||
// 清理临时目录
|
|||
deleteDirectory(tempDir); |
|||
} |
|||
|
|||
return results; |
|||
} |
|||
|
|||
/** |
|||
* 解压KMZ文件到指定目录 |
|||
* |
|||
* @param inputStream KMZ文件路径 |
|||
* @param outputDir 输出目录 |
|||
*/ |
|||
private static void extractKmz(InputStream inputStream, String outputDir) throws IOException { |
|||
try (ZipInputStream zis = new ZipInputStream(inputStream)) { |
|||
ZipEntry entry; |
|||
while ((entry = zis.getNextEntry()) != null) { |
|||
Path outputPath = Paths.get(outputDir, entry.getName()); |
|||
|
|||
// 创建必要的父目录
|
|||
Files.createDirectories(outputPath.getParent()); |
|||
|
|||
// 跳过目录条目
|
|||
if (entry.isDirectory()) { |
|||
continue; |
|||
} |
|||
|
|||
// 解压文件内容
|
|||
try (OutputStream out = Files.newOutputStream(outputPath)) { |
|||
byte[] buffer = new byte[1024]; |
|||
int len; |
|||
while ((len = zis.read(buffer)) > 0) { |
|||
out.write(buffer, 0, len); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 递归删除目录及其内容 |
|||
* |
|||
* @param directory 要删除的目录 |
|||
*/ |
|||
private static void deleteDirectory(Path directory) throws IOException { |
|||
Files.walk(directory) |
|||
.sorted(Comparator.reverseOrder()) |
|||
.forEach(path -> { |
|||
try { |
|||
Files.delete(path); |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 解析KML文件内容 |
|||
* |
|||
* @param kmlContent KML文件内容 |
|||
* @param placemarks 存储解析出的地标信息 |
|||
*/ |
|||
private static void parseKmlContent(String kmlContent, List<Placemark> placemarks) { |
|||
String[] lines = kmlContent.split("\n"); |
|||
Placemark currentPlacemark = null; |
|||
boolean inDescription = false; |
|||
StringBuilder descriptionContent = new StringBuilder(); |
|||
|
|||
// 添加调试日志
|
|||
System.out.println("开始解析KML内容,总行数: " + lines.length); |
|||
|
|||
for (String line : lines) { |
|||
line = line.trim(); |
|||
|
|||
if (line.startsWith("<Placemark>")) { |
|||
if (currentPlacemark != null) { |
|||
placemarks.add(currentPlacemark); |
|||
} |
|||
currentPlacemark = new Placemark(); |
|||
System.out.println("发现新的Placemark"); |
|||
} else if (line.startsWith("<name>")) { |
|||
if (currentPlacemark != null) { |
|||
String name = line.replace("<name>", "").replace("</name>", "").trim(); |
|||
currentPlacemark.setName(name); |
|||
System.out.println("解析到名称: " + name); |
|||
} |
|||
} else if (line.startsWith("<description>")) { |
|||
inDescription = true; |
|||
descriptionContent = new StringBuilder(); |
|||
System.out.println("开始解析描述"); |
|||
} else if (line.endsWith("</description>")) { |
|||
inDescription = false; |
|||
if (currentPlacemark != null) { |
|||
String desc = descriptionContent.toString(); |
|||
System.out.println("描述内容: " + desc); |
|||
parseDescription(desc, currentPlacemark); |
|||
} |
|||
} else if (inDescription) { |
|||
descriptionContent.append(line).append("\n"); |
|||
} else if (line.startsWith("<coordinates>")) { |
|||
if (currentPlacemark != null) { |
|||
String coords = line.replace("<coordinates>", "").replace("</coordinates>", "").trim(); |
|||
currentPlacemark.setCoordinates(coords); |
|||
System.out.println("解析到坐标: " + coords); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (currentPlacemark != null) { |
|||
placemarks.add(currentPlacemark); |
|||
} |
|||
|
|||
// 打印解析结果
|
|||
System.out.println("解析完成,共找到 " + placemarks.size() + " 个地标"); |
|||
for (Placemark p : placemarks) { |
|||
System.out.println("地标信息:"); |
|||
System.out.println(" 名称: " + p.getName()); |
|||
System.out.println(" 属性: " + p.getAttributes()); |
|||
System.out.println(" 坐标: " + p.getCoordinates()); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 解析描述内容,提取属性信息 |
|||
* |
|||
* @param description 描述内容 |
|||
* @param placemark 地标对象 |
|||
*/ |
|||
private static void parseDescription(String description, Placemark placemark) { |
|||
System.out.println("开始解析描述内容: " + description); |
|||
String[] lines = description.split("\n"); |
|||
Map<String, String> attributes = new HashMap<>(); |
|||
for (String line : lines) { |
|||
line = line.trim(); |
|||
if (line.contains("\":")) { |
|||
String[] parts = line.split("\":"); |
|||
if (parts.length == 2) { |
|||
String key = parts[0].replace("\"", "").trim(); |
|||
String value = parts[1].replace("\"", "").trim(); |
|||
attributes.put(key, value); |
|||
System.out.println("解析到属性 - 键: " + key + ", 值: " + value); |
|||
} |
|||
} |
|||
} |
|||
|
|||
placemark.setAttributes(attributes); |
|||
} |
|||
|
|||
/** |
|||
* 将坐标字符串转换为WKT(Well-Known Text)格式 |
|||
* |
|||
* @param coordinates 坐标字符串 |
|||
* @return WKT格式的字符串 |
|||
*/ |
|||
public static String convertToWKT(String coordinates) { |
|||
if (coordinates == null || coordinates.trim().isEmpty()) { |
|||
return ""; |
|||
} |
|||
|
|||
// 构建WKT格式的多边形
|
|||
StringBuilder wkt = new StringBuilder("POLYGON(("); |
|||
String[] coordPairs = coordinates.trim().split("\\s+"); |
|||
|
|||
// 处理每个坐标对
|
|||
for (int i = 0; i < coordPairs.length; i++) { |
|||
String[] coords = coordPairs[i].split(","); |
|||
if (coords.length >= 2) { |
|||
wkt.append(coords[0]).append(" ").append(coords[1]); |
|||
if (i < coordPairs.length - 1) { |
|||
wkt.append(", "); |
|||
} |
|||
} |
|||
} |
|||
|
|||
wkt.append("))"); |
|||
|
|||
StringBuffer polygonSb = new StringBuffer("GEOMETRYCOLLECTION("); |
|||
polygonSb.append(wkt); |
|||
polygonSb.append(")"); |
|||
|
|||
return polygonSb.toString(); |
|||
} |
|||
} |
|||
|
|||
|
@ -1,11 +0,0 @@ |
|||
package org.dromara.system.utils; |
|||
|
|||
|
|||
/** |
|||
* 解析ovkmz文件 |
|||
*/ |
|||
public class OvkmzParser { |
|||
|
|||
|
|||
|
|||
} |
Loading…
Reference in new issue