ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

KML/KMZ转Shapefile属性完整保留:原理、操作与避坑指南

KML/KMZ转Shapefile属性完整保留:原理、操作与避坑指南 简介针对ArcGIS中KML/KMZ转Shapefile时属性字段容易丢失的常见问题这份工具包为GIS数据处理人员提供了一套即下即用的解决方案尤其适合经常导入谷歌地球数据、又需要保留非几何属性的制图与分析场景。包内共2个文件主体是一个Python转换脚本可基于GDAL/OGR等开源库完成KML/KMZ到Shapefile的格式转换并同步保留点、线、面要素的原始属性信息另有一个SWF格式的运行说明动画直观演示脚本的调用流程与参数注意事项帮助零基础用户降低上手门槛。整个压缩包仅3MB轻量实用已有2259人学习下载。借助该工具用户可绕过ArcGIS内置转换功能丢属性的限制在转换后继续使用完整的描述性字段开展属性查询、分类符号化及后续空间分析对依赖数据完整性的项目具有明确价值也能减少手工核对与补录属性的额外工作量。1. 这个转换为什么会丢属性从一次野外数据导入开始去年有一回同事把外业采集的几十个土壤采样点导成了带样点编号、采样深度、土质类型和现场备注的 KMZ 文件发给我在 ArcGIS 里转 shapefile。按说这是很常规的操作实际转完一开属性表只剩 Name 和 Description 两个字段Depth、SoilType、备注全没了。跟“谷歌kml/kmz文件转ArcGIS shapefile文件保留属性”这个目标完全对不上。这个丢属性不是玄学而是 KML 和 Shapefile 两种格式在字段表达上的默认行为差异。很多教程只演示“能转出来”却不提属性表里到底还剩什么。本文把这件事拆开讲清楚什么情况下属性会丢、ArcGIS 默认工具能做到哪一步、哪些操作和脚本能把属性完整捞回来以及动手之后才遇得到的坑都在哪里。2. KML/KMZ 的存储结构Placemark 与 ExtendedData 决定了属性去向在动工具之前先把文件结构看明白。KML 是一种 XML 方言Google Earth 导出的 KML 里点、线、面都被包在 Placemark 里。每个 Placemark 又分两大部分Geometry 描述几何坐标属性则存在两个不同的位置。理解了这两个位置你就知道 ArcGIS 默认丢失了哪部分数据。2.1 属性存在 Description 还是 ExtendedData导出结果完全不同KML 里属性字段有两种存放方式。第一种是老的、简单的方式属性内容直接写进description标签用 HTML 表格包裹比如![CDATA[tabletrth采样深度/thtd1.5m/td/trtrth土质类型/thtd黏土/td/tr/table]]。这种写法在 ArcGIS 里经常被当成一个长文本字段处理结果就是属性表里多一条叫 Description 的长字符串所有自定义属性全挤在一格里字段是有一堆但根本不能按列分析。第二种是规范的结构化方式用ExtendedData下的Data name采样深度value1.5m/value/Data存放属性。这才是转换时应该读取的来源。问题在于 ArcGIS 对 ExtendedData 的解析并不彻底它默认只读一部分基础字段自定义的 Data 节点经常被忽略。为什么要先搞清这两种写法因为你的 KML 可能来自其他工程软件、外业 APP 或别人的二次导出属性到底存在哪直接决定你该用默认工具还是脚本方案。我一般建议先拿文本编辑器打开 KML 看前几十行搜索一下Data name和ExtendedData节点出现的密集程度。如果一整份文件里一个Data name都搜不到那就算用对了转换工具属性表也是空的——因为源头 KML 本身就没有结构化属性只有 HTML 表格。2.2 KMZ 是压缩包图层结构会影响转换后的文件层级KMZ 本质上是 ZIP 压缩包内部通常有一个主文档 doc.kml可能还带图片、地面叠加层。Google Earth 导出时可以同时打多个图层进去这个内部结构对 ArcGIS 的转换逻辑影响很大。两个实际影响需要留意转换工具读到的不是单层数据而是压缩包内的 doc.kml。如果 KMZ 内部有多个 Folder 图层ArcGIS 的“KML 转图层”工具会按图层名生成多个要素类分别放到文件地理数据库里。附件类内容比如点位的现场照片会被放到独立的附件结构里默认不会直接出现在 shapefile 字段中。所以遇到一个 KMZ 转出多个要素类的情况不必怀疑工具出错这是正常的图层层级映射。后面第 5.5 条会展开讲如何合并。2.3 Shapefile 的字段先天限制dbf 受限的中文与长度接下来看目的地 Shapefile。属性存储在 .dbf 文件里这是一个很老的格式有几个先天性约束字段名最大支持 10 个字符且通常不支持中文字段名。ArcGIS 里用中文命名字段导出时经常被转义或截断成乱码。字段个数有限制部分环境上限 255 个超过会报错或截断。dbf 单条记录长度约 4000 字节部分工具实现里上限更低。这就是为什么经常有人抱怨“KML 里明明有 30 个属性字段转了 shapefile 之后断断续续丢了一堆”。不是 KML 读不出来是 dbf 装不下。理解了这两头文件格式的差异下面配置参数时你就能知道哪些设置是必须调的。3. ArcGIS 转 Shapefile 的完整操作从 KML 转图层到要素转 Shapefile3.1 工具位置与三个必调参数ArcGIS Desktop 和 ArcGIS Pro 的工具位置不同DesktopArcToolbox 转换工具 从 KML 转出 KML 转图层ArcGIS Pro工具箱 转换工具 KML 转图层工具全名是KMLToLayer_conversion作用是把 KML/KMZ 转换成文件地理数据库中的要素类。然后再用导出工具把要素类转成 shapefile。关键参数有三个参数作用推荐设置输入 KML/KMZ 文件直接选择 KMZ 或 KML 文件KMZ 不必先解压工具能直接读输出文件夹存放中间文件地理数据库的目录建议单独建临时目录比如 C:/gisdata/temp便于清理输出要素类名称生成的要素类名称建议用英文例如 soil_points避免后续路径中文问题这里有个容易误解的点有人以为“输出文件夹”直接选一个包含 .shp 文件的目录执行完就能拿到 shapefile结果工具只生成了一堆 .gdb 和要素类压根没看到 .shp。原因是这个工具的输出是地理数据库要素类不是 shapefile。你要把它当作中间的“几何与基础字段提取层”后面再二次导出。3.2 输出要素类里到底保留哪些字段按默认方式执行 KML 转图层之后打开属性表通常能看到这些字段NamePlacemark 的名称DescriptionHTML 描述文本几何字段按要素类型显示为点、线、面如果有 TimeSpan 相关标签可能生成时间字段如果源 KML 用了 ExtendedData 标签ArcGIS 默认只会把一部分读出来。在部分版本里它会自动创建一个叫DataName或类似结构的字段来承接但不会把所有 Data 子节点都展平成独立列。所以如果你的需求是“保留全部属性”只靠界面工具一步到位是不可能的后面一定要走脚本或字段规整流程。3.3 二次导出 Shapefile 时不能跳过的一步中间要素类转 shapefile一般用 ArcToolbox 中的“要素转 Shapefile”工具FeatureClassToShapefile_conversion或者右键图层导出。为什么不能省这一步因为 ArcGIS 的原生 KML 解析停留在要素类层面无法直接输出 .shp必须经过一次导出。二次导出时注意两个问题坐标系KML 的坐标是 WGS84 经纬度EPSG:4326导出 shapefile 后默认也是这个坐标系。如果后续要转投影坐标应该用“投影”工具单独做不要直接在导出时乱选坐标系否则几何位置会偏移。字段映射要素转 Shapefile 会按字段名“尽量映射”遇到长度超标的字段名会自动截断。界面上不会有提示你得到 .shp 之后再打开属性表才会发现字段名变了。4. 用脚本补回属性ArcPy 解析 ExtendedData 与字段合并方案默认工具流程可以保住几何和基础字段但 ExtendedData 里的自定义属性经常漏。这里给出两条稳定路线先用 XML 解析把属性节点抠出来再用 ArcPy 把默认转换结果和属性表合并。4.1 自己解析 KML从 XML 里把 Data 节点抠出来KML 本质是 XML属性提取在 Python 里用内置的xml.etree.ElementTree就能做到。关键是正确处理命名空间。import xml.etree.ElementTree as ET kml_file C:/gisdata/input.kml ns {k: http://www.opengis.net/kml/2.2} tree ET.parse(kml_file) root tree.getroot() records [] for placemark in root.iter({%s}Placemark % ns[k]): name_el placemark.find(k:name, ns) name name_el.text if name_el is not None else row {name: name} # 提取 ExtendedData 下每个 Data 节点的属性名与值 for data in placemark.findall(k:ExtendedData/k:Data, ns): attr_name data.get(name, field_{}.format(len(row))) value_el data.find(k:value, ns) row[attr_name] value_el.text if value_el is not None else records.append(row) # 输出前几条人工确认字段完整性 for r in records[:5]: print(r)逻辑说明命名空间k对应 KML 2.2 标准findall里的路径写法是k:ExtendedData/k:Data中间层级不能省略否则找不到节点Data节点的name属性是最终字段名value子节点的文本是属性内容。参数说明如果字段特别多建议把records转成 pandas DataFrame 再写出 csv这样后面 ArcPy 合并时不容易出错。另外个别 KML 是 Google Earth 老版本导出的命名空间可能是http://www.google.com/kml/2.0解析时要把 ns 字典改成对应值。4.2 用 ArcPy 把默认转换结果和属性表合并另一种方式是用 ArcPy 调用转换工具然后把自己解析出的属性表以 Name 为关联键 JOIN 到要素类上。import arcpy import os kmz_path C:/gisdata/sample.kmz out_folder C:/gisdata/gdb_out fc_name extracted_points # 第一步KML 转图层生成的 gdb 路径通常是 输出文件夹/要素类名称.gdb arcpy.KMLToLayer_conversion(kmz_path, out_folder, fc_name) intermediate_gdb os.path.join(out_folder, fc_name .gdb) fc_path os.path.join(intermediate_gdb, fc_name, fc_name) # 第二步把外部解析得到的 attr.csv 加进内存 attr_csv C:/gisdata/attrs.csv arcpy.TableToTable_conversion(attr_csv, in_memory, attrs_table) # 第三步按 Name 字段 JOIN arcpy.JoinField_management( fc_path, Name, in_memory/attrs_table, name, [depth_m, soil_type, remark] ) # 第四步直接导出 shapefile arcpy.FeatureClassToShapefile_conversion(fc_path, C:/gisdata/shp_out)逻辑说明KMLToLayer_conversion的输出目录结构是“输出文件夹 要素类名称.gdb 要素类名称子目录”代码里用os.path.join拼接避免手写路径时漏掉层级。第三步 JOIN 时外部 csv 的字段名必须与要素类的 Name 字段值一一对应大小写和首尾空格都会导致关联失败。参数说明TableToTable_conversion与JoinField_management都是 ArcGIS 自带工具不需要额外安装。JOIN 字段列表用 Python 列表传入不要用字符串。如果属性列里有中文列名建议在解析阶段就重命名成英文短名比如 depth_m、soil_type否则后续写 .shp 时 dbf 字段名会被截断。4.3 完全不依赖 ArcGIS 的 GDAL 兜底方案有些环境没有 ArcGIS 许可或者只是临时处理一次数据可以用 GDAL 的 ogr2ogr 做转换。GDAL 默认会把 ExtendedData 展平成 OGR 字段转换属性比 ArcGIS 默认工具更彻底。ogr2ogr -f ESRI Shapefile C:/gisdata/gdal_out.shp C:/gisdata/input.kml -preserve_fid -select Name,Depth,SoilType这条命令的要点-select后面列出的字段名要与 KML 中 Data 节点在 GDAL 映射后的字段名一致不是原始 XML 名称需要先跑一次不带 -select 的命令查看字段列表。不加-select时默认导出全部可识别字段但字段名可能被 GDAL 改写成合法命名方式。KMZ 文件可以直接交给 ogr2ogr 读取不需要手动解压。GDAL 方案的优势是批量处理和投影变换方便但如果你需要跟着 ArcGIS 的图层符号体系走最后还是回到 ArcPy 流程。实际生产中两条路线可以并行输出对比一下字段数就知道有没有漏。5. 避坑排查转换后 5 个高频问题及处理办法5.1 属性全是空值JOIN 外键格式不一致现象KML 转出来的要素类属性表里ExtendedData 相关字段全是 Null或者自己做的属性表 JOIN 之后关联不上。原因最多的是Data节点的name属性里带了不可见字符前面或后面多了一个空格另一个常见原因是 ArcGIS 的 Name 字段区分大小写而外部属性表的 name 字段值是全部小写两边不匹配。解决在解析脚本里统一做清洗对name字段执行strip().lower()对 ArcGIS 的 Name 字段执行strip().lower()。两边都处理之后再 JOIN关联成功率能提上来一大半。5.2 字段名被截断成 10 个字符dbf 规范的限制现象属性表字段名叫 sampling_dpth_m导出 shp 后变成 sampling_dp或者中文名字直接变成乱码。原因Shapefile 的 dbf 字段名上限是 10 字节ArcGIS 在导出时不做智能缩写直接把超长部分砍掉而且不提示。解决在 KML 解析阶段就把字段映射成短英文名比如 depth_m、soil_tp、remark。已经导出的 shp 只能新建字段然后用字段计算器重新赋值这一步属于事后补救数据量大时会比较耗时间。“字段计算器只保留前几位”这种操作原理相通但改字段名这种事最好在前面解决。5.3 面要素的“内洞”消失坐标环方向约定不一致现象一个带湖泊岛屿的多边形转成 shapefile 后内环洞不见了整个面被“填满”。原因KML 与 Shapefile 对面要素坐标环的方向约定不完全一致。KML 默认外环逆时针、内环顺时针部分导出工具生成的 KML 恰好相反。ArcGIS 读入时会依据坐标环方向判断内外环一错就把内环也当作外环的一部分。解决先对比转换前后的要素面积如果面积突然增大明显多半是内环翻转。用 ArcGIS 的“修复几何”工具过一遍检查是否恢复。如果还没恢复只能回到 KML 源文件里调整目标子节点的坐标顺序。5.4 导出 shp 时报错“错误已超过最大记录长度”现象ArcGIS 导出 shp 或者向要素类插入字段时提示“错误已超过最大记录长度”。原因dbf 单条记录长度限制到了。尤其是 Description 里塞了几百字符的 HTML 表格或图片链接再加上字段数量多记录总长度超过 dbf 上限。我见过一个采样点 KML 的 Description 里带了整段多媒体链接转出来记录直接超长。解决转换前先清理长字段。Description 这类长文本能丢就丢或者单独存到另一个表不要让长文本与几十个属性字段挤在同一个 shp 里。如果字段数量精简不掉优先把超长文本用字段计算器截断到安全长度再导出。5.5 KMZ 内包含多个图层转出来文件散落在不同要素类现象一个内含多个 KML 图层Folder的 KMZ转完后获得多个要素类分散在同一个文件地理数据库里命名不直观无法直接得到单一 shp。原因KMZ 的 doc.kml 中 Folder 层级被 ArcGIS 解释为不同图层每个图层生成独立要素类名称取自图层名。解决转换后用arcpy.ListFeatureClasses()先去列出全部要素类确认有哪些再决定是否合并。通用做法是用 Merge 工具把所有要素类合并成一个再导出 shp。但前提是各图层字段结构一致否则合并后字段会互相补空。字段不一致时优先统一字段映射关系再合并。6. 把属性保留做成流程用 ModelBuilder 和脚本固化为批处理工具单次转换通了真正值钱的是把它固化成团队能直接用的一个小工具。我在 ArcGIS Pro 里用 ModelBuilder 把流程串起来输入 KMZ 路径、输出目录、属性 CSV 三个参数模型里放“KML 转图层”和“要素转 Shapefile”两个工具加的“连接字段”操作放在中间跑完直接出带完整属性的 shp。import arcpy import os def kmz_to_shp_preserve_attrs(kmz_path, out_dir): # 防止重复执行时因同名要素类报错 arcpy.env.overwriteOutput True fc_name os.path.basename(kmz_path).split(.)[0] # 第一步KML 转图层 arcpy.KMLToLayer_conversion(kmz_path, out_dir, fc_name) # 第二步定位中间要素类 gdb os.path.join(out_dir, fc_name .gdb) fc os.path.join(gdb, fc_name, fc_name) # 第三步直接导出 shp shp os.path.join(out_dir, fc_name .shp) arcpy.FeatureClassToShapefile_conversion(fc, out_dir) return shp result kmz_to_shp_preserve_attrs(C:/gisdata/sample.kmz, C:/gisdata/out) print(result)这段脚本最核心的是overwriteOutput True不然后续重复执行会卡在“要素类已存在”上。批处理进阶参数方面可以把目标坐标系也放进来导出后用arcpy.Project_management转到 GCJ02 或地方坐标系一次性完成空间参考统一。实际操作里我习惯在这段脚本开头打印arcpy.GetCount_management的统计数量看输入要素数与输出是否一致不一致就不往下走直接肉眼检查中间结果。这几年处理最多的场景就是外业采集数据批量导入内业系统属性这步保住之后后面做符号化、做统计图表都顺了。希望这个流程和避坑记录能帮到你。本文还有配套的精品资源点击获取
返回列表