Search code examples
xmlopenxmllinq-to-xmlmemorystreamfile-manipulation

In-memory XML manipulation


I'm trying to do a find and replace in an OpenXML word document which I've openened into a MemoryStream.

using (WordprocessingDocument _document = WordprocessingDocument.Open(_ms, true))
{
    var placeHolder = _document.MainDocumentPart.Document
                          .Descendants<DocumentFormat.OpenXml.Wordprocessing.Text>()
                          .Where(node => node.InnerText.Contains("***PlaceHolderText***"))
                          .FirstOrDefault();

    placeHolder.InnerText.Replace("***PlaceHolderText***", "hello world!");
}

This doesn't work. I'm not sure why, but manipulating the document in this way doesn't seem to have any affect on the MemoryStream.

I found this blog by Eric White which does something similar, but I still can't quite get it. He uses an XDocument, so I've got something like the following:

XDocument doc = _document.MainDocumentPart.GetXDocument(); // this is an extension method
var textNodes = doc.DescendantNodes().Where(n => n.NodeType == XmlNodeType.Text);

This finds the right nodes in my document, but the problem is now I can't work out how to change the text. The System.Xml.Linq.XNodes which I end up with this way (instead of the DocumentFormat.OpenXml.Wordprocessing.Text nodes I really want) don't have an InnerText or Value property or anything like that. I can't see any way to get the text from the nodes, or update them. I tried casting the node but that didn't compile.

Am I even going in the right direction? Or is there an easier way? Any pointers would be very much appreciated, thanks.


Solution

  • I finally got this working. Taking the first code snippet, the last line should read placeHolder.Text and not placeHolder.InnerText. Can't believe I wasted 4 hours on that! :(