示例#1
0
        private static object MergeAdjacentRunsTransform(XNode node)
        {
            if (node is XElement element)
            {
                return(element.Name == W.p
                    ? WordprocessingMLUtil.CoalesceAdjacentRunsWithIdenticalFormatting(element)
                    : new XElement(element.Name,
                                   element.Attributes(),
                                   element.Nodes().Select(MergeAdjacentRunsTransform)));
            }

            return(node);
        }
        private static object MergeAdjacentRunsTransform(XNode node)
        {
            var element = node as XElement;

            if (element == null)
            {
                return(node);
            }

            if (element.Name == W.p)
            {
                return(WordprocessingMLUtil.CoalesceAdjacentRunsWithIdenticalFormatting(element));
            }

            return(new XElement(element.Name,
                                element.Attributes(),
                                element.Nodes().Select(n => MergeAdjacentRunsTransform(n))));
        }
        private static object WmlSearchAndReplaceTransform(XNode node, Regex regex, string replacement,
                                                           Func <XElement, Match, bool> callback, bool trackRevisions, string revisionTrackingAuthor, ReplaceInternalInfo replInfo, bool coalesceContent)
        {
            XElement element = node as XElement;

            if (element != null)
            {
                if (element.Name == W.p)
                {
                    var    paragraph = element;
                    string contents  = element
                                       .DescendantsTrimmed(W.txbxContent)
                                       .Where(d => d.Name == W.t)
                                       .Select(t => (string)t)
                                       .StringConcatenate();
                    if (regex.IsMatch(contents))
                    {
                        contents = element
                                   .DescendantsTrimmed(W.txbxContent)
                                   .Where(d => d.Name == W.t)
                                   .Select(t => (string)t)
                                   .StringConcatenate();
                        if (regex.IsMatch(contents))
                        {
                            XElement paragraphWithSplitRuns = new XElement(W.p,
                                                                           paragraph.Attributes(),
                                                                           paragraph.Nodes().Select(n => WmlSearchAndReplaceTransform(n, regex, replacement, callback,
                                                                                                                                      trackRevisions, revisionTrackingAuthor, replInfo, coalesceContent)));

                            var runsTrimmed = paragraphWithSplitRuns
                                              .DescendantsTrimmed(W.txbxContent)
                                              .Where(d => d.Name == W.r)
                                              .ToList();

                            var charsAndRuns = runsTrimmed
                                               .Select(r =>
                            {
                                if (r.Element(W.t) != null)
                                {
                                    return new
                                    {
                                        Ch = r.Element(W.t).Value,
                                        r,
                                    }
                                }
                                ;
                                else
                                {
                                    return new
                                    {
                                        Ch = "\x01",
                                        r,
                                    }
                                };
                            })
                                               .ToList();

                            var content     = charsAndRuns.Select(t => t.Ch).StringConcatenate();
                            var alignedRuns = charsAndRuns.Select(t => t.r).ToArray();

                            var matchCollection = regex.Matches(content);
                            replInfo.Count += matchCollection.Count;
                            if (replacement == null)
                            {
                                if (callback != null)
                                {
                                    foreach (var match in matchCollection.Cast <Match>())
                                    {
                                        callback(paragraph, match);
                                    }
                                }
                            }
                            else
                            {
                                foreach (var match in matchCollection.Cast <Match>())
                                {
                                    if (match.Length == 0)
                                    {
                                        continue;
                                    }
                                    if (callback == null || callback(paragraph, match))
                                    {
                                        var runCollection = alignedRuns
                                                            .Skip(match.Index)
                                                            .Take(match.Length)
                                                            .ToList(); // uses the Skip / Take special semantics of array to implement efficient finding of sub array

                                        var firstRun           = runCollection.First();
                                        var firstRunProperties = firstRun.Elements(W.rPr).FirstOrDefault(); // save away first run properties

                                        if (trackRevisions)
                                        {
                                            if (replacement != null && replacement != "")
                                            {
                                                var newIns = new XElement(W.ins,
                                                                          new XAttribute(W.author, revisionTrackingAuthor),
                                                                          new XAttribute(W.date, DateTime.Now.ToString("s") + "Z"),
                                                                          new XElement(W.r,
                                                                                       firstRunProperties,
                                                                                       new XElement(W.t, replacement)));
                                                if (firstRun.Parent.Name == W.ins)
                                                {
                                                    firstRun.Parent.AddBeforeSelf(newIns);
                                                }
                                                else
                                                {
                                                    firstRun.AddBeforeSelf(newIns);
                                                }
                                            }

                                            foreach (var run in runCollection)
                                            {
                                                var isInIns = run.Parent.Name == W.ins;
                                                if (isInIns)
                                                {
                                                    var parentIns = run.Parent;
                                                    if ((string)parentIns.Attributes(W.author).FirstOrDefault() == revisionTrackingAuthor)
                                                    {
                                                        var parentInsSiblings = parentIns
                                                                                .Parent
                                                                                .Elements()
                                                                                .Where(c => c != parentIns)
                                                                                .ToList();
                                                        parentIns.Parent.ReplaceNodes(parentInsSiblings);
                                                    }
                                                    else
                                                    {
                                                        var parentInsSiblings = parentIns
                                                                                .Parent
                                                                                .Elements()
                                                                                .Select(c =>
                                                        {
                                                            if (c == parentIns)
                                                            {
                                                                var newIns = new XElement(W.ins,
                                                                                          parentIns.Attributes(),
                                                                                          new XElement(W.del,
                                                                                                       new XAttribute(W.author, revisionTrackingAuthor),
                                                                                                       new XAttribute(W.date, DateTime.Now.ToString("s") + "Z"),
                                                                                                       parentIns.Elements().Select(r => TransformToDelText(r))));
                                                                return(newIns);
                                                            }
                                                            else
                                                            {
                                                                return(c);
                                                            }
                                                        })
                                                                                .ToList();
                                                        parentIns.Parent.ReplaceNodes(parentInsSiblings);
                                                    }
                                                }
                                                else
                                                {
                                                    var delRun = new XElement(W.del,
                                                                              new XAttribute(W.author, revisionTrackingAuthor),
                                                                              new XAttribute(W.date, DateTime.Now.ToString("s") + "Z"),
                                                                              TransformToDelText(run));
                                                    run.ReplaceWith(delRun);
                                                }
                                            }
                                        }
                                        else // not tracked revisions
                                        {
                                            foreach (var runToDelete in runCollection.Skip(1).ToList())
                                            {
                                                if (runToDelete.Parent.Name == W.ins)
                                                {
                                                    runToDelete.Parent.Remove();
                                                }
                                                else
                                                {
                                                    runToDelete.Remove();
                                                }
                                            }

                                            XAttribute xs = null;
                                            if (replacement.Length > 0 && (replacement[0] == ' ' || replacement[replacement.Length - 1] == ' '))
                                            {
                                                xs = new XAttribute(XNamespace.Xml + "space", "preserve");
                                            }

                                            var newFirstRun = new XElement(W.r,
                                                                           firstRun.Element(W.rPr),
                                                                           new XElement(W.t,
                                                                                        xs,
                                                                                        replacement)); // creates a new run with proper run properties

                                            if (firstRun.Parent.Name == W.ins)
                                            {
                                                firstRun.Parent.ReplaceWith(newFirstRun);
                                            }
                                            else
                                            {
                                                firstRun.ReplaceWith(newFirstRun);  // finds firstRun in its parent's list of children, unparents firstRun,
                                            }
                                            // sets newFirstRun's parent to firstRuns old parent, and inserts in the list
                                            // of children at the right place.
                                        }
                                    }
                                }

                                if (coalesceContent)
                                {
                                    paragraph = WordprocessingMLUtil.CoalesceAdjacentRunsWithIdenticalFormatting(paragraphWithSplitRuns);
                                }
                                else
                                {
                                    paragraph = paragraphWithSplitRuns;
                                }
                            }
                        }
                        return(paragraph);
                    }
                    var newEle = new XElement(element.Name,
                                              element.Attributes(),
                                              element.Nodes().Select(n =>
                    {
                        var e = n as XElement;
                        if (e != null)
                        {
                            if (e.Name == W.pPr || e.Name == W.rPr)
                            {
                                return(e);
                            }
                            if (e.Name == W.r && (e.Element(W.t) != null) || e.Element(W.tab) != null)
                            {
                                return(e);
                            }
                            if (e.Name == W.ins && e.Element(W.r) != null && e.Element(W.r).Element(W.t) != null)
                            {
                                return(e);
                            }
                            var newContent = WmlSearchAndReplaceTransform(e, regex, replacement, callback, trackRevisions, revisionTrackingAuthor, replInfo, coalesceContent);
                            return(newContent);
                        }
                        return(n);
                    }));
                    if (newEle.Name == W.p)
                    {
                        //if (newEle.Descendants(W.ins).Any())
                        //    Console.WriteLine();
                        if (coalesceContent)
                        {
                            var newPara = CoalesceContent(newEle);
                            return(newPara);
                        }
                        else
                        {
                            return(newEle);
                        }
                    }
                    else
                    {
                        return(newEle);
                    }
                }
                if (element.Name == W.ins && element.Elements(W.r).Any())
                {
                    var collectionOfCollections = element
                                                  .Elements()
                                                  .Select(n => WmlSearchAndReplaceTransform(n, regex, replacement, callback, trackRevisions, revisionTrackingAuthor, replInfo, coalesceContent))
                                                  .ToList();
                    var collectionOfIns = collectionOfCollections
                                          .Select(c =>
                    {
                        if (c is IEnumerable <XElement> )
                        {
                            var ix = (IEnumerable <XElement>)c;
                            var collectionOfNewIns = ix
                                                     .Select(ixc =>
                            {
                                var newIns = new XElement(W.ins,
                                                          element.Attributes(),
                                                          ixc);
                                return(newIns);
                            });
                            return(collectionOfNewIns);
                        }
                        return(c);
                    })
                                          .ToList();
                    return(collectionOfIns);
                }
                if (element.Name == W.r && element.Elements(W.t).Any())
                {
                    var collectionOfCollections = element.Elements()
                                                  .Where(e => e.Name != W.rPr)
                                                  .Select(e =>
                    {
                        if (e.Name == W.t)
                        {
                            string s = (string)e;
                            IEnumerable <XElement> collectionOfSubRuns = s.Select(c =>
                            {
                                XElement newRun = new XElement(W.r,
                                                               element.Elements(W.rPr),
                                                               new XElement(W.t,
                                                                            c == ' ' ?
                                                                            new XAttribute(XNamespace.Xml + "space", "preserve") :
                                                                            null, c));
                                return(newRun);
                            });
                            return(collectionOfSubRuns);
                        }
                        else
                        {
                            XElement newRun = new XElement(W.r,
                                                           element.Elements(W.rPr),
                                                           e);
                            return(new [] { newRun });
                        }
                    })
                                                  .ToList();
                    var collectionOfRuns = collectionOfCollections.SelectMany(t => t);
                    return(collectionOfRuns);
                }
                return(new XElement(element.Name,
                                    element.Attributes(),
                                    element.Nodes().Select(n => WmlSearchAndReplaceTransform(n, regex, replacement, callback, trackRevisions,
                                                                                             revisionTrackingAuthor, replInfo, coalesceContent))));
            }
            return(node);
        }
        private static object TransformToMetadata(XNode node, XElement data, TemplateError te)
        {
            XElement element = node as XElement;

            if (element != null)
            {
                if (element.Name == W.sdt)
                {
                    var alias = (string)element.Elements(W.sdtPr).Elements(W.alias).Attributes(W.val).FirstOrDefault();
                    if (alias == null || alias == "" || s_AliasList.Contains(alias))
                    {
                        var ccContents = element
                                         .DescendantsTrimmed(W.txbxContent)
                                         .Where(e => e.Name == W.t)
                                         .Select(t => (string)t)
                                         .StringConcatenate()
                                         .Trim()
                                         .Replace('“', '"')
                                         .Replace('”', '"');
                        if (ccContents.StartsWith("<"))
                        {
                            XElement xml = TransformXmlTextToMetadata(te, ccContents);
                            if (xml.Name == W.p || xml.Name == W.r)  // this means there was an error processing the XML.
                            {
                                if (element.Parent.Name == W.p)
                                {
                                    return(xml.Elements(W.r));
                                }
                                return(xml);
                            }
                            if (alias != null && xml.Name.LocalName != alias)
                            {
                                if (element.Parent.Name == W.p)
                                {
                                    return(CreateRunErrorMessage("Error: Content control alias does not match metadata element name", te));
                                }
                                else
                                {
                                    return(CreateParaErrorMessage("Error: Content control alias does not match metadata element name", te));
                                }
                            }
                            xml.Add(element.Elements(W.sdtContent).Elements());
                            return(xml);
                        }
                        return(new XElement(element.Name,
                                            element.Attributes(),
                                            element.Nodes().Select(n => TransformToMetadata(n, data, te))));
                    }
                    return(new XElement(element.Name,
                                        element.Attributes(),
                                        element.Nodes().Select(n => TransformToMetadata(n, data, te))));
                }
                if (element.Name == W.p)
                {
                    var paraContents = element
                                       .DescendantsTrimmed(W.txbxContent)
                                       .Where(e => e.Name == W.t)
                                       .Select(t => (string)t)
                                       .StringConcatenate()
                                       .Trim();
                    int occurances = paraContents.Select((c, i) => paraContents.Substring(i)).Count(sub => sub.StartsWith("<#"));
                    if (paraContents.StartsWith("<#") && paraContents.EndsWith("#>") && occurances == 1)
                    {
                        var      xmlText = paraContents.Substring(2, paraContents.Length - 4).Trim();
                        XElement xml     = TransformXmlTextToMetadata(te, xmlText);
                        if (xml.Name == W.p || xml.Name == W.r)
                        {
                            return(xml);
                        }
                        xml.Add(element);
                        return(xml);
                    }
                    if (paraContents.Contains("<#"))
                    {
                        List <RunReplacementInfo> runReplacementInfo = new List <RunReplacementInfo>();
                        var      thisGuid = Guid.NewGuid().ToString();
                        var      r        = new Regex("<#.*?#>");
                        XElement xml      = null;
                        OpenXmlRegex.Replace(new[] { element }, r, thisGuid, (para, match) =>
                        {
                            var matchString = match.Value.Trim();
                            var xmlText     = matchString.Substring(2, matchString.Length - 4).Trim().Replace('“', '"').Replace('”', '"');
                            try
                            {
                                xml = XElement.Parse(xmlText);
                            }
                            catch (XmlException e)
                            {
                                RunReplacementInfo rri = new RunReplacementInfo()
                                {
                                    Xml = null,
                                    XmlExceptionMessage     = "XmlException: " + e.Message,
                                    SchemaValidationMessage = null,
                                };
                                runReplacementInfo.Add(rri);
                                return(true);
                            }
                            string schemaError = ValidatePerSchema(xml);
                            if (schemaError != null)
                            {
                                RunReplacementInfo rri = new RunReplacementInfo()
                                {
                                    Xml = null,
                                    XmlExceptionMessage     = null,
                                    SchemaValidationMessage = "Schema Validation Error: " + schemaError,
                                };
                                runReplacementInfo.Add(rri);
                                return(true);
                            }
                            RunReplacementInfo rri2 = new RunReplacementInfo()
                            {
                                Xml = xml,
                                XmlExceptionMessage     = null,
                                SchemaValidationMessage = null,
                            };
                            runReplacementInfo.Add(rri2);
                            return(true);
                        }, false);

                        var newPara = new XElement(element);
                        foreach (var rri in runReplacementInfo)
                        {
                            var runToReplace = newPara.Descendants(W.r).FirstOrDefault(rn => rn.Value == thisGuid && rn.Parent.Name != PA.Content);
                            if (runToReplace == null)
                            {
                                throw new OpenXmlPowerToolsException("Internal error");
                            }
                            if (rri.XmlExceptionMessage != null)
                            {
                                runToReplace.ReplaceWith(CreateRunErrorMessage(rri.XmlExceptionMessage, te));
                            }
                            else if (rri.SchemaValidationMessage != null)
                            {
                                runToReplace.ReplaceWith(CreateRunErrorMessage(rri.SchemaValidationMessage, te));
                            }
                            else
                            {
                                var newXml = new XElement(rri.Xml);
                                newXml.Add(runToReplace);
                                runToReplace.ReplaceWith(newXml);
                            }
                        }
                        var coalescedParagraph = WordprocessingMLUtil.CoalesceAdjacentRunsWithIdenticalFormatting(newPara);
                        return(coalescedParagraph);
                    }
                }

                return(new XElement(element.Name,
                                    element.Attributes(),
                                    element.Nodes().Select(n => TransformToMetadata(n, data, te))));
            }
            return(node);
        }
示例#5
0
        private static object WmlSearchAndReplaceTransform(XNode node, Regex regex, string replacement,
                                                           Func <XElement, Match, bool> callback, bool trackRevisions, string revisionTrackingAuthor,
                                                           ReplaceInternalInfo replInfo, bool coalesceContent)
        {
            var element = node as XElement;

            if (element == null)
            {
                return(node);
            }

            if (element.Name == W.p)
            {
                XElement paragraph = element;

                string preliminaryContent = paragraph
                                            .DescendantsTrimmed(W.txbxContent)
                                            .Where(d => d.Name == W.r && (d.Parent == null || d.Parent.Name != W.del))
                                            .Select(UnicodeMapper.RunToString)
                                            .StringConcatenate();
                if (regex.IsMatch(preliminaryContent))
                {
                    var paragraphWithSplitRuns = new XElement(W.p,
                                                              paragraph.Attributes(),
                                                              paragraph.Nodes().Select(n => WmlSearchAndReplaceTransform(n, regex, replacement, callback,
                                                                                                                         trackRevisions, revisionTrackingAuthor, replInfo, coalesceContent)));

                    IEnumerable <XElement> runsTrimmed = paragraphWithSplitRuns
                                                         .DescendantsTrimmed(W.txbxContent)
                                                         .Where(d => d.Name == W.r && (d.Parent == null || d.Parent.Name != W.del));

                    var charsAndRuns = runsTrimmed
                                       .Select(r => new { Ch = UnicodeMapper.RunToString(r), r })
                                       .ToList();

                    string     content     = charsAndRuns.Select(t => t.Ch).StringConcatenate();
                    XElement[] alignedRuns = charsAndRuns.Select(t => t.r).ToArray();

                    MatchCollection matchCollection = regex.Matches(content);
                    replInfo.Count += matchCollection.Count;

                    // Process Match
                    if (replacement == null)
                    {
                        if (callback == null)
                        {
                            return(paragraph);
                        }

                        foreach (Match match in matchCollection.Cast <Match>())
                        {
                            callback(paragraph, match);
                        }

                        return(paragraph);
                    }

                    // Process Replace
                    foreach (Match match in matchCollection.Cast <Match>())
                    {
                        if (match.Length == 0)
                        {
                            continue;
                        }
                        if ((callback != null) && !callback(paragraph, match))
                        {
                            continue;
                        }

                        List <XElement> runCollection = alignedRuns
                                                        .Skip(match.Index)
                                                        .Take(match.Length)
                                                        .ToList();

                        // uses the Skip / Take special semantics of array to implement efficient finding of sub array

                        XElement firstRun           = runCollection.First();
                        XElement firstRunProperties = firstRun.Elements(W.rPr).FirstOrDefault();

                        // save away first run properties

                        if (trackRevisions)
                        {
                            if (replacement != "")
                            {
                                // We coalesce runs as some methods, e.g., in DocumentAssembler,
                                // will try to find the replacement string even though they
                                // set coalesceContent to false.
                                string          newTextValue = match.Result(replacement);
                                List <XElement> newRuns      = UnicodeMapper.StringToCoalescedRunList(newTextValue,
                                                                                                      firstRunProperties);
                                var newIns = new XElement(W.ins,
                                                          new XAttribute(W.author, revisionTrackingAuthor),
                                                          new XAttribute(W.date, DateTime.UtcNow.ToString("s") + "Z"),
                                                          newRuns);

                                if (firstRun.Parent != null && firstRun.Parent.Name == W.ins)
                                {
                                    firstRun.Parent.AddBeforeSelf(newIns);
                                }
                                else
                                {
                                    firstRun.AddBeforeSelf(newIns);
                                }
                            }

                            foreach (XElement run in runCollection)
                            {
                                bool isInIns = run.Parent != null && run.Parent.Name == W.ins;
                                if (isInIns)
                                {
                                    XElement parentIns            = run.Parent;
                                    XElement grandParentParagraph = parentIns.Parent;
                                    if (grandParentParagraph != null)
                                    {
                                        if ((string)parentIns.Attributes(W.author).FirstOrDefault() ==
                                            revisionTrackingAuthor)
                                        {
                                            List <XElement> parentInsSiblings = grandParentParagraph
                                                                                .Elements()
                                                                                .Where(c => c != parentIns)
                                                                                .ToList();
                                            grandParentParagraph.ReplaceNodes(parentInsSiblings);
                                        }
                                        else
                                        {
                                            List <XElement> parentInsSiblings = grandParentParagraph
                                                                                .Elements()
                                                                                .Select(c => c == parentIns
                                                    ? new XElement(W.ins,
                                                                   parentIns.Attributes(),
                                                                   new XElement(W.del,
                                                                                new XAttribute(W.author, revisionTrackingAuthor),
                                                                                new XAttribute(W.date, DateTime.UtcNow.ToString("s") + "Z"),
                                                                                parentIns.Elements().Select(TransformToDelText)))
                                                    : c)
                                                                                .ToList();
                                            grandParentParagraph.ReplaceNodes(parentInsSiblings);
                                        }
                                    }
                                }
                                else
                                {
                                    var delRun = new XElement(W.del,
                                                              new XAttribute(W.author, revisionTrackingAuthor),
                                                              new XAttribute(W.date, DateTime.UtcNow.ToString("s") + "Z"),
                                                              TransformToDelText(run));
                                    run.ReplaceWith(delRun);
                                }
                            }
                        }
                        else // not tracked revisions
                        {
                            foreach (XElement runToDelete in runCollection.Skip(1).ToList())
                            {
                                if (runToDelete.Parent != null && runToDelete.Parent.Name == W.ins)
                                {
                                    runToDelete.Parent.Remove();
                                }
                                else
                                {
                                    runToDelete.Remove();
                                }
                            }

                            // We coalesce runs as some methods, e.g., in DocumentAssembler,
                            // will try to find the replacement string even though they
                            // set coalesceContent to false.
                            string          newTextValue = match.Result(replacement);
                            List <XElement> newRuns      = UnicodeMapper.StringToCoalescedRunList(newTextValue,
                                                                                                  firstRunProperties);
                            if (firstRun.Parent != null && firstRun.Parent.Name == W.ins)
                            {
                                firstRun.Parent.ReplaceWith(newRuns);
                            }
                            else
                            {
                                firstRun.ReplaceWith(newRuns);
                            }
                        }
                    }

                    return(coalesceContent
                        ? WordprocessingMLUtil.CoalesceAdjacentRunsWithIdenticalFormatting(paragraphWithSplitRuns)
                        : paragraphWithSplitRuns);
                }

                var newParagraph = new XElement(W.p,
                                                paragraph.Attributes(),
                                                paragraph.Nodes().Select(n =>
                {
                    var e = n as XElement;
                    if (e == null)
                    {
                        return(n);
                    }

                    if (e.Name == W.pPr)
                    {
                        return(e);
                    }
                    if (((e.Name == W.r) && e.Elements(W.t).Any()) || e.Elements(W.tab).Any())
                    {
                        return(e);
                    }
                    if ((e.Name == W.ins) && e.Elements(W.r).Elements(W.t).Any())
                    {
                        return(e);
                    }

                    return(WmlSearchAndReplaceTransform(e, regex, replacement, callback,
                                                        trackRevisions, revisionTrackingAuthor, replInfo, coalesceContent));
                }));
                return(coalesceContent
                    ? WordprocessingMLUtil.CoalesceAdjacentRunsWithIdenticalFormatting(newParagraph) // CoalesceContent(newParagraph)
                    : newParagraph);
            }

            if (element.Name == W.ins && element.Elements(W.r).Any())
            {
                List <object> collectionOfCollections = element
                                                        .Elements()
                                                        .Select(n => WmlSearchAndReplaceTransform(n, regex, replacement, callback, trackRevisions,
                                                                                                  revisionTrackingAuthor, replInfo, coalesceContent))
                                                        .ToList();
                List <object> collectionOfIns = collectionOfCollections
                                                .Select(c =>
                {
                    var elements = c as IEnumerable <XElement>;
                    return(elements != null
                            ? elements.Select(ixc => new XElement(W.ins, element.Attributes(), ixc))
                            : c);
                })
                                                .ToList();
                return(collectionOfIns);
            }

            if (element.Name == W.r)
            {
                return(element.Elements()
                       .Where(e => e.Name != W.rPr)
                       .Select(e => e.Name == W.t
                        ? ((string)e).Select(c =>
                                             new XElement(W.r,
                                                          element.Elements(W.rPr),
                                                          new XElement(W.t, XmlUtil.GetXmlSpaceAttribute(c), c)))
                        : new[] { new XElement(W.r, element.Elements(W.rPr), e) })
                       .SelectMany(t => t));
            }

            return(new XElement(element.Name,
                                element.Attributes(),
                                element.Nodes()
                                .Select(n => WmlSearchAndReplaceTransform(n, regex, replacement, callback, trackRevisions,
                                                                          revisionTrackingAuthor, replInfo, coalesceContent))));
        }