Modifying WordprocessingDocument does not save changes

938 Views Asked by At

It's my first time using DocumentFormat.OpenXml so I have a noob question/problem.

Using help from this post: Save modified WordprocessingDocument to new file I wrote the code below to change some text (by tag) in an existing Word (.docx) document and then download as a new file.

I'm using Asp.Net Core 3.1 for a small web application.

byte[] result;
//source file
var path = Path.Combine(_webHostingEnvironment.WebRootPath, "templates\\MyReport.docx");
string documentText;

byte[] byteArray = System.IO.File.ReadAllBytes(path);
using (MemoryStream stream = new MemoryStream())
{
    stream.Write(byteArray, 0, (int)byteArray.Length);
    using (WordprocessingDocument doc = WordprocessingDocument.Open(stream, true))
    {
        using (StreamReader reader = new StreamReader(doc.MainDocumentPart.GetStream()))
        {
            documentText = reader.ReadToEnd();
        }

    documentText = documentText.Replace("company", "My Company ltd.");
    }
    result = stream.ToArray();
}

//download new file
return File(result, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "MyReport.docx");

I'm experiencing two problems:

  1. file downloaded is exactly the same as the source Word file. documentText.Replace seems to have no effect on the file being downloaded
  2. when I want to use a bit more "complex" tags within the source Word file, e.g. {company} it gets "split" in the documentText into separate words...

What am I doing wrong?

1

There are 1 best solutions below

0
TheMixy On BEST ANSWER

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");
}