1

I have an word file template and xml file for data. I want to find content Content control in word and get data from xml and then replace text in word template. i'm using the following code but it is not updating word file.

using (WordprocessingDocument document = WordprocessingDocument.CreateFromTemplate(txtWordFile.Text))       
{
           MainDocumentPart mainPart = document.MainDocumentPart;
            IEnumerable<SdtBlock> block = mainPart.Document.Body.Descendants<SdtBlock>().Where
                (r => r.SdtProperties.GetFirstChild<Tag>().Val == "TotalClose");
            Text t = block.Descendants<Text>().Single();
             t.Text = "13,450,542";
            mainPart.Document.Save();
}
Cindy Meister
  • 25,071
  • 21
  • 34
  • 43
farrukh aziz
  • 162
  • 1
  • 2
  • 9

3 Answers3

3

For anyone still struggling with this - you can check out this library https://github.com/antonmihaylov/OpenXmlTemplates

With it you can replace the text inside all content controls of the document based on a JSON object (or a basic C# dictionary) without writing specific code, instead you specify the variable name in the tag of the content control.

(Note - i am the maker of that library, but it is open sourced and licensed under LGPLv3)

Anton Mihaylov
  • 938
  • 5
  • 10
1

I think you should write changes to temporary file. See Save modified WordprocessingDocument to new file or my code from work project:

    MemoryStream yourDocStream = new MemoryStream();
    ... // populate yourDocStream with .docx bytes
    using (Package package = Package.Open(yourDocStream, FileMode.Open, FileAccess.ReadWrite))
    {
        //  Load the document XML in the part into an XDocument instance.  
        PackagePart packagePart = LoadXmlPackagePart(package);
        XDocument xDocument = XDocument.Load(XmlReader.Create(packagePart.GetStream()));

        // making changes

        //  Save the XML into the package  
        using (XmlWriter xw = XmlWriter.Create(packagePart.GetStream(FileMode.Create, FileAccess.Write)))
        {
            xDocument.Save(xw);
        }

        var resultDocumentBytes = yourDocStream.ToArray();
    }
anechaev
  • 61
  • 5
0

The basic approach you use works fine, but I'm surprised you're not getting any compile-time errors because

IEnumerable<SdtBlock> block = mainPart.Document
                                      .Body
                                      .Descendants<SdtBlock>()
                                      .Where(r => r.SdtProperties.GetFirstChild<Tag>().Val == "TotalClose");

is not compatible with

Text t = block.Descendants<Text>().Single();

block, as IEnumerable has no Descendants property. You either need to loop through all the items in IEnumerable and perform this on each item, or you need to define and instantiate a single item, like this:

using (WordprocessingDocument document = WordprocessingDocument.CreateFromTemplate(txtWordFile.Text))
{
    MainDocumentPart mainPart = pkgDoc.MainDocumentPart;

    SdtBlock block = mainPart.Document.Body.Descendants<SdtBlock>().Where
            (r => r.SdtProperties.GetFirstChild<Tag>().Val == "test1").FirstOrDefault();

    Text t = block.Descendants<Text>().Single();
    t.Text = "13,450,542";

    mainPart.Document.Save();
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Cindy Meister
  • 25,071
  • 21
  • 34
  • 43