I have an ASP.NET 4.5 web forms application, running on an IIS 7.5.
I'm trying to generate a word document from one of it's pages where I have a custom form.
I uploaded a word document template which contains merge fields. In the code behind, I want to populate the merge fields based on sql database queries.
For some merge fields, I need to insert multiple lines of text. Some of them even have bullet lists. These text fragments I can't store in sql so I have added them in a separate word document with bookmarks.
So, just to recap:
Template.dotx -> contains the merge fields
Data.docx -> contains the text fragments that have been marked with bookmarks.
I have managed to replace the merge fields from Template.dotx with the use of OpenXML, but I can't find a way to get the data from the bookmarks into the merge fields.
This works great with Interop, but I had problems when I uploaded it on the server so I switched to OpenXML.
This is what I have tried so far:
private string GetBookmarkData(WordprocessingDocument secondWordDoc, string bookmarkKey)
{
string returnVal = "";
foreach (BookmarkStart bookmarkStart in secondWordDoc.MainDocumentPart.RootElement.Descendants<BookmarkStart>())
{
if(bookmarkStart.Name == bookmarkKey)
{
foreach(Run run in bookmarkStart.Parent.Descendants<Run>())
{
returnVal += run.Descendants<Text>().FirstOrDefault().Text + "<br/>";
}
}
}
return returnVal;
}
protected void PrintBtn_Click(object sender, EventArgs e)
{
string mainTemplate = Server.MapPath("~/MyFolder/Template.dotx");
string savePath = Server.MapPath("~/SaveFolder/Final.docx");
File.Copy(mainTemplate, savePath);
using(WordprocessingDocument firstDoc = WordprocessingDocument.Open(savePath, true))
{
using (WordprocessingDocument secondDoc = WordprocessingDocument.Open(Server.MapPath("~/MyFolder/Data.docx"), true))
{
foreach (FieldCode field in firstDoc.MainDocumentPart.RootElement.Descendants<FieldCode>())
{
var fieldNameStart = field.Text.LastIndexOf(" MERGEFIELD", System.StringComparison.Ordinal);
String fieldText = field.InnerText;
if (fieldText.StartsWith(" MERGEFIELD"))
{
Int32 endMerge = fieldText.IndexOf("\\");
Int32 fieldNameLength = fieldText.Length - endMerge;
String fieldName = fieldText.Substring(11, endMerge - 11);
fieldName = fieldName.Trim();
string autoFill = "";
switch (fieldName)
{
case "MergeField1":
autoFill = mergefield_1;
break;
case "MergeField2":
autoFill = mergefield_2;
break;
case "MergeField3":
autoFill = GetBookmarkData(secondDoc, "Bookmark1");
break;
case "MergeField4":
autoFill = GetBookmarkData(secondDoc, "Bookmark2");
break;
case "MergeField5":
autoFill = GetBookmarkData(secondDoc, "Bookmark3");
break;
}
}
foreach (Run run in firstDoc.MainDocumentPart.Document.Descendants<Run>())
{
foreach (Text txtFromRun in run.Descendants<Text>().Where(a => a.Text == "«" + fieldName + "»"))
{
txtFromRun.Text = autoFill;
}
}
}
}
}
firstDoc.ChangeDocumentType(WordprocessingDocumentType.Document);
firstDoc.MainDocumentPart.Document.Save();
}
}
So what does this do ?
When I click on a button, I call the method PrintBtn_Click. After doing some SQL magic (that I haven't included in this), I initialize some variables which will fill each merge field. This example is a short and edited version. The original is much bigger. Using this code I managed to populate the merge fields. It works great. However the method: `
string GetBookmarkData(WordprocessingDocument secondWordDoc, string bookmarkKey)`
Doesn't really do what it's supposed to. It should go into the Data.docx, retrieve all the text from the bookmark I specified. It only returns the rows that have no bullets or weird formatting.
I have used the same process using Interop and I had no problem. How can I do this with OpenXML ? Are the rows with bullets stored in a different xml ?
I tried to retrieve all the Runs between BookmarkStart and BookmarkEnd and grab the Text from it.
Update
The secondDoc is actually the Data.docx and looks something like this:
Bookmark1
• Text-Information 1 (This is just an example)
• Text-Information 2 (This is just an example)
• Text-Information 3 (This is just an example)
• Text-Information 4 (This is just an example)
Bookmark2
This is a list of multiple items:
Item 1 x.000,00
Item 2 x.000,00
Item 3 x.000,00
Item 4 x.000,00
Item 5 000,00
This is the conclusion for this list.
Following is a list of other multiple items:
Item 1 x.000,00
Item 2 x.000,00
Item 3 x.000,00
Item 4 x.000,00
Item 5 000,00
This is the conclusions for this list
Bookmark3
a) Another example of text that needs to go in the mergefield:
• Article 1 xxxx Quantity/Producer etc
• Article 2 xxxx Quantity/Producer etc
Some details about this block of text that is not relevant but I need to insert it in the merge field as well
So the entire text after "Bookmark1"/"Bookmark2"/"Bookmark3", needs to go in their specific merge fields, if a certain radiobutton is pressed. I have bookmarked these blocks of text. As I told you above, it only inserts some rows which have no bullets. For instance, the merge field which corresponds to Bookmark2, receives only "This is a list of multiple items:".