Friday, September 17, 2010

Migrating Data from Trimble GPS Pathfinder Office to an ESRI Geodatabase

If you use Trimble GPS Pathfinder Office, you have probably discovered that it does not export data directly into an ESRI geodatabase.  This can be a significant problem, especially if you have a large data dictionary with many features.  However, GPS Pathfinder Office does allow you to export each feature to an individual shapefile.  Using Python, we can quickly move all of the data in the shapefiles into a geodatabase.  The following script will do this automatically for you.  Some important notes, however, are:

1.) This script was written quickly to get the job done.  There are many ways this can be done, and this is only one of them.
2.) The data model of the geodatabase must match the data dictionary exactly.  This is important because the script only works if it does.  Actually, the fields do not have to have the same name, but they need to be in the same order.  You will see below why this is important.
3.) The feature classes in the geodatabase must mach the names of the features in the data dictionary.  For example, if it is called "Roads" in the data dictionary, the feature class shoudl be called "Roads" as well.
4.) All of the feature classes must be in the same data set.

Now let's get started.  First import your modules, create a geoprocessing object, and load the Data Management Toolbox:

import sys, string, os, arcgisscripting

gp = arcgisscripting.create(9.3)

gp.AddToolbox("C:/Program Files/ArcGIS/ArcToolbox/Toolboxes/Data Management Tools.tbx")

Next get a list of all the shapefiles in the output directory from GPS Pathfinder Office:

fileList = os.listdir("C:\\Project\\Data_Dictionary\\SHP")

Now we need to iterate through the list of files in the directory.  We first need to determine if the file is a shapefile by getting its extension:

for i in fileList:
    splitText = os.path.splitext(i)

Now we need to check if the file extension is a shapefile, create and empty string for creating the Append parameter, and start a counter that will be used to keep track of the position of the fields:

    if splitText[1] == fileExt:
        fieldMap = ""
        count = -1

Now we need to get a list of the fields in the matching feature class.  If the shapefile does not match a feature class, it will be skipped:

        try:
            fields = gp.ListFields("C:\\test.mdb\\Data\\" +\
                splitText[0])
        except:
            continue

Let's loop through the fields in the feature class and match them up to the shapefile.  We also need to increase the counter:

        for field in fields:
            count += 1

It is actually not possible to make the data model exactly the same because the feature class requires an OBJECTID and Shape field.  To overcome this we will skip these fields in the field mapping:

            if field.Name == "Shape" or 
            field.Name == "OBJECTID":
                break

We must now get the information from the shapefile:

            else:
                gp.MakeFeatureLayer("C:\\SHP\\" + i,
                    "tempLayer")
                desc = gp.Describe("tempLayer")
                fieldInfo = desc.FieldInfo
               
In the parameter for the Append tool, we need to sepearte each field with a semicolon except for the last field:

                if count > 2:
                    fieldmap += ";"

Now we build our field mapping string from all the information we just collected.  Here you will see we use the counter as the index number of the field:

                fieldMap += field.Name + " '" + field.Name +\
                   "' true true false " +\
                   str(field.Length) + " " + field.Type +\
                   " 0 0 ,First,#,C:\\SHP\\" + i + "," +\
                   fieldInfo.GetFieldName(count) + ",-1,-1"

We can now finish the script by using the Append tool to append the records from the shapefile to the feature class:

        gp.Append_management("C:\\SHP\\" + i,
           "C:\\test.mdb\\Data\\" + splitText[0], "NO_TEST",
           fieldMap, "")

As you can tell, this not necessarily the most efficient way to do this.  I have since rewritten this process using C# to create a more stable tool, however, this fairly simple script can save you quite a bit of time.  I encourage you to modify it and make it work even better.