This repository has been archived by the owner on Jul 20, 2020. It is now read-only.
/
esri2open.py
302 lines (280 loc) · 12.6 KB
/
esri2open.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# ---------------------------------------------------------------------------
# esri2open.py
# Created on: March 11, 2013
# Created by: Michael Byrne
# Federal Communications Commission
# exports the feature classes for any feature class to
# a csv file, JSON file or geoJSON file
# also adding edits from sgillies and Shaun Walbridge
# updates include using the python json.dumps method and indentation issues
# edits made 3/19/2013
# ---------------------------------------------------------------------------
# Import system modules
import arcpy
from arcpy import env
import json
import sys, string, os, math
##set up arguments
#acquire arguments
theIF = sys.argv[1] #the input Feature Class
theOF = sys.argv[2] #the output folder (output file will have same prefix
#as the input feature class w/ extension for the
#output file type
theOType = sys.argv[3] #the output file type CSV or JSON or GeoJSON
theDelim = sys.argv[4] #the delimiter for the csv output selection
#global variables
##Function wrtiteCSV - for each row, writes out each field w/ a delimiter
##right now does not deal w/ geometry, blob, or rasters
##has one argument; the name of the output file
def wrtiteCSV(myOF):
#go open up and read this table
myFile = open(myOF, 'a') #open the output file and append to it
for row in arcpy.SearchCursor(theIF): #use a search cursor for each row
myStr = ""
for myF in arcpy.ListFields(theIF):
#if it is a string type field, then make sure it is utf-8 and has
#no spaces before or after it
if myF.type == "String":
myStr = myStr + \
str(row.getValue(myF.name).encode('utf-8')).strip()\
+ theDelim
#if it is a number type field, no need to quote it; keep it as a number
if (myF.type == "Float") or (myF.type == "Double") or \
(myF.type == "Short") or (myF.type == "Integer") or \
(myF.type == "OID"):
myStr = myStr + str(row.getValue(myF.name)) + theDelim
#if it is a date field, make sure there are no spaces before/after
#and quote it
if (myF.type == "Date"):
myStr = myStr + str(row.getValue(myF.name)).strip() + theDelim
#need to deal , blob, and raster
myLen = len(myStr) - 1
myStr = myStr[:myLen]
myFile.write(myStr + "\n")
myFile.close()
del myLen, myStr, myF, myFile, myOF
del row
return()
##Function wrtiteJSON - for each row, writes out a JSON Object
##right now does not deal w/ multi-part points
##has one argument; the name of the output file
def wrtiteJSON(myOF):
#go open up and read this table
myFile = open(myOF, 'a')
cnt = 1 #used to determine the end of the rows
#for each row in the feature class input
for row in arcpy.SearchCursor(theIF):
myFcnt = 1
#the next line initializes the variable myGeomStr so that it is available
#this code sets the geometry object for geoJson at the end of the line
#the attributes or properties
myGeomStr = ""
myStr = '{"type": "Feature", "id": ' + str(cnt) + ', "properties": '
# for each field in the feature class input
properties = {}
for myF in arcpy.ListFields(theIF):
fCnt = int(len(arcpy.ListFields(theIF)))
#if you are a shape field, so something special w/ it
if myF.name.lower() == "shape":
if theOType == "GeoJSON": # avoid globals!
myField = "geometry"
myGeomStr = myGeomStr + writeGeom(row.getValue(myF.name)) + "}"
else: #otherwise, just write up the attribues as "properties"
key = myF.name.lower()
val = row.getValue(myF.name)
if val is None:
# skip this field
continue
if myF.type == "String":
properties[key] = val.strip()
if myF.type in ("Float", "Double", "Short", "Integer", "OID"):
properties[key] = val
# TODO: convert these to ISO 8601 datetime strings.
if (myF.type == "Date"):
properties[key] = '"%s"' % val.strip()
# The json module handles UTF-8 encoding and everything for
# you, and at C speed.
##############################################
#need to deal , blob, and raster at some point
##############################################
myStr += json.dumps(properties)
#if its not the last row, then add a comma
if cnt < theCnt :
#if if the oType is a geoJson file, append the geomStr
if theOType == "GeoJSON":
myFile.write(myStr + ", " + myGeomStr + "," + "\n")
#if the oType is Json, don't append the geomStr
else:
myFile.write(myStr + "}, \n") #"} " + "}," +
#if it is the last row then just add the ending brackets
else:
#if if the oType is a geoJson file, append the geomStr
if theOType == "GeoJSON":
myFile.write(myStr + ", " + myGeomStr + " \n")
#if the oType is Json, don't append the geomStr
else:
myFile.write(myStr + "} \n")
cnt = cnt + 1
myFile.write("]}" + "\n")
myFile.close()
##Function writeGeom - writes out the geometry object to text
##has one argument; first is for the geometry object itelself,
##myStr gets concatenated and returned
def writeGeom(myGeom):
#initialize the geometry object
myGeomStr = '"geometry": { "type": '
if myGeom.isMultipart == 0: #then it is simple geometry
if myGeom.type == "point": #then write out the simple point attributes
myGeomStr = myGeomStr + '"Point", "coordinates": ['
myGeomStr = myGeomStr + str(myGeom.getPart().X) + ", "
myGeomStr = myGeomStr + str(myGeom.getPart().Y) + "] "
#then write out the simple polygon features;
#currently not supportinginside rings
if myGeom.type == "polygon":
#initialize the coordinates object
myGeomStr = myGeomStr + '"Polygon", "coordinates": [['
#set up a geometry part counting variable
partnum = 0
for part in myGeom:
for pnt in myGeom.getPart(partnum):
myGeomStr = myGeomStr + "[" + str(pnt.X) + ", "\
+ str(pnt.Y) + "],"
partnum = partnum + 1
myLen = len(myGeomStr) - 1
myGeomStr = myGeomStr[:myLen] + "]] "
del myLen, partnum, part, pnt
if myGeom.type == "polyline": #then write out the simple line features
myGeomStr = myGeomStr + '"LineString", "coordinates": ['
partnum = 0
for part in myGeom:
for pnt in myGeom.getPart(partnum):
myGeomStr = myGeomStr + "[" + str(pnt.X) + ", "\
+ str(pnt.Y) + "],"
partnum = partnum + 1
myLen = len(myGeomStr) - 1
myGeomStr = myGeomStr[:myLen] + "] "
del myLen, partnum, part, pnt
if myGeom.isMultipart == 1: #then it is multipart geometry
if myGeom.type == "multipoint":
#initialize the coordinates object for the geoJson file
myGeomStr = myGeomStr + '"MultiPoint", "coordinates": ['
partnum = 0
partcount = myGeom.partCount
while partnum < partcount:
pnt = myGeom.getPart(partnum)
myGeomStr = myGeomStr + "[" + str(pnt.X) + ", "
myGeomStr = myGeomStr + str(pnt.Y) + "],"
partnum = partnum + 1
myLen = len(myGeomStr) - 1
myGeomStr = myGeomStr[:myLen] + "]"
del partnum, partcount, pnt
if myGeom.type == "polygon":
#initialize the coordinates object for the geoJson file
myGeomStr = myGeomStr + '"MultiPolygon", "coordinates": [[['
#set up a geometry part counting variable
partnum = 0
partcount = myGeom.partCount
while partnum < int(partcount):
part = myGeom.getPart(partnum)
pnt = part.next()
pntcnt = 0
while pnt:
myGeomStr = myGeomStr + "[" + str(pnt.X) + ", "\
+ str(pnt.Y) + "],"
pnt = part.next()
pntcnt = pntcnt + 1
if not pnt:
pnt = part.next()
if pnt:
arcpy.AddMessage(" interior ring found")
myLen = len(myGeomStr) - 1
myGeomStr = myGeomStr[:myLen] + "]],[["
partnum = partnum + 1
myLen = len(myGeomStr) - 3
myGeomStr = myGeomStr[:myLen] + "]"
del partnum, partcount, part, pnt, pntcnt
if myGeom.type == "polyline":
#initialize the coordinates object for the geoJson file
myGeomStr = myGeomStr + '"MultiLineString", "coordinates": [['
#set up a geometry part counting variable
partnum = 0
partcount = myGeom.partCount
while partnum < int(partcount):
part = myGeom.getPart(partnum)
pnt = part.next()
pntcnt = 0
while pnt:
myGeomStr = myGeomStr + "[" + str(pnt.X) + ", "\
+ str(pnt.Y) + "],"
pnt = part.next()
pntcnt = pntcnt + 1
if not pnt:
pnt = part.next()
if pnt:
arcpy.AddMessage(" interior ring found")
myLen = len(myGeomStr) - 1
myGeomStr = myGeomStr[:myLen] + "],["
partnum = partnum + 1
myLen = len(myGeomStr) - 2
myGeomStr = myGeomStr[:myLen] + "]"
del partnum, partcount, part, pnt, pntcnt
myGeomStr = myGeomStr + " } "
del myGeom
return(myGeomStr)
##Function prepJSonFile preps the file for writing to a JSON file type
##has one argument, the output file
def prepJSonFile (myOF):
myFile = open(theOF, 'w')
myFile.write("{" + "\n")
myStr = '"type": "FeatureCollection",'
myFile.write(myStr + "\n")
myStr = '"features": ['
myFile.write(myStr + "\n")
myFile.close()
del myOF, myStr, myFile
return()
##Function prepCSVFile preps the file for writing to a CSV file type
##if the field is a geometry, blob, or raster, it does not write them out
def prepCSVFile (myOF):
myStr = ""
for myF in arcpy.ListFields(theIF): #only create data for field types that make sense
if (myF.type == "String") or (myF.type == "Float") or\
(myF.type == "Double") or (myF.type == "Short") or\
(myF.type == "Integer") or (myF.type == "OID") or\
(myF.type == "Date"):
myStr = myStr + myF.name + theDelim
myLen = len(myStr) - 1
myStr = myStr[:myLen]
myFile = open(myOF, 'w')
myFile.write(myStr + "\n")
myFile.close()
del myOF, myStr, myLen, myFile
return()
#****************************************************************************
##################Main Code below
#****************************************************************************
try:
#make sure variables are set
if theDelim == None:
theDelim = "|"
#get the file prefix by truncating the featureclass
theOF = theOF + "/" + str(os.path.splitext(os.path.basename(theIF))[0])\
+ "." + theOType.lower()
arcpy.AddMessage(theOF)
#get a count of all rows in the feature class
theCnt = int(arcpy.GetCount_management(theIF).getOutput(0))
#message to the end user what you are going to do
arcpy.AddMessage("Going to write out " + str(theCnt) + " records ")
arcpy.AddMessage(" from feature class " + theIF)
arcpy.AddMessage(" to the file " + theOF)
arcpy.AddMessage(" as a " + theOType + " file")
#if the output type is csv, write a csv
if theOType == "CSV":
prepCSVFile(theOF)
wrtiteCSV(theOF)
#if the output type is json, or geojson, write a json file
if (theOType == "JSON") or (theOType == "GeoJSON"):
prepJSonFile(theOF)
wrtiteJSON(theOF)
except:
arcpy.AddMessage("Something bad happened")