Save Modified Wordprocessingdocument to New File

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:

  1. Make a temporary copy of your template file, naming it whatever you want.
  2. Perform your OpenXml changes on the above file.
  3. Save the appropriate sections (ie. using the .myWordDocument.MainDocumentPart.Document.Save() method for the main content or someHeaderPart.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



Leave a reply



Submit