在项目开发中,遇到这样的需求:要把一堆数据快速整理成格式规范的Word文档。比如:
- 人力资源要给新员工批量制作入职通知书
- 学校老师要为全班同学生成期末成绩单
- 销售部门要给不同客户发送个性化的报价单
- 财务人员要定期生成标准格式的统计报表
这些场景都有一个共同特点:数据量大、格式固定、重复性高。查找资料后了解到两个.NET库可以很轻松的就能够解决上述问题:
- MiniWord(0.9.2):可以根据模板加填充符合快速的填充数据
- DocumentFormat.OpenXml(3.3.0):可以把多个文档合并成一个
🛠️ 技术栈介绍
MiniWord - 文档内容填充
创建一个Word模板,只需要在需要填数据的地方写上{{姓名}}
、{{成绩}}
这样的标记,然后把数据扔给MiniWord,它就能自动生成完整的文档。同时还能够填充Image图片、字体颜色、超链接
等功能,非常的方便!
DocumentFormat.OpenXml - 微软官方的文档操作工具
这个工具比较专业,能直接操作Word文档的内部结构。我主要用它来做文档合并------把多个小文档拼接成一个大文档,还能自动加上分页符,让每个部分都从新的一页开始。
💻 完整实现代码
c#
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using MiniSoftware;
// 生成 100 条随机数据
List<Person> persons = GenerateRandomData(100);
// 准备临时目录
string tempDir = "TempDocs";
if (!Directory.Exists(tempDir)) Directory.CreateDirectory(tempDir);
string tplPath = "template.docx"; // MiniWord 模板
// 每 10 人一组
int groupSize = 10;
int groupCount = (int)Math.Ceiling(persons.Count / (double)groupSize);
var groupFiles = new List<string>(groupCount);
for (int g = 0; g < groupCount; g++)
{
// 当前 10 人
var group = persons.GetRange(g * groupSize,
Math.Min(groupSize, persons.Count - g * groupSize));
// 构建表格行
var rows = new List<Dictionary<string, object>>();
foreach (var p in group)
{
rows.Add(new Dictionary<string, object>
{
["Id"] = p.Id,
["Name"] = p.Name,
["Age"] = p.Age,
["City"] = p.City,
["Email"] = p.Email,
["Score"] = p.Score
});
}
// 模板变量
var dict = new Dictionary<string, object>
{
["GroupNo"] = g + 1,
["Persons"] = rows // MiniWord 支持集合标签 {{Persons}}
};
string groupPath = Path.Combine(tempDir, $"Group_{g + 1}.docx");
MiniWord.SaveAsByTemplate(groupPath, tplPath, dict);
groupFiles.Add(groupPath);
}
// 4. 合并所有组文件
string finalPath = "成绩单_总.docx";
MergeWordDocuments(groupFiles.ToArray(), finalPath);
Console.WriteLine($"完成!共 {groupCount} 个组(每组 10 人),已合并为 {finalPath}");
Console.ReadKey();
// 生成 n 条随机数据
static List<Person> GenerateRandomData(int n)
{
var list = new List<Person>(n);
var rnd = new Random(Guid.NewGuid().GetHashCode());
string[] cities = { "北京", "上海", "广州", "深圳", "成都", "杭州", "西安", "武汉", "南京", "重庆" };
string[] firstNames = { "王", "李", "张", "刘", "陈", "杨", "赵", "黄", "周", "吴" };
string[] lastNames = { "伟", "芳", "娜", "敏", "静", "丽", "强", "磊", "洋", "勇" };
for (int i = 1; i <= n; i++)
{
string name = firstNames[rnd.Next(firstNames.Length)] +
lastNames[rnd.Next(lastNames.Length)] +
(rnd.Next(2) == 0 ? lastNames[rnd.Next(lastNames.Length)] : "");
int age = rnd.Next(18, 66);
string city = cities[rnd.Next(cities.Length)];
string email = $"{name.ToLower()}@example.com";
double score = Math.Round(rnd.NextDouble() * 100, 1);
list.Add(new Person
{
Id = i,
Name = name,
Age = age,
City = city,
Email = email,
Score = score
});
}
return list;
}
// 合并Word文档
static void MergeWordDocuments(string[] sourcePaths, string outputPath)
{
using (WordprocessingDocument mergedDoc =
WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document))
{
// 创建文档主体
MainDocumentPart mainPart = mergedDoc.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
for (int i = 0; i < sourcePaths.Length; i++)
{
string sourcePath = sourcePaths[i];
if (!File.Exists(sourcePath))
{
throw new FileNotFoundException($"文件不存在: {sourcePath}");
}
// 复制源文档内容
using (WordprocessingDocument sourceDoc =
WordprocessingDocument.Open(sourcePath, false))
{
Body sourceBody = sourceDoc.MainDocumentPart.Document.Body;
foreach (OpenXmlElement element in sourceBody.ChildElements)
{
mainPart.Document.Body.AppendChild(element.CloneNode(true));
}
}
// 如果不是最后一个文档,添加分页符
if (i < sourcePaths.Length - 1)
{
mainPart.Document.Body.AppendChild(new Paragraph(
new Run(new Break() { Type = BreakValues.Page })));
}
}
mainPart.Document.Save();
}
}
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string City { get; set; }
public string Email { get; set; }
public double Score { get; set; }
}
📝 模板设计
要使用 MiniWord,需要创建一个模板文档 template.docx
。在模板中,我们可以使用简单的标记语法:
第 {{GroupNo}} 组学生成绩单
Id | 姓名 | 年龄 | 城市 | 邮箱 | 成绩 |
---|---|---|---|---|---|
{{Persons.Id}} | {{Persons.Name}} | {{Persons.Age}} | {{Persons.City}} | {{Persons.Email}} | {{Persons.Score}} |
🔍 技术要点解析
MiniWord 数据绑定
c#
// 构建表格数据
var rows = new List<Dictionary<string, object>>();
foreach (var p in group)
{
rows.Add(new Dictionary<string, object>
{
["Id"] = p.Id,
["Name"] = p.Name,
// ... 其他属性
});
}
// 使用模板生成文档
var dict = new Dictionary<string, object>
{
["GroupNo"] = g + 1,
["Persons"] = rows
};
// 主要部分
MiniWord.SaveAsByTemplate(groupPath, tplPath, dict);
DocumentFormat.OpenXml 文档合并
c#
// 创建目标文档
using (WordprocessingDocument mergedDoc =
WordprocessingDocument.Create(outputPath, WordprocessingDocumentType.Document))
{
MainDocumentPart mainPart = mergedDoc.AddMainDocumentPart();
mainPart.Document = new Document(new Body());
// ...省略
// 逐个复制源文档内容
foreach (OpenXmlElement element in sourceBody.ChildElements)
{
mainPart.Document.Body.AppendChild(element.CloneNode(true));
}
// ...省略
// 添加分页符
mainPart.Document.Body.AppendChild(new Paragraph(
new Run(new Break() { Type = BreakValues.Page })));
}
相关资源: