当前位置: 首页 > news >正文

DocumentFormat.OpenXml + MiniWord:Word 文档合并与内容赋值的优雅组合

在项目开发中,遇到这样的需求:要把一堆数据快速整理成格式规范的Word文档。比如:

  • 人力资源要给新员工批量制作入职通知书
  • 学校老师要为全班同学生成期末成绩单
  • 销售部门要给不同客户发送个性化的报价单
  • 财务人员要定期生成标准格式的统计报表

这些场景都有一个共同特点:数据量大、格式固定、重复性高。查找资料后了解到两个.NET库可以很轻松的就能够解决上述问题:

  • MiniWord(0.9.2):可以根据模板加填充符合快速的填充数据
  • DocumentFormat.OpenXml(3.3.0):可以把多个文档合并成一个

🛠️ 技术栈介绍

MiniWord - 文档内容填充

创建一个Word模板,只需要在需要填数据的地方写上{{姓名}}{{成绩}}这样的标记,然后把数据扔给MiniWord,它就能自动生成完整的文档。同时还能够填充Image图片、字体颜色、超链接等功能,非常的方便!

DocumentFormat.OpenXml - 微软官方的文档操作工具

这个工具比较专业,能直接操作Word文档的内部结构。我主要用它来做文档合并——把多个小文档拼接成一个大文档,还能自动加上分页符,让每个部分都从新的一页开始。

💻 完整实现代码

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 数据绑定

// 构建表格数据
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 文档合并

// 创建目标文档
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 })));
}

相关资源

  • MiniWord GitHub仓库
  • DocumentFormat.OpenXml GitHub仓库
  • 阅读原文
http://www.rkmt.cn/news/22395.html

相关文章:

  • 【学习笔记】回文自动机初步总结
  • rest_framework框架视图集整理
  • SPP question regarding Issues Due To Gaming Spoofers
  • 类型安全ORM的高并发场景解决方案 - 实践
  • 提供给第三方接口的验证方法
  • vue 下拉框 vxe-select 实现人员选择下拉列表
  • 最后防线 解题报告
  • AI时代我们需要更多开发者:Shalini Kurapati的技术洞察
  • 从此,不再开口就紧张
  • 基于Qt实现百度地图路径规划功能
  • 基于C#的湿度上位机实现方案
  • C盘满了怎么清理?10种安全释放Win10/Win11空间的方法(详细图文版)
  • 2025 护眼灯生产厂家最新推荐榜:精选资深与新锐品牌,深度解析生产实力与市场口碑
  • 【IEEE出版|快至3-4个月EI检索】第五届电力系统与能源互联网国际学术会议(PoSEI 2025)
  • 复盘:如何用Coze+Kimi,搭建一个能自动分析财报的“金融助理”?
  • 详细介绍:【算法竞赛学习笔记】基础算法篇:递归再探
  • 折腾笔记:免费用上 Claude Code 的两个方案
  • 2025 年最新金蝶云服务商代理机构权威推荐排行榜:聚焦铂金伙伴技术实力与万级客户口碑,上海金蝶云最新推荐优质公司
  • 可视化图解算法64:哈希表基础
  • SqlServer Arithmetic overflow error converting expression to data type int
  • 医疗公有云市场第一!
  • 2025手持光谱仪/光谱分析仪/便携式光谱仪、矿石/元素分析仪、合金/金属/不锈钢/铝合金、贵金属、三元催化、赛普斯、IF光谱仪推荐榜
  • 在 Android 11 上构建 WiFi 热点并发协助(同时开启 STA + AP 模式)
  • 25 LCA模拟赛3T1 ROI 2012马赛克 题解
  • uni-app x开发商城系统,Swiper 轮播图
  • 昂瑞微OM6651A:国产车规级蓝牙芯片的破局者
  • 打破应用跳转流失困局,提升推广链接转化率
  • 检查cpu是否支撑minio方法
  • Codeforces Round 1058 (Div. 2) A~E
  • 2025 年生料带厂家最新推荐排行榜:解析优质品牌优势,涵盖新型、彩色、液态等多类型生料带厂家企业推荐