public void ReplaceString(OpenXmlElement element, string val) { var text = element.Descendants <Word.Text>().FirstOrDefault(); var run = text == null?element.Descendants <Word.Run>().FirstOrDefault() : FindParent <Word.Run>(text); var runp = run.Parent; var paragraph = FindParent <Word.Paragraph>(runp); run.RsidRunProperties = null; run.RemoveAllChildren <Word.Text>(); run.RemoveAllChildren <Word.RunProperties>(); runp.RemoveAllChildren <Word.Run>(); runp.RemoveAllChildren <Word.Break>(); if (paragraph.ParagraphProperties?.ParagraphMarkRunProperties != null) { run.RunProperties = new Word.RunProperties(); foreach (var item in paragraph.ParagraphProperties.ParagraphMarkRunProperties) { run.RunProperties.AppendChild(item.CloneNode(true)); } } if (text == null) { text = new Word.Text(); } else if (text.Parent != null) { text.Remove(); } string[] pagesplit = val.TrimEnd("\r\n".ToCharArray()).Split("\f".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); for (int p = 0; p < pagesplit.Length; p++) { var lineSpit = pagesplit[p].Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); if (lineSpit.Length > 0) { for (int i = 0; i < lineSpit.Length; i++) { if (p == 0 && i == 0) { text.Text = lineSpit[0]; text.Space = SpaceProcessingModeValues.Preserve; run.Append(text); runp.Append(run); continue; } Word.Run r = run.Clone() as Word.Run; r.RemoveAllChildren <Word.Text>(); r.Append(new Word.Text(lineSpit[i]) { Space = SpaceProcessingModeValues.Preserve }); Word.Paragraph pr = (Word.Paragraph)paragraph.Clone(); pr.RemoveAllChildren <Word.Run>(); pr.RemoveAllChildren <Word.Break>(); pr.RemoveAllChildren <Word.SdtBlock>(); pr.RemoveAllChildren <Word.SdtRun>(); pr.Append(r); paragraph.Parent.InsertAfter <Word.Paragraph>(pr, paragraph); paragraph = pr; } } if (p < pagesplit.Length - 1) { var bp = new Word.Break() { Type = Word.BreakValues.Page }; paragraph.AppendChild(bp); } } }
public static MemoryStream BuildReport(IConfigurationRoot config) { //Read the template from disk byte[] byteArray = File.ReadAllBytes(config["ReportConfiguration:TemplateFile"]); //Load it into memory MemoryStream mem = new MemoryStream(); mem.Write(byteArray, 0, byteArray.Length); //Open the word document from memory using (WordprocessingDocument output = WordprocessingDocument.Open(mem, true)) { var doc = output.MainDocumentPart.Document; var contentControls = output.ContentControls().ToList(); foreach (var cc in contentControls) { wp.SdtProperties props = cc.Elements <wp.SdtProperties>().FirstOrDefault(); string controlTitle = props.Elements <wp.SdtAlias>().FirstOrDefault().Val; string controlTag = props.Elements <wp.Tag>().FirstOrDefault().Val; string configKeyResult = String.Format("{0}:Result", controlTitle); string queryResult = config[configKeyResult]; Type sdtType = ((wp.SdtElement)cc).GetType(); OpenXmlElement targetContent = null; //Determine if the content control is actually a docpart (Table of Contents, etc.), so we can ignore it. bool isDocPart = false; //If the content control document tag is a block tag and has docpart object children, it's a docpart. if (sdtType == typeof(wp.SdtBlock) && (((wp.SdtBlock)cc).Descendants <wp.SdtContentDocPartObject>().Count() > 0)) { isDocPart = true; } if (!isDocPart) { //Replace our ReportParameter placeholders. if (controlTag.Equals("ReportParameter")) { if (config[controlTitle] != null) { targetContent = new wp.Text(config[controlTitle]); } else { targetContent = new wp.Text("No Result"); } } //Replace our SingleValue placeholders with tables containing the query results. if (controlTag.Equals("SingleValue")) { if (queryResult != null) { dynamic svData = JsonConvert.DeserializeObject <dynamic>(queryResult); if (svData.rows.Count == 1) { targetContent = new wp.Text(svData.rows[0][0].ToString()); } else { throw new IndexOutOfRangeException(String.Format("The QueryResult for {0} contained {1} row/s but a single row was expected.", controlTitle, svData.rows.Count)); } } else { targetContent = new wp.Text("No Result"); } } //Special handling is needed if a SingleValue or ReportParameter content control is actually configured as a SdtBlock instead of SdtRun. if (controlTag.Equals("ReportParameter") || controlTag.Equals("SingleValue")) { if (sdtType == typeof(wp.SdtBlock)) { var targetContentParent = cc.GetFirstChild <wp.SdtContentBlock>().GetFirstChild <wp.Paragraph>().CloneNode(true); targetContentParent.GetFirstChild <wp.Run>().InsertAfterSelf(new wp.Run(targetContent)); targetContentParent.GetFirstChild <wp.Run>().Remove(); targetContent = targetContentParent; } } //Replace our Table placeholders with tables containing the query results. if (controlTag.Equals("Table")) { targetContent = BuildTable(queryResult, config["ReportConfiguration:TableStyle"]); } //Update the charts in our Chart placeholders with the data from the query results. if (controlTag.Equals("Chart")) { UpdateChart( cc.Descendants <drc.ChartReference>().FirstOrDefault(), output, controlTitle.Split(':').Last(), queryResult); targetContent = cc.GetFirstChild <wp.SdtContentBlock>().GetFirstChild <wp.Paragraph>().CloneNode(true); } //Remove PlaceholderText styles from all Run elements foreach (var item in cc.Descendants <wp.Run>()) { var rPr = item.GetFirstChild <wp.RunProperties>(); if (rPr != null && rPr.RunStyle != null) { if (rPr.RunStyle.Val == "PlaceholderText") { rPr.RunStyle.Remove(); } } } if (targetContent != null) { //The content control is inline if (sdtType == typeof(wp.SdtRun)) { cc.InsertAfterSelf(new wp.Run(targetContent)); cc.Remove(); } //The content control is a table cell else if (sdtType == typeof(wp.SdtCell)) { wp.TableCell tc = (wp.TableCell)((cc.Descendants <wp.TableCell>().FirstOrDefault()).CloneNode(true)); if (targetContent.GetType() == typeof(wp.Text)) { wp.Run targetRun = tc.Descendants <wp.Run>().FirstOrDefault(); targetRun.RemoveAllChildren(); targetRun.Append(targetContent); } else { tc.Append(targetContent); } cc.InsertAfterSelf(tc); cc.Remove(); } //The content control is multi-line else if (sdtType == typeof(wp.SdtBlock)) { cc.InsertAfterSelf(targetContent); cc.Remove(); } } } } foreach (var footer in output.MainDocumentPart.FooterParts) { footer.Footer.Save(); } doc.Save(); output.Close(); return(mem); } }