1

I'm using DocumentFormat.OpenXml to replace merge fields in my template docx file.

Step 1, I write method to find merge field

            var instructionRegEx = new Regex(@"[\w]*\sMERGEFIELD\s+(?<name>[\w]+)", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline);

            string GetFieldName(OpenXmlElement field)
            {
                string outerXml = field.OuterXml;
                if (!string.IsNullOrEmpty(outerXml))
                {
                    Match m = instructionRegEx.Match(outerXml);
                    if (m.Success)
                    {
                        return m.Groups["name"].ToString().Trim();
                    }
                }
                return string.Empty;
            }

            using (var docx = WordprocessingDocument.Open(filePath, true))
            {
                var fields = docx.MainDocumentPart.RootElement.Descendants<SimpleField>().Select(item => (OpenXmlElement)item)
                    .Concat(docx.MainDocumentPart.RootElement.Descendants<FieldCode>().Select(item => (OpenXmlElement)item))
                    .ToList();
                foreach (var field in fields)
                {
                    var name = GetFieldName(field);
                    if (string.IsNullOrEmpty(name)) continue;
                    switch (name)
                    {
                     ///
                    }
                }
            }

Step 2, I write method to replace html text

 public static void ReplaceHtml(this WordprocessingDocument document, OpenXmlElement el, string html, bool disableHtmlHeader = false, string color = "", string alignment = "", string lineHeight = "", bool removeStyle = true)
        {
            var formatImportPart = document.MainDocumentPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.Html);
            var idOfPart = document.MainDocumentPart.GetIdOfPart(formatImportPart);
            var convertedHtml = html.ConvertHtmlContent(disableHtmlHeader: disableHtmlHeader, aligment: alignment, color: color, lineHeight: lineHeight, removeStyle: removeStyle);
            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(convertedHtml)))
            {
                formatImportPart.FeedData(ms);
            }
            var altChunk = new AltChunk
            {
                Id = idOfPart
            };
            var r = new Run();
            foreach (RunProperties placeholderrpr in el.Parent.Descendants<RunProperties>())
            {
                r.Append(new RunProperties(placeholderrpr.OuterXml));
            }
            r.Append(altChunk);
            ReplaceElement(el, r);
        }
private static void ReplaceElement(OpenXmlElement el, OpenXmlElement newEl)
        {
            if (el == null) return;
            if (el is SimpleField)
            {
                el.Parent.ReplaceChild(newEl, el);
            }
            else if (el is FieldCode)
            {
                var parent = el.Parent;
                var begin = parent.PreviousSibling();
                var separate = parent.NextSibling();
                var runText = separate.NextSibling();
                var end = runText.NextSibling();
                var another = end.NextSibling();
                var container = parent.Parent;                    
                container.InsertAfter(newEl, parent);
                container.RemoveChild(parent);
                container.RemoveChild(begin);
                container.RemoveChild(separate);
                container.RemoveChild(runText);
                container.RemoveChild(end);
            }
        }

Code work well when after RemoveChild, the paragraph that contains merge field become empty. But if it still contains some element, the docx file after replace merge fields will corrupt. I've open docx file by xml tool, and see results are as follows: enter image description here

enter image description here

So, my question is, how can I replace a merge field inside a paragraph that contains another fields. Sorry for my English not good

Minh Giang
  • 631
  • 9
  • 28
  • Why aren't you deleting the entire paragraph's Descendents, then? If you do that you wouldn't even need to distinguish between simple and complex field codes? – Cindy Meister Jul 16 '18 at 13:49
  • Because paragraph not only contains the merge field, it can contains another text fields, break page... – Minh Giang Jul 16 '18 at 16:04
  • Well, I can't read the text in your images - you should post the relevant part as plain text, in that case. But it's quite possible that the HTML you're passing simply can't be incorporated into a paragraph with other content. But there's really nothing more one can say without seeing that raw HTML... – Cindy Meister Jul 16 '18 at 16:26
  • https://i.stack.imgur.com/Iitcy.png Just click to the images, you will see very clearly – Minh Giang Jul 17 '18 at 02:50

0 Answers0