contentcontrol.XMLMapping.SetMapping

Custom XML mapping of content control in a SharePoint Document Library Template

Posted on Updated on

Hi Developers,

After a long time ( was in a busy schedule of establishing family after my marriage ūüôā ) I thought I will post this article for setting the XML mapping ¬†of content control ¬†in a Word document template ¬†for SharePoint Document Library. To be frank, in most of the cases we are / will be ¬†using QuickParts Add-in to add the content controls ¬†which are already mapped with SharePoint ContentType fields. But in this article I will be explaining how to set up a document template for a document library without touching the QuickParts Add- in. Sometimes this will be helpful to the developers who are¬†programmatic-ally/dynamically¬†¬†creating ¬†document templates or content controls to document templates. ¬†To make this article in one line, its about setting XPath, Prefix Mapping for content controls using SetMapping function of XMLMapping property of content control, like contentControl.XMLMapping.SetMapping(Xpath,PrefixMapping).

These are things that  you should have handy with you before starting this exercise.

  1. A ¬†Document Content Type with some site columns referred inside – Say, we will name it as “ExpenseContentType” that have ¬†2 site columns (SC_ExpenseName, SC_ExpenseCount )
  2. A Document Library created which have content type that is mentioned on the above step( Step 1) – Say , ExpenseDocumentLibrary.
  3. Word Content Control Tool Kit РDownload this tool kit.  This is just for the analysis purpose of the template or to understand what is happening behind the scene.
  4. Visual Studio РJust in case if  you need to code the logic for XML mapping. (Code is embedded on the bottom of the post)

So, Lets start from the document library (ExpenseDocumentLibrary)

Step 1 . Go the document library setting –> ContentType (ExpenseContentType) –> Advanced Settings

Here on the Advanced setting page of the Document library Content Type, Click on the Edit Template link(see image below) . This will open a blank document template on the MS Word . Save this locally on your machine with any user friendly name , Say ExpenseTemplate.docx

Edit Template from the Document ContentType of the document library

Step 2. For analysis, open the locally saved blank template using the Word Content Control toolkit. We can see the content type fields on the custom XML parts of the document. This means the ContentType related data like Fields etc are there in this document in XML(XSD) format.  Since its a blank document , there is no matter in the Content Controls section.

Blank document

Step 3. Let us add some content controls to this document template. For that, Open the word document using MS Word and from Developer tab add 1 or 2 plain text content controls to the document as if ¬†it resemble a template. (See image below). Name the content controls exactly as the Site Columns name in ContentType. Means, name Expense Name content control as “SC_ExpenseName”.

Save this document after the adding the controls.

Step 4 . Re-Open the document in the Word Content Control Tool Kit. Now we can observe that on the content controls section it showing the control entries without having its XPath set with ContentType Fields inside the file. (See the Image below). Basically XPath and Prefix mapping of the Custom XML parts shown on the right pane for the each field need to be mapped with content control.

Step 5. In this step we will set the mapping between the content controls and ContentType fields. Actually we can set mapping using Word Content Control Tool kit itself , but it will become a manual process. Better we will do it “programmatic-ally” ¬†ūüôā .

For doing this, I am creating ¬†a Word Add-In project ¬†in Visual Studio . So open a Visual Studio Instance –> New Project –> Word Add – In (see image below).

Give any user friendly name to the project. ¬†After that , Add a “Ribbon” into this ¬†Add- in project (Right Click on Project –> Add –> ¬†New Item –> Ribbon (see image below))

Again, give a user friendly name to the ribbon. On the visual designer of the ribbon add a button(label it as “Set Mapping”) and on the click event of ¬†button , we will write some code as shown¬†below .

      ///
<summary> /// Click event of the Set Mapping button
 /// </summary>
        ///
        ///
        private void button1_Click(object sender, RibbonControlEventArgs e)
        {
            //Accessing the active document
            Document document = Globals.ThisAddIn.Application.ActiveDocument;
            string nsURI = string.Empty;

            //retreving the content control collection of the active document.
            ContentControls contentControls = document.ContentControls;

            //Looping through the content Control collection.
            foreach (ContentControl cntntCtrl in contentControls)
            {

                var ctrlTitle = cntntCtrl.Title;
                //Setting the XPath for each control. this is under a condition that name of the Content type site column /field
                // and content control name & tag is exactly same.
                string xpath = "/ns0:properties[1]/documentManagement[1]/ns1:" + ctrlTitle + "[1]";

                //Private function to get the NameSpace URI of the content type field
                nsURI = GetXSDNameSpaceURI(document, cntntCtrl);

                //Mapping the content control.
                bool isMapped = cntntCtrl.XMLMapping.SetMapping("/ns0:properties[1]/documentManagement[1]/ns1:" + ctrlTitle + "[1]", "xmlns:ns0='http://schemas.microsoft.com/office/2006/metadata/properties' xmlns:ns1='" + nsURI + "'", null);

                if (isMapped == true)
                { MessageBox.Show("Mapping successfully done...!"); }
                else
                { MessageBox.Show("Error in XML Mapping"); }

            }

        }

        ///
<summary> /// private function to get the namespace URI of the content type.
 /// </summary>
        ///
        ///
        ///
        private string GetXSDNameSpaceURI(Document document, ContentControl control)
        {
            string nsURI = string.Empty;
            CustomXMLParts xmlParts = document.CustomXMLParts.SelectByNamespace("http://schemas.microsoft.com/office/2006/metadata/properties");
            foreach (CustomXMLPart xmlPart in xmlParts)
            {
                XmlDocument XDoc = new XmlDocument();
                XDoc.LoadXml(xmlPart.XML);
                XmlNodeList result = XDoc.GetElementsByTagName(control.Title);
                nsURI = result[0].NamespaceURI;
                break;
            }

            return nsURI;
        }

Build the project and press F5. This will open a default word document. Close that document and open our document library template where we have add content control. Find the ribbon that we have created on the opened document and press the button “Set mapping”. This will set the XPath mapping for each content control and throw a message box saying “Mapping successfully done…!”.(see image below)

Now I will explain what actually the above code does. Basically it iterates through the content controls collection and by using each content control’s title its creating an “XPath” string and “Prefix mapping” using the content type namespace URI . The key player is SetMapping Function of the content control’s XMLMapping property. This function is used to set the mapping for the content control. The SetMapping function can be called on the event after the control adding to make it more clean. But since this is a POC we will use iteration logic. The entire article is based on the SetMapping function to make link between content control and content type.

Now just open the document in the Word Content Control toolkit and see the XPath set against each content control. (see image below)

This is the time to upload this document template back into Sharepoint. Go to the Advanced settings of the Document library content type and upload the template using “upload a new document template”. After the uploading is over try adding document files which have data inserted. You can see content control data getting binded with content type columns within the document library.

I hope you enjoyed/ understood this article. Thanks for readings. Comments are invited.