2

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?

TheMixy
  • 1,049
  • 15
  • 36
  • if you look you modify documentText but then save or coninue with result, and result is the steam array, which you never modified , you modified documentText... dont know how the lib works. but you could of searched the stream and replaced it directly or some how saved the documentText back to a new doc. – Seabizkit Nov 01 '20 at 09:04
  • does `doc` not have a replace... – Seabizkit Nov 01 '20 at 09:08
  • @Seabizkit: the code was wrong like I explained in my answer and provided a working example – TheMixy Nov 01 '20 at 09:26
  • im just explaining why it didn't work, change how you doing something doesn't explain why the first didn't work.... its like saying here my c# which doesn't work and someone says ok here is a working java example. it doesn't help with why it didn't work...aka the problem with the first version, your answer completely by passes the actual reason, in your case it is extremely similar aka not a drastic but still same concept applies. in other words with a few simple changes the original could of been fixed. instead you did a different way... many ways to skin a cat. i get it. – Seabizkit Nov 01 '20 at 09:33
  • I understand, but I posted my solution below, because I do not know how to fix the code in my original question – TheMixy Nov 01 '20 at 09:57

1 Answers1

2

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

TheMixy
  • 1,049
  • 15
  • 36