Use OpenXML to Create a Word Document from an Existing docx File
Create a Word document from a docx template
Introduction
Hi, thanks for your interest in this tip. I am writing this tip because I faced a problem in achieving a simple goal. The goal was to use a Word document as a template and create a new one, some contents from the template should get replaced by user provided values.
There are plenty of ways provided for this task but it needed more understanding of XML templates. May be some of us expect rapid task completion without spending more time on understandings. Hence this tip is useful.
A detailed problem and its solution are provided below.
Background
OpenXML is widely used for creating/updating Office documents. It has a predefined structure of XML for document. One can refer to this link for details.
My Task: Use Open XML and create a new Word document. Template is predefined with extension as "*.docx". This template contains some words which need to be replaced by user provided values.
Let's Do It
Before you start using Visual Studio, check whether you have installed Open XML 2.0 on machine. If yes, we are good to go forward.
Follows the steps:
- Open Visual Studio and select the blank ASP.NET project, add references
of two DLLs to the project: "
WindowsBase
" and "DocumentFormat.OpenXml
". - Then create two folders "Templates" and "New Documents".
- Add a Word document "mytemplate.docx" in the template folder to use it as template for new documents.
- Add your text in document. E.g., Hi folks, My name is “Replaceable Text”.
- Now on default.aspx, add the following code:
- Now click onto button to generate click event and add the below code in it.
- Add one more function below above event.
- Compile code and execute it and we are done with code.
- Enter name in text box and file will open automatically.
Please enter your name <asp:TextBox ID="txtName" runat="server" />
:
<asp:Button ID="btnSubmit" runat="server" Text="Create" />
protected void btnSubmit_Click(object sender, EventArgs e){
#region
try
{
string sourceFile = Server.MapPath(Path.Combine("/", "Templates/mytemplate.docx"));
string destinationFile = Server.MapPath
(Path.Combine("/", "New Documents/FirstDocument.docx"));
// Create a copy of the template file and open the copy
File.Copy(sourceFile, destinationFile, true);
// create key value pair, key represents words to be replace and
//values represent values in document in place of keys.
Dictionary<string, string> keyValues = new Dictionary<string, string>();
keyValues.Add("“Replaceable Text”", txtName.Text);
SearchAndReplace(destinationFile, keyValues);
Process.Start(destinationFile);
}
catch (Exception ex)
{
throw ex;
}
#endregion
}
Note: "Replaceable Text" can be any text like 'My text' or ::#My Text::#
// To search and replace content in a document part.
public static void SearchAndReplace(string document, Dictionary<string, string> dict)
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(document, true))
{
string docText = null;
using (StreamReader sr = new StreamReader(wordDoc.MainDocumentPart.GetStream()))
{
docText = sr.ReadToEnd();
}
foreach (KeyValuePair<string, string> item in dict)
{
Regex regexText = new Regex(item.Key);
docText = regexText.Replace(docText, item.Value);
}
using (StreamWriter sw = new StreamWriter(
wordDoc.MainDocumentPart.GetStream(FileMode.Create)))
{
sw.Write(docText);
}
}
}
Expected Problems and Limitations
This article has been developed by considering that the template you are using is correctly formatted.
- Let me explain in detail as:
- We have used
Regx
class so take care of those charters used in regular expression formatting.
Consider you are trying to replace word from document is "Employee
" it will not work with above code replacement.
Because docx file is formatted in XML format internally. XML format for this word can be as follows:
<w:r>
<w:rPr>
<w:b />
<w:color w:val="333333" />
<w:sz w:val="32" />
<w:szCs w:val="32" />
</w:rPr>
<w:t>E</w:t>
</w:r>
<w:r w:rsidRPr="00DA41AA">
<w:rPr>
<w:color w:val="333333" />
<w:sz w:val="32" />
<w:szCs w:val="32" />
</w:rPr>
<w:t>mployee</w:t>
</w:r>
As you can see, it has <w:t>E</w:t>
formatting for E and rest of the characters are in <w:t>mployee</w:t>
XML element, hence our code won't find Employee
word.
So it cannot be replaced.