Blog Map
[Blog Map] This blog is inactive. New blog: EricWhite.com/blog
Sometimes you want to work with Open XML documents in memory. There are two scenarios that I know of:
This blog post presents a bit of code that shows how to work with in-memory documents as a MemoryStream. The code works with either Open XML SDK V1 or CTP1 of the Open XML SDK V2.
There is one important point to make about using the Open XML SDK with MemoryStream objects. There is a MemoryStream constructor that takes a byte array as an argument. However, we can’t use that constructor because it creates a non-resizable instance of the MemoryStream class, and the Open XML SDK needs a resizable memory stream, as parts may change in size when serialized back into the Open XML package. Instead, we use the constructor that takes no parameters. This creates a resizable MemoryStream. We can then write the byte array to the MemoryStream, and then open the Open XML package from the MemoryStream (using the WordprocessingDocument class in this example).
After opening the WordprocessingDocument, we can work with the document as normal using the Open XML SDK. After leaving the scope of the ‘using’ statement that opens the document, the memory stream will contain the new, modified document.
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.IO;using System.Xml;using System.Xml.Linq;using DocumentFormat.OpenXml.Packaging; public static class LocalExtensions{ public static XDocument GetXDocument(this OpenXmlPart part) { XDocument xdoc = part.Annotation<XDocument>(); 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<string> source) { return source.Aggregate( new StringBuilder(), (s, i) => s.Append(i), s => s.ToString()); }} class Program{ static void Main(string[] args) { byte[] byteArray = File.ReadAllBytes("Test.docx"); 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"; // modify the document as necessary // for this example, we'll convert the first paragraph to upper case XDocument doc = wordDoc.MainDocumentPart.GetXDocument(); XElement firstParagraph = doc .Element(w + "document") .Element(w + "body") .Element(w + "p"); if (firstParagraph != null) { string text = firstParagraph .Descendants() .Where(n => n.Name == w + "t" || n.Name == w + "ins") .Select(n => (string)n) .StringConcatenate(); firstParagraph.ReplaceWith( new XElement(w + "p", new XElement(w + "r", new XElement(w + "t", text.ToUpper())))); // write the XDocument back into the Open XML document wordDoc.MainDocumentPart.PutXDocument(); } } // at this point, the MemoryStream contains the modified document. // We could write it back to a SharePoint document library or serve // it from a web server. // in this example, we'll serialize back to the file system to verify // that the code worked properly. using (FileStream fileStream = new FileStream("Test2.docx", System.IO.FileMode.CreateNew)) { mem.WriteTo(fileStream); } } }}
Code is attached.
Sometimes you want to work with Open XML documents in memory. This blog post presents a bit of code that shows how to work with in-memory documents as a MemoryStream. The code works with either Open XML SDK V1 or CTP1 of the Open XML SDK V2.
This post describes the issues and presents a minimal amount of code that shows how to open an Open XML document from a SharePoint list, modify it, and then save it back to either the same location, or a different one if you desire.
By combining LINQ to SQL with LINQ to Objects in this fashion, you can write some pretty simple C# code that uses LINQ to join data across two separate, disparate data sources.
There is an approach using LINQ to XML that provides some of the benefits of a strongly typed document object model. The approach consists of declaring a static class with static, initialized XName and XNamespace fields in the class, and then using those XName and XNamespace objects in the LINQ to XML code that creates and queries XML trees.