模板文档手动添加占位符:
1)使用邮件合并域方式:
快捷键:按**Ctrl+F9
** 插入域代码括号**{ }--
** 在括号内输入:MERGEFIELD 占位符名称
例:{ MERGEFIELD Name } 或:插入->文档部件->域->MERGEFIELD 域名部分输入名称
使用 Aspose.Words 填充数据:
Document doc = new Document("模板.docx");
// 创建数据源(例如 DataTable 或自定义对象)
DataTable dataTable = new DataTable();
dataTable.Columns.Add("Name"); // 列名需匹配占位符名称
dataTable.Rows.Add("张三");
// 执行邮件合并
doc.MailMerge.Execute(dataTable);
doc.Save("结果.docx");
2)使用自定义文本标记(简单替换)
直接写入可识别的唯一文本,例如:
[姓名]
、{``{COMPANY}}
、%%DATE%%
等。
Document doc = new Document("模板.docx");
// 替换所有匹配的占位符
doc.Range.Replace("[姓名]", "李四", new FindReplaceOptions());
doc.Range.Replace("{{COMPANY}}", "Acme Corp", new FindReplaceOptions());
doc.Range.Replace("%%DATE%%", DateTime.Now.ToString("yyyy-MM-dd"), new FindReplaceOptions());
doc.Save("结果.docx");
一些详细的配置项:
// 配置替换选项(区分大小写、全字匹配等)
FindReplaceOptions options = new FindReplaceOptions {
MatchCase = true, // 区分大小写
FindWholeWordsOnly = true // 全字匹配
};
3)复杂内容的插入:
Aspose.Words提供了强大的扩展能力,主要通过`MailMerge`的`FieldMergingCallback`和域代码(如IF域)来实现。
(1)插入表格或图片(使用FieldMergingCallback)
在需要插入表格或图片的位置,插入一个MERGEFIELD域,例如:`{ MERGEFIELD InsertTable }`。
创建一个类,实现`IFieldMergingCallback`接口,并在`FieldMerging`方法中处理特定域的合并行为。
在`FieldMerging`方法中: - 判断当前域的名称。 - 如果是要插入表格或图片的域,则创建表格或图片对象,并将其添加到当前合并域的位置。
// 1. 创建自定义回调类
public class ImageTableFieldMerger : IFieldMergingCallback
{
public void FieldMerging(FieldMergingArgs args)
{
// 处理图片插入
if (args.FieldName == "CompanyLogo")
{
// 从文件加载图片
Shape shape = new Shape(args.Document, ShapeType.Image);
shape.ImageData.SetImage("logo.png");
shape.Width = 100; // 设置宽度
shape.Height = 50; // 设置高度
// 插入到文档
args.Document.FirstSection.Body.FirstParagraph.AppendChild(shape);
args.Text = ""; // 清除默认文本
}
// 处理表格插入
else if (args.FieldName == "ProductTable")
{
// 创建数据表格
DataTable products = new DataTable();
products.Columns.Add("Name");
products.Columns.Add("Price");
products.Rows.Add("Laptop", "$1200");
products.Rows.Add("Phone", "$800");
// 创建Word表格
Table table = new Table(args.Document);
table.PreferredWidth = PreferredWidth.FromPercent(100);
// 添加表头
Row headerRow = new Row(args.Document);
headerRow.RowFormat.HeadingFormat = true;
headerRow.Cells.Add(new Cell(args.Document) { CellFormat = { Shading = { BackgroundPatternColor = Color.LightGray }}}).AppendChild(new Paragraph(args.Document)).AppendChild(new Run(args.Document, "Product"));
headerRow.Cells.Add(new Cell(args.Document)).AppendChild(new Paragraph(args.Document)).AppendChild(new Run(args.Document, "Price"));
table.AppendChild(headerRow);
// 添加数据行
foreach (DataRow row in products.Rows)
{
Row dataRow = new Row(args.Document);
dataRow.Cells.Add(new Cell(args.Document)).AppendChild(new Paragraph(args.Document)).AppendChild(new Run(args.Document, row["Name"].ToString()));
dataRow.Cells.Add(new Cell(args.Document)).AppendChild(new Paragraph(args.Document)).AppendChild(new Run(args.Document, row["Price"].ToString()));
table.AppendChild(dataRow);
}
// 插入表格到文档
args.Document.FirstSection.Body.AppendChild(table);
args.Text = ""; // 清除默认文本
}
}
public void ImageFieldMerging(ImageFieldMergingArgs args)
{
// 图片处理接口(可空实现)
}
}
// 2. 使用回调执行邮件合并
Document doc = new Document("template.docx");
doc.MailMerge.UseNonMergeFields = true; // 允许处理非MERGEFIELD
doc.MailMerge.FieldMergingCallback = new ImageTableFieldMerger();
// 3. 执行合并(即使没有数据源也需要调用)
doc.MailMerge.Execute(new string[0], new object[0]);
doc.Save("result.docx");
(2)条件文本(使用IF域):
域内输入条件语句:
{ IF { MERGEFIELD Amount } > 100 "High Value" "Normal Value" }
Document doc = new Document("template.docx");
// 准备数据源
DataTable data = new DataTable();
data.Columns.Add("Amount");
data.Rows.Add(150); // 测试值1
data.Rows.Add(80); // 测试值2
// 执行邮件合并
doc.MailMerge.Execute(data);
// 更新域计算结果(必须调用)
doc.UpdateFields();
doc.Save("result.docx");
带条件的表格输入:
// 自定义回调类增强版
public class AdvancedFieldMerger : IFieldMergingCallback
{
public void FieldMerging(FieldMergingArgs args)
{
// 根据条件动态插入表格
if (args.FieldName == "DetailTable")
{
// 从数据源获取条件值
int orderAmount = (int)args.Record.GetValue("Amount");
// 仅当金额>100时插入表格
if (orderAmount > 100)
{
Table table = CreateDetailTable(args.Document);
args.Document.FirstSection.Body.AppendChild(table);
}
args.Text = "";
}
}
private Table CreateDetailTable(Document doc)
{
// 创建详细表格(代码同上)
// ...
}
}
// 使用方式
doc.MailMerge.FieldMergingCallback = new AdvancedFieldMerger();
doc.MailMerge.Execute(data);
doc.UpdateFields(); // 更新条件域
如何实习:
using Aspose.Words;
using FreeSql;
using System.Collections.Generic;
using System.Data;
using System.Linq;
public class ContractGenerator
{
private readonly IFreeSql _fsql; // FreeSql数据库访问对象
// 构造函数:注入FreeSql实例
public ContractGenerator(IFreeSql freeSql)
{
_fsql = freeSql; // 初始化数据库访问对象
}
// 主方法:生成合同文档
public void GenerateContract(int contractId)
{
// 1. 从数据库获取合同数据
var contract = _fsql.Select<Contract>() // 创建查询
.Where(c => c.Id == contractId) // 按ID过滤
.First(); // 获取第一条记录
// 2. 根据合同类型选择模板路径
string templatePath = contract.Type switch // switch表达式匹配合同类型
{
1 => "Templates/contract_type1.docx", // 类型1使用模板1
2 => "Templates/contract_type2.docx", // 类型2使用模板2
_ => throw new Exception("未知合同类型") // 其他类型抛出异常
};
// 3. 加载Word模板
Document doc = new Document(templatePath);
// 4. 准备字段值字典
Dictionary<string, object> fieldValues = PrepareFieldValues(contract);
// 5. 执行邮件合并
ExecuteMailMerge(doc, fieldValues);
// 6. 保存生成的合同文档
doc.Save($"Output/contract_{contractId}.docx");
}
// 准备字段值字典:核心逻辑
private Dictionary<string, object> PrepareFieldValues(Contract contract)
{
// 创建字典存储字段名和对应值
var values = new Dictionary<string, object>();
// 添加基本字段
values.Add("ContractId", contract.Id); // 合同ID
values.Add("ClientName", contract.ClientName); // 客户名称
values.Add("SignDate", contract.SignDate.ToString("yyyy-MM-dd")); // 格式化签约日期
// 处理单选框值:将逗号分隔字符串转换为列表
var radioValues = contract.RadioValue?
.Split(',') // 按逗号分割
.Select(v => v.Trim()) // 去除空格
.ToList() ?? new List<string>(); // 空值处理
// 处理复选框值:同样转换为列表
var checkValues = contract.CheckValues?
.Split(',')
.Select(v => v.Trim())
.ToList() ?? new List<string>();
// 单选框处理:检查值是否存在,返回对应符号
values.Add("RADIO_Agree",
radioValues.Contains("Agree") ? "☑" : "□");
values.Add("RADIO_Disagree",
radioValues.Contains("Disagree") ? "☑" : "□");
// 复选框处理:同样逻辑
values.Add("CHECK_24Support",
checkValues.Contains("24Support") ? "☑" : "□");
values.Add("CHECK_FreeUpgrade",
checkValues.Contains("FreeUpgrade") ? "☑" : "□");
values.Add("CHECK_VIPService",
checkValues.Contains("VIPService") ? "☑" : "□");
// 动态内容处理
values.Add("DYNAMIC_CONTENT", PrepareDynamicContent(contract));
return values; // 返回填充好的字典
}
// 准备动态内容:根据合同类型返回不同文本
private string PrepareDynamicContent(Contract contract)
{
// 使用switch表达式处理不同类型
return contract.Type switch
{
1 => "【类型1专属条款】\n1. 条款内容 A\n2. 条款内容 B", // 类型1内容
2 => "〖类型2特别约定〗\n• 特殊条款 1\n• 特殊条款 2", // 类型2内容
_ => string.Empty // 默认空内容
};
}
// 执行邮件合并
private void ExecuteMailMerge(Document doc, Dictionary<string, object> fieldValues)
{
// 创建DataTable作为邮件合并数据源
DataTable dataTable = new DataTable("ContractData");
// 添加列:字典的每个键作为列名
foreach (var key in fieldValues.Keys)
{
dataTable.Columns.Add(key);
}
// 创建数据行
DataRow row = dataTable.NewRow();
// 填充行数据:遍历字典键值对
foreach (var kvp in fieldValues)
{
row[kvp.Key] = kvp.Value; // 设置每列的值
}
// 添加行到DataTable
dataTable.Rows.Add(row);
// 配置邮件合并
doc.MailMerge.UseNonMergeFields = true; // 允许处理所有域,不仅是MERGEFIELD
// 执行邮件合并:将DataTable数据合并到文档
doc.MailMerge.Execute(dataTable);
}
}
// 数据库实体类
public class Contract
{
public int Id { get; set; } // 合同ID
public int Type { get; set; } // 合同类型(1或2)
public string ClientName { get; set; } // 客户名称
public DateTime SignDate { get; set; } // 签约日期
// 单选框值(逗号分隔的选项字符串)
public string RadioValue { get; set; }
// 复选框值(逗号分隔的选项字符串)
public string CheckValues { get; set; }
}