Programowo identyfikuje połączone pole w ArcMap?

9

Czy jest możliwe programowe zidentyfikowanie pola łączenia, które jest używane do łączenia tabeli dwóch zestawów danych w ArcMap? Obecnie używam ArcGIS 10.0, SP5 i wolę rozwiązanie ArcPy , jednak nie sprzeciwiałbym się innym rozwiązaniom, jeśli rozwiązanie ArcPy nie jest dostępne.

Jedną z metod, które wypróbowałem, było zapętlenie wszystkich pól i poszukiwanie pasującego „baseName”, ale jest to tylko „wyuczone przypuszczenie”, w którym masz nadzieję, że nazwy pól w obu bazach danych są takie same.

Aby przedstawić graficznie to, czego szukam, zasadniczo chcę zidentyfikować „wejściowe pole łączenia” i „wyjściowe pole łączenia”, jak widać w oknie dialogowym „Dodaj łączenie”, ale oczywiście po fakcie.

Jak rozpoznać „wejściowe pole przyłączeniowe” i „wyjściowe pole przyłączeniowe”?

To jest pytanie do tagu. Czy program „Dołącz” może zostać wykryty programowo? , ale w tym przypadku chcę rozszerzyć funkcjonalność w celu identyfikacji FIELD (ów) używanych do łączenia dwóch (lub więcej) zestawów danych razem.

RyanKDalton
źródło
Z którą wersją ArcGIS pracujesz? I zakładam na podstawie tagów, że szukasz sposobu, aby to zrobić za pomocą arcpy, a nie ArcObjects?
blah238,
Obecnie używam ArcGIS 10.0, SP5. I tak, szukam / mam nadzieję na rozwiązanie ArcPy, jednak nie byłbym przeciwny rozwiązaniu ArcObjects, gdyby to była jedyna alternatywa.
RyanKDalton,
1
Oto niektóre potencjalnie rewelacyjna dokumentacja: edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/… Dotyczy pRelClass Jest to klasa RelationshipClass używana do definiowania tabel łączenia i pól łączenia, a także liczności. Metoda Open albo tworzy nową RelQueryTable, albo zwraca odwołanie do istniejącej RelQueryTable, jeśli ta klasa została już utworzona. Możesz wywołać tę metodę i znaleźć odniesienie dotyczące pRelClass
lewis
@lewis, nie musisz używać obiektu fabryki, aby uzyskać odwołanie do istniejącej tabeli RelQueryTable - patrz moja odpowiedź.
blah238

Odpowiedzi:

8

Oto podejście ArcObjects, oparte na tym przykładzie , w celu wyliczenia wszystkich złączeń na warstwie i wyświetlenia ich nazw miejsc docelowych i tabel źródłowych oraz kluczy podstawowych i obcych:

  1. Uzyskaj odniesienie do elementu, ILayerktóry ma jedno lub więcej złączeń
  2. Prześlij ILayerdoIDisplayTable
  3. Prześlij IDisplayTable.DisplayTablewłaściwość doIRelQueryTable
  4. Podczas gdy bieżąca tabela to IRelQueryTable:
    1. Sprawdzić RelQueryTable„s DestinationTablei SourceTablewłaściwości
    2. Sprawdź OriginPrimaryKeyi OriginForeignKeywłaściwości IRelQueryTable.RelationshipClassnieruchomości.
    3. Ustawić aktualną tabelę do obecnego RelQueryTable„s SourceTablenieruchomości

Ten skrypt w języku Python (wykorzystujący komty i ten moduł pomocniczy ) przejdzie przez wszystkie złączenia, od najnowszego do najwcześniejszego, i wydrukuje nazwy tabeli docelowej i źródłowej, pierwotny klucz źródłowy i początkowy klucz obcy dla każdego złączenia:

from ESRICOMHelpers import * # helper module from https://gis.stackexchange.com/a/5082/753
esriArcMapUI = GetESRIModule("esriArcMapUI")
esriCarto = GetESRIModule("esriCarto")
esriGeoDatabase = GetESRIModule("esriGeoDatabase")

def listJoins(table):
    while CType(table, esriGeoDatabase.IRelQueryTable):
        relQueryTable = CType(table, esriGeoDatabase.IRelQueryTable)
        destTable = relQueryTable.DestinationTable
        sourceTable = relQueryTable.SourceTable
        destDataset = CType(destTable, esriGeoDatabase.IDataset)
        sourceDataset = CType(sourceTable, esriGeoDatabase.IDataset)
        relClass = relQueryTable.RelationshipClass
        print destDataset.Name, sourceDataset.Name, relClass.OriginPrimaryKey, relClass.OriginForeignKey
        table = sourceTable

if __name__ == "__main__":
    #app = GetCurrentApp() # Use if run in-process
    app = GetApp("ArcMap") # Use if run in a standalone script
    mxd = CType(app.Document, esriArcMapUI.IMxDocument)

    # Gets the first layer in the active data frame
    map = mxd.FocusMap
    lyr = map.Layer[0]

    # Need to get the "display table" to access the joins
    displayTable = CType(lyr, esriCarto.IDisplayTable).DisplayTable

    # List the layer's joined tables
    listJoins(displayTable)

Przykładowe dane wyjściowe, biorąc pod uwagę warstwę źródłową z trzema połączeniami:

join_table_3 master_fc_join_table_1_join_table_2 JOIN_ID_3 master_fc.MASTER_ID
join_table_2 master_fc_join_table_1 JOIN_ID_2 master_fc.MASTER_ID
join_table_1 master_fc JOIN_ID_1 MASTER_ID

Aby uzyskać więcej informacji, zobacz Jak uzyskać dostęp do ArcObjects z Python?

blah238
źródło
To wygląda bardzo obiecująco. Mam zainstalowany pakiet comtypes i dodany kod funkcji pomocniczej, ale pojawia się błąd "global name 'esriGeoDatabase' is not defined". Gdzie / jak należy to zdefiniować w kodzie poprzedzającym wiersz while CType(table, esriGeoDatabase.IRelQueryTable)?
RyanKDalton
Nie załączyłem go, ale w pewnym momencie musisz zaimportować opakowania typów wokół określonych bibliotek obiektów ESRI, których potrzebujesz. Korzystanie z mojego modułu pomocniczego jest tak proste jak esriGeoDatabase = GetESRIModule("esriGeoDatabase").
blah238,
Mam to, dzieki. Czy to zadziała również dla warstw w ArcMap? Przekazuję każdą warstwę layerList = arcpy.mapping.ListLayers(mxd)do listJoins(table)kodu, ale pomija on whileinstrukcję.
RyanKDalton
Nie sądzę, że można rzucać między obiektami typu arcpy i obiektami typu comtypes, dlatego trzeba uzyskać referencję ILayer za pomocą ArcObjects. Zaktualizowałem kod, aby zawierał bardziej kompletny przykład. Powinno to być możliwe do wykorzystania zarówno w trakcie, jak i poza procesem poprzez komentowanie / odkomentowanie odpowiednich wierszy.
blah238,
Zbliżam się, dziękuję za cierpliwość ... jak teraz wysłałeś plik mapy (* .mxd), na który chcesz spojrzeć? app.Documentwraca z'NoneType' object has no attribute 'Document'
RyanKDalton
1

Umieść wszystkie dane pól w ciągach, (po ich zamówieniu) porównaj je z funkcją fuzzycompare i wybierz te, które dały najlepsze dopasowanie lub dopasowanie, z określoną precyzją.

To rozwiązanie występuje, gdy niektóre dane nie pasują. Jeśli uważasz, że obie kolumny zawsze pasują, po prostu zamów i porównaj, aby uzyskać idealne dopasowanie za pomocą zwykłej funkcji porównania.

Poniżej radaru
źródło
0

Spróbuj tego:

  • Użyj narzędzia Przekształcenie XSLT z zestawu narzędzi Metadane, aby zapisać plik metadanych xml / html dla danego zestawu danych.

    arcpy.XSLTransform_conversion(r'X:\temp\Scratch.gdb\fc_FeatureToPoint',"C:\Program Files\ArcGIS\Desktop10.1\Metadata\Stylesheets\ArcGIS.xsl", r'X:\temp\Metadata.html')
  • Użyj parsera HTML, aby odczytać plik metadanych i wyszukać pole złączenia z historii geoprzetwarzania narzędzia Połącz pole

  • Przykładowe dane wyjściowe z narzędzia Transformacja XSLT

Dane wyjściowe z narzędzia Transformacja XSLT

Nxaunxau
źródło
1
To naprawdę sprytny pomysł, który moim zdaniem miał obiecać, ale z moich testów wynika, że ​​zadziała to tylko wtedy, gdy plik zostanie dołączony za pomocą narzędzia GP o nazwie „JoinField”, ponieważ jest to zapisane w ramach historii procesów GP dla tej warstwy. Jeśli użytkownik utworzył złączenie za pomocą interfejsu użytkownika, linia procesu JoinField nie istnieje w pliku wyjściowym. Świetny pomysł!
RyanKDalton
1
Zresztą i tak nie polegałbym na historii GP. Staramy się go usunąć tak szybko, jak to możliwe, ponieważ w przypadku powtarzających się procesów szybko gromadzi się w ogromnej ilości danych, co sprawia, że ​​klasa funkcji jest prawie bezużyteczna.
blah238
-1

Połączone nazwy tabel znajdują się w obiekcie IFeatureLayer - IFeatureLayerDefinition jako ciąg znaków, który, jak sądzę, prawdopodobnie zawiera sprzężony SQL, a tym samym nazwy pól.

http://edndoc.esri.com/arcobjects/8.3/diagrams/Map%20Layer%20Object%20Model.pdf

Czy masz na myśli, że nie możesz uzyskać dostępu do tego obiektu?

AnserGIS
źródło
IFeatureLayerDefinitionnie zawiera „dołączenia SQL”, ma jedynie DefinitionExpressionwłaściwość ujawniającą zapytanie definicji warstwy obiektów, jeśli jest ustawione, co jest klauzulą ​​WHERE ograniczającą liczbę wyświetlanych wierszy.
blah238,
Ma jednak RelationshipClasswłaściwość, ale myślę, że ujawnia to tylko ostatnie sprzężenie. Musisz użyć IRelQueryTablezamiast tego, aby uzyskać je wszystkie.
blah238,
-2

aby znaleźć pasujące pola niezależnie od nazwy pola, możesz zrobić coś takiego:

import arcpy

fc = r"temp/RiversJoined.shp"

fldList1 = [f.name for f in arcpy.ListFields(fc)]
fldList2 =[g.name for g in arcpy.ListFields(fc)]

for f in fldList1:
    values1 = [f_row[0] for f_row in arcpy.da.SearchCursor(fc, (f))]
    for g in fldList2:
        values2 = [g_row[0] for g_row in arcpy.da.SearchCursor(fc,(g))]
        #compare field values
        #get names of matching fields
        if (fldList2.index(g) != fldList1.index(f) and values1 == values2):
            print "match: " + str(g) + " match: "+ str(f)
mwil
źródło
hej, ktokolwiek zapukał moją odpowiedź: czy możesz mi powiedzieć, co jest nie tak z moją odpowiedzią? dzięki.
mwil
1
To nie wydaje się odpowiadać na zadane pytanie. To samo z rozmytą odpowiedzią porównawczą. Pola identyczne (lub nawet dziwnie podobne) nie mają wpływu na to, czy faktycznie zostały użyte w złączeniu.
blah238