Using the MS OpenXml Sdk I have been able to copy a templatestream to a resultstream and append dynamic text(w.p>>w.r>>w.t) at the end of the body using the following code:
var templateStream = File.OpenRead(templatePath);
templateStream.CopyTo(resultStream);
using (var resultPackage = WordprocessingDocument.Open(resultStream, true))
{
var document = resultPackage.MainDocumentPart.Document;
var body = document.Body;
// Add new text.
var para = body.AppendChild(new Paragraph());
var run = para.AppendChild(new Run());
run.AppendChild(new Text(firstName));
document.Save();
}
My next logical step was to then replace the innertext of a textbox in the resultStream with the firstName as in the code below.
// replacing code in using statement from above
var document = resultPackage.MainDocumentPart.Document;
var textbox = document.Descendants<TextBox>().First();
const string firstNametag = "<<IH.FirstName>>";
if (textbox.InnerText.Contains(firstNametag))
{
var textboxContent = textbox.Elements<TextBoxContent>().First();
textboxContent.RemoveAllChildren();
var paragraph = textboxContent.AppendChild(new Paragraph());
var run = paragraph.AppendChild(new Run());
run.AppendChild(new Text(firstName));
}
document.Save();
In the first example and with some additional code the result stream is appropriately serialized to a docx and the firstName is appended to the end of the body when viewed in Word. In the second example though the textbox and its contents remain the same even though further examination in the debugger showed the textboxContent’s children reflecting the changes made above.
I am new to OpenXML development so if there is anything obvious please point it out.
Oh wow, I don’t even want to think I understand the whole picture around this but here’s a quick stab at it. Someone with more openXml experience please chime in…
Turns out when you create a textbox in word on a docx the document.xml file get’s the following markup:
Notice the mc.AlternateContent, mc.Choice, and mc.Fallback tags. What the heck are these??? Someone put it this way on a blog article I came across –
“As I understand it – but don’t take my word as gospel – AlternateContent can
appear anywhere and provides a mechanism for including enhanced
functionality if the consuming application can handle it, along with a
fallback if it can’t.”
-Tony Jollans – http://social.msdn.microsoft.com/Forums/en-US/worddev/thread/f8a5c277-7049-48c2-a295-199d2914f4ba/
In my case I was only modifying the fallback textbox(v.txbx not wps.txbx) because of my mishap in assuming Resharper was right in asking me to import the DocumentFormat.OpenXml.Vml namespace for my dependency on the TextBox object. Not sure why there isn’t a Textbox definition in one of my already included namespaces, DocumentFormat.OpenXml.Packaging or DocumentFormat.OpenXml.Wordprocessing but that’s beyond the scope of this question. Needless to say, upon realizing this and updating my code to look for the common w.txbxContent for the two I achieved what I wanted to do.
Here’s the updated code with some refactoring, call the ReplaceTag method in the using statement from the original question and supply a model object instead of a string. Also, use the tagToValueSelector dictionary for convenience.
Happy openXmling 🙂