Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I am having some difficulty changing the data source for a group layer. Below is the code that I am using. It processes a LYR file successfully that has a single data source but if LYR file has more than one data layer, it doesn't do it.

import arcpy, datetime, os, io, sys

try:
    #Read input parameters from GP dialog

    # Prod Setting...
    folderPath = arcpy.GetParameterAsText(0)
    output = arcpy.GetParameterAsText(1)
    sourceString = r"P:\Temp" #
    replacmentString = r"Z:\Temp" #

    #Create an output file
    outFile = open(output, "w")

    #Loop through each "LYR" file
    count = 0
    for path, dires, files in os.walk(folderPath):
        #for filename in os.listdir(folderPath):
        for filename in files:
            #fullpath = os.path.join(folderPath, filename)
            fullpath = os.path.join(path, filename)

        if os.path.isfile(fullpath):
            if filename.lower().endswith(".lyr"):
                groupLayerName = ""
                #Reference LYR
                layerFile = arcpy.mapping.Layer(fullpath)

                #Reference each layer in a layer file
                count = 1
                for lyr in arcpy.mapping.ListLayers(layerFile):
                    if lyr.isGroupLayer:
                        groupLayerName = lyr.name

                    if lyr.supports("DATASOURCE"):
                        dataSourceOrig = str(lyr.dataSource)
                        if dataSourceOrig.find(sourceString) >= 0:
                            dataSourceNew = dataSourceOrig.replace(sourceString, replacmentString)
                            if groupLayerName:
                                outFile.write(fullpath + "\t" + groupLayerName + "\t" +lyr.name + "\t" + dataSourceOrig + "\t" + dataSourceNew + "\t" + "GROUP LAYER SOURCE" "\n")
                                lyr.findAndReplaceWorkspacePath(sourceString, replacmentString, True)
                                lyr.save()
                            else:
                                outFile.write(fullpath + "\t" + "Non Group Layer" + "\t" + lyr.name + "\t" + dataSourceOrig + "\t" + dataSourceNew + "\t" + "SINGLE LAYER SOURCE" "\n")
                                lyr.findAndReplaceWorkspacePath(sourceString, replacmentString, True)
                                lyr.save()
                del layerFile

    outFile.close()

    #Open the resulting text file
    os.startfile(output)

    #Delete variables that reference data on disk
    del outFile

except Exception, e:
    import traceback
    map(arcpy.AddError, traceback.format_exc().split("\n"))
    arcpy.AddError(str(e))

(the code block above transcribed from this screenshot, indentation errors may remain)

share|improve this question
1  
I applied formatting to your code, but you need to go back and put in the indents, as they never got setup properly in the first place it appears. –  Chad Cooper Jun 1 '12 at 15:32
1  
Jay, to retain proper formatting including indents: 1) In your editor select all and copy, 2) paste into edit pane here, 3) select all lines of the code block, and 4) press Ctrl+K. –  matt wilkie Jun 1 '12 at 16:26
add comment

1 Answer

The problem you are encountering is that when a .lyr file contains more than one layer, you cannot simply set a new workspace path for that .lyr file. You have to iterate over each layer in the layer file and set the new path individually. You tried to do that using this section of code:

if groupLayerName:
  outFile.write(fullpath + "\t" + groupLayerName + "\t" +lyr.name + "\t" + dataSourceOrig + "\t" + dataSourceNew + "\t" + "GROUP LAYER SOURCE" "\n")
  lyr.findAndReplaceWorkspacePath(sourceString, replacmentString, True)
  lyr.save()
else:
  outFile.write(fullpath + "\t" + "Non Group Layer" + "\t" + lyr.name + "\t" + dataSourceOrig + "\t" + dataSourceNew + "\t" + "SINGLE LAYER SOURCE" "\n")
  lyr.findAndReplaceWorkspacePath(sourceString, replacmentString, True)
  lyr.save()

You could simply add another for loop to step through each group layer and reassign the dataset name, but this does not take into account multiply nested group layers. Instead, you could try something like the following, which calls a Recursive function to step through all nested group layers and act on each individual layer.

import arcpy, datetime, os, io, sys

def walknestedgroups(layerlist,srcString,repString,pathfull,outputFile):
  if layerlist.isGroupLayer:
    #Cycle through grouplayer
    for layer in layerlist:
      #This will continue to cycle through and test for group layers
      walknestedgroups(layer,srcString,repString,pathfull,outputFile)
  else:
    #Once a non-group layer is returned, head through the rest of original script
    singlelayer = layerlist
    if singlelayer.supports("DATASOURCE"):
      dataSourceOrig = str(singlelayer.dataSource)
      if dataSourceOrig.find(srcString) >= 0:
        dataSourceNew = dataSourceOrig.replace(srcString, repString)
        #This comparison test for layers in a group layer vs those not in.  The .longName property includes all group layers as part of path
        if Not singlelayer.name = singlelayer.longName:
          outputFile.write(pathfull + "\t" + singlelayer.longName + "\t" + singlelayer.name + "\t" + dataSourceOrig + "\t" + dataSourceNew + "\t" + "GROUP LAYER SOURCE" "\n")
          singlelayer.findAndReplaceWorkspacePath(sourceString, replacmentString, True)
          singlelayer.save()
        else:
          outputFile.write(pathfull + "\t" + "Non Group Layer" + "\t" + singlelayer.longName + "\t" + dataSourceOrig + "\t" + dataSourceNew + "\t" + "SINGLE LAYER SOURCE" "\n")
          singlelayer.findAndReplaceWorkspacePath(srcString, repString, True)
          singlelayer.save()

    return layerlist

try:

#Read input parameters from GP dialog

# Prod Setting...
folderPath = arcpy.GetParameterAsText(0)
output = arcpy.GetParameterAsText(1)
sourceString = r"P:\Temp" # 
replacmentString = r"Z:\Temp" # 

#Create an output file
outFile = open(output, "w")

#Loop through each "LYR" file
count = 0
for path, dires, files in os.walk(folderPath): 
  #for filename in os.listdir(folderPath):
  for filename in files:
    #fullpath = os.path.join(folderPath, filename)
    fullpath = os.path.join(path, filename)

    if os.path.isfile(fullpath):
      if filename.lower().endswith(".lyr"):
        groupLayerName = ""
        #Reference LYR
        layerFile = arcpy.mapping.Layer(fullpath)

        #Iterate through layer list and all group layers.  Return single layer

        for totallayer in arcpy.mapping.ListLayers(layerFile):
          #This function will take each layer in the .lyr file, cycle through any group layers then apply path changes to individual layers
          singlelayer = walknestedgroups(totallayer,sourceString,replacementString,fullpath,outFile)
        del layerFile

outFile.close()

#Open the resulting text file
os.startfile(output)

#Delete variables that reference data on disk
del outFile

except Exception, e:
import traceback
map(arcpy.AddError, traceback.format_exc().split("\n"))
arcpy.AddError(str(e)) 

A couple items here are the use of the .longName property, and a recursive function. The .longName property returns the layer name, including any group layers that it is a part of. Here is the ArcGIS help file discussing the Layer Class. The recursive function is used to iterate through nested group layers. Hat tip to @blah238 for the recursive function vocabulary lesson.

share|improve this answer
1  
+1, though I think it would be remiss to not mention that a function that calls itself is a recursive function :) –  blah238 Jun 2 '12 at 8:02
    
@blah238, thank you. –  Get Spatial Jun 2 '12 at 8:10
    
Thank you so very much for sharing this script. I am getting this error: NameError: global name 'walknestegroups' is not defined on line 6. I found that walknestegroups(layer, srcString, repString, pathfull, outputFile) takes a layer as an input whereas the function takes layerList as input. I am a Python newbie and would appreciate your feedback. Thanks, Jay –  jay Jun 5 '12 at 20:07
    
It is a spelling error in my code. It should be walknestedgroups, with a "d". I'll revise in the answer as well. –  Get Spatial Jun 5 '12 at 20:41
    
I have tried the script with several layer files, working really really well. I did get this message for one of teh folder that i was processing, not sure what may be causing this. Here it is: singlelayer.save() File "C:\Program Files\ArcGIS\Desktop10.0\arcpy\arcpy\utils.py", line 179, in fn_ return fn(*args, **kw) File "C:\Program Files\ArcGIS\Desktop10.0\arcpy\arcpy\arcobjects\mixins.py", line 268, in save assert hasattr(self, '_lyr'), gp.getIDMessage(89003, "No filename set.")...Any ideas? –  jay Jun 5 '12 at 21:52
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.