您的位置:首页 > 编程语言 > Python开发

[ArcPy] 使用Python脚本实现kml转shp文件

2017-09-23 19:42 706 查看
涉及内容:ArcPy操作shape文件;python2解析xml文档

实验课中需要kml文件转shp文件

ArcGIS Desktop工具箱中有 “kml转图层” 与 “要素类转shp”两个工具,我们可以利用这两个工具制作一个模型,这个比较简单

因为小生最近接触ArcPy,所以想用Python在文件转换的角度进行转换

相关文件下载: http://download.csdn.net/download/summer_dew/9992151

若要运行此示例需要在Python2安装BeautifulSoup模块 点我

BeautifulSoup解析XML文档
读取文档

查找标签

获得标签里的数据

ArcPy操作shp文件

完整代码

详细 为脚本创建工具箱

注意

BeautifulSoup解析XML文档

读取文档

# 打开kmlFilePath文件('r'只读)
openKmlFile = open(kmlFilePath,"r")
# 读取到文件中文本
kmlDom = openKmlFile.read()
# 解析字符串,返回一个BeautifulSoup的对象
bsObj = BeautifulSoup(kmlDom,"html.parser")
#关闭文本
openKmlFile.close()


查找标签

bsObj.findAll("<body>") #返回bsObj里的所有<body>标签
bsObj.find("<body>") #返回bsObj里的第一个<body>标签


获得标签里的数据

bsObj.find("<body>").get_text()


ArcPy操作shp文件

# 输出地址
outPath = r"F:\study\school\analyze\lab1\workspace\polygon.shp"
# 获取shape文件保存的地址
outWorkspace = os.path.split(outPath)[0]
# shape文件保存的名字
shpName = os.path.split(outPath)[-1]
# 坐标系
spat_ref = "4326"
# 创建shape文件
gp.CreateFeatureClass_management(outWorkspace,shpName,featureType,"","","",spat_ref)
# 创建字段
gp.addfield(outPath, "NAME", "text", "", "", "100")
gp.addfield(outPath, "DESCR", "text", "", "", "250")
gp.addfield(outPath, "FOLDER", "text", "", "", "100")
# 获取插入游标
cur = gp.InsertCursor(outPath)
# 新建一行
newRow = cur.newRow()
# 遍历数据
for feature in kmlDataList:
name = feature[0] #名称字段
desc = feature[1] #描述字段
XYList = feature[2] #XY坐标
folderName = feature[3] #文件夹名称字段

if len(XYList)==0: #如果没有XY坐标
print "no find coordinate -- feature's name :%s  " % name
continue

# 创建点
pnt = gp.CreateObject("point")
# 对shp文件中要素赋予空间坐标
if featureType=="POLYGON" or featureType == "POLYLINE":
array = gp.CreateObject("array")
for XY in XYList:
pnt.X,pnt.Y = XY[0],XY[1]
array.add(pnt)
newRow.Shape = array
else:
pnt.X,pnt.Y = XYList[0][0],XYList[0][1]
newRow.Shape = pnt
# 对该行的字段赋值
newRow.NAME = name
newRow.DESCR = desc
newRow.FOLDER = folderName
#插入数据,newRow自动下移
cur.InsertRow(newRow)


完整代码

若该脚本要创建为工具箱,内容一定不能出现中文!连注释都不行!(ArcGIS10.2)

其他环境下可以出现中文

# -*- coding:utf-8 -*-
# Author: PasserQi
# time: 2017/9/23
# Dependence: BeautifulSoup
# function: kml to shp

import arcpy,arcgisscripting,os,sys
from bs4 import BeautifulSoup

# create gp
gp = arcgisscripting.create()
gp.OverwriteOutput = 1

# -------------------------------------------------------------------
# init param

gp.AddMessage("get init param....")
print "get init param"

# get param
kmlFilePath = sys.argv[1]
featureType = sys.argv[2]
outPath = sys.argv[3]
# test param
# kmlFilePath = r"F:\study\school\analyze\lab1\songbai.kml"
# featureType = "POLYGON"
# outPath = r"F:\study\school\analyze\lab1\workspace\polygon.shp"

# UI
gp.AddMessage("kml file path %s \n feature type %s \n out path %s" % (kmlFilePath,featureType,outPath) )
print "kml file path %s \n feature type %s \n out path %s" % (kmlFilePath,featureType,outPath)

# ------------------------------------------------
# read kml and analysis

openKmlFile = open(kmlFilePath,"r")
kmlDom = openKmlFile.read()
bsObj = BeautifulSoup(kmlDom,"html.parser")
openKmlFile.close()

# ---------------------------------------------------
# get kml data

kmlDataList = [] # list kml feature data
# search feature type
if featureType=="POLYGON": type = "polygon"
elif featureType=="POLYLINE" : type = "linestring"
elif featureType=="POINT" : type = "point"

folders = bsObj.findAll("folder")
for folder in folders:
folderName = folder.find("name").get_text() # folder name
print folderName
features = bsObj.findAll(type) #Search for specified type
for feature in features:
name = description = ""
XYList = []

coordinateStr = feature.find("coordinates").get_text() #get coordinates
coordinateStr = coordinateStr.replace('\t','').replace('\n','') #remove \n \t
coordinateList = coordinateStr.split(' ')
if coordinateList:
for XYZstr in coordinateList:
if XYZstr=='': #coordinateList:the last one is ''
continue
XYZ = XYZstr.split(',')
x = float(XYZ[0])
y = float(XYZ[1])
XYList.append([x,y])  #coordinate string to float
else:
XYList = []

if (feature.parent.find("name")):
name = feature.parent.find("name").get_text()
print "name %s " % name
if (feature.parent.find("description")):
description = feature.parent.find("description").get_text()
print "description %s" %description

folderPath = '/'.join(folderName)
kmlDataList.append([name,description,XYList,folderPath])

# -----------------------------------------------------------------------
# create shapefile
if kmlDataList:

# create shp
outWorkspace = os.path.split(outPath)[0]
shpName = os.path.split(outPath)[-1]
spat_ref = "4326"
gp.CreateFeatureClass_management(outWorkspace,shpName,featureType,"","","",spat_ref)
# create field
gp.addfield(outPath, "NAME", "text", "", "", "100")
gp.addfield(outPath, "DESCR", "text", "", "", "250")
gp.addfield(outPath, "FOLDER", "text", "", "", "100")
# get cursor
cur = gp.InsertCursor(outPath)
newRow = cur.newRow()
for feature in kmlDataList:
name = feature[0]
desc = feature[1]
XYList = feature[2]
folderName = feature[3]

if len(XYList)==0:
print "no find coordinate -- feature's name :%s  " % name
continue

pnt = gp.CreateObject("point")
if featureType=="POLYGON" or featureType == "POLYLINE":
array = gp.CreateObject("array")
for XY in XYList:
pnt.X,pnt.Y = XY[0],XY[1]
array.add(pnt)
newRow.Shape = array
else:
pnt.X,pnt.Y = XYList[0][0],XYList[0][1]
newRow.Shape = pnt

newRow.NAME = name
newRow.DESCR = desc
newRow.FOLDER = folderName

cur.InsertRow(newRow)
print "finish"
del cur,newRow


详细 为脚本创建工具箱

查看.kml文件

在谷歌地球上随意画两个面,然后导出成KML格式



使用记事本查看



结论:其实kml文件是自定义的xml文件,观察到我们所需要的信息在<Folder>标签中,查看数据特点,便于读取

查看ArcPy如何操作shp文件

ArcPy帮助文档查找shape文件操作,找了好久。原来不在ArcPy下

结论:创建shape文件,详细定义请看

http://resources.arcgis.com/zh-cn/help/main/10.2/index.html#/na/00170000002p000000/

arcpy.CreateFeatureclass_management (输出的位置, 输出的文件名, {要素类型}, {要素类属性方案}, {素类是否包含线性测量值(m 值)}, {要素类是否包含高程值}, {空间参考方案}, ...)
# 例子
arcpy.CreateFeatureclass_management("C:/output", "habitatareas.shp", "POLYGON", "study_quads.shp", "DISABLED", "DISABLED", "C:/workspace/landuse.shp")


代码

因kml为自定义的xml文件,需要解析它,这里使用BeautifulSoup包,ArcPy下(Python2版本)安装BeautifulSoup

需要对文件进行写入,使用到ArcPy 游标 与 插入游标:http://resources.arcgis.com/zh-cn/help/main/10.2/index.html#/na/03q300000044000000/

创建新的工具箱

在ArcCatalog新建一个工具箱–>添加一个脚本



脚本内容



添加脚本路径



设置三个参数







测试



结果



注意

工具运行异常

Python脚本如果要添加成工具,脚本内一定不能出现中文!会报异常错误!

ValueError: could not convert string to float

问题一

kml文件标签<coordinates></coordinates>中存放坐标集,坐标集内一个坐标的格式是:
X,Y,Z
(Z后面有一个空格字符)

所以split字符串时会多解析一个坐标,是一个空的字符串

所以会出现以上string转float的报错

解决方法:

coordinateStr = feature.find("coordinates").get_text() #得到坐标集
coordinateStr = coordinateStr.replace('\t','').replace('\n','') #移除\n与\t
coordinateList = coordinateStr.split(' ') #以空格分隔字符串,提取坐标
if coordinateList: #坐标不为空
for XYZstr in coordinateList: #遍历坐标集
if XYZstr=='': #遇到""退出该次循环
continue
XYZ = XYZstr.split(',')
x = float(XYZ[0])
y = float(XYZ[1])
XYList.append([x,y])  #coordinate string to float
else:
XYList = []


问题2

kml文件中<coordinates></coordinates>中值会有\n与\t不必要字符

解决方法:

coordinateStr = coordinateStr.replace('\t','').replace('\n','') #移除\n与\t
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python arcgis
相关文章推荐