I started this series to show how to copy different kinds of lists in SharePoint. Each type of list has its own challenges. In this article I will also demonstrate how to copy custom fields and keep the same internal name. It’s kind of annoying that you can’t create a field with the internal name you specify, but I found a pretty easy workaround. You create the field using AddFieldAsXml on the list Fields collection, and you use the internal name as the display name. This creates the field with the correct internal name. Then just change the Title property of the field to what you want displayed. Problem solved.
Copying a document library is similar to copying a generic list, except that you also need to copy the document file attached to the list item. You also need to determine the template that was used to create the original list, and use that template to create the new list. That way, when users add a new document, it is of the right document type. Another gotcha in copying document libraries, is that there is a subfolder structure that needs to be copied recursively to get everything in its correct place.
Here's the code. I copied it out of my project, which has everything in its own method, so I apologize if some of my capitalization or field names are not correct. Also, there is a function referenced, CopyFieldValues. If you need to know how to do this, refer to Part 1 of this series. Document libraries can have field values just like other lists, so you'll need to copy those too if you want a complete copy of the list.
// get the document template to use when creating the new list
SPDocTemplate docTemplate;
SPDocTemplateCollection templates = destinationWeb.DocTemplates;
XDocument templateSchema = XDocument.Parse(templates.SchemaXml);
IEnumerable<XElement> paths = templateSchema.Descendants("DocumentTemplateFile");
string sourceUrl = sourceDocumentTemplateUrl.Substring(sourceDocumentTemplateUrl.IndexOf("/") + 1);
XElement path = paths.Where(p => p.Attribute("TargetName").Value == sourceUrl).Single();
XElement docTemplate = path.Parent.Parent;
int type = Convert.ToInt32(docTemplate.Attribute("Type").Value);
SPDocTemplate destTemplate = null;
foreach (SPDocTemplate template in templates)
{
if (template.Type == type)
docTemplate = template;
}
Guid newListID = destinationWeb.Lists.Add(sourceList.Title,
sourceList.Description,
destinationWeb.ListTemplates["Document Library"], docTemplate);
SPList destinationList = destinationWeb.Lists[newListID];
// add any custom fields that were created
foreach (SPField field in SourceList.Fields)
{
if (!DestinationList.Fields.ContainsField(field.InternalName))
{
// create field with correct internal name
XDocument fieldXdoc = XDocument.Parse(field.SchemaXml);
XElement fieldElement = fieldXdoc.Element("Field");
XAttribute displayName = fieldElement.Attribute("DisplayName");
displayName.Value = field.InternalName;
string fieldName = DestinationList.Fields.AddFieldAsXml(fieldXdoc.ToString());
SPField newfield = DestinationList.Fields.GetField(fieldName);
newfield.Title = field.Title;
}
}
Here is the code for CopyDocumentLibraryItems, which needs to be recursive to get all the items in all the subfolders:
protected virtual void CopyDocumentLibraryItems(SPFolder sourceFolder, SPFolder destFolder)
{
// get a list of items in the source folder
SPListItemCollection items = ((SPDocumentLibrary)SourceList).GetItemsInFolder(SourceList.DefaultView, sourceFolder);
foreach (SPListItem item in items)
{
SPFileSystemObjectType myType = item.FileSystemObjectType;
string relativeDestinationUrl = "{0}/{1}";
if (myType == SPFileSystemObjectType.File)
{
SPFile fi = item.File;
byte[] filebytes = fi.OpenBinary();
relativeDestinationUrl = string.Format(relativeDestinationUrl, destFolder.Url, fi.Name);
SPFile newFile = destFolder.Files.Add(relativeDestinationUrl, filebytes, true);
SPListItem newItem = newFile.Item;
CopyFieldValues(item, newItem);
newItem.UpdateOverwriteVersion();
}
else
{
relativeDestinationUrl = string.Format(relativeDestinationUrl, destFolder.Url, item.Folder.Name);
SPFolder destSubFolder = destFolder.SubFolders.Add(relativeDestinationUrl);
SPFolder sourceSubFolder = item.Folder;
// copy everything in sub folder
CopyDocumentLibraryItems(sourceSubFolder, destSubFolder);
}
}
}
Technorati Tags:
SharePoint
Print | posted on Sunday, March 15, 2009 8:14 AM