From c19afa2511c330b687660dd912d5cc71e317388e Mon Sep 17 00:00:00 2001 From: Claire Harrison Date: Mon, 22 Apr 2024 08:38:59 -0600 Subject: [PATCH] update RemoveControlsAndKeepContent to support nested table rows --- .../Documents/TemplateDocument.cs | 59 ++++++++++++++---- .../ControlRemovalTest/Doc.docx | Bin 0 -> 20079 bytes .../ControlRemovalTest/Tests.cs | 57 +++++++++++++++++ .../ControlRemovalTest/data.json | 35 +++++++++++ .../ControlRemovalTest/~$Doc.docx | Bin 0 -> 162 bytes .../OpenXMLTemplatesTest.csproj | 6 ++ 6 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 OpenXMLTemplatesTest/ControlRemovalTest/Doc.docx create mode 100644 OpenXMLTemplatesTest/ControlRemovalTest/Tests.cs create mode 100644 OpenXMLTemplatesTest/ControlRemovalTest/data.json create mode 100644 OpenXMLTemplatesTest/ControlRemovalTest/~$Doc.docx diff --git a/OpenXMLTemplates/Documents/TemplateDocument.cs b/OpenXMLTemplates/Documents/TemplateDocument.cs index e81c37a..64d7602 100644 --- a/OpenXMLTemplates/Documents/TemplateDocument.cs +++ b/OpenXMLTemplates/Documents/TemplateDocument.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using OpenXMLTemplates.Utils; @@ -113,25 +114,57 @@ internal void AddControl(ContentControl control, bool isFirstOrder) public void RemoveControlsAndKeepContent() { - foreach (var control in allContentControls) - { - var sdtElement = control.SdtElement; - - var contentElement = sdtElement.Descendants() - .FirstOrDefault(d => d is SdtContentBlock || d is SdtContentRun); - if (contentElement != null) - foreach (var contentElementChildElement in contentElement.ChildElements.ToList()) - { - contentElementChildElement.Remove(); - sdtElement.InsertBeforeSelf(contentElementChildElement); - } + var contentControls = WordprocessingDocument.MainDocumentPart.Document.Descendants().ToList(); - sdtElement.Remove(); + // Process each content control from innermost to outermost + foreach (var sdt in contentControls.OrderByDescending(s => s.Ancestors().Count())) + { + if (sdt is SdtBlock sdtBlock) + { + HandleSdtContent(sdtBlock, sdtBlock.SdtContentBlock); + } + else if (sdt is SdtRun sdtRun) + { + HandleSdtContent(sdtRun, sdtRun.SdtContentRun); + } + else if (sdt is SdtRow sdtRow) + { + HandleSdtRow(sdtRow); + } } allContentControls.Clear(); innerContentControls.Clear(); firstOrderContentControls.Clear(); } + + private static void HandleSdtContent(SdtElement sdt, OpenXmlElement content) + { + if (content != null) + { + var parent = sdt.Parent; + var elementsToMove = content.ChildElements.ToArray(); // Make a copy to avoid modifying the collection during iteration + foreach (var elem in elementsToMove) + { + parent.InsertBefore(elem.CloneNode(true), sdt); + } + // Remove the content control itself + sdt.Remove(); + } + } + private static void HandleSdtRow(SdtRow sdtRow) + { + if (sdtRow.SdtContentRow != null) + { + var tableRow = sdtRow.SdtContentRow.GetFirstChild(); + if (tableRow != null) + { + var parent = sdtRow.Parent; // This should be the Table + parent.InsertBefore(tableRow.CloneNode(true), sdtRow); + sdtRow.Remove(); + } + } + } + } } \ No newline at end of file diff --git a/OpenXMLTemplatesTest/ControlRemovalTest/Doc.docx b/OpenXMLTemplatesTest/ControlRemovalTest/Doc.docx new file mode 100644 index 0000000000000000000000000000000000000000..f4af6ffd5456cfeb50119343831578146caced42 GIT binary patch literal 20079 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å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 new TemplateDocument(this.CurrentFolder() + "Doc.docx"); + private string GetData => File.ReadAllText(this.CurrentFolder() + "data.json"); + + [Test] + public void TestControlRemoval() + { + using var doc = GetDoc; + var data = GetData; + + var src = new VariableSource(); + src.LoadDataFromJson(data); + + var engine = new DefaultOpenXmlTemplateEngine + { + KeepContentControlAfterReplacement = false + }; + engine.ReplaceAll(doc, src); + + doc.SaveAs(this.CurrentFolder() + "result.docx"); + + // confirm new content has been included in document + string? docText = null; + + using (StreamReader sr = new StreamReader(doc.WordprocessingDocument.MainDocumentPart.GetStream())) + { + docText = sr.ReadToEnd(); + } + + Assert.IsTrue(docText != null); + var replacedText = src.GetVariable("nested.[1].nestedList.[1]"); + Assert.IsTrue(docText.Contains(replacedText)); + + // confirm controls have been removed + Assert.AreEqual(0, + doc.WordprocessingDocument.ContentControls().Count(cc => + cc.GetContentControlTag() != null && cc.GetContentControlTag().StartsWith("repeatingitem"))); + + Assert.AreEqual(0, + doc.WordprocessingDocument.ContentControls().Count(cc => + cc.GetContentControlTag() != null && cc.GetContentControlTag() == "repeating_nestedList")); + + doc.WordprocessingDocument.AssertValid(); + } + } +} diff --git a/OpenXMLTemplatesTest/ControlRemovalTest/data.json b/OpenXMLTemplatesTest/ControlRemovalTest/data.json new file mode 100644 index 0000000..c7ade24 --- /dev/null +++ b/OpenXMLTemplatesTest/ControlRemovalTest/data.json @@ -0,0 +1,35 @@ +{ + "items": [ + "Item 1", + "Item 2", + "Item 3", + "Item 4" + ], + "complexItems": [ + { + "name": "First Name", + "address": "First Address" + }, + { + "name": "Second name", + "address": "Second address" + } + ], + "nested": [ + { + "name": "List 1", + "nestedList": [ + "item1-1", + "item1-2", + "item1-3" + ] + }, + { + "name": "List 2", + "nestedList": [ + "item2-1", + "item2-2" + ] + } + ] +} \ No newline at end of file diff --git a/OpenXMLTemplatesTest/ControlRemovalTest/~$Doc.docx b/OpenXMLTemplatesTest/ControlRemovalTest/~$Doc.docx new file mode 100644 index 0000000000000000000000000000000000000000..37c76e15cce1f5849aba14aca9d76ccf25a8b476 GIT binary patch literal 162 zcmd;g&PmKHN>%VkEGo(@&d*~Y3h*;HGvqKNGGsCoF{CmmFn9pjML?LzP|T3efG~s! wYFfS@gkieHz;OSRTa1?`c^0U;Gcd4Sm3wgj$cI@PWZv8Sryj_IYLo&p0e^cLivR!s literal 0 HcmV?d00001 diff --git a/OpenXMLTemplatesTest/OpenXMLTemplatesTest.csproj b/OpenXMLTemplatesTest/OpenXMLTemplatesTest.csproj index f0358e7..2a2c441 100644 --- a/OpenXMLTemplatesTest/OpenXMLTemplatesTest.csproj +++ b/OpenXMLTemplatesTest/OpenXMLTemplatesTest.csproj @@ -18,6 +18,12 @@ + + PreserveNewest + + + Always + PreserveNewest