Zmieniasz masowo klasę obiektów i aliasy pól za pomocą ArcPy?

14

Mam ponad sto FC, każdy z 10 lub 20 atrybutami, aby dodać lub zmienić aliasy, dwa lub więcej razy w roku. Nie trzeba dodawać, że to nie jest coś, przez co będę chrząkać. Jak mogę zautomatyzować ten proces?

Preferowane jest rozwiązanie Python, ale będzie ono wykorzystywać wszystko, co działa.

Mam dostęp do Arcgis 9.3.1 i 10 (poziom licencji ArcInfo).

matowe wilkie
źródło
1
Znalazłem próbkę programisty [Edycja klasy elementów] [1] v9.3 dla ArcCatalog. Zmienia alias dla wybranych klas obiektów na wartość zakodowaną na stałe w skrypcie. Nie był to proces wsadowy, ale zmierzał w tym kierunku. [1]: resources.esri.com/help/9.3/ArcGISDesktop/com/samples/…
matt wilkie
powiązane (blok fundamentowy): gis.stackexchange.com/questions/80/…
matt wilkie

Odpowiedzi:

7

Od wersji 10.1 AlterAliasName () może być używany do ponownego aliasu tabel:

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

Od wersji 10.3 Alter Field można używać do ponownego aliasu pól:

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

Z pomocą Mark Cederholm mam działające rozwiązanie wykorzystujące python i arcobjects . Jest szorstki na brzegach, ale wykonał zadanie. Postępując zgodnie z przepisem na tej stronie, utwórz nowy skrypt, który używa GetLibPath, NewObj, CType, OpenFeatureClassfunkcji z snippets.py. Utwórz także tabele wyszukiwania nazw w formacie .csv:

Wyszukiwanie aliasu od pola do pola (att_code-name_lookup.csv):

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

Klasa funkcji do wyszukiwania FC Alias ​​(fc_code-name_lookup.csv):

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

i skrypt:

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()
matowe wilkie
źródło
Jest to tak blisko tego, czego potrzebuję (aktualizacja aliasów pól). Jak wygląda część wycinków OpenFeatureClass? Kod Marka nie ma tego kawałka. Dzięki
Cześć Jasperoid: możesz skomentować konkretną odpowiedź, klikając link „dodaj komentarz”. Migrowałem Twoją odpowiedź na tę odpowiedź.
scw
@Jasperiod, przeniosłem większość fragmentów Marka do modułu , który nazywam parco , czyli tam, gdzie jest również OpenFeatureClass. Nie pamiętam, żeby sam to tworzyłem, ale może tak zrobiłem. W każdym razie jest na linii 125 .
matt wilkie
6

Ten kod działa dla mnie w 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
źródło
dzięki Kirk, nie masz pojęcia, jak długo próbowałem to rozgryźć. Zgaduję, że to C #?
matt wilkie
1
Tak C#. Nie testowałem jednak z zestawami funkcji, ale powinno działać.
Kirk Kuykendall
3

Inne rozwiązanie dzięki uprzejmości Roba Clarka :

Możesz użyć featureclass_to_featureclass z mapowaniem pól. Tak, tworzy kolejną klasę funkcji, ale możesz mieć po prostu obszar wyjściowy do kopiowania danych i zmiany aliasów.

Okno dialogowe FC do FC z otwartymi właściwościami (z menu kontekstowego)

W pythonie składnia field_mapczęści jest trudna, więc przejrzyj ją raz interaktywnie, aby ustawić parametry prosto, pozwól mu działać. Następnie przejdź do okna wyników , kliknij prawym przyciskiem myszy i skopiuj fragment kodu python . Oto fragment ponownie połączony w coś nieco łatwiejszego do rozszerzenia i ponownego użycia (można by zrobić więcej pracy, aby rozdzielić fragmenty mapy pola i właściwości):

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","#")
matowe wilkie
źródło
2

To rozwiązanie jest przeznaczone dla użytkowników, którzy używają serwera SQL jako geobazy. możesz to zmienić ręcznie za pomocą polecenia aktualizacji SQL. wszystkie nazwy funkcji są zapisywane w [sde]. Tabela [GDB_OBJECTCLASSES]. nazwa aliasu jest ustawiona po prostu, jeśli zmienisz wartość kolumny aliasu.

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

EDYCJA: ta metoda jest szybką metodą zmiany nazwy aliasu. ale użycie IClassSchemaEdit jest lepsze, ponieważ w metodzie aktualizacji sql nie można używać aliasu name, dopóki nie zresetuje się obszaru roboczego funkcji.

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
źródło
1
Teraz tak oczywiste, że o tym myślę! To samo podejście powinno być możliwe przy użyciu osobistego GDB (Access .mdb) lub dowolnej opcji przechowywania RDBMS.
matt wilkie
aby znaleźć go w innych RDBMS, myślę, że lepiej skopiować kopię zapasową z RDBMS, a następnie zmienić nazwę aliasu za pomocą ArcCatalog, a następnie porównać bieżącą bazę danych z kopią zapasową, aby zobaczyć zmiany i dowiedzieć się, gdzie zapisać alias.
Mehdi,