Remove broken links from a list

841
4
08-21-2012 08:35 AM
LucaMoiana
New Contributor
Hello,
I create a list of feature in an MXD files, now I'd like to remove the features with broken links.
What I did is create two list:
1 features in MXD
2 features in MXD with broken links
Now I'd like to subtract...but ain't working.
Here is a code sample:

##############################
# LIST ALL SHP IN MXD
list = []
df_list = arcpy.mapping.ListDataFrames (mxd)
for df in df_list: 
    for fc in arcpy.mapping.ListLayers (mxd, "", df):
  if (fc.supports("DATASOURCE")) and (fc.dataSource.endswith(".shp")):
                    list.append(fc)
print("List created")

#############################
# REMOVE BROKEN LINKS FROM LIST
brokenList = arcpy.mapping.ListBrokenDataSources(mxd)
for broken in brokenList:
    list.remove(broken)
    print ("Broken data removed from list")
Tags (2)
0 Kudos
4 Replies
KevinHibma
Esri Regular Contributor
Are you trying to remove the layer from the mxd or simply the layer in the list from the python list ?

If the first, I think you want to use RemoveLayer: http://resources.arcgis.com/en/help/main/10.1/index.html#/RemoveLayer/00s300000039000000/

If you simply want to modify lists built in Python, the ListBrokenDataSources returns an actual layer. So your code is trying to remove a "layer" from the list. In other words, because the ListLayers and FindBrokenDataSources command dont return exactly the same thing, you cant remove the layer in that way.

I think if you force NAMES into the list and work directly with those, it'll work. Is this applicable for your workflow, having a list of layer NAMES?

##############################
# LIST ALL SHP IN MXD
list = []
df_list = arcpy.mapping.ListDataFrames (mxd)
for df in df_list: 
    for fc in arcpy.mapping.ListLayers (mxd, "", df):
  if (fc.supports("DATASOURCE")) and (fc.dataSource.endswith(".shp")):
                    list.append(fc.name)
print("List created")

#############################
# REMOVE BROKEN LINKS FROM LIST
brokenList = arcpy.mapping.ListBrokenDataSources(mxd)
for broken in brokenList:
    list.remove(broken.name)
    print ("Broken data removed from list")
0 Kudos
LucaMoiana
New Contributor
Are you trying to remove the layer from the mxd or simply the layer in the list from the python list ?

If the first, I think you want to use RemoveLayer: http://resources.arcgis.com/en/help/main/10.1/index.html#/RemoveLayer/00s300000039000000/

If you simply want to modify lists built in Python, the ListBrokenDataSources returns an actual layer. So your code is trying to remove a "layer" from the list. In other words, because the ListLayers and FindBrokenDataSources command dont return exactly the same thing, you cant remove the layer in that way.

I think if you force NAMES into the list and work directly with those, it'll work. Is this applicable for your workflow, having a list of layer NAMES?

##############################
# LIST ALL SHP IN MXD
list = []
df_list = arcpy.mapping.ListDataFrames (mxd)
for df in df_list: 
    for fc in arcpy.mapping.ListLayers (mxd, "", df):
  if (fc.supports("DATASOURCE")) and (fc.dataSource.endswith(".shp")):
                    list.append(fc.name)
print("List created")

#############################
# REMOVE BROKEN LINKS FROM LIST
brokenList = arcpy.mapping.ListBrokenDataSources(mxd)
for broken in brokenList:
    list.remove(broken.name)
    print ("Broken data removed from list")

Thanks for your kind reply.
I'm trying to remove the layer from the list, but I don't know how ( I am exploring set and so on but no luck).
Otherwise I could also remove the layer from the mxd since for my purpose I will create a new mxd.
Here is what I'm trying to do, move SHP to GDB.


########################
# IMPORT MODULES
import sys, arcpy, datetime, os, traceback, time 
import arcpy.mapping
from arcpy import env

 
############################
# ADD NECESSARY TOOLBOXES
try:
    arcpy.AddToolbox("C:\\Program Files\\ArcGIS\\Desktop10.0\\ArcToolbox\\Toolboxes\\Data Management Tools.tbx");
except (RuntimeError):
    arcpy.AddToolbox("C:\\Program Files (x86)\\ArcGIS\\Desktop10.0\\ArcToolbox\\Toolboxes\\Data Management Tools.tbx")

 
##############################
# SET CURRENT AS MXD
mxd = arcpy.mapping.MapDocument ("CURRENT") 
 
##########################
# SET WORKSPACE
ws = 'C:\\PARK' 
arcpy.env.workspace = ws 
print("Workspace completed successfully") 
installdir = arcpy.GetInstallInfo("desktop")

#################
# CREATE A NEW FEATURE DATASET ON EXISTING GDB
gdb_full_path = 'E:\\PROGETTI\\PROGETTI_SICILIA\\007_SORGENTE_RIZZICONI\\007_SORGENTE_RIZZICONI.gdb'
mxd_date = time.gmtime(os.path.getctime(mxd.filePath))
mxd_name = os.path.basename(mxd.filePath)
fd_temp = '_' + time.strftime("%Y%m%d", mxd_date )+ '_' + (os.path.splitext(mxd_name)[0])
fd_name = arcpy.ValidateTableName(fd_temp)
fd_path = gdb_full_path + '\\' + fd_name
#    if arcpy.Exists (fd_path):
#        arcpy.AddError ("FEATURE DATASET GIA' ESISTENTE!")
#        print ("FEATURE DATASET GIA' ESISTENTE!")
fd = arcpy.CreateFeatureDataset_management(gdb_full_path, fd_name)


arp#################
# REPLACE DATASOURCE
new_path = 'I:\\20120208_Backup_disco_E\\'
mxd.findAndReplaceWorkspacePaths('E:\\', new_path)
 
##############################
# LIST ALL SHP IN MXD
list = []
df_list = arcpy.mapping.ListDataFrames (mxd)
for df in df_list: 
    for fc in arcpy.mapping.ListLayers (mxd, "", df):
  if (fc.supports("DATASOURCE")) and (fc.dataSource.endswith(".shp")):
                    list.append(fc)
print("List created")

#############################
# REMOVE BROKEN LINKS FROM LIST
#brokenList = arcpy.mapping.ListBrokenDataSources(mxd)
#for broken in brokenList:
#    list.remove(broken)
#    print ("Broken data removed from list")

################
# MOVE SHP TO GDB
remove_list = []
for fc in list:
    try:
        fc_date = time.strftime("%Y%m%d", time.gmtime(os.path.getctime(fc.dataSource)))
        desc = arcpy.Describe(fc)
        SR = desc.spatialReference
        #out_name = arcpy.ValidateTableName('_' + fc_date + '_' + fc.name + '_' + SR.name)
        out_name = '_' + fc_date + '_' + fc.name + '_' + SR.name
        arcpy.FeatureClassToFeatureClass_conversion(fc, fd_path, out_name)
        print ('Created ' + out_name + ' to ' + gdb_full_path)
        replace_name = fd_path + '\\' + out_name
        fc.replaceDataSource (gdb_full_path, "FILEGDB_WORKSPACE", out_name)
        remove_list.append(out_name)        
        print ('Replaced data source ' + out_name + ' in ' + gdb_full_path)
    except:
        print ("SKIP")


# REMOVE NEW LAYERS FROM TOC
for layer in remove_list:
    arcpy.mapping.RemoveLayer(((df_list)[0]), layer)

# Refresh the Table of Contents to reflect the change
# CREATE A COPY OF THE EXISTING MXD

new_mxd = ws + '\\' + 'MXD' + '\\' +  time.strftime("%Y%m%d", mxd_date )+ '_' + (mxd_name)
arcpy.RefreshTOC()
mxd.saveACopy(new_mxd)
0 Kudos
JustinShepard
Occasional Contributor II
So what you want is a list of broken layers and a list of nonbroken layers? You already have the broken list figured out. To get the list of nonbroken just loop through the layers and check if it's broken or not.

nonbrokenList = []
for layerItem in layersList:
     if not layerItem.isBroken:
         nonbrokenList.append(layerItem)

you could even build the broken list at the same time rather than calling the listBrokenLayers.
nonbrokenList = []
brokenList = []
for layerItem in layersList:
     if layerItem.isBroken:
         brokenList.append(layerItem)
     else:
         nonbrokenList.append(layerItem)
0 Kudos
LucaMoiana
New Contributor
So what you want is a list of broken layers and a list of nonbroken layers? You already have the broken list figured out. To get the list of nonbroken just loop through the layers and check if it's broken or not. 

nonbrokenList = [] 
for layerItem in layersList: 
if not layerItem.isBroken: 
nonbrokenList.append(layerItem) 

you could even build the broken list at the same time rather than calling the listBrokenLayers. 
nonbrokenList = [] 
brokenList = [] 
for layerItem in layersList: 
if layerItem.isBroken: 
brokenList.append(layerItem) 
else: 
nonbrokenList.append(layerItem)


Hi thank you for your help!

I picked the first solution so I don't have to add a passage to the code.
Here is what I did

list = []
df_list = arcpy.mapping.ListDataFrames (mxd)
for df in df_list: 
    for fc in arcpy.mapping.ListLayers (mxd, "", df):
  if (fc.supports("DATASOURCE")) and (fc.dataSource.endswith(".shp")):
                    if not fc.isBroken:
                        list.append(fc)
print("List created")


Unfortunately I have this error:

Runtime error <type 'exceptions.AttributeError'>: 'Layer' object has no attribute 'isBroken'
0 Kudos