Save modified WordprocessingDocument to new file
If you use a MemoryStream
you can save the changes to a new file like this:
byte[] byteArray = File.ReadAllBytes("c:\\data\\hello.docx");
using (MemoryStream stream = new MemoryStream())
{
stream.Write(byteArray, 0, (int)byteArray.Length);
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(stream, true))
{
// Do work here
}
// Save the file with the new name
File.WriteAllBytes("C:\\data\\newFileName.docx", stream.ToArray());
}
Modifying WordprocessingDocument does not save changes
Apparently using StreamReader within WordprocessingDocument was wrong. Here is a working example in case anyone else is looking for a similar solution (with the help from this article: OfficeTalk: Working with In-Memory Open XML Documents):
public virtual IActionResult ExportWord()
{
byte[] result;
// path to where your template is stored
var path = Path.Combine(_webHostingEnvironment.WebRootPath, "files\\template.docx");
// key-value pairs of what you want to change
Dictionary<string, string> dict = new Dictionary<string, string>
{
{ "key1", "value1" },
{ "key2", "value2" },
{ "key3", "value3" },
// etc.
};
// read template into stream
byte[] byteArray = System.IO.File.ReadAllBytes(path);
using (MemoryStream mem = new MemoryStream())
{
mem.Write(byteArray, 0, (int)byteArray.Length);
using (WordprocessingDocument doc = WordprocessingDocument.Open(mem, true))
{
// Modify the document as necessary.
var body = doc.MainDocumentPart.Document.Body;
var paras = body.Elements<Paragraph>();
foreach (var para in paras)
{
foreach (var run in para.Elements<Run>())
{
foreach (var text in run.Elements<Text>())
{
foreach (var item in dict)
{
if (text.Text.Contains(item.Key))
{
text.Text = text.Text.Replace(item.Key, item.Value);
}
}
}
}
}
}
// At this point, the memory stream contains the modified document.
result = mem.ToArray();
}
return File(result, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "modified.docx");
}
Saving an OpenXML Document (Word) generated from a template
Are you referring to the OpenXml SDK? Unfortunately, as of OpenXml SDK 2.0, there's no SaveAs method. You'll need to:
- Make a temporary copy of your template file, naming it whatever you want.
- Perform your OpenXml changes on the above file.
- Save the appropriate sections (ie. using the .
myWordDocument.MainDocumentPart.Document.Save()
method for the main content orsomeHeaderPart.Header.Save()
method for a particular header).
Replacing data in word using DocumentFormat.OpenXml
Just Change=>
var sdtCont = body.InnerXml.Replace("Hello", "Hi");
To
body.InnerXml=body.InnerXml.Replace("Hello", "Hi");
Open XML WordprocessingDocument with MemoryStream is 0KB
There's a couple of things going on here:
First, unlike Microsoft's sample, I was nesting the using
block code that writes the file to disk inside the block that creates and modifies the file. The WordprocessingDocument
gets saved to the stream until it is disposed or when the Save()
method is called. The WordprocessingDocument
gets disposed automatically when reaching the end of it's using
block. If I had not nested the third using statement, thus reaching the end of the second using
statement before trying to save the file, I would have allowed the document to be written to the MemoryStream
- instead I was writing a still empty stream to disk (hence the 0KB file).
I suppose calling Save()
might have helped, but it is not supported by .Net core (which is what I'm using). You can check whether Save()
is supported on you system by checking CanSave
.
/// <summary>
/// Gets a value indicating whether saving the package is supported by calling <see cref="Save"/>. Some platforms (such as .NET Core), have limited support for saving.
/// If <c>false</c>, in order to save, the document and/or package needs to be fully closed and disposed and then reopened.
/// </summary>
public static bool CanSave { get; }
So the code ended up being almost identical to Microsoft's code except I don't read any files beforehand, rather I just begin with an empty MemoryStream
:
using (var mem = new MemoryStream())
{
using (var doc = WordprocessingDocument.Create(mem, WordprocessingDocumentType.Document, true))
{
doc.AddMainDocumentPart().Document = new Document();
var body = doc.MainDocumentPart.Document.AppendChild(new Body());
var paragraph = body.AppendChild(new Paragraph());
var run = paragraph.AppendChild(new Run());
run.AppendChild(new Text("Hello docx"));
}
using (var file = new FileStream(destination, FileMode.CreateNew))
{
mem.WriteTo(file);
}
}
Also you don't need to reopen the document before saving it, but if you do remember to use Open()
instead of Create()
because Create()
will empty the MemoryStream
and you'll also end with a 0KB file.
How to modify a DocX file and save to a different location with OpenXML SDK?
I use a memory stream and pass it to the WordprocessingDocument.Open
method. After I'm done changing the document, I just write the bytes to the destination:
var source = File.ReadAllBytes(filename);
using (var ms = new MemoryStream()) {
ms.Write(source, 0, source.Length);
/* settings defined elsewhere */
using (var doc = WordprocessingDocument.Open(ms, true, settings)) {
/* do something to the doc */
}
/* used in File.WriteAllBytes elsewhere */
return ms.ToArray();
}
SaveAs Wordprocessingdocument (Open XML) file is locked
You were so close:
wordDoc.SaveAs(tempfileMerged).Close();
Related Topics
How to Change Originating Ip in Httpwebrequest
Is There a Synchronization Class That Guarantee Fifo Order in C#
Asynchronous Iterator Task<Ienumerable<T>>
Apiresource VS APIscope VS Identityresource
How to Write to a Onenote 2013 Page Using C# and the Onenote Interop
How to Drag a Usercontrol Inside a Canvas
Extract All Strings Between Two Strings
Serialize as Ndjson Using JSON.Net
Controls in Container Form Come Over Child Form
Difference Between the Keydown Event, Keypress Event and Keyup Event in Visual Studio
No Database Provider Has Been Configured for This Dbcontext' on Signinmanager.Passwordsigninasync
What's the Difference Between Double Quotes and Single Quote in C#
Share Session Between Two Web Sites Using ASP.NET and State Server
Xmlserializer Serialize Generic List of Interface