Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to insert text into a content control with the Open XML SDK

I'm trying to develop a solution which takes the input from a ASP.Net Web Page and Embed the input values into Corresponding Content Controls within a MS Word Document. The MS Word Document has also got Static Data with some Dynamic data to be Embed into the Header and Footer fields.

The Idea here is that the solution should be Web based. Can I use OpenXML for this purpose or any other approach that you can suggest.

Thank you very much in advance for all your valuable inputs. I really appreciate them.

like image 414
Bryan Jacob Avatar asked Apr 13 '16 13:04

Bryan Jacob


People also ask

How do I add a reference to DocumentFormat OpenXml packaging?

Go to your Solution Explorer > right click on references and then click Manage NuGet Packages . Then search in tab "Online" for DocumentFormat. OpenXml and install it.

What is Open XML SDK?

The Open XML SDK provides . NET developers with a set of strongly typed classes that make it easy to read, write and manipulate the parts and content in an Open XML document such as the DOCX, XLSX or PPTX files created by Microsoft Office. It can be used in any .

How do I open Office Open XML in word-processing?

#1) Open Windows Explorer and browse to the location where the XML file is located. We have browsed to the location of our XML file MySampleXML as seen below. #2) Now right-click over the file and select Open With to choose Notepad or Microsoft Office Word from the list of options available to open the XML file.


1 Answers

I have a little code sample from my project, to insert a few words in a content control you've created in a Word document:

public static WordprocessingDocument InsertText(this WordprocessingDocument doc, string contentControlTag, string text)
{
    SdtElement element = doc.MainDocumentPart.Document.Body.Descendants<SdtElement>()
      .FirstOrDefault(sdt => sdt.SdtProperties.GetFirstChild<Tag>()?.Val == contentControlTag);

    if (element == null)
      throw new ArgumentException($"ContentControlTag \"{contentControlTag}\" doesn't exist.");

    element.Descendants<Text>().First().Text = text;
    element.Descendants<Text>().Skip(1).ToList().ForEach(t => t.Remove());

    return doc;
}

It simply looks for the first contentcontrol in the document with a specific Tag (you can set that by enabling designer mode in word and right-clicking on the content control), and replaces the current text with the text passed into the method. After this the document will still contain the content controls of course which may not be desired. So when I'm done editing the document I run the following method to get rid of the content controls:

internal static WordprocessingDocument RemoveSdtBlocks(this WordprocessingDocument doc, IEnumerable<string> contentBlocks)
{
    List<SdtElement> SdtBlocks = doc.MainDocumentPart.Document.Descendants<SdtElement>().ToList();

    if (contentBlocks == null)
        return doc;

    foreach(var s in contentBlocks)
    {
        SdtElement currentElement = SdtBlocks.FirstOrDefault(sdt => sdt.SdtProperties.GetFirstChild<Tag>()?.Val == s);
        if (currentElement == null)
            continue;
        IEnumerable<OpenXmlElement> elements = null;

        if (currentElement is SdtBlock)
            elements = (currentElement as SdtBlock).SdtContentBlock.Elements();
        else if (currentElement is SdtCell)
            elements = (currentElement as SdtCell).SdtContentCell.Elements();
        else if (currentElement is SdtRun)
            elements = (currentElement as SdtRun).SdtContentRun.Elements();

        foreach (var el in elements)
            currentElement.InsertBeforeSelf(el.CloneNode(true));
        currentElement.Remove();
    }
    return doc;
}

To open the WordProcessingDocument from a template and edit it, there is plenty of information available online.

Edit:

Little sample code to open/save documents while working with them in a memorystream, of course you should take care of this with an extra repository class that takes care of managing the document in the real code:

byte[] byteArray = File.ReadAllBytes(@"C:\...\Template.dotx");

using (var stream = new MemoryStream())
{
    stream.Write(byteArray, 0, byteArray.Length);

    using (WordprocessingDocument doc = WordprocessingDocument.Open(stream, true))
    {
       //Needed because I'm working with template dotx file, 
       //remove this if the template is a normal docx. 
        doc.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
        doc.InsertText("contentControlName","testtesttesttest");
    }
    using (FileStream fs = new FileStream(@"C:\...\newFile.docx", FileMode.Create))
    {
       stream.WriteTo(fs);
    }
}
like image 82
Alexander Derck Avatar answered Sep 22 '22 11:09

Alexander Derck