From 8e5d4e6b71c0f50b237540c268120241e7414ec6 Mon Sep 17 00:00:00 2001 From: Emily Kho Date: Fri, 12 Apr 2024 11:00:31 +0200 Subject: [PATCH] add multi-line support --- .../XWPF/XWPFParagraphExtensions.cs | 48 +++++++++++++++++++ .../XWPF/XWPFParagraphMapper.cs | 6 +-- 2 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 NPOI.WordTemplateMapper/Extensions/XWPF/XWPFParagraphExtensions.cs diff --git a/NPOI.WordTemplateMapper/Extensions/XWPF/XWPFParagraphExtensions.cs b/NPOI.WordTemplateMapper/Extensions/XWPF/XWPFParagraphExtensions.cs new file mode 100644 index 0000000..1dff17e --- /dev/null +++ b/NPOI.WordTemplateMapper/Extensions/XWPF/XWPFParagraphExtensions.cs @@ -0,0 +1,48 @@ +using NPOI.XWPF.UserModel; +using System.Text.RegularExpressions; + +namespace NPOI.WordTemplateMapper.Extensions.XWPF; + +public static class XWPFParagraphExtensions +{ + public static void ReplaceTextKeepLineEndings(this XWPFParagraph xwpfParagraph, string textToReplace, string replacementText) + { + string paragraphText = xwpfParagraph.Text; + + if (!paragraphText.Contains(textToReplace)) + return; + + if (!replacementText.Contains('\n')) + { + string textToInsert = paragraphText.Replace(textToReplace, replacementText); + if (!string.IsNullOrEmpty(xwpfParagraph.Text)) + xwpfParagraph.ReplaceText(xwpfParagraph.Text, textToInsert); + return; + } + + List positionsOfOldTextOccurences = new(); + positionsOfOldTextOccurences + .AddRange( + Regex.Matches(paragraphText, Regex.Escape(textToReplace)) + .Select(match => match.Index) + ); + + for (int i = positionsOfOldTextOccurences.Count - 1; i >= 0; i--) + { + int currentPosition = positionsOfOldTextOccurences[i]; + paragraphText = paragraphText + .Remove(currentPosition, textToReplace.Length) + .Insert(currentPosition, replacementText); + } + + string[] newParagraphsToInsert = paragraphText.Split('\n'); + xwpfParagraph.ReplaceText(xwpfParagraph.Text, string.Empty); + + XWPFRun run = xwpfParagraph.CreateRun(); + foreach (string newParagraph in newParagraphsToInsert) + { + run.AppendText(newParagraph); + run.AddCarriageReturn(); + } + } +} diff --git a/NPOI.WordTemplateMapper/XWPF/XWPFParagraphMapper.cs b/NPOI.WordTemplateMapper/XWPF/XWPFParagraphMapper.cs index e4f879e..b7b6b6b 100644 --- a/NPOI.WordTemplateMapper/XWPF/XWPFParagraphMapper.cs +++ b/NPOI.WordTemplateMapper/XWPF/XWPFParagraphMapper.cs @@ -3,6 +3,7 @@ using NPOI.WordTemplateMapper.Interfaces.XWPF; using System.Text.RegularExpressions; using System.Collections; +using NPOI.WordTemplateMapper.Extensions.XWPF; namespace NPOI.WordTemplateMapper.XWPF; @@ -33,10 +34,7 @@ public XWPFParagraph MapParagraph(XWPFParagraph paragraph, IDictionary mappedValue = GetMappedValue(paragraph, mapping); string oldText = paragraph.Text; - // Workaround for malfunctioning ReplaceText from NPOI - string newText = paragraph.Text.Replace(mappedValue.Key, mappedValue.Value); - if (!string.IsNullOrEmpty(paragraph.Text)) - paragraph.ReplaceText(paragraph.Text, newText); + paragraph.ReplaceTextKeepLineEndings(mappedValue.Key, mappedValue.Value); if (oldText == paragraph.Text) keepMapping = false;