Save Microsoft Office Document To SharePoint Using Custom XML Web Parts

Office documents can be uploaded to the SharePoint document library using different methods. The SOM, CSOM and REST approaches are all applicable to upload a document to the document library. The trouble occurs when we want any change to the uploaded document to be reflected directly in the document library. This can also be managed by updating the document by any of the above mentioned methods, but the problem is that every time the document is updated a new version is created in SharePoint. Now in this case the file is to be updated programmatically after every edit.

While working on an add in that uploaded the office document to SharePoint, we came across a requirement where we had to upload the document to SharePoint and any further edits in the documents should also be reflected in the uploaded document;  i.e, any changes the user saves in the document should be reflected in SharePoint. We tried to accomplish this task using REST but the user could edit and save very frequently and every update to the document would create a new version. We found the solution to this is to save the document using the SaveAs() COM function of Office. But the problem of how to save metadata along with the document still remains. After lots of exploration we found that metadata can be saved along with the document using BuiltInDocumentProperties and CustomXMLParts.

BuiltInDocumentProperties

The BuiltInDocumentProperties are used to save the built in properties of the document. The properties like Title, Subject, Author can be saved using BuiltInDocumentProperties.

  1. DocumentProperties docproperties = (DocumentProperties)(activeDoc.BuiltInDocumentProperties);  
  2. DocumentProperty propDocumentSubject = docproperties["Title"];  
  3. propDocumentSubject.Value = Document.DocumentTitle;  
CustomXMLParts

The CustomXMLParts are used to save the custom metadata or properties with the document. Firstly, we need to format a value xml that contains all the metadata property names and their values. This value xml is to be added to CustomXMLParts of active document and the document is saved using the SaveAs().
  1. private static string GetValueXml()  
  2. {  
  3.     StringBuilder valueXml = new StringBuilder();  
  4.     try {  
  5.         valueXml.AppendFormat(  
  6.             "<?xml version=\"1.0\"?><p:properties xmlns:p=\"http://schemas.microsoft.com/office/2006/metadata/properties\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:pc=\"http://schemas.microsoft.com/office/infopath/2007/PartnerControls\"><documentManagement>");  
  7.   
  8.   
  9.   
  10.         if (!String.IsNullOrEmpty(Document.Companies))  
  11.         {  
  12.             valueXml.AppendFormat("<{0}><Value>{1}</Value></{0}>", AddinConstants.DocumentLibrary.Fields.Company, Document.Companies);  
  13.         }  
  14.   
  15.         if (!String.IsNullOrEmpty(Document.Contacts))   
  16.         {  
  17.             valueXml.AppendFormat("<{0}><Value>{1}</Value></{0}>", AddinConstants.DocumentLibrary.Fields.Contact, Document.Contacts);  
  18.         }  
  19.   
  20.   
  21.   
  22.         if (!String.IsNullOrEmpty(Document.Projects))  
  23.         {  
  24.             valueXml.AppendFormat("<{0}><Value>{1}</Value></{0}>", AddinConstants.DocumentLibrary.Fields.Project, Document.Projects);  
  25.         }  
  26.   
  27.   
  28.   
  29.         if (!String.IsNullOrEmpty(Document.DocumentId))  
  30.         {  
  31.             valueXml.AppendFormat("<{0}><Value>{1}</Value></{0}>", AddinConstants.DocumentLibrary.Fields.DocumentId, Document.DocumentId);  
  32.         }  
  33.   
  34.         if (!String.IsNullOrEmpty(Document.DocumentCategoryType))  
  35.         {  
  36.             valueXml.AppendFormat("<{0}><Value>{1}</Value></{0}>", AddinConstants.DocumentLibrary.Fields.DocumentCategoryType, Document.DocumentCategoryType);  
  37.         }  
  38.   
  39.         if (!String.IsNullOrEmpty(Document.DocumentDiscipline))   
  40.         {  
  41.             valueXml.AppendFormat("<{0}><Value>{1}</Value></{0}>", AddinConstants.DocumentLibrary.Fields.DocumentDiscipline, Document.DocumentDiscipline);  
  42.         }  
  43.   
  44.         if (!String.IsNullOrEmpty(Document.DocumentAuthor))  
  45.         {  
  46.             valueXml.AppendFormat("<{0}>{1}</{0}>", AddinConstants.DocumentLibrary.Fields.DocumnetAuthor, Document.DocumentAuthor);  
  47.         }  
  48.   
  49.         valueXml.Append("</documentManagement></p:properties>");  
  50.     } catch (Exception ex) {  
  51.         ErrorLogger.LogError(ex.ToString());  
  52.     }  
  53.   
  54.     return valueXml.ToString();  
  55. }  
The lookup values should have their lookup id as value and the text fields should text value as value. The xml string is formatted in the above manner. Add the xml string to custom xml part.
  1. activeDoc.CustomXMLParts.Add(valueXml);  
Now save the document using SaveAs(). The document should be uploaded with all its properties and all updates and edits in the document will be reflected in SharePoint directly.
  1. activeDoc.SaveAs(spUrl + "/" + AddinConstants.DocumentLibrary.ListUrl + "/" + Filename);