¿Cambiar la clase de entidad y los alias de campo en masa usando ArcPy?

14

Tengo más de cien FC, cada uno con 10 o 20 atributos para agregar o cambiar los alias, dos o más veces al año. No hace falta decir que esto no es algo por lo que voy a gruñir. ¿Cómo puedo automatizar este proceso?

Se prefiere la solución Python, pero usará todo lo que funcione.

Tengo acceso a Arcgis 9.3.1 y 10 (nivel de licencia de ArcInfo).

wilkie mate
fuente
1
Encontré el [Editar esquema de clase de entidad] [1] v9.3 muestra de desarrollador para ArcCatalog. Cambia el alias de las clases de entidad seleccionadas en el valor codificado en el script. Entonces, no es un proceso por lotes, sino que se dirige en esa dirección. [1]: resources.esri.com/help/9.3/ArcGISDesktop/com/samples/…
matt wilkie
relacionado (un bloque de construcción de cimientos): gis.stackexchange.com/questions/80/…
matt wilkie

Respuestas:

7

A partir de la versión 10.1, AlterAliasName () se puede usar para volver a crear alias de tablas:

table = r"C:\path\to\connection.sde\OWNER.TABLE"
arcpy.AlterAliasName(table, "table_alias")

A partir de la versión 10.3, Alter Field se puede utilizar para volver a crear alias de los campos:

table = r"C:\path\to\connection.sde\OWNER.TABLE"
arcpy.AlterField_management(table, "FIELD_NAME", new_field_alias="field_alias")
Kelly Thomas
fuente
8

Con la ayuda de Mark Cederholm, tengo una solución de trabajo que utiliza python y arcobjects . Es duro por los bordes, pero hizo el trabajo. Después de seguir la receta en esa página, cree un nuevo script que use las GetLibPath, NewObj, CType, OpenFeatureClassfunciones de snippets.py. También cree las tablas de búsqueda de cambio de nombre en formato .csv:

Búsqueda de alias de campo a campo (att_code-name_lookup.csv):

Attrib_Name,Alias_Name
CODE,Specification Code
VALDATE,Validity Date
...

Clase de entidad para la búsqueda de FC Alias ​​(fc_code-name_lookup.csv):

"FC_Name","AliasName"
"BS_1250009_0","Navigational Aid"
"BS_1370009_2","Residential Area"
...

y el guión:

import sys
sys.path.append('k:/code')
from snippets import GetLibPath, NewObj, CType, OpenFeatureClass
sWorkingDir = "k:/code/"
sFileGDB = sWorkingDir + "blank_canvec.gdb"
sResourceDir = "k:/code/"
sFCAliasFile = sResourceDir + "fc_code-name_lookup.csv"
sAttAliasFile = sResourceDir + "att_code-name_lookup.csv"
sProduct = "ArcEditor"

def BuildFieldAliasLookup():
    lookup = {}
    f = open(sAttAliasFile, "r")
    bFirst = True
    for line in f:
        # Skip first line
        if bFirst:
            bFirst = False
            continue
        sTokens = line.replace('"','').split(',')
        sFieldName = sTokens[0]
        sAlias = sTokens[1]
        lookup[sFieldName] = sAlias
    return lookup

def AlterAlias():
    # Initialize
    from comtypes.client import GetModule
    import arcgisscripting
    sLibPath = GetLibPath()
    GetModule(sLibPath + "esriGeoDatabase.olb")
    GetModule(sLibPath + "esriDataSourcesGDB.olb")
    import comtypes.gen.esriGeoDatabase as esriGeoDatabase
    gp = arcgisscripting.create(9.3)

    try:
        gp.setproduct(sProduct)
    except:
        gp.AddMessage(gp.GetMessages(2))

    # Build field alias lookup table
    AttrLookup = BuildFieldAliasLookup()
    # Open alias file and loop through lines
    f = open(sFCAliasFile, "r")
    bFirst = True
    for line in f:
        # Skip first line
        if bFirst:
            bFirst = False
            continue
        sTokens = line.replace('"','').split(',')
        sFCName = sTokens[0]
        sAlias = sTokens[1]
        print "Processing: ", sFCName
        # Open feature class
        try:
            pFC = OpenFeatureClass(sFCName)
        except:
            print "Could not open ", sFCName
            continue
        # Alter feature class alias
        try:
            pSE = CType(pFC, esriGeoDatabase.IClassSchemaEdit)
            pSE.AlterAliasName(sAlias)
        except:
            print "Error altering class alias"
            continue
        # Alter field aliases
        try:
            for sKey in AttrLookup.keys():
                i = pFC.FindField(sKey)
                if i == -1:
                    continue
                sAlias = AttrLookup[sKey]
                pSE.AlterFieldAliasName(sKey, sAlias)
        except:
            print "Error altering field aliases"
    print "Done."

print 'Field <--> Alias lookup table is:', BuildFieldAliasLookup()
print AlterAlias()
wilkie mate
fuente
Esto está muy cerca de lo que necesito (actualizar alias de campo). ¿Cómo se ve la porción de fragmentos de OpenFeatureClass? El código de Mark no tiene esa pieza. Gracias
Hola Jasperoid: puedes comentar una respuesta específica haciendo clic en el enlace "agregar comentario". He migrado tu respuesta a esta respuesta.
scw
@Jasperiod, moví la mayoría de los fragmentos de Mark a un módulo que llamo parco , que es donde también está OpenFeatureClass. No recuerdo haberlo creado yo mismo, pero tal vez lo hice. De todos modos, ahí está en la línea 125 .
Matt Wilkie
6

Este código me funciona en 9.3.1 ...

public static void TestAlterAlias(IApplication app)
{
    // make a dictionary of old/new names
    Dictionary<string, string> nameDict = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
    nameDict.Add("qsectionalias", "qsectionalias2");
    nameDict.Add("sursysalias", "sursysalias2");
    string[] directories =  System.IO.Directory.GetDirectories(@"D:\Projects\EmpireOil\data",@"*.gdb",
        System.IO.SearchOption.TopDirectoryOnly);
    foreach(string dir in directories)
    {
        List<IName> fcnames = GetFCNames(dir);
        foreach (IName fcName in fcnames)
        {
            ChangeFieldAliases(fcName, nameDict);
        }
    }
}

public static void ChangeFieldAliases(IName fcName, Dictionary<string, string> aliasDict)
{
    IFeatureClass fc = (IFeatureClass)fcName.Open();
    IClassSchemaEdit3 cse = (IClassSchemaEdit3)fc;
    ((ISchemaLock)fc).ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
    SortedList<string, string> changeList = new SortedList<string, string>();
    for (int i = 0; i < fc.Fields.FieldCount; i++)
    {
        string fldName = fc.Fields.get_Field(i).Name;
        string alias = fc.Fields.get_Field(i).AliasName;
        if (aliasDict.ContainsKey(alias))
        {
            changeList.Add(fldName, aliasDict[alias]);
            // set it blank for now, to avoid problems if two fields have same aliasname.
            cse.AlterFieldAliasName(fldName, "");
        }
    }

    // change the alias
    foreach (KeyValuePair<string, string> kvp in changeList)
        cse.AlterFieldAliasName(kvp.Key, kvp.Value);
    ((ISchemaLock)fc).ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
}

public static List<IName> GetFCNames(string wsPath)
{
    List<IName> names = new List<IName>();
    IWorkspaceFactory wsf = new ESRI.ArcGIS.DataSourcesGDB.FileGDBWorkspaceFactoryClass();
    IWorkspace ws = wsf.OpenFromFile(wsPath, 0);
    IEnumDatasetName enumName = ws.get_DatasetNames(esriDatasetType.esriDTAny);
    enumName.Reset();
    IDatasetName dsName = null;
    while ((dsName = enumName.Next()) != null)
    {
        if(dsName is IFeatureClassName)
            names.Add((IName)dsName);
        else if(dsName is IFeatureDatasetName)
        {
            IEnumDatasetName enumName2 = dsName.SubsetNames;
            enumName2.Reset();
            IDatasetName dsName2;
            while((dsName2=enumName2.Next())!= null)
            {
                if(dsName2 is IFeatureClassName)
                    names.Add((IName)dsName2);
            }
        }
    }
    return names;
}
Kirk Kuykendall
fuente
gracias Kirk, no tienes idea de cuánto tiempo he estado tratando de resolver esto. Supongo que esto es C #?
matt wilkie
1
Si c#. Sin embargo, no probé con conjuntos de datos de características, pero debería funcionar.
Kirk Kuykendall el
3

Otra solución cortesía de Rob Clark :

Puede usar featureclass_to_featureclass con mapeo de campo. Sí, crea otra clase de entidad, pero podría tener un área de salida para copiar datos y cambiar los alias mientras lo hace.

Cuadro de diálogo FC a FC con Propiedades abiertas (desde el menú contextual)

En python, la sintaxis de la field_mapparte es complicada, así que repítela una vez de manera interactiva para establecer los parámetros correctamente, déjelo funcionar. Luego vaya a la ventana de resultados , haga clic con el botón derecho y Copie el fragmento de Python . Aquí hay un fragmento combinado en algo un poco más fácil de extender y reutilizar (podría hacerse más trabajo para separar las partes del mapa de campo y las propiedades):

inFC = 'e:/Canvec/fix.gdb/HD_1480009_2'
outFC = 'HD_with_aliases'
out_wspace = 'e:/canvec/fix.gdb'
where_clause = '#'      # use default
config_keyword = '#'    #    "

# build field map
fmap_out_att = 'CODE /\Specification code/\ '  # field and alias name
fmap_properties = 'true true false 4 Long 0 0 ,First,#,'  # field properties
fmap_in_att = 'e:/Canvec/fix.gdb/HD_1480009_2,CODE,-1,-1'  # input FC and field

# construct the complete field map
field_map = fmap_out_att + fmap_properties + fmap_in_att
   # results in:
   # "CODE /\Specification code/\ true true false 4 Long 0 0 ,First,#,e:/Canvec/fix.gdb/HD_1480009_2,CODE,-1,-1"


arcpy.FeatureClassToFeatureClass_conversion(inFC, out_wspace, outFC, 
        where_clause, field_map, config_keyword)

# the template command copied from Results window, used for building above
# arcpy.FeatureClassToFeatureClass_conversion("e:/Canvec/fix.gdb/HD_1480009_2","e:/canvec/fix.gdb","HD_with_aliases3","#","CODE /\Specification code/\ true true false 4 Long 0 0 ,First,#,e:/Canvec/fix.gdb/HD_1480009_2,CODE,-1,-1","#")
wilkie mate
fuente
2

Esta solución es para usuarios que usan el servidor SQL como geodatabase. puede cambiarlo manualmente mediante un comando de actualización SQL. el nombre de todas las funciones se guarda en la tabla [sde]. [GDB_OBJECTCLASSES]. el nombre de alias se establece simplemente si cambia el valor de la columna de alias.

UPDATE [sde].[sde].[GDB_OBJECTCLASSES] 
SET AliasName = 'an alias name' 
WHERE Name='your feature class name'

EDITAR: este método es un método rápido para cambiar el nombre del alias. pero usar IClassSchemaEdit es mejor porque en el método de actualización SQL no puede usar el nombre de alias hasta que se restablezca el espacio de trabajo de la función.

Public Sub SetAliasName(FeatureClass As IFeatureClass, AliasName As String)
        Dim abjTable As ITable = FeatureClass
        Dim objClass As IObjectClass = abjTable
        Dim edit As IClassSchemaEdit = objClass
        edit.AlterAliasName(AliasName)
End Sub
Mehdi
fuente
1
¡Tan obvio ahora que lo pienso! El mismo enfoque debería ser posible utilizando un GDB personal (Access .mdb) o cualquiera de las opciones de almacenamiento RDBMS también.
Matt Wilkie
para encontrarlo en otro RDBMS, creo que es mejor copiar una copia de seguridad de su RDBMS y luego cambiar el nombre del alias por ArcCatalog, luego comparar la base de datos actual con la copia de seguridad, puede ver los cambios y averiguar dónde se guarda el aliasname.
Mehdi