How to geocode a table of addresses with the match table


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

  1. Paste this code into VBA in ArcCatalog.
  2. In the ArcCatalog tree, select a table containing address information.
  3. Run the MatchTable macro.
  4. When prompted, browse for a geocoding service to use to geocode the table.
  5. When prompted, specify the location and name of the geocoded feature class or shapefile.
[VBA]
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






Additional Requirements
  • A table containing address information and an address locator.