矢量篇 - KML&KMZ转SHP
@ 20240908 & lth
目标:从kml或kmz带属性转成shp
逻辑:主要是对kml的description字段的处理,他的格式是html的


目前我搜了一下没有现成的工具,要想将kml带属性转成shp,我这里工具选的是fme或python
用fme的话,关键点就是StringSearcher转换器,(?<=<td>).+?(?=</td>),然后用AttributeExposer暴露出来把获取的字段


用python的话,关键点就是对description字段的处理
import xml.etree.ElementTree as ET
import os
from osgeo import ogr
def parse_kml_description(html_content):
"""
解析 KML description 字段中的 HTML 表格,提取属性字典。
参数:
html_content (str): 描述字段的 HTML 内容(如 '<table>...</table>')
返回:
dict: 提取的属性字典,例如 {'bh': '40339', 'name': '831774/2023', 'FID': '40338'}
"""
# 尝试修复不完整的 HTML(比如缺少根标签)
if not html_content.strip().startswith('<table'):
# 查找第一个 <table> 开始位置
start = html_content.find('<table')
end = html_content.find('</table>')
if start == -1 or end == -1:
return {}
html_content = html_content[start:end + 8] # 截取完整 table
try:
# 使用 XML 解析器解析 HTML 表格
root = ET.fromstring(html_content)
# 如果根节点不是 <table>,尝试找子节点中的 <table>
if root.tag != 'table':
table = root.find('.//table')
if table is not None:
root = table
else:
return {}
attr_dict = {}
# 遍历所有表格行
for row in root.findall('.//tr'):
ths = row.findall('th')
tds = row.findall('td')
if len(ths) > 0 and len(tds) > 0:
key = ths[0].text
value = tds[0].text
if key: # 确保字段名不为空
attr_dict[key.strip()] = value.strip() if value else ''
return attr_dict
except ET.ParseError as e:
print(f"HTML 解析失败: {e}")
return {}
def convert_kml_to_shp(in_file, out_file):
"""
将 KML 文件转换为 Shapefile,并从 description 中提取嵌套属性。
参数:
in_file (str): 输入 KML 文件路径。
out_file (str): 输出 SHP 文件路径。
"""
# 打开输入 KML 文件
ds_in = ogr.Open(in_file)
if ds_in is None:
print(f"无法打开输入文件:{in_file}")
return
layer = ds_in.GetLayer(0)
srs = layer.GetSpatialRef() # 获取空间参考
# 创建输出 Shapefile
driver = ogr.GetDriverByName('ESRI Shapefile')
# 删除已存在的输出文件(OGR 不会自动覆盖)
if os.path.exists(out_file):
driver.DeleteDataSource(out_file)
ds_out = driver.CreateDataSource(out_file)
if ds_out is None:
print(f"无法创建输出文件:{out_file}")
return
# 获取输入图层定义
layer_defn = layer.GetLayerDefn()
geom_type = layer_defn.GetGeomType()
# 创建输出图层(暂时无字段,后面动态添加)
layer_out = ds_out.CreateLayer('output', srs=srs, geom_type=geom_type)
# 存储已创建的字段名,避免重复创建
created_fields = set()
# === 第一步:遍历所有要素,提取 description 中的所有唯一字段名 ===
print("正在扫描所有要素以提取字段...")
all_attributes = set()
features_data = [] # 临时存储每个要素的 geometry 和属性字典
for feat_in in layer:
desc = feat_in.GetField('description') # 获取 description 字段
if desc is not None:
attrs = parse_kml_description(desc)
all_attributes.update(attrs.keys())
features_data.append({
'geometry': feat_in.GetGeometryRef().Clone(),
'attributes': attrs
})
else:
features_data.append({
'geometry': feat_in.GetGeometryRef().Clone(),
'attributes': {}
})
# === 第二步:根据提取出的所有字段,创建 Shapefile 的字段 ===
print(f"发现以下属性字段: {sorted(all_attributes)}")
for field_name in sorted(all_attributes):
# 检查字段名是否合法(Shapefile 字段名不能太长,且只能用字母数字下划线)
safe_name = field_name.strip()
if not safe_name.isidentifier():
safe_name = ''.join(c if c.isalnum() or c == '_' else '_' for c in safe_name)
if len(safe_name) > 10: # Shapefile 字段名最多 10 字符
safe_name = safe_name[:10]
# 避免重复
if safe_name not in created_fields:
field_defn = ogr.FieldDefn(safe_name, ogr.OFTString)
field_defn.SetWidth(254)
layer_out.CreateField(field_defn)
created_fields.add(safe_name)
# 获取输出图层的要素定义
feat_defn = layer_out.GetLayerDefn()
# === 第三步:写入所有要素 ===
for data in features_data:
feat_out = ogr.Feature(feat_defn)
feat_out.SetGeometry(data['geometry'])
# 填充从 description 中提取的属性
for key, value in data['attributes'].items():
safe_key = key.strip()
if not safe_key.isidentifier():
safe_key = ''.join(c if c.isalnum() or c == '_' else '_' for c in safe_key)
if len(safe_key) > 10:
safe_key = safe_key[:10]
if safe_key in created_fields:
feat_out.SetField(safe_key, value)
layer_out.CreateFeature(feat_out)
feat_out = None # 释放内存
# 清理
ds_out = None
ds_in = None
print(f" 转换完成!已将 {len(features_data)} 个要素写入 {out_file}")
插入一个打包的知识点用Nuitka比pyinstaller要好很多,生成的exe要小很多大概是5倍,然后要注意的是pyqt5不太兼容Nuitka

矢量篇 - KML&KMZ转SHP的更多相关文章
- geoserver源码学习与扩展——kml/kmz转shapefile文件
geoserver通过工作空间Workspace-数据源DataStore-图层Layer管理地理数据,默认只支持shapefile格式的文件发布,不支持kml/kmz.csv的文件格式,所以存在将这 ...
- ArcGIS Earth(原谷歌地球)如何获取高精度矢量地图数据?(shp文件/要素类/kml)
大家好,这次来分享干货.做地理分析的同学,或者需要使用地图却不知道哪里有矢量数据的时候,怎么办呢? 这次,我就告诉大家哪里能自己手工制作矢量点线面数据!注意哦,是自己绘制的. 使用到的软件: ArcG ...
- ArcGIS学习记录—KMZ KML与SHP文件互相转换
1.在google earth中绘制边界 工具栏中选择"Add Polygon".随意绘制一个多边形. 右击添加的图层名(左侧)保存位置为,选择保存为kmz或kml文件. ...
- arcgis api 3.x for js 入门开发系列批量叠加 zip 压缩 SHP 图层优化篇(附源码下载)
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- ArcGIS中KML转为shp文件
问题:如何将KML转为shp文件? 方法: 1.打开ArcMap -> ArcToolbox: 2.在ArcToolbox中选择“转换工具”-> “由KML转出” -> “KML转图 ...
- cesium 之图层管理器篇(附源码下载)
前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. 内 ...
- GADL针对矢量数据格式转换的实用工具 —— ogr2ogr
最初,因为可爱的学弟请教如何将ESRI Shapefile文件导入Google Earth接触到了Ogr2Ogr.粗略了解之后发现,这小东西功能强大. 谷歌地球支持矢量数据的展示,前提是数据符合KML ...
- ArcGIS 网络分析[1.2] 利用1.1的线shp创建网络数据集/并简单试验最佳路径
上篇已经创建好了线数据(shp文件格式)链接:点我 这篇将基于此shp线数据创建网络数据集. 在此说明:shp数据的网络数据集仅支持单一线数据,也就是说基于shp文件的网络数据集,只能有一个shp线文 ...
- Qt+QGis二次开发:加载栅格图层和矢量图层
一.加载栅格图像 加载栅格图像的详细步骤在下面代码里: //添加栅格数据按钮槽函数 void MainWindow::addRasterlayers() { //步骤1:打开文件选择对话框 QStri ...
- 解析KML文件并提取coordinates中的经纬度坐标信息
从googleEarh导出的kml文件 <?xml version="1.0" encoding="UTF-8"?><kml xmlns=&q ...
随机推荐
- Linux 查找Redis配置信息
前言 有时在使用Redis时密码或者配置信息经常忘记,应该怎么找回呢? 解决 如果设置了自启动,先查找服务状态(systemctl status redis服务名称) 根据服务可以找到服务的启动脚本, ...
- java--Hibernate关联映射
hibernate 程序执行流程 集合映射 User.java public class User { private int userId; private String userName; // ...
- Hive与Clickhouse对比
个人理解,欢迎指正 对比指标 Hive Clickhouse 元数据管理 元数据存MySQL,通过HiveMetaStore管理 每个Shard自己管理 数据存储 HDFS 本地磁盘 架构设计 MR架 ...
- 解决了AI聊天的10个痛点后,我又做了一个新功能:交叉分析表
前言 不久前,我写了一篇长文,吐槽了当前 Web 和桌面端 AI 聊天工具的 10 个体验问题.从"找不到几周前绝妙点子"的全局检索缺失,到"置顶所有等于没置顶" ...
- sass 定义全局变量
定义变量文件 随便写一个scss文件,比如在 src/assets/var.scss $my-color: #00b96b; 打包工具配置 不同工具 如webpack.vite有不同的处理方式加载到全 ...
- 前端开发系列111-工程化篇之Yeoman脚手架工具使用入门
Yeoman是一款流行的前端的脚手架工具. 脚手架工具可以用来快速的自动生成项目的必要文件和基础文件结构.Yeoman使用的内建命令为yo,同时它自己也是一个包管理工具和自动化任务工具,它基于特定的模 ...
- 转载的 linux 下的搜狗拼音问题
转载自http://blog.csdn.net/jilijelon/article/details/53759965 炎热的夏日 拼音问题搞的我很烦躁 之前一段时间正常使用的搜狗输入法突然无法输出中 ...
- LInux main.cpp 编码问题 导致影响后面的内容
euc-cn linux 的vim 可以查看和设置编码 :set fileencoding euc-cn 表示的是 gbk编码 1.在Vim中直接进行转换文件编码,比如将一个文件转换成utf-8格式 ...
- Maui 实践:用 Channel 实现数据库查询时读取速度与内存占用的平衡
我们在进行数据库查询时,通常并不是为了取得整个表的数据,而是某些符合过滤条件的记录.比如: var unassociatedSudokus = await _dbContext.DbSudokus . ...
- FFmpeg开发笔记(七十五)使用qrencode和quirc对视频画面读写二维码
上一篇文章<Windows给FFmpeg集成二维码图像的编解码器>介绍了给FFmpeg集成二维码的编解码器qrencode和quirc,接下来讲解如何利用编码器qrencode向视频画面添 ...