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

4

0 回答 0