3

Is there a way to use Map Packaging so that multiple mxds draw data from the same geodatabase when unpacked? We've broken our project area into 14 divisions. Each division has it's own geodatabase and there are about 30 mxds per division drawing data from that geodatabase. I've been asked to give all our project data (over 400 mxds) to clients and I want to do that efficiently from a file storage standpoint?

In my limited experience with map packaging, it looks like it would create one geodatabase file for every MXD. If true, I'd have over 400 .MPK with each one having it's own geodatabase. Is there a way to reduce the redundancy in geodatabases since there are about 30 mxds pulling data from the same .gdb?

If file duplication and storage is a concern, would it be better to abandon map packages and provide the mxds and data using relative paths?

1
  • I suspect you also want to include layouts and such, but if you can skip that for some of them you should also consider using .lyr-files. I'm leaning towards it's easier to go with relative paths, but I'll leave the answering to someone with good arguments. MPK-files are supposed to be self-contained, that's their raison d'être, so I doubt you can create any synergies storage-wise between map packages.
    – Martin
    Aug 27, 2015 at 13:02

3 Answers 3

4

A Map Package (mpk) will only hold 1 MXD, but could hold multiple GDBs. If your original MXD has 100 featureclasses from 5 different databases (multiple fGDB or SDE instances), the data that gets copied to the package will be held inside 5 GDBs named based on the original database. So to your point, you're sort of correct. Its more you'd have 400 MPKs if you had 400 MXDs.

If you want to cut down on the number of MPKs, you'll need to cut down the number of MXDs. You'd have to go through the process of merging MXDs into one (or just a few) master MXDs and packaging those. You could maybe use dataframes as an indicator of what was an MXD. When you package the master MXDs into an MPK, data inside is not duplicated. If a layer existed in multiple dataframe all pointing at the same source, you only get 1 copy of it in the MXD (unless it came from a different database...)

If you have ArcGIS Pro, you could make a PPKX (package project). You'd import all your MXDs into the project, then package the project itself. Of course your client would need ArcGIS Pro.

2
  • While you're last suggestion looks promising, I'm working in ArcMAP v. 10.1. I'm also stuck with the 400+ mxds.
    – Bernie
    Aug 27, 2015 at 15:26
  • 1
    I realize my comments above may not provide a "solution", hopefully it provides at least a starting point to help you chose a direction. You'll probably end up writing some script to help merge multiple MXDs OR create multiple packages. Based on what you want today and what you already have, theres no simple way to get to the end.
    – KHibma
    Aug 27, 2015 at 16:06
0

Map packages are just zip files with a different extension. Use 7zip or whatever to unpack the package somewhere, delete the internal .gdb that hold the in-common data across all MXD, then repack the package.

When the MPK is delivered and opened the MXD will have broken layers; use the standard "Repair data sources" tools/methods to point to the shared in-common data GDB.

The "repair data sources" part can be scripted done before the projects are re-packed and delivered.

Command line example to remove all occurrencess of the shared data (common.gdb) from a map package and repack automatically (ref):

7z d -r repack-example.mpk common.gdb

Script examples for changing layer paths can be seen at Changing data source for all layers in MXD?

0

Seven years old but in case anyone is looking for an solution.. I wanted to be able to do this, and the ridiculous data structures created by the map packaging process just didn't cut it for me so I did my normal hacking and chopping of Midalvo's script and came up with the following:

import arcpy, os, datetime
arcpy.env.overwriteOutput = True

folderPath = arcpy.GetParameterAsText(0)
newBasePath = arcpy.GetParameterAsText(1)
OutFGDBName = arcpy.GetParameterAsText(2)
OutFGDBName = OutFGDBName + ".gdb"

newPath = newBasePath # Create new folder for MXD and FGDB
newFGDB = str(newPath)+"\\" +OutFGDBName
if not os.path.isdir(newFGDB):
    newFGDB = arcpy.CreateFileGDB_management(newPath, OutFGDBName) # Create new FGDB
newFGDB = str(newFGDB)


#Loop through each MXD file
for root, dirs, files in os.walk(folderPath):
    for file in files: # files is a list of files in the current directory
        if file.lower().endswith(".mxd"):
            dataSourceSet = set() # Keep track of already copied datasources

            fullpath = os.path.join(root, file) # root is the current directory
            fileName = os.path.splitext(file)[0] # Get filename for new folder name
            arcpy.AddMessage("FileName = {}".format(fileName))

            #Reference MXD
            mxd = arcpy.mapping.MapDocument(fullpath)
            DFList = arcpy.mapping.ListDataFrames(mxd)
            for df in DFList:
                lyrList = arcpy.mapping.ListLayers(mxd, "", df)
                arcpy.AddMessage("Fullpath = {}".format(fullpath))

                for lyr in lyrList:

                    
                    lyrName = lyr.name
                    if lyr.supports("dataSource"):
                        lyrDatasource = lyr.dataSource
                        lyrDataSetName = lyr.datasetName
                        qname, q_extension = os.path.splitext(lyrDatasource)
                        if q_extension in (".TIF", ".tif",".JPG",".jpg",".png",".PNG",".ECW",".ecw",".sid",".SID",".img",".IMG",".grd",".GRD"):
                            lyrDataSetName = lyrDataSetName[:-4]
                        if lyrDataSetName[:1].isdigit():
                            lyrDataSetName = "y" + lyrDataSetName                        
                        lyrDataSetName1= (lyrDataSetName.replace(" ","").replace("?","").replace(",","").replace(chr(33),"").replace("-","").replace(chr(64),"").replace(chr(36),"").replace(chr(42),"").replace(chr(35),"").replace(chr(59),""))
                        arcpy.AddMessage("lyrName = {}".format(lyrName))
                        arcpy.AddMessage("lyrDatasource = {}".format(lyrDatasource))
                        arcpy.AddMessage("newLayername = {}".format(lyrDataSetName1))
                        destfeature = (str(newFGDB) + "\\" + str(lyrDataSetName1))
                        arcpy.AddMessage("destLayerfull = " +(destfeature))
                        
                        if lyrDatasource not in dataSourceSet:# If datasource not already copied, then copy it
                            arcpy.env.workspace = newFGDB
                            chkpath = (os.path.join(newFGDB, lyrDataSetName1))
                            if arcpy.Exists(destfeature) == True:
                                arcpy.AddMessage("Already exists")
                            elif arcpy.Exists(chkpath) == False:
                                arcpy.AddMessage("New Layer")
                                newLyrPath = arcpy.CopyFeatures_management(lyrDatasource, lyrDataSetName1)
                            else:
                                arcpy.AddMessage("None")

                        lyr.replaceDataSource(newFGDB, "FILEGDB_WORKSPACE", lyrDataSetName1) # Repoint layer datasource to new FGDB
                        arcpy.AddMessage(newFGDB + "    "+ lyrDataSetName1)
                        dataSourceSet.add(lyrDatasource) # Keep track of datasource name to avoid copying same datasource twice
            savefile = str(newPath+"\\"+fileName+".mxd")
            arcpy.AddMessage (savefile)

            mxd.save() # Save new MXD in new folder

Set this up as a script tool and set the parameters as follows:

enter image description here

I copy my mxd's to a single folder and use that as the input folder.. provide an output folder path and a name for the output gdb. It does very simple data comparisons to avoid duplication. It just looks at the layer name... If you had 2 mxd's that both had a layer named "camps" that were meant to point at different datasets it would only copy the first one as it only looks at filenames to decide if it is duplicate data or not.

Once it is done I run another script on the folder to make the mxds all relative path and zip the whole folder.

import arcpy, os

FileName = []
FolderPath = []
FolderPath = arcpy.GetParameterAsText(0)

for FileName in os.listdir(FolderPath):
    FullPath = os.path.join(FolderPath, FileName)
    if os.path.isfile(FullPath):
        BaseName, extension = os.path.splitext(FullPath)
        if extension.lower() == ".mxd":
            arcpy.AddMessage(FullPath)
            mxd = arcpy.mapping.MapDocument(FullPath)
            mxd.relativePaths = True
            mxd.save()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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