Search code examples
c#openxmlopenxml-sdk

How to replace text with Image / Table in OpenXML (C# .Net core 3.1)


I am just using OpenXML for manipulating docx document. I have templates that has notation like {{userFirstName}} {{tableOfUsers}} {{signatureImage}} etc

I need to replace those text with table, image etc. How to do that in Openxml ? I'm using C# .Net core 3.1 with OpenXML 2.5

My code was like this, but the table still not inserted into the right place:

    var fileName = Path.Combine(_hostingEnv.WebRootPath, "test/test.docx");
    var fileNameResult = Path.Combine(_hostingEnv.WebRootPath, "test/result.docx");

    byte[] byteArray = System.IO.File.ReadAllBytes(fileName);

    using (MemoryStream stream = new MemoryStream())
    {
        stream.Write(byteArray, 0, (int)byteArray.Length);
        using (WordprocessingDocument wd = WordprocessingDocument.Open(stream, true))
        {
            Table table = new Table();

            // Create a TableProperties object and specify its border information.
            TableProperties tblProp = new TableProperties(
                new TableBorders(
                    new TopBorder()
                    {
                        Val =
                        new EnumValue<BorderValues>(BorderValues.Dashed),
                        Size = 24
                    },
                    new BottomBorder()
                    {
                        Val =
                        new EnumValue<BorderValues>(BorderValues.Dashed),
                        Size = 24
                    },
                    new LeftBorder()
                    {
                        Val =
                        new EnumValue<BorderValues>(BorderValues.Dashed),
                        Size = 24
                    },
                    new RightBorder()
                    {
                        Val =
                        new EnumValue<BorderValues>(BorderValues.Dashed),
                        Size = 24
                    },
                    new InsideHorizontalBorder()
                    {
                        Val =
                        new EnumValue<BorderValues>(BorderValues.Dashed),
                        Size = 24
                    },
                    new InsideVerticalBorder()
                    {
                        Val =
                        new EnumValue<BorderValues>(BorderValues.Dashed),
                        Size = 24
                    }
                )
            );

            // Append the TableProperties object to the empty table.
            table.AppendChild<TableProperties>(tblProp);

            // Create a row.
            TableRow tr = new TableRow();

            // Create a cell.
            TableCell tc1 = new TableCell();

            // Specify the width property of the table cell.
            tc1.Append(new TableCellProperties(
                new TableCellWidth() { Type = TableWidthUnitValues.Dxa, Width = "2400" }));

            // Specify the table cell content.
            tc1.Append(new Paragraph(new Run(new Text("some text"))));

            // Append the table cell to the table row.
            tr.Append(tc1);

            // Create a second table cell by copying the OuterXml value of the first table cell.
            TableCell tc2 = new TableCell(tc1.OuterXml);

            // Append the table cell to the table row.
            tr.Append(tc2);

            // Append the table row to the table.
            table.Append(tr);  
            var tblStr = table.ToString();

            //wd.MainDocumentPart.Document.Body.Append(table);
            Text tablePl = wd.MainDocumentPart.Document.Body.Descendants<Text>().Where(x => x.Text == "{{tableOfUsers}}").First();
            if(tablePl != null)
            {
                var parent = tablePl.Parent;
                tablePl.Parent.InsertAfter<Table>(table, tablePl);
                tablePl.Remove();
            }

            string docText = null;
            using (StreamReader sr = new StreamReader(wd.MainDocumentPart.GetStream()))
            {
                docText = sr.ReadToEnd();
            }
            Regex regexText = new Regex("{{name}}");
            docText = regexText.Replace(docText, "Claire " + DateTime.Now.ToString());
            // Regex regextable = new Regex("{{tableOfUsers}}");
            // docText = regextable.Replace(docText, tblStr);


            using (StreamWriter sw = new StreamWriter(wd.MainDocumentPart.GetStream(FileMode.Create)))
            {
                sw.Write(docText);
            }
        }
        await System.IO.File.WriteAllBytesAsync(fileNameResult, stream.ToArray());
    }

    _fileRepo.SetPath("test");
    string fileName2 = "result.docx";
    var data = await _fileRepo.DownloadFile(fileName2);
    return File(data, "application/octet-stram", "filename.docx");
}

My docx file looks like

Hello {{name}}

Here is the list of users : {{tableOfUsers}}

Sincerely,

{{signatureImage}}


Solution

  • Use the code below to insert a table:

    ............
    string tablePlaceholder = "{{tableOfUsers}}";
    Text tablePl = wd.MainDocumentPart.Document.Body
        .Descendants<Text>()
        .Where(x => x.Text.Contains(tablePlaceholder))
        .First();
    if (tablePl != null)
    {
        //Insert the table after the paragraph.
        var parent = tablePl.Parent.Parent.Parent;
        parent.InsertAfter(table, tablePl.Parent.Parent);
        tablePl.Text = tablePl.Text.Replace(tablePlaceholder, "");
        wd.MainDocumentPart.Document.Save();
    }
    
    string docText = wd.MainDocumentPart.Document.Body.OuterXml;
    Regex regexText = new Regex("{{name}}");
    docText = regexText.Replace(docText, "Claire " + DateTime.Now.ToString());
    wd.MainDocumentPart.Document.Body = new Body(docText);
    wd.MainDocumentPart.Document.Save();
    .............
    

    You are looking for {{table}} in your code, but the notation in your template is {{tableOfUsers}}.