private static void DoMailMerge(WordOpenXmlDocument document, DataTable data, IEnumerable <MailMergeMapping> mappings) { var bodyElements = document.Body.ChildElements; var tempBody = new Body(document.Body.OuterXml); //Remove original elements: while (bodyElements.Count() > 0) { bodyElements.ElementAt(0).Remove(); } bool firstIteration = true; foreach (DataRow row in data.Rows) { var newBody = new Body(tempBody.OuterXml); var mapValues = new Dictionary <string, string>(); mappings.ForEach(kv => { if (!mapValues.ContainsKey(kv.MailMergeFieldName)) { mapValues.Add(kv.MailMergeFieldName, row.Field <string>(kv.DataColumnFieldName)); } }); MailMergeHelper.ProcessBody(document, newBody, null, mapValues); if (firstIteration) { firstIteration = false; } else { document.InsertPageBreak(); } newBody.ChildElements.ForEach(e => document.Body.AppendChild(e.CloneNode(true))); } document.Save(); }
public static WordOpenXmlDocument Create(string filePath) { var word = new WordOpenXmlDocument(); word.Document = WordprocessingDocument.Create(filePath, WordprocessingDocumentType.Document); var mainDocumentPart = word.Document.AddMainDocumentPart(); const string docXml = @"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?> <w:document xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main""> <w:body> </w:body> </w:document>"; using (var stream = mainDocumentPart.GetStream()) { byte[] buffer = (new UTF8Encoding()).GetBytes(docXml); stream.Write(buffer, 0, buffer.Length); } return(word); }
public static void ProcessHeadersAndFooters(WordOpenXmlDocument document, IDictionary <string, string> values) { // process header(s) foreach (var headerPart in document.Document.MainDocumentPart.HeaderParts) { // 2010/08/01: addition ConvertComplexFieldsToSimpleFields(headerPart.Header); FillWordFieldsInElement(values, headerPart.Header); headerPart.Header.Save(); // save header back in package } // process footer(s) foreach (var footerPart in document.Document.MainDocumentPart.FooterParts) { // 2010/08/01: addition ConvertComplexFieldsToSimpleFields(footerPart.Footer); FillWordFieldsInElement(values, footerPart.Footer); footerPart.Footer.Save(); // save footer back in package } document.Save(); }
/// <summary> /// Fills in the body element with the provided data. /// </summary> /// <param name="dataSet">Dataset with the datatables to use to fill the document tables with. Table names in the dataset should match the table names in the document.</param> /// <param name="values">Values to fill the document. Keys should match the MERGEFIELD names.</param> /// <returns>The filled-in document.</returns> public static void ProcessBody(WordOpenXmlDocument document, Body body, DataSet dataSet, IDictionary <string, string> values) { ConvertComplexFieldsToSimpleFields(body); #region Process All Tables string[] switches = null; foreach (var field in body.Descendants <SimpleField>()) { string fieldName = GetFieldName(field, out switches); if (!string.IsNullOrEmpty(fieldName) && fieldName.StartsWith("TBL_")) { var tableRow = GetFirstParent <TableRow>(field); if (tableRow == null) { // can happen because table contains multiple fields, and after 1 pass, the initial row is already deleted continue; } var table = GetFirstParent <Table>(tableRow); if (table == null) { // can happen because table contains multiple fields, and after 1 pass, the initial row is already deleted continue; } string tableName = GetTableNameFromFieldName(fieldName); if (dataSet == null || !dataSet.Tables.Contains(tableName) || dataSet.Tables[tableName].Rows.Count == 0) { // don't remove table here: will be done in next pass continue; } var dataTable = dataSet.Tables[tableName]; var cellPropertiesList = new List <TableCellProperties>(); var cellColumnNamesList = new List <string>(); var paragraphPropertiesList = new List <string>(); var cellFieldsList = new List <SimpleField>(); foreach (var tableCell in tableRow.Descendants <TableCell>()) { cellPropertiesList.Add(tableCell.GetFirstChild <TableCellProperties>()); var paragraph = tableCell.GetFirstChild <Paragraph>(); if (paragraph != null) { var pp = paragraph.GetFirstChild <ParagraphProperties>(); if (pp != null) { paragraphPropertiesList.Add(pp.OuterXml); } else { paragraphPropertiesList.Add(null); } } else { paragraphPropertiesList.Add(null); } string columnName = string.Empty; SimpleField columnField = null; foreach (var cellField in tableCell.Descendants <SimpleField>()) { columnField = cellField; columnName = GetColumnNameFromFieldName(GetFieldName(cellField, out switches)); break; // supports only 1 cellfield per table } cellColumnNamesList.Add(columnName); cellFieldsList.Add(columnField); } // keep reference to row properties var rowProperties = tableRow.GetFirstChild <TableRowProperties>(); foreach (DataRow dataRow in dataTable.Rows) { var row = new TableRow(); if (rowProperties != null) { row.Append(new TableRowProperties(rowProperties.OuterXml)); } for (int i = 0; i < cellPropertiesList.Count; i++) { var cellProperties = new TableCellProperties(cellPropertiesList[i].OuterXml); var cell = new TableCell(); cell.Append(cellProperties); var p = new Paragraph(new ParagraphProperties(paragraphPropertiesList[i])); cell.Append(p); // cell must contain at minimum a paragraph ! if (!string.IsNullOrEmpty(cellColumnNamesList[i])) { if (!dataTable.Columns.Contains(cellColumnNamesList[i])) { throw new Exception(string.Format("Unable to complete template: column name '{0}' is unknown in parameter tables !", cellColumnNamesList[i])); } if (!dataRow.IsNull(cellColumnNamesList[i])) { string val = dataRow[cellColumnNamesList[i]].ToString(); p.Append(GetRunElementForText(val, cellFieldsList[i])); } } row.Append(cell); } table.Append(row); } // finally : delete template-row (and thus also the mergefields in the table) tableRow.Remove(); } } #endregion Process All Tables #region Clean Empty Tables foreach (var field in body.Descendants <SimpleField>()) { string fieldName = GetFieldName(field, out switches); if (!string.IsNullOrEmpty(fieldName) && fieldName.StartsWith("TBL_")) { var tableRow = GetFirstParent <TableRow>(field); if (tableRow == null) { continue; // can happen: is because table contains multiple fields, and after 1 pass, the initial row is already deleted } var table = GetFirstParent <Table>(tableRow); if (table == null) { continue; // can happen: is because table contains multiple fields, and after 1 pass, the initial row is already deleted } string tableName = GetTableNameFromFieldName(fieldName); if (dataSet == null || !dataSet.Tables.Contains(tableName) || dataSet.Tables[tableName].Rows.Count == 0) { // if there's a 'dt' switch: delete Word-table if (switches.Contains("dt")) { table.Remove(); } } } } #endregion Clean Empty Tables #region Process Remaining Fields In Main Document & Save FillWordFieldsInElement(values, body); document.Save(); // save main document back in package #endregion Process Remaining Fields In Main Document & Save }