アクティブなドメインを持つフィーチャクラスをリストしますか?


19

属性ドメインが定義されたEsriファイルジオデータベースがあります。一部の属性ドメインを削除する必要がありますが、「ドメインは属性ルールによって使用されている」ため削除できません。ドメインを使用しているフィーチャクラスを見つけるにはどうすればよいですか?

Executing: DeleteDomain R:\v5\YT_Canvec.gdb Permanency
Start Time: Thu May 19 11:01:02 2011
ERROR 999999: Error executing function.
The domain is used by an attribute rule.
Failed to execute (DeleteDomain).
Failed at Thu May 19 11:01:02 2011 (Elapsed Time: 0.00 seconds)

ジオデータベースには100を超えるフィーチャクラスがあり、それぞれのFCフィールドプロパティをインタラクティブに確認するのは簡単ではありません。gdbは大きすぎて個人用gdbに変換できず、ms-accessを使用してバックドアに入ります(とにかく危険な方法です)。


(2011-May-26):これを表現する別の方法は、「どのフィーチャクラスがドメインXを使用していますか?」です。


サブタイプのドメインを使用していますか?
カーククイケンドール

@kirk、はいサブタイプがありますが、削除しようとしているドメインはサブタイプを使用していません
マットウィルキー

1
その場合、ブライアンのコードが機能すると思います。
カーククイケンドール

1
@kirk、修正:サブタイプ+ドメインを使用しているとは思いませんでしたが、技術サポートケースをいじくり回して開いた後、実際に使用したことが判明しました。残りの特定のカプリットを特定することは、真のクリックフェストでした。あなたのc#メソッドのフォローアップにより多くの時間を費やすべきでした!
マットウィルキー

回答:


3

サブタイプを持つフィーチャクラスの処理の質問に答えるには、arcpy(10.1+)を使用できます。

arcpy.env.workspace = your_gdb

for FC in arcpy.ListFeatureClasses():
    for stcode, stdict in list(arcpy.da.ListSubtypes(FC).items()):
        for stkey in list(stdict.keys()):
            if stkey == 'FieldValues':
                for field, fieldvals in list(stdict[stkey].items()):
                    if fieldvals[1] is not None:
                        print(
                            "{},{},{},{}".format(FC,
                                                 'None' if stcode == 0 else stdict['Name'],
                                                 field,
                                                 fieldvals[1].name))

サブタイプがない場合、サブタイプコードstcodeはゼロになるため、コードは「なし」を出力します。

サブタイプの辞書はより多くのそれに、そのコードでそれを点検しています。


これに対する受け入れられた答えを変える。それは短くて直接的です。github.com/envygeo/arcplus/blob/master/ArcToolbox/Scripts/…にあるコードの私のバージョン。ありがとう!
マットウィルキー

21

Pythonには、ジオデータベースにフィーチャクラスをリストし、リスト内の各フィーチャクラスをループし、各フィーチャクラスのフィールドをリストし、各フィールドのドメインを表示するためのメソッドがあります。

import arcpy

#Set workspace environment to geodatabase
arcpy.env.workspace = your_gdb

#Get list of feature classes in geodatabase
FCs = arcpy.ListFeatureClasses()

#Loop through feature classes in list
for FC in FCs:

    #List fields in feature class
    fields = arcpy.ListFields(FC)

    #Loop through fields
    for field in fields:

        #Check if field has domain
        if field.domain != "":

            #Print feature class, field, domain name
            print FC, field.name, field.domain

上記のコードはArcGIS 10で動作するはずで、Pythonインタープリターウィンドウにリストを直接印刷します。その後、リストをコピーしてテキストエディターまたはExcelに貼り付け、結果をより簡単に確認できます。


これはサブタイプドメインも処理しますか?
カーククイケンドール

これがサブタイプまたはサブタイプドメインを処理するかどうかはわかりません。サブタイプを使用したことがありません。特定のフィールドにドメインが割り当てられている場合、ドメイン名が印刷されます。
ブライアン

美しい、ブライアンに感謝。当初はうまくいきませんでしたが、最終的にはlistFCが追加の支援なしでFeatureDatasetsに再帰しないことを思い出しました(gis.stackexchange.com/questions/5893/…)。すべて良いです!:)
マットウィルキー

@Kirk、いいえ、ドメインを使用するサブタイプは表示されません。
マットウィルキー

サンプルのresources.arcgis.com/en/help/main/10.1/index.html#//…に従って、すべてのサブタイプとその関連ドメインを調べます。
マイケルスティムソン

8

私はpythonがサブタイプを処理するとは思わないので、このc#コードを投稿するべきです。Esriのサンプル水/廃水ジオデータベースでテストし、次の未使用ドメインを見つけました。

HistoryType is not used
PLSSFirstDivisionType is not used
PLSSDirection is not used
PLSSPrincipalMeridian is not used
ParcelType is not used
PLSSSpecialSurveyType is not used
CartoLineType is not used
PLSSSecondDivisionType is not used

多くの場合、DBAは、本質的にルックアップテーブルであるドメインにSQLを介してアクセスできないことに悩まされます。

このコードはarcmapからテストしました(Mattのコメントごとに更新):

protected override void OnClick()
{
    string fgdbPath = @"C:\projects\NetTools\InfrastructureEditingTemplate\MapsandGeodatabase\LocalGovernment.gdb";
    var dict = SummarizeDomains(fgdbPath);
    ListDomains(dict);
    // list what featureclasses use a particular domain ...
    string domName = "State_Bnd_Rules";
    if (dict.ContainsKey(domName))
    {
        if (dict[domName].Count > 0)
        {
            Debug.Print("{0} is used by these featureclasses: ", domName);
            foreach (string fcfldName in dict[domName])
            {
                Debug.Print("\t{0}", fcfldName);
            }
        }
        else
            Debug.Print("{0} is not used by any featureclasses", domName);
    }
    else
    {
        Debug.Print("Domain name not found in geodb: {0}", domName);
    }
}

private void ListDomains(Dictionary<string,List<string>> dict)
{
    foreach (KeyValuePair<string, List<string>> kvp in dict)
    {
        Debug.Print("Domain {0}",kvp.Key);
        if (kvp.Value.Count > 0)
        {
            foreach (string fcfldName in kvp.Value)
            {
                Debug.Print("\t{0}", fcfldName);
            }
        }
        else
            Debug.Print("\tUNUSED DOMAIN!");
    }
}

private Dictionary<string, List<string>> SummarizeDomains(string fgdPath)
{
    var ws = Open(fgdPath);
    var dict = InitDict(ws);

    var enumDs1 = ws.get_Datasets(esriDatasetType.esriDTAny);
    IDataset ds;
    while ((ds = enumDs1.Next()) != null)
    {
        Debug.Print("processing {0}", ds.Name);
        if (ds is IObjectClass)
            LoadDomains((IObjectClass)ds, dict);
        else if (ds is IFeatureDataset)
        {
            var enumDs2 = ds.Subsets;
            enumDs2.Reset();
            IDataset ds2;
            while ((ds2 = enumDs2.Next()) != null)
            {
                if (ds2 is IObjectClass)
                    LoadDomains((IObjectClass)ds2, dict);
            }
        }
    }
    return dict;
}
private void LoadDomains(IObjectClass oc, Dictionary<string, List<string>> dict)
{
    if (oc is ISubtypes && ((ISubtypes)oc).HasSubtype)
        LoadSubtypeDomains(oc, dict);
    else
    {
        for (int i = 0; i < oc.Fields.FieldCount; i++)
        {
            var fld = oc.Fields.get_Field(i);
            if (fld.Domain == null)
                continue;
            if (dict.ContainsKey(fld.Domain.Name))
                dict[fld.Domain.Name].Add(String.Format("{0}.{1}",((IDataset)oc).Name,fld.Name));
            else
                throw new Exception("domain not found: " + fld.Domain.Name);
        }
    }
}
private void LoadSubtypeDomains(IObjectClass oc, Dictionary<string, List<string>> dict)
{
    ISubtypes subTypes = oc as ISubtypes;
    var enumSubtypes = subTypes.Subtypes;
    enumSubtypes.Reset();
    int code;
    string stName;
    while ((stName = enumSubtypes.Next(out code)) != null)
    {
        for (int i = 0; i < oc.Fields.FieldCount; i++)
        {
            string fldName = oc.Fields.get_Field(i).Name;
            var domain = subTypes.get_Domain(code, fldName);
            if (domain != null)
            {
                if (dict.ContainsKey(domain.Name))
                    dict[domain.Name].Add(String.Format("{0}.{1}.{2}",stName,((IDataset)oc).Name,fldName));
                else
                    throw new Exception("domain not found: " + domain.Name);
            }
        }
    }
}
private Dictionary<string, List<string>> InitDict(IWorkspace ws)
{
    var dict = new Dictionary<string, List<string>>(StringComparer.InvariantCultureIgnoreCase);
    var enumDomain = ((IWorkspaceDomains)ws).Domains;
    enumDomain.Reset();
    IDomain d = null;
    while ((d = enumDomain.Next()) != null)
        dict.Add(d.Name, new List<string>());
    return dict;
}

private IWorkspace Open(string fgdbPath)
{
    Type t = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
    var wsf = Activator.CreateInstance(t) as IWorkspaceFactory;
    return wsf.OpenFromFile(fgdbPath, 0);
}

未使用のドメインをリストすることは有用ですが、これは解決すべき問題の逆です。私は実際に「どのFCがドメインXを使用しているか」を探していました(私はリンクを削除してもよく作るドメインに使用されていないドメインを)。((私はまだコードを試していません。関数の名前を続けています))
マットウィルキー

@マットああ、そう、それは理にかなっています。その方法を示すためにコードを変更しました。
カーククイケンドール

うーん、多分これは本格的な質問になるはずですが、このコードはどこに置けばいいですか?VBAエディター(ツール->マクロ-> Visual Basic Editor)に相当するv10が見つかりません。
マットウィルキー

Visual Studio Express(無料)以上、およびArcGIS SDKをインストールする必要があります。それが完了したら、このチュートリアルに従ってコマンドボタンを作成し、コードをコピーしてClickイベントに貼り付けることができるはずです。また、プロジェクトに適切な参照を追加する必要があります。
カーククイケンドール

5

このコードは、求められているものを返すはずです。ワークスペースGDB / FS内のすべてのフィーチャクラスとテーブルを簡潔にトラバースし、ドメイン、フィールド名、および所属するフィーチャクラス/テーブルに関連付けられているすべてのフィールドを返します。

import os
import arcpy
lst=[]
for dirpath,dirnames,files in arcpy.da.Walk( # the path to your workspace
, datatype=["FeatureClass","Table"]):
     for file in files:
         lst.append(os.path.join(dirpath,file))
for i in lst:
     for fld in arcpy.ListFields(i):
         if fld.domain != "":
             print os.path.basename(i),fld.name, fld.domain 

4

残念なことに、ブライアンの答えは、質問が尋ねた直接的で有用な答えですが、私の実際の問題を解決しません。手元にあるgdbのバグが原因であると考えられます(どのフィーチャクラスにもドメインがアタッチされていなくても、削除できないドメインはまだあります)。いずれにせよ、どのfcにドメインが関連付けられているかを判断する別の方法を見つけました。インタラクティブですが、すべてのfcで各フィールドプロパティを使用するよりもはるかに高速です。

問題のあるgdbから別のgdbにfcの束をドラッグアンドドロップし、[ データ転送 ]ダイアログを調べます。リンクされた属性ドメインがある場合、リストの下部に表示されます。@ $%## fcがあなたに苦労を与えているものを絞り込むまで、より小さな束で繰り返します。

最終的に、CVドメインにリンクされた2つのFCに絞り込まれました


奇妙なことに、ドラッグアンドドロップHD_148009_2がCVドメインにリンクされていてもPermanency、ブライアンのarcpyスクリプトはリンクされたドメインを報告せず、ArcCatalogのフィーチャクラスプロパティフィールドインスペクターも報告しません。しかし、Esriの技術サポートでバグレポートを記録できるように、ようやく絞り込みました。
マットウィルキー

4

これは、Brianのコードを補強するためにMatt Wilkieが調べて記述しなければならなかったものだと思います。テーブルのすべてのドメイン、データベースのルートディレクトリのフィーチャクラス、およびすべてのフィーチャデータセットのフィーチャを取得する必要がありました。他のワーカーが古いドメインのジオデータベース環境をクリーンアップできるように、情報をcsvとしてエクスポートしました。

def domainInfo(csvExportFolder):
    import arcpy,csv,os

    fcTabList = []
    list = []

    #Set workspace environment to geodatabase
    arcpy.env.workspace = r"H:\GIS\SDEConnections\Admin\Infrastructure.sde"

    #Prepping the csv
    csvFile = csv.writer(open(csvExportFolder+"\\"+ "Infrastructure Domains" + ".csv","wb"),delimiter = "|")
    csvFile.writerow(["FeatureDataSet","FeatureClass","FieldName","Domain"])

    #Get list of all features in geodatabase
    fdsList = arcpy.ListDatasets()
    fcs = arcpy.ListFeatureClasses()
    tbs = arcpy.ListTables()

    for fds in fdsList:
        fcs = arcpy.ListFeatureClasses("","",fds)
        if len(fcs) != 0:
            for fc in fcs:
                fcTabList.append([fds,fc])

    for fc in fcs:
        fcTabList.append([None,fc])

    for tb in tbs:
        fcTabList.append([None,tb])

    # Loop through all features in the database list
    for item in fcTabList:
        fds = item[0]
        fc = item[1]
        # List fields in feature class
        fields = arcpy.ListFields(fc)

        # Loop through fields
        for field in fields:

            # Check if field has domain
            if field.domain != "":

                # Print feature class, field, domain name
                csvFile.writerow([fds,fc,field.name,field.domain])

def main():
    csvExportFolder = r"H:\GIS"
    domainInfo(csvExportFolder)

if __name__ == "__main__":
    main()

0

Esri:FAQ:ジオデータベースでドメインが参照されているすべての場所を見つけるにはどうすればよいですか?「ジオデータベース内のこれらの構造のプロパティを一覧表示できるPython関数。プロパティには参照ドメインがあります。Python関数を使用してフィーチャクラスのドメインとその他のプロパティを一覧表示する方法を示すサンプルスクリプトとファイルジオデータベースが提供されますテーブル。ドメインは、フィーチャクラスまたはテーブル内のフィールドに関連付けることができます。さらに、サブタイプで分類されたフィールドに対しても設定できます。

結果はこの質問に対して騒々しく、使用されているドメインを超えていますが、開始するためのより広いプラットフォームです。

Executing: ParseDomainReferences [...]

fc at root level: Pt1
  fld OBJECTID
  fld SHAPE
  fld Field_Text, domain [Pets]
  fld Field_Long
  fld Field_Short, domain [Counts]
  fld Field_Double, domain [Ratios]
[...]
Subtype Code: 1
subCode: ('Default', False)
subCode: ('Name', u'One')
subCode: ('SubtypeField', u'Field_Long')
FieldValues
fldName: Field_Double, default: [no default], domain: Ratios
fldName: OBJECTID, default: [no default], domain: [no domain]
fldName: Field_Long, default: [no default], domain: [no domain]
fldName: Field_Short, default: 1, domain: Counts
fldName: SHAPE, default: [no default], domain: [no domain]
fldName: Field_Text, default: N, domain: [no domain]
[...etc]

簡潔にするために編集されたコードの抜粋:

def ParseFieldList (fc, fcPath):
...
      for fld in fldList:
        if fld.domain != None:
          if fld.domain != "":
...
        arcpy.AddMessage ("  fld " + fld.name + s)

      # get subtype list
      subDict = arcpy.da.ListSubtypes (fcPath)
      if len (subDict) > 0:
        for stCode in subDict.iteritems():
...
          valkey, vallist = stCode
          arcpy.AddMessage ("Subtype Code: {0}".format(valkey))
          i = 0
          for subCode in vallist.iteritems():
            i += 1
            if i < 4:
              arcpy.AddMessage ("subCode: {0}".format(subCode))
            else:
              fldkey, fldlist = subCode
              arcpy.AddMessage (fldkey)
              for fld in fldlist.iteritems():
...
                if dom != None:
                  s2 = dom.name
                arcpy.AddMessage ("fldName: " + fldName + ", default: " + s1 + ", domain: " + s2)
...
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.