This VBA code demonstrates how to geocode a table of addresses.
To geocode a table of addresses, you must specify which fields in the table contain address information. Next, you must construct a set of fields for the output feature class. Finally, use the Locator to geocode the table.
In order to be able to rematch the geocoded feature class, you must copy the fields that contain the address information in the table to the geocoded feature class. By default, ArcGIS creates two copies of the address fields: one copy maintains the original address information from the table. The other copy can be edited when you rematch the feature class interactively. You must also attach a Locator to the geocoded feature class in order to be able to rematch it.
This sample creates a static geocoded feature class that is not related to the table of addresses. In order create a dynamic geocoded feature class that is related to the table of addresses, you must create a relationship class between the table and the geocoded feature class, register the geocoded feature class as containing GeocodedFeature objects, and set the ObjectClassExtension on the geocoded feature class to be the GeocodedFeatureClassExtension.
How to use
- Paste this code into VBA in ArcCatalog.
- In the ArcCatalog tree, select a table containing address information.
- Run the MatchTable macro.
- When prompted, browse for a geocoding service to use to geocode the table.
- When prompted, specify the location and name of the geocoded feature class or shapefile.
Private Const ERR_NUMBER_REQUIREDFIELDMISSING = 1002
Private Const ERR_DESCRIPTION_REQUIREDFIELDMISSING = "A required address field was missing."
Private Const MESSAGEBOX_TITLE = "Match Table Geocoding Developer Tip"
Public Sub MatchTable()
Const FIELD_FID_NAME = "OBJECT_ID" '+++ ObjectID field name in the geocoded feature class
Const UID_FEATURE = "esriGeoDatabase.Feature" '+++ UID for simple features
Dim pGxApplication As esriCatalogUI.IGxApplication '+++ reference to the parent ArcCatalog application
Dim pGxObject As esriCatalog.IGxObject '+++ the selected GXObject in ArcCatalog
Dim pGxDataset As esriCatalog.IGxDataset '+++ IGxDataset interface on the selected GxObject
Dim pTable As esriGeoDatabase.ITable '+++ the selected table
Dim pLocator As esriGeoDatabase.ILocator '+++ the locator to use to match the table
Dim strAddressFieldNames As String '+++ address input field names
Dim pClass As esriGeoDatabase.IClass '+++ IClass interface on the table
Dim pTableFieldsEdit As esriGeoDatabase.IFieldsEdit '+++ the set of fields to copy from the table
Dim i As Long '+++ loop counter
Dim binOIDFieldFound As Boolean '+++ indicates if the OID field in the table has been found
Dim pAddressGeocoding As esriLocation.IAddressGeocoding '+++ IAddressGeocoding interface on the locator
Dim pMatchFields As esriGeoDatabase.IFields '+++ match fields for the locator
Dim pOutputFields As esriGeoDatabase.IFieldsEdit '+++ fields for the geocoded feature class
Dim pTableFields As esriGeoDatabase.IFields '+++ set of fields to copy from the table
Dim pFieldEdit As esriGeoDatabase.IFieldEdit '+++ a field in the geocoded feature class
Dim pGxOutputLocation As esriCatalog.IGxObject '+++ output location specified by the user
Dim strOutputName As String '+++ name of the geocoded feature class
Dim pUID As esriSystem.UID '+++ GUID for simple features
Dim strShapeFieldName As String '+++ name of the shape field
Dim pGxOutputDataset As esriCatalog.IGxDataset '+++ output feature dataset specified by the user
Dim pFeatureDataset As esriGeoDatabase.IFeatureDataset '+++ output feature dataset selected by the user
Dim pFeatureClass As esriGeoDatabase.IFeatureClass '+++ geocoded feature class
Dim pGxDatabase As esriCatalog.IGxDatabase '+++ output database selected by the user
Dim pFeatureWorkspace As esriGeoDatabase.IFeatureWorkspace '+++ feature workspace for the output database selected by the user
Dim pGxFile As esriCatalog.IGxFile '+++ IGxFile interface on the output folder selected by the user
Dim pWorkspaceFactory As esriGeoDatabase.IWorkspaceFactory '+++ shapefile workspace factory
Dim strOutputFieldNames As String '+++ names of the match fields in the output feature class
Dim pPropertySet As esriSystem.IPropertySet '+++ PropertySet containing fields to copy
Dim pLocatorDataset As esriGeoDatabase.ILocatorDataset '+++ ILocatorDataset interface on the locator
Dim pLocatorAttach As esriLocation.ILocatorAttach2 '+++ ILocatorAttach2 interface on the LocatorWorkspace
On Error GoTo ErrorHandler
'+++ get the selected table
Set pGxApplication = ThisDocument.Parent
Set pGxObject = pGxApplication.SelectedObject
If Not (TypeOf pGxObject Is esriCatalog.IGxDataset) Then
MsgBox "The selected object is not a table.", vbCritical, MESSAGEBOX_TITLE
Exit Sub
End If
Set pGxDataset = pGxObject
If Not (pGxDataset.Type = esriDTTable) Then
MsgBox "The selected object is not a table.", vbCritical, MESSAGEBOX_TITLE
Exit Sub
End If
Set pTable = pGxDataset.Dataset
'+++ browse for a locator to geocode this table
Set pLocator = BrowseForLocator
If pLocator Is Nothing Then Exit Sub
'+++ get the names of the fields that contain the address information
strAddressFieldNames = GetAddressFieldNames(pLocator, pTable)
'+++ create a set of fields to copy from the table
Set pClass = pTable
If pClass.HasOID Then
Set pTableFieldsEdit = New esriGeoDatabase.Fields
pTableFieldsEdit.FieldCount = pTable.Fields.FieldCount - 1
For i = 0 To pTable.Fields.FieldCount - 1
If pTable.Fields.Field(i).Type = esriFieldTypeOID Then
binOIDFieldFound = True
Else
If binOIDFieldFound Then
Set pTableFieldsEdit.Field(i - 1) = pTable.Fields.Field(i)
Else
Set pTableFieldsEdit.Field(i) = pTable.Fields.Field(i)
End If
End If
Next i
Else
Set pTableFieldsEdit = pTable.Fields
End If
'+++ create a set of fields for the output feature class
Set pAddressGeocoding = pLocator
Set pMatchFields = pAddressGeocoding.MatchFields
Set pOutputFields = New esriGeoDatabase.Fields
Set pTableFields = pTableFieldsEdit
pOutputFields.FieldCount = pTableFields.FieldCount + pMatchFields.FieldCount + 1
'+++ create a feature ID field
Set pFieldEdit = New esriGeoDatabase.Field
With pFieldEdit
.Type = esriFieldTypeOID
.Name = FIELD_FID_NAME
End With
Set pOutputFields.Field(0) = pFieldEdit
'+++ add the fields from the table
For i = 1 To pTableFields.FieldCount
Set pOutputFields.Field(i) = pTableFields.Field(i - 1)
Next i
'+++ add the match fields
For i = 1 + pTableFields.FieldCount To pMatchFields.FieldCount + pTableFields.FieldCount
Set pOutputFields.Field(i) = pMatchFields.Field(i - pTableFields.FieldCount - 1)
Next i
'+++ browse for a location in which to create the geocoded feature class
If Not BrowseForOutput(pGxOutputLocation, strOutputName) Then Exit Sub
'+++ create the feature class for geocoding output
'+++ create a UID for simple features
Set pUID = New esriSystem.UID
pUID.Value = UID_FEATURE
'+++ get the name of the shape field
For i = 0 To pMatchFields.FieldCount - 1
If pMatchFields.Field(i).Type = esriFieldTypeGeometry Then
strShapeFieldName = pMatchFields.Field(i).Name
Exit For
End If
Next i
If (TypeOf pGxOutputLocation Is esriCatalog.IGxDataset) Then
Set pGxOutputDataset = pGxOutputLocation
Set pFeatureDataset = pGxOutputDataset.Dataset
Set pFeatureClass = pFeatureDataset.CreateFeatureClass(strOutputName, pOutputFields, pUID, Nothing, esriFTSimple, strShapeFieldName, "")
ElseIf (TypeOf pGxOutputLocation Is esriCatalog.IGxDatabase) Then
Set pGxDatabase = pGxOutputLocation
Set pFeatureWorkspace = pGxDatabase.Workspace
Set pFeatureClass = pFeatureWorkspace.CreateFeatureClass(strOutputName, pOutputFields, pUID, Nothing, esriFTSimple, strShapeFieldName, "")
ElseIf (TypeOf pGxOutputLocation Is esriCatalog.IGxFolder) Then
Set pGxFile = pGxOutputLocation
Set pWorkspaceFactory = New esriDataSourcesFile.ShapefileWorkspaceFactory
Set pFeatureWorkspace = pWorkspaceFactory.OpenFromFile(pGxFile.Path, 0)
Set pFeatureClass = pFeatureWorkspace.CreateFeatureClass(strOutputName, pOutputFields, pUID, Nothing, esriFTSimple, strShapeFieldName, "")
End If
'+++ create the set of output field names
For i = 0 To pMatchFields.FieldCount - 1
strOutputFieldNames = strOutputFieldNames & pMatchFields.Field(i).Name
If Not (i = pMatchFields.FieldCount - 1) Then
strOutputFieldNames = strOutputFieldNames & ","
End If
Next i
'+++ create an PropertySet to specify the fields to copy from the table
Set pPropertySet = New esriSystem.PropertySet
For i = 0 To pTableFields.FieldCount - 1
pPropertySet.SetProperty pTableFields.Field(i).Name, pTableFields.Field(i).Name
Next i
'+++ geocode the table of addresses
pAddressGeocoding.MatchTable pTable, strAddressFieldNames, "", pFeatureClass, strOutputFieldNames, pPropertySet
'+++ attach a locator to the geocoded feature class
Set pLocatorDataset = pLocator
Set pLocatorAttach = pLocatorDataset.LocatorWorkspace
pLocatorAttach.AttachLocator pLocator, pFeatureClass, strAddressFieldNames, strOutputFieldNames
Exit Sub
ErrorHandler:
MsgBox "An unexpected error occurred." & vbNewLine & Err.Number & ": " & Err.Description, vbCritical, MESSAGEBOX_TITLE, Err.HelpFile, Err.HelpContext
End Sub
Private Function BrowseForLocator() As esriGeoDatabase.ILocator
Const GXDIALOG_BUTTON = "Open"
Const GXDIALOG_TITLE = "Select an address locator..."
Dim pGxDialog As esriCatalogUI.IGxDialog '+++ ArcCatalog mini-browser dialog
Dim pEnumGxObject As esriCatalog.IEnumGxObject '+++ enumeration of selected objects
Dim pGxObject As esriCatalog.IGxObject '+++ the selected GxObject
Dim pGxLocator As esriCatalog.IGxLocator '+++ the selected GxLocator
'+++ create the GxDialog and browse for feature classes
Set pGxDialog = New esriCatalogUI.GxDialog
With pGxDialog
.ButtonCaption = GXDIALOG_BUTTON
.Title = GXDIALOG_TITLE
Set .ObjectFilter = New esriLocationUI.GxFilterAddressLocators
If .DoModalOpen(ThisDocument.Parent.hWnd, pEnumGxObject) = False Then Exit Function
End With
pEnumGxObject.Reset
Set pGxObject = pEnumGxObject.Next
Set pGxLocator = pGxObject
Set BrowseForLocator = pGxLocator.Locator
End Function
Private Function BrowseForOutput(ByRef pGxObject As esriCatalog.IGxObject, ByRef strName As String) As Boolean
Const GXDIALOG_BUTTON = "Save"
Const GXDIALOG_TITLE = "Select a location for the geocoded feature class..."
Dim pGxDialog As esriCatalogUI.IGxDialog '+++ ArcCatalog mini-browser dialog
Dim pGxObjectFilterCollection As esriCatalog.IGxObjectFilterCollection '+++ IGxObjectFilterCollection on the GxDialog
Dim pGxObjectFilter As esriCatalog.IGxObjectFilter '+++ ArcCatalog filter
Dim pESRILicenseInfo As esriSystem.IESRILicenseInfo '+++ license information object
'+++ set the function's default value to false
BrowseForOutput = False
'+++ create the ArcCatalog mini-browser and set the filters
Set pGxDialog = New esriCatalogUI.GxDialog
Set pGxObjectFilterCollection = pGxDialog
pGxObjectFilterCollection.RemoveAllFilters
'+++ add shapefile filter
Set pGxObjectFilter = New esriCatalog.GxFilterShapefiles
pGxObjectFilterCollection.AddFilter pGxObjectFilter, False
'+++ add the personal geodatabase feature class filter
Set pGxObjectFilter = New esriCatalog.GxFilterPGDBFeatureClasses
pGxObjectFilterCollection.AddFilter pGxObjectFilter, False
'+++ if the user does not have an ArcView license, add the ArcSDE feature class filter
Set pESRILicenseInfo = New esriSystem.ESRILicenseInfo
If Not pESRILicenseInfo.DefaultProduct = esriProductCodeViewer Then
Set pGxObjectFilter = New esriCatalog.GxFilterSDEFeatureClasses
pGxObjectFilterCollection.AddFilter pGxObjectFilter, False
End If
'+++ set options for the dialog and displays it
With pGxDialog
.ButtonCaption = GXDIALOG_BUTTON
.Title = GXDIALOG_TITLE
Do
If .DoModalSave(ThisDocument.Parent.hWnd) = False Then Exit Function
If .ReplacingObject Then
MsgBox "Feature class already exists.", vbCritical, MESSAGEBOX_TITLE
Else
Exit Do
End If
Loop
End With
'+++ set the return values for the function
Set pGxObject = pGxDialog.FinalLocation
strName = pGxDialog.Name
BrowseForOutput = True
End Function
Private Function GetAddressFieldNames(pAddressInputs As esriLocation.IAddressInputs, pTable As esriGeoDatabase.ITable) As String
Dim pTableFields As esriGeoDatabase.IFields '+++ fields collection from the table
Dim pAddressFields As esriGeoDatabase.IFields '+++ address input fields for the locator
Dim i As Long, j As Long, k As Long '+++ loop counters
Dim binFieldFound As Boolean '+++ indicates if an address input field was found in the table
Dim strDefaultInputFieldNames() As String '+++ array of default names for a field
Dim strAddressFieldNames As String '+++ string containing address field names
Set pTableFields = pTable.Fields
Set pAddressFields = pAddressInputs.AddressFields
'+++ search the table to find each of the address input fields
For i = 0 To pAddressFields.FieldCount - 1
binFieldFound = False
'+++ get the default names for this field
strDefaultInputFieldNames = pAddressInputs.DefaultInputFieldNames(pAddressFields.Field(i).Name)
'+++ search for the default names in the table
For j = LBound(strDefaultInputFieldNames) To UBound(strDefaultInputFieldNames)
For k = 0 To pTableFields.FieldCount - 1
'+++ compare the default name to this field's name
If StrComp(pTableFields.Field(k).Name, strDefaultInputFieldNames(j), vbTextCompare) = 0 Then
strAddressFieldNames = strAddressFieldNames & pTableFields.Field(k).Name
If Not i = pAddressFields.FieldCount - 1 Then
strAddressFieldNames = strAddressFieldNames & ","
End If
binFieldFound = True
Exit For
End If
Next k
If binFieldFound Then Exit For
Next j
If Not (binFieldFound) Then
'+++ if the field was required, then raise an error, otherwise, just add a comma to the string
If pAddressFields.Field(i).Required Then
Err.Raise ERR_NUMBER_REQUIREDFIELDMISSING, MESSAGEBOX_TITLE, ERR_DESCRIPTION_REQUIREDFIELDMISSING
Exit Function
Else
If Not i = pAddressFields.FieldCount - 1 Then
strAddressFieldNames = strAddressFieldNames & ","
End If
End If
End If
Next i
GetAddressFieldNames = strAddressFieldNames
End Function