Identifikasi secara terprogram Bidang yang Bergabung dalam ArcMap?

9

Apakah mungkin untuk secara terprogram mengidentifikasi Field Gabung yang sedang digunakan untuk Tabel Gabung dua dataset bersama di ArcMap? Saat ini saya menggunakan ArcGIS 10.0, SP5 dan lebih suka solusi ArcPy , namun saya tidak akan menentang solusi lain, jika solusi ArcPy tidak tersedia.

Salah satu metode yang saya coba adalah mengulang-ulang semua bidang dan mencari "baseName" yang cocok, tapi itu hanya "tebakan terpelajar" di mana Anda berharap bahwa nama-nama bidang di kedua basis data sama.

Untuk representasi grafis dari apa yang saya cari, pada dasarnya saya ingin mengidentifikasi "Input Join Field" dan "Output Join Field" seperti yang terlihat dalam dialog "Add Join", tapi tentu saja setelahnya, tentu saja.

Bagaimana cara mengidentifikasi "Input Join Field" dan "Output Join Field"?

Ini adalah pertanyaan tag-on untuk Bisakah “Bergabung” dideteksi secara terprogram? , tetapi dalam kasus ini saya ingin memperluas fungsionalitas untuk mengidentifikasi FIELD (s) yang digunakan untuk menggabungkan dua (atau lebih) dataset bersama.

RyanKDalton
sumber
ArcGIS versi apa yang Anda gunakan? Dan saya berasumsi berdasarkan tag yang Anda cari secara khusus untuk melakukan hal ini dengan arcpy dan bukan ArcObjects?
blah238
Saat ini saya menggunakan ArcGIS 10.0, SP5. Dan ya, saya mencari / berharap untuk solusi ArcPy, namun saya tidak akan menentang solusi ArcObjects, jika itu satu-satunya alternatif.
RyanKDalton
1
Berikut adalah beberapa dokumentasi yang mungkin sangat menarik: edndoc.esri.com/arcobjects/9.2/ComponentHelp/esriGeoDatabase/… Ini melibatkan pRelClass. Ini adalah RelationshipClass yang digunakan untuk mendefinisikan tabel join dan menggabungkan field serta kardinalitas. Metode Terbuka baik membuat RelQueryTable baru atau mengembalikan referensi ke RelQueryTable yang sudah ada jika kelas itu telah dibuat. Anda dapat menjalankan metode ini dan menemukan referensi yang melibatkan thepRelClass
lewis
@lewis, Anda tidak perlu menggunakan objek pabrik untuk mendapatkan referensi ke RelQueryTable yang ada - lihat jawaban saya.
blah238

Jawaban:

7

Berikut ini adalah pendekatan ArcObjects, yang didasarkan pada contoh ini , untuk menghitung semua gabungan pada layer dan daftar tujuan dan nama tabel sumber dan kunci utama dan asing:

  1. Dapatkan referensi ke ILayeryang memiliki satu atau lebih gabungan
  2. Lemparkan ILayerkeIDisplayTable
  3. Cast IDisplayTable.DisplayTableproperti keIRelQueryTable
  4. Sementara tabel saat ini adalah IRelQueryTable:
    1. Memeriksa RelQueryTable's DestinationTabledan SourceTablesifat
    2. Periksa OriginPrimaryKeydan OriginForeignKeyproperti IRelQueryTable.RelationshipClassproperti.
    3. Mengatur meja saat ini untuk saat ini RelQueryTable's SourceTableproperti

Skrip Python ini (menggunakan comtypes dan modul helper ini ) akan melewati semua gabungan , dari yang terbaru hingga yang paling awal, dan mencetak nama tabel tujuan dan sumber, kunci primer asal dan kunci asing asal untuk setiap bergabung:

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)

Contoh output, diberi layer sumber dengan tiga gabungan:

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

Untuk info lebih lanjut, lihat Bagaimana cara mengakses ArcObjects dari Python?

blah238
sumber
Ini terlihat sangat menjanjikan. Saya telah menginstal paket comtypes dan kode fungsi helper ditambahkan, tetapi saya mendapatkan kesalahan "global name 'esriGeoDatabase' is not defined". Di mana / Bagaimana seharusnya didefinisikan dalam kode sebelum baris while CType(table, esriGeoDatabase.IRelQueryTable)?
RyanKDalton
Saya tidak memasukkannya, tetapi pada titik tertentu Anda harus mengimpor pembungkus comtypes di sekitar perpustakaan objek ESRI tertentu yang Anda butuhkan. Menggunakan modul helper saya sesederhana itu esriGeoDatabase = GetESRIModule("esriGeoDatabase").
blah238
Terima kasih, terima kasih. Apakah ini akan berfungsi untuk lapisan di ArcMap juga? Saya melewati setiap lapisan dari layerList = arcpy.mapping.ListLayers(mxd)ke dalam listJoins(table)kode, tetapi tidak muncul pada whilepernyataan.
RyanKDalton
Saya tidak berpikir Anda bisa melemparkan antara objek arcpy dan objek comtypes, jadi Anda perlu mendapatkan referensi ILayer melalui ArcObjects. Saya telah memperbarui kode untuk memasukkan contoh yang lebih lengkap. Ini harus dapat digunakan baik di dalam maupun di luar proses dengan mengomentari / menghapus komentar pada baris yang relevan.
blah238
Semakin dekat, terima kasih atas kesabaran walk-through ... sekarang, bagaimana Anda mengirim file dokumen peta yang sebenarnya (* .mxd) yang ingin Anda lihat? app.Documentkembali dengan'NoneType' object has no attribute 'Document'
RyanKDalton
1

Masukkan semua data bidang dalam string, (setelah dipesan) membandingkannya dengan fungsi fuzzcompare dan memilih orang-orang yang memberikan kecocokan terbaik atau kecocokan dengan ketepatan tertentu.

Solusi ini adalah ketika beberapa data tidak cocok. Jika menurut Anda kedua kolom akan selalu pas, maka pesan saja dan bandingkan untuk pasangan yang cocok dengan fungsi perbandingan biasa.

Di bawah Radar
sumber
0

Coba ini:

  • Gunakan alat Transformasi XSLT dari perangkat Metadata untuk menulis file metadata xml / html untuk dataset yang dimaksud.

    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')
  • Gunakan parser HTML untuk membaca dalam file metadata dan mencari bidang gabungan dari riwayat geoproses alat Gabung Bidang ini

  • Sampel keluaran dari alat Transformasi XSLT

Output dari alat Transformasi XSLT

Nxaunxau
sumber
1
Itu ide yang sangat pintar yang saya pikir benar-benar menjanjikan, tetapi dari pengujian saya, sepertinya ini hanya akan berfungsi jika file tersebut bergabung menggunakan Alat GP yang disebut "JoinField", karena ini ditulis sebagai bagian dari sejarah proses GP untuk lapisan itu. Jika pengguna telah membuat gabungan melalui UI, jalur proses JoinField tidak ada di file output. Ide bagus!
RyanKDalton
1
Saya tidak akan bergantung pada sejarah GP untuk ini. Kami mencoba untuk menghapusnya sesegera mungkin karena untuk proses berulang itu meningkat dengan cepat ke sejumlah besar data yang membuat kelas fitur hampir tidak dapat digunakan.
blah238
-1

Nama tabel yang tergabung ada di objek IFeatureLayer - IFeatureLayerDefinition sebagai string .. yang menurut saya mungkin berisi SQL join dan dengan demikian nama bidang.

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

Atau maksud Anda jika Anda tidak dapat mengakses objek itu?

AnserGIS
sumber
IFeatureLayerDefinitiontidak mengandung "join SQL", itu hanya memiliki DefinitionExpressionproperti yang mengekspos permintaan definisi layer fitur, jika diatur, yang merupakan klausa WHERE yang membatasi baris yang ditampilkan.
blah238
Memang memiliki RelationshipClassproperti, tetapi saya pikir ini hanya memperlihatkan bergabung paling baru. Anda harus menggunakan IRelQueryTablesebagai gantinya untuk mendapatkan semuanya.
blah238
-2

untuk menemukan bidang yang cocok terlepas dari nama bidang, Anda dapat melakukan sesuatu seperti ini:

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
sumber
hei kepada siapa pun yang mengetuk jawaban saya: dapatkah Anda memberi tahu saya apa yang salah dengan jawaban saya? Terima kasih.
mwil
1
Tampaknya ini tidak menjawab pertanyaan yang ditanyakan. Sama dengan fuzzy bandingkan jawaban. Fields yang identik (atau bahkan serupa fuzzily) tidak ada kaitannya apakah mereka benar-benar telah digunakan dalam bergabung.
blah238