Hello All,
We are using DocParts to generate content for Aspose.Words mail merge. Within the DocParts, we utilize Word’s Outline/Navigation feature, applying built-in heading styles (e.g., Heading 1, Heading 2) to enable collapsible sections for better document structure.
However, when we insert these DocParts into our template and generate the final document using our algorithm, we’re encountering formatting inconsistencies:
The font color changes from black (as defined in the DocPart) to blue.
The font style changes from Arial to Aptos (Body).
We want to preserve the original formatting defined in the DocPart (including font family, size, and color) and prevent any automatic style overrides during document generation.
@Vaibhavi_Lad Could you please attach your sample template and data that will allow us to reproduce the problem? We will check the issue and provide you more information.
As I can see from the provided screenshot you are using LINQ Reporting Engine, not Mail Merge feature.
@Vaibhavi_Lad Thank you for additional information. The problem occurs because by default, while inserting content of an outer document, the engine applies corresponding styles of a template document. This makes content of a result document look more consistent. However, you can keep source formatting for content being inserted by using a sourceStyles switch. Please try modifying your template like this:
@Vaibhavi_Lad Could you please provide simple code that will allow us to reproduce the problem? I tested with the following simple code and everything works as expected:
Document doc = new Document(@"C:\Temp\in.docx");
ReportingEngine engine = new ReportingEngine();
engine.BuildReport(doc,
new object[] { new Document(@"C:\Temp\1.docx"), new Document(@"C:\Temp\2.docx") },
new string[] { "DocPart_CoverLetter_Docpart06212025_2", "DocPart_StateDisc_Docpart_06212025_2" });
doc.Save(@"C:\Temp\out.docx");
Hello,
I am provide you sample example that you can regenerate above output
docpart_1 and docpart_2 are two doc part which I want to generate together
I uploaded using template name two_docpart then the resulted output has which has mismatch of styles which is attach screen shot and for same if I do with tag you suggested then it template used updated with latest syntax then output that I am getting. Can you please suggest how can I use both docpart in one template ? output.docx (14.6 KB)
Document doc = new Document(@"C:\Temp\Updated_with_latest_syntax.docx");
ReportingEngine engine = new ReportingEngine();
engine.BuildReport(doc,
new object[] { new Document(@"C:\Temp\docpart_1.docx"), new Document(@"C:\Temp\docpart_2.docx") },
new string[] { "DocPart_docpart_1", "DocPart_docpart_2" });
doc.Save(@"C:\Temp\out.docx");
I get the same output as yours: out.docx (13.1 KB), that is expected as formatting of the doc parts is preserved.
{
if (mergeReq is null)
{
throw new ArgumentNullException(nameof(mergeReq));
}
using var template = new MemoryStream(Convert.FromBase64String(mergeReq.Settings.Template));
var doc = new Document(template);
//Append Docs
if (mergeReq.Data.TryGetProperty("__AppendDocs", out var appendDocs))
{
doc.AppendDocs(appendDocs);
}
// Replace snippets
if (mergeReq.Data.TryGetProperty("__Templates", out var templates))
{
doc.ExecuteReplaceBySnippet(templates);
}
// Report engine
var reportingEngine = new ReportingEngine();
reportingEngine.KnownTypes.Add(typeof(x));
reportingEngine.KnownTypes.Add(typeof(m));
reportingEngine.KnownTypes.Add(typeof(Math));
reportingEngine.KnownTypes.Add(typeof(DateTime));
// This is Code where we enable the error message in our generated document
var reportBuildOptions = ReportBuildOptions.InlineErrorMessages;
if (!mergeReq.Settings.ReportEngineOptions.IsNullOrWhiteSpace())
{
var engineOptions = mergeReq.Settings.ReportEngineOptions.Split(new[] { '|', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var option in engineOptions)
{
reportBuildOptions = reportBuildOptions | option.ParseEnum<ReportBuildOptions>(true);
}
}
reportingEngine.Options = reportBuildOptions;
using MemoryStream ms = new(Encoding.UTF8.GetBytes(mergeReq.Data.ToJsonString()));
JsonDataLoadOptions jOpt = new ();
jOpt.SimpleValueParseMode = JsonSimpleValueParseMode.Strict;
jOpt.ExactDateTimeParseFormats = [string.Empty];
reportingEngine.BuildReport(doc, new JsonDataSource(ms, jOpt), "ds");
// MailMerge
Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
var data = mergeReq.Data
.EnumerateObject()
.ToDictionary(p => p.Name, p =>
{
switch (p.Value.ValueKind)
{
case JsonValueKind.String:
case JsonValueKind.True:
case JsonValueKind.False:
return p.Value.GetString() as object;
case JsonValueKind.Number:
return p.Value.GetDouble() as object;
case JsonValueKind.Array:
case JsonValueKind.Object:
case JsonValueKind.Null:
case JsonValueKind.Undefined:
default:
return "" as object;
}
});
var mailMergeCleanupOptions = MailMergeCleanupOptions.None;
if (!mergeReq.Settings.MailMergeOptions.IsNullOrWhiteSpace())
{
var mailMergeOptions = mergeReq.Settings.MailMergeOptions.Split(new[] { '|', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var option in mailMergeOptions)
{
mailMergeCleanupOptions = mailMergeCleanupOptions | option.ParseEnum<MailMergeCleanupOptions>(true);
}
}
doc.MailMerge.CleanupOptions = mailMergeCleanupOptions;
doc.MailMerge.Execute(data.Keys.ToArray(), data.Values.ToArray());
using var outputStream = new MemoryStream();
var saveFormat = mergeReq.Settings.OutputDocType.ParseEnum<SaveFormat>(true);
if (saveFormat == SaveFormat.Pdf)
{
PdfSaveOptions pdfOpts = new PdfSaveOptions();
if (!mergeReq.Settings.OutputDocOptions.IsNullOrWhiteSpace())
pdfOpts.Compliance = mergeReq.Settings.OutputDocOptions.ParseEnum<PdfCompliance>(true);
pdfOpts.SaveFormat = saveFormat;
doc.Save(outputStream, pdfOpts);
}
else if (saveFormat == SaveFormat.Text)
{
TxtSaveOptions textOpts = new();
textOpts.SaveFormat = saveFormat;
doc.Save(outputStream, textOpts);
}
else
{
OoxmlSaveOptions docOpts = new OoxmlSaveOptions();
docOpts.SaveFormat = saveFormat;
doc.Save(outputStream, docOpts);
}
return outputStream.ToArray();
}
above code I am using for generation can you please suggest me here why I am getting that error ??
@Vaibhavi_Lad Could you please create a simple console application that will demonstrate the problem? Unfortunately, I cannot reproduce the problem on my side.
Hello ,
Can you please try with below code snippet ?
using Aspose.Words;
using Aspose.Words.Reporting;
using System.Text;
using System.Text.Json;
var doc = new Document("two_docpart.docx");
// Reporting engine setup
var engine = new ReportingEngine();
engine.Options = ReportBuildOptions.InlineErrorMessages;
var json = "{ \"Title\": \"Test Document\" }";
using var jsonStream = new MemoryStream(Encoding.UTF8.GetBytes(json));
// Build document with both docparts
engine.BuildReport(doc, new JsonDataSource(jsonStream), "ds");
// Save output
doc.Save("Output.docx");
However, I would like to clarify that the code sample you’ve provided:
csharp
CopyEdit
engine.BuildReport(doc,
new object[] { new Document("docpart_1.docx"), new Document("docpart_2.docx") },
new string[] { "DocPart_docpart_1", "DocPart_docpart_2" });
is not the same scenario I’m reporting.
Why It’s Different:
Your code example builds external Document instances and injects them as data.
In my case, the DocParts are defined inside the GlossaryDocument of the template (two_docpart.docx) — and I’m referencing them with this syntax in the main body:
Yes, with your code I can reproduce the same output as yours and the output is expect. Your data source does not contain value for DocPart_docpart_1 field. Since ReportBuildOptions.InlineErrorMessages option is set, Aspose.Words shows the error in the output document. The error is shown for the first encountered problem, in your case, this is missed DocPart_docpart_1 field. So the output is expected and correct.
A doc tag denotes a placeholder within a template for a document to be inserted during runtime. > An expression declared within a doc tag is used by the engine to load a document to be inserted during runtime. The expression must return a value of one of the following types:
A string containing a document URI, path, or Base64-encoded document data
As you can see there is no option to insert doc part defined inside the GlossaryDocument of the template.
By default, while inserting content of an outer document, the engine applies corresponding styles of a template document. You can keep source formatting for content being inserted by using a sourceStyles switch.
Cookie Notice
To provide you with the best experience, we use cookies for personalization, analytics, and ads. By using our site, you agree to our cookie policy.
Enables storage, such as cookies, related to analytics.
Sets consent for sending user data to Google for online advertising purposes.
Sets consent for personalized advertising.
Cookie Notice
To provide you with the best experience, we use cookies for personalization, analytics, and ads. By using our site, you agree to our cookie policy.
More info
Enables storage, such as cookies, related to analytics.
Enables storage, such as cookies, related to advertising.
Sets consent for sending user data to Google for online advertising purposes.
Sets consent for personalized advertising.
Cookie Notice
To provide you with the best experience, we use cookies for personalization, analytics, and ads. By using our site, you agree to our cookie policy.
More info
Enables storage, such as cookies, related to analytics.
Enables storage, such as cookies, related to advertising.
Sets consent for sending user data to Google for online advertising purposes.