Friday, May 30, 2014

SharePoint 2010: Read content controls values from Microsoft Word via OpenXml and save as Metadata (properties) of a Document Set on Event Reciever (C#.Net) 

Context: The customer wants to use the Microsoft Word to fill up his data on a daily basis. They want a functionality in SharePoint that when a document is uploaded into the document set of a document library then all the data from a word document should be synchronized into the document set.

Solution: The solution I proposed is to use content controls in the word document and later I will use event receiver to read the information from a word document and update that information into the (metadata) properties of the document set.

I used ‘ItemAdded’ event receiver for reading the word document via Open Xml sdk 2.0. The following is the code for reading the word document and updating the information of a word document into the document set properties;
     /// 
        /// An item was added.
        /// 
        public override void ItemAdded(SPItemEventProperties properties)
        {
            if (properties.ListTitle == "ListName")
            {
                if (IsFolder(properties.ListItem) == false)
                {
                    DocumentSet documentSet = GetDocumentSet(properties);
                    SPFile spfile = properties.ListItem.File;
                    if (spfile.Name.Contains(".doc"))
                    {
                        if (!spfile.Name.Contains("MetaDataReport"))
                        {
                            
                            byte[] byteArray = spfile.OpenBinary();
                            using (MemoryStream mem = new MemoryStream())
                            {
                                mem.Write(byteArray, 0, (int)byteArray.Length);

                                using (WordprocessingDocument wordDoc =
                                    WordprocessingDocument.Open(mem, true))
                                {
                                    XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";

                                    XDocument xdoc = wordDoc.MainDocumentPart.Annotation();
                                    
                                    #region "Read word document and find & get content controls"

                                    using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
                                    using (XmlReader xr = XmlReader.Create(sr))
                                        xdoc = XDocument.Load(xr);
                                    wordDoc.MainDocumentPart.AddAnnotation(xdoc);
                                    XElement bodyElement = xdoc
                                                            .Element(w + "document")
                                                            .Element(w + "body");
                                    IEnumerable contentControlsTags = bodyElement.Descendants(w + "sdt");

                                    #endregion
                                    //Check whether the user is uploading in Document Set or on a Library
                                    SPListItem spListItem = null;
                                    if (documentSet != null)
                                        spListItem = documentSet.Item;
                                    else
                                        spListItem = properties.ListItem;

                                    foreach (XElement contentControlsTag in contentControlsTags)
                                    {
                                        string strSpFldName = contentControlsTag.Element(w + "sdtPr").Element(w + "tag").Attribute(w + "val").Value.ToString();
                                        string strValue = contentControlsTag.Element(w + "sdtContent").Element(w + "r").Element(w + "t").Value.ToString();

                                        if (spListItem.Fields.ContainsField(strSpFldName))
                                            spListItem[strSpFldName] = strValue;
                                    }
                                    spListItem.Update();
                                }
                            }
                        }
                    }
                }
            }

        }

        /// 
        /// Get document set Object
        /// 
        private DocumentSet GetDocumentSet(SPItemEventProperties properties)
        {
            SPFile spfile = properties.ListItem.File;
            DocumentSet documentSet = DocumentSet.GetDocumentSet(spfile.ParentFolder);
            if (documentSet.ParentFolder.Name == properties.List.Title)
            {
                if (documentSet != null)
                    return documentSet;
            }
            return null;
        }

        /// 
        /// Check if the item is a folder
        /// 
        public bool IsFolder(SPListItem item)
        {
            return item.Folder != null;
        }

public static class LocalExtensions
    {
        public static XDocument GetXDocument(this OpenXmlPart part)
        {
            XDocument xdoc = part.Annotation();
            if (xdoc != null)
                return xdoc;
            using (StreamReader sr = new StreamReader(part.GetStream()))
            using (XmlReader xr = XmlReader.Create(sr))
                xdoc = XDocument.Load(xr);
            part.AddAnnotation(xdoc);
            return xdoc;
        }

        public static void PutXDocument(this OpenXmlPart part)
        {
            XDocument xdoc = part.GetXDocument();
            if (xdoc != null)
            {
                // Serialize the XDocument object back to the package.
                using (XmlWriter xw =
                    XmlWriter.Create(part.GetStream
                   (FileMode.Create, FileAccess.Write)))
                {
                    xdoc.Save(xw);
                }
            }
        }

        public static string StringConcatenate(
            this IEnumerable source)
        {
            return source.Aggregate(
                new StringBuilder(),
                (s, i) => s.Append(i),
                s => s.ToString());
        }
    }

public class Utility
    {
        public static string GetStringBySplit(string stringWords, int returnPostion, string[] splitChar)
        {
            string[] split = stringWords.Split(splitChar, StringSplitOptions.RemoveEmptyEntries);
            if (split.Length > 1)
                return split[returnPostion];

            return stringWords;
        }
    }


Note: It is not the actual solution but the foundation from where I started building the solution.

Cheers…. J

No comments:

Post a Comment