diff --git a/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink.sln b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink.sln new file mode 100644 index 00000000..236647ef --- /dev/null +++ b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34622.214 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Replace-MergeField-with-Bookmark-Hyperlink", "Replace-MergeField-with-Bookmark-Hyperlink\Replace-MergeField-with-Bookmark-Hyperlink.csproj", "{ED3D612A-7416-4DB4-9C33-B772BEAF52A6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ED3D612A-7416-4DB4-9C33-B772BEAF52A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED3D612A-7416-4DB4-9C33-B772BEAF52A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED3D612A-7416-4DB4-9C33-B772BEAF52A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED3D612A-7416-4DB4-9C33-B772BEAF52A6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {4353CBCF-E886-4543-982B-CBB8018082D2} + EndGlobalSection +EndGlobal diff --git a/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Data/Template.docx b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Data/Template.docx new file mode 100644 index 00000000..272d0c4e Binary files /dev/null and b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Data/Template.docx differ diff --git a/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Output/.gitkeep b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Output/.gitkeep new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Output/.gitkeep @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Output/Result.docx b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Output/Result.docx new file mode 100644 index 00000000..230b7cb2 Binary files /dev/null and b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Output/Result.docx differ diff --git a/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Program.cs b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Program.cs new file mode 100644 index 00000000..905fe16c --- /dev/null +++ b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Program.cs @@ -0,0 +1,146 @@ +using Syncfusion.DocIO.DLS; +using Syncfusion.DocIO; + +namespace Replace_MergeField_with_Bookmark_Hyperlink +{ + internal class Program + { + static void Main(string[] args) + { + // Open the existing Word document using a FileStream. + using (FileStream docStream = new FileStream(Path.GetFullPath(@"Data/Template.docx"), FileMode.Open, FileAccess.Read)) + { + // Load the Word document into the WordDocument object. + using (WordDocument document = new WordDocument(docStream, FormatType.Docx)) + { + // Find the first merge field with the name "Test" in the document. + WMergeField mergeField = document.FindItemByProperty(EntityType.MergeField, "FieldName", "Test") as WMergeField; + + // Convert the merge field to a placeholder and get the placeholder text. + string textToFind = ConvertMergeFieldToPlaceHolder(mergeField); + + // Replace the placeholder text with "2" in the document. + document.Replace(textToFind, "2", false, true); + + // Create a new TextBodyPart to hold the bookmark hyperlink. + TextBodyPart textBodyPart = new TextBodyPart(document); + + // Create a new paragraph to add the hyperlink. + WParagraph paragraphHyperlink = new WParagraph(document); + textBodyPart.BodyItems.Add(paragraphHyperlink); + + // Append a hyperlink to the paragraph that links to the bookmark "Bookmark1" with display text "Syncfusion". + paragraphHyperlink.AppendHyperlink("Bookmark1", "Syncfusion", HyperlinkType.Bookmark); + + // Replace the text "2" with the bookmark hyperlink in the document. + document.Replace("2", textBodyPart, false, true); + + // Save the modified document to a new file. + using (FileStream outputStream = new FileStream(Path.GetFullPath(@"Output/Result.docx"), FileMode.Create, FileAccess.Write)) + { + document.Save(outputStream, FormatType.Docx); + } + } + } + } + + /// + /// Converts the specified merge field into a placeholder text by extracting + /// its displayed content and replacing the merge field with a text range. + /// + /// The merge field to be converted. + /// + /// The text extracted from the merge field that is used as a placeholder. + /// + private static string ConvertMergeFieldToPlaceHolder(WMergeField field) + { + // Get the paragraph that contains the merge field. + WParagraph paragraph = field.OwnerParagraph; + + // Find the index of the merge field in the paragraph's child entities. + int itemIndex = paragraph.ChildEntities.IndexOf(field); + + // Create a new WTextRange to hold the text that will replace the merge field. + WTextRange textRange = new WTextRange(paragraph.Document); + + // Get the text from the merge field (which may be a hyperlink field). + textRange.Text = GetMergeFieldText(itemIndex, paragraph); + + // Remove the merge field from the paragraph's child entities. + paragraph.ChildEntities.RemoveAt(itemIndex); + + // Insert the text that replaces the merge field at the same position. + paragraph.ChildEntities.Insert(itemIndex, textRange); + + // Return the text that will replace the merge field. + return textRange.Text; + } + + /// + /// Extracts the displayed text from a merge field by traversing its field + /// elements and handling nested fields when present. + /// + /// + /// The index of the merge field within the paragraph child entities collection. + /// + /// + /// The paragraph containing the merge field. + /// + /// + /// The text displayed by the merge field. + /// + private static string GetMergeFieldText(int hyperlinkIndex, WParagraph paragraph) + { + string text = string.Empty; + + // Stack to handle nested fields while iterating through paragraph child entities. + Stack fieldStack = new Stack(); + fieldStack.Push(paragraph.ChildEntities[hyperlinkIndex]); + + // Flag to control whether to collect text or skip field code sections. + bool isFieldCode = true; + int i = (hyperlinkIndex + 1); + + // Iterate through the paragraph's items (child entities) to collect text between field separator and field end. + while (i < paragraph.Items.Count) + { + Entity item = paragraph.ChildEntities[i]; + + // Check if the current item is a field and handle it by adding to the stack. + if (item is WField) + { + fieldStack.Push(item); + isFieldCode = true; // Set flag to skip text in field code section. + } + // Check if the current item is a field separator and enable collecting text. + else if (item is WFieldMark && ((WFieldMark)item).Type == FieldMarkType.FieldSeparator) + { + isFieldCode = false; + } + // Check if the current item is a field end and handle field stack. + else if (item is WFieldMark && ((WFieldMark)item).Type == FieldMarkType.FieldEnd) + { + // If it's the end of the outermost field, return the collected text. + if (fieldStack.Count == 1) + { + fieldStack.Clear(); + return text; + } + else + { + fieldStack.Pop(); + } + } + // If not in field code section and the item is a text range, collect the text. + else if (!isFieldCode && item is WTextRange) + { + text += ((WTextRange)item).Text; + } + + i++; + } + + return text; + } + } +} diff --git a/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Replace-MergeField-with-Bookmark-Hyperlink.csproj b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Replace-MergeField-with-Bookmark-Hyperlink.csproj new file mode 100644 index 00000000..57734744 --- /dev/null +++ b/Find-and-Replace/Replace-MergeField-with-Bookmark-Hyperlink/.NET/Replace-MergeField-with-Bookmark-Hyperlink/Replace-MergeField-with-Bookmark-Hyperlink.csproj @@ -0,0 +1,23 @@ + + + + Exe + net8.0 + Replace_MergeField_with_Bookmark_Hyperlink + enable + enable + + + + + + + + + Always + + + Always + + +