Skip to content

Commit c023f11

Browse files
Merge pull request #364 from SyncfusionExamples/ES-933789-Replace-merge-field-with-markdown
ES-933789- Add the sample Replace-merge-field-with-markdown-imageURL
2 parents 580ba84 + 498d3e0 commit c023f11

File tree

5 files changed

+213
-0
lines changed

5 files changed

+213
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.31911.196
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Replace-merge-field-with-markdown-imageURL", "Replace-merge-field-with-markdown-imageURL\Replace-merge-field-with-markdown-imageURL.csproj", "{38FB99D1-DB4A-4A3F-B90B-7135724337EF}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{38FB99D1-DB4A-4A3F-B90B-7135724337EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{38FB99D1-DB4A-4A3F-B90B-7135724337EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{38FB99D1-DB4A-4A3F-B90B-7135724337EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{38FB99D1-DB4A-4A3F-B90B-7135724337EF}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {B75368E1-9546-4CD5-BE4C-5C905E8D16C2}
24+
EndGlobalSection
25+
EndGlobal
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
using Syncfusion.DocIO;
2+
using Syncfusion.DocIO.DLS;
3+
using System.Collections.Generic;
4+
using System.Data;
5+
using System.IO;
6+
using System.Net;
7+
using System.Text;
8+
9+
namespace Replace_merge_field_with_markdown_imageURL
10+
{
11+
class Program
12+
{
13+
// Dictionary to store paragraphs and corresponding merge field positions with Markdown content.
14+
static Dictionary<WParagraph, Dictionary<int, string>> paraToInsertMarkdown = new Dictionary<WParagraph, Dictionary<int, string>>();
15+
16+
static void Main(string[] args)
17+
{
18+
// Open the template document.
19+
using (FileStream inputFileStream = new FileStream(Path.GetFullPath(@"Data/Template.docx"), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
20+
{
21+
using (WordDocument document = new WordDocument(inputFileStream, FormatType.Automatic))
22+
{
23+
// Attach mail merge event handler to replace merge field with Markdown.
24+
document.MailMerge.MergeField += MergeFieldEvent;
25+
26+
// Retrieve data for mail merge.
27+
DataTable table = GetDataTable();
28+
29+
// Perform mail merge.
30+
document.MailMerge.Execute(table);
31+
32+
// Insert the Markdown content at the specified positions.
33+
InsertMarkdown();
34+
35+
// Detach mail merge event handler.
36+
document.MailMerge.MergeField -= MergeFieldEvent;
37+
38+
// Save the updated document.
39+
using (FileStream outputFileStream = new FileStream(Path.GetFullPath(@"Output/Result.docx"), FileMode.Create, FileAccess.ReadWrite))
40+
{
41+
document.Save(outputFileStream, FormatType.Docx);
42+
}
43+
44+
// Close the document.
45+
document.Close();
46+
}
47+
}
48+
}
49+
50+
#region Helper Methods
51+
52+
/// <summary>
53+
/// Event handler to replace merge fields with Markdown content.
54+
/// </summary>
55+
private static void MergeFieldEvent(object sender, MergeFieldEventArgs args)
56+
{
57+
if (args.TableName == "Markdown" && args.FieldName == "ProductList")
58+
{
59+
// Get the paragraph containing the merge field.
60+
WParagraph paragraph = args.CurrentMergeField.OwnerParagraph;
61+
62+
// Get the merge field position in the paragraph.
63+
int mergeFieldIndex = paragraph.ChildEntities.IndexOf(args.CurrentMergeField);
64+
65+
// Store the Markdown content along with its position in the paragraph.
66+
if (!paraToInsertMarkdown.ContainsKey(paragraph))
67+
{
68+
paraToInsertMarkdown[paragraph] = new Dictionary<int, string>();
69+
}
70+
paraToInsertMarkdown[paragraph][mergeFieldIndex] = args.FieldValue.ToString();
71+
72+
// Set the field value as empty to remove the original merge field.
73+
args.Text = string.Empty;
74+
}
75+
}
76+
77+
/// <summary>
78+
/// Generates the data required for the mail merge operation.
79+
/// </summary>
80+
private static DataTable GetDataTable()
81+
{
82+
DataTable dataTable = new DataTable("Markdown");
83+
dataTable.Columns.Add("CustomerName");
84+
dataTable.Columns.Add("Address");
85+
dataTable.Columns.Add("Phone");
86+
dataTable.Columns.Add("ProductList");
87+
88+
DataRow dataRow = dataTable.NewRow();
89+
dataRow["CustomerName"] = "Nancy Davolio";
90+
dataRow["Address"] = "59 rue de I'Abbaye, Reims 51100, France";
91+
dataRow["Phone"] = "1-888-936-8638";
92+
93+
// Markdown content containing an image URL.
94+
dataRow["ProductList"] = "![Mountain-300](https://www.syncfusion.com/downloads/support/directtrac/general/Mountain-300-989274178.png)";
95+
96+
dataTable.Rows.Add(dataRow);
97+
return dataTable;
98+
}
99+
100+
/// <summary>
101+
/// Inserts Markdown content at the correct positions in the Word document.
102+
/// </summary>
103+
private static void InsertMarkdown()
104+
{
105+
foreach (var paragraphEntry in paraToInsertMarkdown)
106+
{
107+
WParagraph paragraph = paragraphEntry.Key;
108+
Dictionary<int, string> fieldValues = paragraphEntry.Value;
109+
110+
foreach (var fieldValueEntry in fieldValues)
111+
{
112+
int index = fieldValueEntry.Key;
113+
string markdownContent = fieldValueEntry.Value;
114+
115+
// Convert Markdown content to bytes and create a stream.
116+
byte[] contentBytes = Encoding.UTF8.GetBytes(markdownContent);
117+
using (MemoryStream memoryStream = new MemoryStream(contentBytes))
118+
{
119+
using (WordDocument markdownDoc = new WordDocument())
120+
{
121+
// Attach an event handler to handle image imports while processing Markdown.
122+
markdownDoc.MdImportSettings.ImageNodeVisited += MdImportSettings_ImageNodeVisited;
123+
124+
// Open the Markdown content as a Word document.
125+
markdownDoc.Open(memoryStream, FormatType.Markdown);
126+
127+
// Prepare to insert the Markdown content at the correct location.
128+
TextBodyPart bodyPart = new TextBodyPart(paragraph.OwnerTextBody.Document);
129+
BodyItemCollection bodyItems = bodyPart.BodyItems;
130+
131+
// Clone and insert Markdown content at the original merge field position.
132+
foreach (Entity entity in markdownDoc.LastSection.Body.ChildEntities)
133+
{
134+
bodyItems.Add(entity.Clone());
135+
}
136+
bodyPart.PasteAt(paragraph.OwnerTextBody, paragraph.OwnerTextBody.ChildEntities.IndexOf(paragraph), index);
137+
}
138+
}
139+
}
140+
}
141+
142+
// Clear the dictionary after processing.
143+
paraToInsertMarkdown.Clear();
144+
}
145+
146+
/// <summary>
147+
/// Event handler to download images when processing Markdown content.
148+
/// </summary>
149+
private static void MdImportSettings_ImageNodeVisited(object sender, Syncfusion.Office.Markdown.MdImageNodeVisitedEventArgs args)
150+
{
151+
// Check if the image URL starts with "https://"
152+
if (args.Uri.StartsWith("https://"))
153+
{
154+
using (WebClient client = new WebClient())
155+
{
156+
// Download the image data and convert it to a stream.
157+
byte[] imageData = client.DownloadData(args.Uri);
158+
args.ImageStream = new MemoryStream(imageData);
159+
}
160+
}
161+
}
162+
163+
#endregion
164+
}
165+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<RootNamespace>Replace_merge_field_with_markdown_imageURL</RootNamespace>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Syncfusion.DocIO.Net.Core" Version="*" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<None Update="Data\Template.docx">
15+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
16+
</None>
17+
<None Update="Output\.gitkeep">
18+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
19+
</None>
20+
</ItemGroup>
21+
22+
</Project>

0 commit comments

Comments
 (0)