当前位置: 首页 > news >正文

矢量篇 - KMLKMZ转SHP

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

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

image
image

用python的话,关键点就是对description字段的处理
import xml.etree.ElementTree as ET
import os
from osgeo import ogrdef 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]  # 截取完整 tabletry:# 使用 XML 解析器解析 HTML 表格root = ET.fromstring(html_content)# 如果根节点不是 <table>,尝试找子节点中的 <table>if root.tag != 'table':table = root.find('.//table')if table is not None:root = tableelse: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].textvalue = tds[0].textif key:  # 确保字段名不为空attr_dict[key.strip()] = value.strip() if value else ''return attr_dictexcept 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}")returnlayer = ds_in.GetLayer(0)srs = layer.GetSpatialRef()  # 获取空间参考# 创建输出 Shapefiledriver = 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 = Noneds_in = Noneprint(f"✅ 转换完成!已将 {len(features_data)} 个要素写入 {out_file}")
插入一个打包的知识点用Nuitka比pyinstaller要好很多,生成的exe要小很多大概是5倍,然后要注意的是pyqt5不太兼容Nuitka

image

http://www.rkmt.cn/news/169.html

相关文章:

  • js空值合并运算符?? - jerry
  • ubuntu上通过kvm新建虚拟机
  • 关于USB 无线 WIF 设备驱动安装的问题
  • Spring Boot常用注解-详细解析+示例 - 指南
  • test
  • linux
  • MAG-GNN: Reinforcement Learning Boosted Graph Neural Network | 代码 |
  • GCFExplainer: Global Counterfactual Explainer for Graph Neural Networks
  • Spring Boot 笔记
  • 使用通义灵码快速生成换装、瘦身程序 #Qwen3-Coder挑战赛# - yi
  • 软件工程第一次作业-tanglei
  • xtrabackup 8.0日常管理
  • 从KPI管理转向更困难的OKR管理的企业都在想什么
  • Day03 课程
  • 【Python】使用matplotlib绘图,显示中文字符。
  • Linux服务器中代码仓库(gitea+drone)搭建
  • IK Multimedia TONEX MAX 1.10.2 逼真音色建模
  • 重塑云上 AI 应用“运行时”,函数计算进化之路
  • 一客一策:Data Agent 如何重构大模型时代的智能营销?
  • MySQL函数
  • 工业主板:工业自动化与智能设备的强大心脏
  • 2025网络赛1 C、D
  • 【URP】Unity Shader Tags
  • 存储器的性能指标 计算机组成原理第三章
  • idea gitee 更新已取消 解决方案
  • 历年 CSP-J/S 数学类真题知识点整理
  • Log4j2 CVE-2021-44228 漏洞复现
  • TeX 的 ctex 宏包的基本用法
  • 原子操作并不能保证数值的准确与一致性
  • mybatis-plus引入