How to: Provision a Document Set using CAML

Posted Monday, November 29, 2010 2:53 PM by CoreyRoth

When it comes to deploying SharePoint artifacts, I pretty much always insist on doing as much as possible using a feature and CAML as opposed to using the UI or writing code.  CAML is very possible and most people don’t realize how much you can do with it.  The XML scares a lot of people but there are a lot of techniques you can use now in SharePoint 2010 to avoid writing a lot of this manually.  This article assumes you have some familiarity in deploying content types and site columns using a feature.  If you need more information on this, feel free to ask and I’ll post more on it.

As you probably know a Document Set is simply a content type which contains other content types.  For today’s example, I’m going to deploy a Document Set called Work Order.  It will contain two child content types: Contract and Invoice.  Let’s look at these child content types real quick.  Both inherit from Document and I only specifically list my custom site columns in it.

Here is what Contract looks like:

<?xml version="1.0" encoding="utf-8"?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <ContentType ID="0x0101000F9EF6A4CF6E7046A227BC48222671DC" Name="Contract" Group="Custom Content Types" Overwrite="TRUE" xmlns="http://schemas.microsoft.com/sharepoint/">

    <Folder TargetName="_cts/Contract" />

    <FieldRefs>

      <FieldRef ID="{6d392ce3-12e0-49f7-ba79-04f2b2e67269}" Name="Contract_x0020_Number" />

      <FieldRef ID="{f7b6fc7c-eb22-43dd-89a5-799874d7a5d7}" Name="Effective_x0020_Date" />

    </FieldRefs>

    <XmlDocuments>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

        <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

          <Display>DocumentLibraryForm</Display>

          <Edit>DocumentLibraryForm</Edit>

          <New>DocumentLibraryForm</New>

        </FormTemplates>

      </XmlDocument>

    </XmlDocuments>

  </ContentType>

</Elements>

My Invoice content type looks quite similar.  Note that the Contract Number field is shared between the two content types.

<?xml version="1.0" encoding="utf-8"?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <ContentType ID="0x0101006754EF61193E3942B6851FBE641DD21E" Name="Invoice" Group="Custom Content Types" Overwrite="TRUE" xmlns="http://schemas.microsoft.com/sharepoint/">

    <Folder TargetName="_cts/Invoice" />

    <FieldRefs>

      <FieldRef ID="{6d392ce3-12e0-49f7-ba79-04f2b2e67269}" Name="Contract_x0020_Number" />

      <FieldRef ID="{1dfcbcef-d1e1-42a1-bd59-a2079cc7ca36}" Name="Amount" />

    </FieldRefs>

    <XmlDocuments>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

        <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

          <Display>DocumentLibraryForm</Display>

          <Edit>DocumentLibraryForm</Edit>

          <New>DocumentLibraryForm</New>

        </FormTemplates>

      </XmlDocument>

    </XmlDocuments>

  </ContentType>

</Elements>

Now how do we deploy the Document Set?  It’s actually not that complicated.  We define it just like a regular content type that inherits from Content Type Id 0x0120D520.  Here is what the first line looks like in the elements.xml for my Document Set.  As you can see, I started with that Content Type Id and appended 00, plus my own GUID (minus dashes and brackets).

<ContentType ID="0x0120D5200032EBDCE82398324CAD4E4E21C3233AA7" Name="Work Order" Group="Custom Content Types" Overwrite="TRUE" ProgId="SharePoint.DocumentSet" PushDownChangedResourceFilesOnly="TRUE" xmlns="http://schemas.microsoft.com/sharepoint/">

In the next section, I reference my custom site columns, Contract Number.  I included all of the other FieldRef elements that are inherited but I expect you can leave them out.

<FieldRefs>

  <FieldRef ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}" Name="ContentType" />

  <FieldRef ID="{b824e17e-a1b3-426e-aecf-f0184d900485}" Name="ItemChildCount" />

  <FieldRef ID="{960ff01f-2b6d-4f1b-9c3f-e19ad8927341}" Name="FolderChildCount" />

  <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="FALSE" Hidden="TRUE" />

  <FieldRef ID="{8553196d-ec8d-4564-9861-3dbe931050c8}" Name="FileLeafRef" Required="TRUE" Hidden="FALSE" />

  <FieldRef ID="{cbb92da4-fd46-4c7d-af6c-3128c2a5576e}" Name="Description" ShowInNewForm="TRUE" ShowInEditForm="TRUE" />

  <FieldRef ID="{6d392ce3-12e0-49f7-ba79-04f2b2e67269}" Name="Contract_x0020_Number" />

</FieldRefs>

The rest of the magic behind Document Sets exists in the XmlDocuments section of the content type.  I won’t describe all of them but I will include the ones that are of interest.  The most important section describes which content types are in the Document Set.  You need to include one AllowedContentType element for each content type included.  In this case, I have the Content Type Ids for Document, Contract, and Invoice.

<XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/allowedcontenttypes">

  <act:AllowedContentTypes xmlns:act="http://schemas.microsoft.com/office/documentsets/allowedcontenttypes" LastModified="11/29/2010 18:57:35">

    <AllowedContentType id="0x0101" />

    <AllowedContentType id="0x0101000F9EF6A4CF6E7046A227BC48222671DC" />

    <AllowedContentType id="0x0101006754EF61193E3942B6851FBE641DD21E" />

  </act:AllowedContentTypes>

</XmlDocument>

The SharedField element specifies which fields are shared between content types.  The value of this site column set at the Document Set level will be written into the child content types automatically.

<XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/sharedfields">

  <sf:SharedFields xmlns:sf="http://schemas.microsoft.com/office/documentsets/sharedfields" LastModified="11/29/2010 18:58:08">

    <SharedField id="6d392ce3-12e0-49f7-ba79-04f2b2e67269" />

  </sf:SharedFields>

</XmlDocument>

The WelcomePageField element controls which site columns show up on the welcome page of the content type.  In this case I want the Contract Number displayed so I include that site column’s Id.

<XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/welcomepagefields">

  <wpf:WelcomePageFields xmlns:wpf="http://schemas.microsoft.com/office/documentsets/welcomepagefields" LastModified="11/29/2010 18:58:08">

    <WelcomePageField id="6d392ce3-12e0-49f7-ba79-04f2b2e67269" />

  </wpf:WelcomePageFields>

</XmlDocument>

Document Sets also give you the ability to create default documents for each content type in the set.  The DefaultDocument element is how you do this by specifying a filename and a Content Type Id.  I’ll talk about how you actually get the files deployed in the right place here in a little bit.

<XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/defaultdocuments">

  <dd:DefaultDocuments xmlns:dd="http://schemas.microsoft.com/office/documentsets/defaultdocuments" LastModified="11/29/2010 17:06:58" AddSetName="True">

    <DefaultDocument name="Contract Template.docx" idContentType="0x0101000F9EF6A4CF6E7046A227BC48222671DC" />

    <DefaultDocument name="Invoice Template.xlsx" idContentType="0x0101006754EF61193E3942B6851FBE641DD21E" />

  </dd:DefaultDocuments>

</XmlDocument>

Here is what the whole elements.xml file looks like for my document set.  I omitted details on a few of the XmlDocument elements but they seem to always have the same values.

<?xml version="1.0" encoding="utf-8"?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <ContentType ID="0x0120D5200032EBDCE82398324CAD4E4E21C3233AA7" Name="Work Order" Group="Custom Content Types" Overwrite="TRUE" ProgId="SharePoint.DocumentSet" PushDownChangedResourceFilesOnly="TRUE" xmlns="http://schemas.microsoft.com/sharepoint/">

    <Folder TargetName="_cts/Work Order" />

    <FieldRefs>

      <FieldRef ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}" Name="ContentType" />

      <FieldRef ID="{b824e17e-a1b3-426e-aecf-f0184d900485}" Name="ItemChildCount" />

      <FieldRef ID="{960ff01f-2b6d-4f1b-9c3f-e19ad8927341}" Name="FolderChildCount" />

      <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="FALSE" Hidden="TRUE" />

      <FieldRef ID="{8553196d-ec8d-4564-9861-3dbe931050c8}" Name="FileLeafRef" Required="TRUE" Hidden="FALSE" />

      <FieldRef ID="{cbb92da4-fd46-4c7d-af6c-3128c2a5576e}" Name="Description" ShowInNewForm="TRUE" ShowInEditForm="TRUE" />

      <FieldRef ID="{6d392ce3-12e0-49f7-ba79-04f2b2e67269}" Name="Contract_x0020_Number" />

    </FieldRefs>

    <XmlDocuments>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/defaultdocuments">

        <dd:DefaultDocuments xmlns:dd="http://schemas.microsoft.com/office/documentsets/defaultdocuments" LastModified="11/29/2010 17:06:58" AddSetName="True">

          <DefaultDocument name="Contract Template.docx" idContentType="0x0101000F9EF6A4CF6E7046A227BC48222671DC" />

          <DefaultDocument name="Invoice Template.xlsx" idContentType="0x0101006754EF61193E3942B6851FBE641DD21E" />

        </dd:DefaultDocuments>

      </XmlDocument>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/welcomepageview">

        <WelcomePageView xmlns="http://schemas.microsoft.com/office/documentsets/welcomepageview" LastModified="1/1/1 0:00:01 AM" />

      </XmlDocument>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/allowedcontenttypes">

        <act:AllowedContentTypes xmlns:act="http://schemas.microsoft.com/office/documentsets/allowedcontenttypes" LastModified="11/29/2010 18:57:35">

          <AllowedContentType id="0x0101" />

          <AllowedContentType id="0x0101000F9EF6A4CF6E7046A227BC48222671DC" />

          <AllowedContentType id="0x0101006754EF61193E3942B6851FBE641DD21E" />

        </act:AllowedContentTypes>

      </XmlDocument>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/sharedfields">

        <sf:SharedFields xmlns:sf="http://schemas.microsoft.com/office/documentsets/sharedfields" LastModified="11/29/2010 18:58:08">

          <SharedField id="6d392ce3-12e0-49f7-ba79-04f2b2e67269" />

        </sf:SharedFields>

      </XmlDocument>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/welcomepagefields">

        <wpf:WelcomePageFields xmlns:wpf="http://schemas.microsoft.com/office/documentsets/welcomepagefields" LastModified="11/29/2010 18:58:08">

          <WelcomePageField id="6d392ce3-12e0-49f7-ba79-04f2b2e67269" />

        </wpf:WelcomePageFields>

      </XmlDocument>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

        <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">

          <Display>ListForm</Display>

          <Edit>ListForm</Edit>

          <New>DocSetDisplayForm</New>

        </FormTemplates>

      </XmlDocument>

      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">

        <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">

          <New>_layouts/NewDocSet.aspx</New>

        </FormUrls>

      </XmlDocument>

    </XmlDocuments>

  </ContentType>

</Elements>

Note the path specified in the folder element as this is important.  I mentioned that there were extra steps involved in deploying the default documents.  For this we need a module element.  We also need this module element to deploy the actual page that is displayed when you view the document set.  Start by creating a new module in Visual Studio 2010.  In the module, create a folder called _cts.  Then create a subfolder under that which is unique to your content type.  In this case, I named it Work Order to match the name of my content type.  Now we need to get a copy of the page that displays when you view the document set.  By default, this file is called docsethomepage.aspx.  You can find it in 14\FEATURES\DocumentSetYou can also get it by exporting a site template that has a document set.  You import the .wsp file in Visual Studio and then look for the corresponding cts module entry.  The last step is a bit more involved, but it is how I determined which web parts to include in the module element.  Drag this page into your module folder along with the default documents you want for your content type (i.e.: Contact Template.docx  and Invoice Template.xlsx).

Here is what my completed module elements.xml looks like.

<?xml version="1.0" encoding="utf-8"?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Module Name="WorkOrderCts">

    <File Path="WorkOrderCts\_cts\Work Order\docsethomepage.aspx" Url="_cts/Work Order/docsethomepage.aspx">

      <AllUsersWebPart WebPartOrder="0" WebPartZoneID="WebPartZone_TopLeft" ID="g_737f2b01_0a4b_4cd9_9c5e_658e2ad65920">

        <![CDATA[<WebPart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/WebPart/v2">

  <Title>Image</Title>

  <FrameType>Default</FrameType>

  <Description>Use to display pictures and photos.</Description>

  <IsIncluded>true</IsIncluded>

  <ZoneID>WebPartZone_TopLeft</ZoneID>

  <PartOrder>0</PartOrder>

  <FrameState>Normal</FrameState>

  <AllowRemove>true</AllowRemove>

  <AllowZoneChange>true</AllowZoneChange>

  <AllowMinimize>true</AllowMinimize>

  <AllowConnect>true</AllowConnect>

  <AllowEdit>true</AllowEdit>

  <AllowHide>true</AllowHide>

  <IsVisible>true</IsVisible>

  <HelpMode>Modeless</HelpMode>

  <Dir>Default</Dir>

  <MissingAssembly>Cannot import this Web Part.</MissingAssembly>

  <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>

  <TypeName>Microsoft.SharePoint.WebPartPages.ImageWebPart</TypeName>

  <ImageLink xmlns="http://schemas.microsoft.com/WebPart/v2/Image">/_layouts/images/docset_welcomepage_big.png</ImageLink>

</WebPart>]]>

      </AllUsersWebPart>

      <AllUsersWebPart WebPartOrder="0" WebPartZoneID="WebPartZone_CenterMain" ID="g_8882074f_409f_4ce4_8fb9_7e4ce9aa1d93">

        <![CDATA[<WebPart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/WebPart/v2">

  <Title>Document Set Contents</Title>

  <FrameType>Default</FrameType>

  <Description>Displays the contents of the Document Set.</Description>

  <IsIncluded>true</IsIncluded>

  <ZoneID>WebPartZone_CenterMain</ZoneID>

  <PartOrder>0</PartOrder>

  <FrameState>Normal</FrameState>

  <AllowRemove>true</AllowRemove>

  <AllowZoneChange>true</AllowZoneChange>

  <AllowMinimize>true</AllowMinimize>

  <AllowConnect>true</AllowConnect>

  <AllowEdit>true</AllowEdit>

  <AllowHide>true</AllowHide>

  <IsVisible>true</IsVisible>

  <HelpMode>Modeless</HelpMode>

  <Dir>Default</Dir>

  <MissingAssembly>Cannot import this Web Part.</MissingAssembly>

  <PartImageLarge>/_layouts/images/msimagel.gif</PartImageLarge>

  <Assembly>Microsoft.Office.DocumentManagement, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>

  <TypeName>Microsoft.Office.Server.WebControls.DocumentSetContentsWebPart</TypeName>

</WebPart>]]>

      </AllUsersWebPart>

      <AllUsersWebPart WebPartOrder="0" WebPartZoneID="WebPartZone_Top" ID="g_357da23e_61eb_473c_8eac_5609fc574329">

        <![CDATA[<WebPart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.microsoft.com/WebPart/v2">

  <Title>Document Set Properties</Title>

  <FrameType>Default</FrameType>

  <Description>Displays the properties of the Document Set.</Description>

  <IsIncluded>true</IsIncluded>

  <ZoneID>WebPartZone_Top</ZoneID>

  <PartOrder>0</PartOrder>

  <FrameState>Normal</FrameState>

  <AllowRemove>true</AllowRemove>

  <AllowZoneChange>true</AllowZoneChange>

  <AllowMinimize>true</AllowMinimize>

  <AllowConnect>true</AllowConnect>

  <AllowEdit>true</AllowEdit>

  <AllowHide>true</AllowHide>

  <IsVisible>true</IsVisible>

  <HelpMode>Modeless</HelpMode>

  <Dir>Default</Dir>

  <MissingAssembly>Cannot import this Web Part.</MissingAssembly>

  <PartImageLarge>/_layouts/images/msimagel.gif</PartImageLarge>

  <Assembly>Microsoft.Office.DocumentManagement, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>

  <TypeName>Microsoft.Office.Server.WebControls.DocumentSetPropertiesWebPart</TypeName>

</WebPart>]]>

      </AllUsersWebPart>

    </File>

    <File Path="WorkOrderCts\_cts\Work Order\Invoice Template.xlsx" Url="_cts/Work Order/Invoice Template.xlsx" />

    <File Path="WorkOrderCts\_cts\Work Order\Contract Template.docx" Url="_cts/Work Order/Contract Template.docx" />

  </Module>

</Elements>

The three web parts included in the docsethomepage.aspx file element display the details of the documents set when a user views the page.  If you want to customize this page, you could add web parts here or customize docsethomepage.aspx itself.  In this section make sure the Url  element of each File element contains the path specified in the Folder element of the Document Set content type (_cts/Work Order in this case).  With all this put together, your Visual Studio project will look something like this.

DocumentSetVisualStudio

At this point, you can deploy this solution.  Make sure the destination site collection has the Document Sets feature activated otherwise things won’t work right.  If all goes well, you will have a working Document Set with all of the settings you specified.  You can go to the Content Types page, edit your content type and look at the Document Set Settings link to verify that it was create successfully.

DocumentSetSettings

If everything looks good with your content type, add it to a document library and try creating a new Document Set.  If it works right, you will have a new instance of your Document Set and you will see a page like the one below.

DocumentSetExample

As you can see, it successfully created the default documents and it is displaying my Contract Number field.

Ok, this process may seem a bit involved at this point but it’s really not bad.  You can always create this stuff in the UI and then export as site template.  Once you export a site template, you can import the pieces you want into a new project.  I’ll write up a post on this topic in the future as it is a great way to learn how SharePoint 2010 works behind the scenes. 

Comments

# re: How to: Provision a Document Set using CAML

Tuesday, December 21, 2010 1:51 AM by Tomek

This article is simply great, I am learning about custom document sets and you explained it very well. Thanks

# re: How to: Provision a Document Set using CAML

Sunday, October 9, 2011 5:46 AM by Nina

Hi

This is the one of the few places I found that explains the document set caml easy thank you. Do you have anything on missing checkout prompt in word for library instances that uses theese custom document set? Checkout prompt are missing in mine when checkout required is set to true. The user opens a document and only gets read only. It is sharepoint and office 2010 seen on several environments.

Thank you for a great blog, have read many other things that has been helful.

Regards Nina

# re: How to: Provision a Document Set using CAML

Sunday, October 9, 2011 3:03 PM by Nina

I figured out my question I wrote here earlier, I was way of. The different behavior seen in Word was because for some reason the libraries was placed under the lists url. And this makes word behave differently.

Regards

# re: How to: Provision a Document Set using CAML

Monday, October 17, 2011 9:40 PM by CoreyRoth

@Nina Thanks! I'm afraid I'm not sure what might be causing that behavior.

# re: How to: Provision a Document Set using CAML

Tuesday, November 1, 2011 6:07 AM by Yogesh

Hi why these fields are added?

<FieldRef ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}" Name="ContentType" />

     <FieldRef ID="{b824e17e-a1b3-426e-aecf-f0184d900485}" Name="ItemChildCount" />

     <FieldRef ID="{960ff01f-2b6d-4f1b-9c3f-e19ad8927341}" Name="FolderChildCount" />

     <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" Required="FALSE" Hidden="TRUE" />

     <FieldRef ID="{8553196d-ec8d-4564-9861-3dbe931050c8}" Name="FileLeafRef" Required="TRUE" Hidden="FALSE" />

     <FieldRef ID="{cbb92da4-fd46-4c7d-af6c-3128c2a5576e}" Name="Description" ShowInNewForm="TRUE" ShowInEditForm="TRUE" />

# re: How to: Provision a Document Set using CAML

Monday, November 7, 2011 8:43 PM by CoreyRoth

@Yogesh They are there when you create a document set using the UI.  I suspect you might be able to drop some of them, but SharePoint includes them by default.

# SharePoint 2010: deploying Document Sets via feature

Tuesday, July 17, 2012 8:27 AM by Curia Damiano blog

SharePoint 2010: deploying Document Sets via feature

# SharePoint 2010: deploying Document Sets via feature

Friday, November 22, 2013 8:26 AM by Curia Damiano blog

SharePoint 2010: deploying Document Sets via feature

# re: How to: Provision a Document Set using CAML

Tuesday, April 8, 2014 6:19 AM by Shakthi

Hi

I tried to follow your post but my custom document set does not add welcomepagefields. Any idea please?

# re: How to: Provision a Document Set using CAML

Wednesday, November 11, 2015 7:26 PM by brigech

Hi Corey,

I have followed your approach and i am able to have the docset items created successfully. though i am facing one issue related to the folder creation.

after creating folder programmatically in to the docset item, if i click on the folder it throws me an error.

have you faced such scenario before ?

your input will be much appreciated.

Best regards,

b

Leave a Comment

(required)
(required)
(optional)
(required)