public static void VisitTextNodes(SyntaxTreeNode node, Action <string> visitText, Func <TagNode, bool> tagFilter) { node.ThrowIfNull(nameof(node)); visitText.ThrowIfNull(nameof(visitText)); if (node is TextNode) { visitText(((TextNode)node).Text); } else { //skip filtered tags if (node is TagNode && (tagFilter != null && !tagFilter((TagNode)node))) { return; } foreach (var subNode in node.SubNodes) { VisitTextNodes(subNode, visitText, tagFilter); } } }
public static SyntaxTreeNode ReplaceTextSpans(SyntaxTreeNode node, Func <string, IList <TextSpanReplaceInfo> > getTextSpansToReplace, Func <TagNode, bool> tagFilter) { node.ThrowIfNull(nameof(node)); getTextSpansToReplace.ThrowIfNull(nameof(getTextSpansToReplace)); if (node is TextNode) { var text = ((TextNode)node).Text; var replacements = getTextSpansToReplace(text); if (replacements is null || replacements.Count == 0) { return(node); } var replacementNodes = new List <SyntaxTreeNode>(replacements.Count * 2 + 1); var lastPos = 0; foreach (var r in replacements) { if (r.Index < lastPos) { throw new ArgumentException("the replacement text spans must be ordered by index and non-overlapping"); } if (r.Index > text.Length - r.Length) { throw new ArgumentException("every replacement text span must reference a range within the text node"); } if (r.Index != lastPos) { replacementNodes.Add(new TextNode(text.Substring(lastPos, r.Index - lastPos))); } if (r.Replacement != null) { replacementNodes.Add(r.Replacement); } lastPos = r.Index + r.Length; } if (lastPos != text.Length) { replacementNodes.Add(new TextNode(text.Substring(lastPos))); } return(new SequenceNode(replacementNodes)); } else { var fixedSubNodes = node.SubNodes.Select(n => { //skip filtered tags if (n is TagNode && (tagFilter != null && !tagFilter((TagNode)n))) { return(n); } var repl = ReplaceTextSpans(n, getTextSpansToReplace, tagFilter); Debug.Assert(repl != null); return(repl); }).ToList(); if (fixedSubNodes.SequenceEqual(node.SubNodes, ReferenceEqualityComparer <SyntaxTreeNode> .Instance)) { return(node); } return(node.SetSubNodes(fixedSubNodes)); } }