当前位置: 首页 > 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.hskmm.com/?act=detail&tid=32442

相关文章:

  • CSS三大特性
  • HolmesGPT 正式上线 丨 KubeSphere 助力云原生智能排障新体验
  • MAUI开发安卓应用,采用PC的chrome浏览器调试平板网页
  • 【SPIE出版 | 高校主办,有ISSN、ISBN号 】第四届交通运输工程前沿国际学术会议(FTTE 2025)
  • 【学习笔记】回文自动机初步总结
  • 【学习笔记】回滚莫队初步总结
  • MATLAB中基于 S-V模型进行毫米波信道建模与仿真
  • python之模块
  • 2025 年电动阀门厂推荐榜:电动/气动/高压/真空阀门厂,上海巨良阀门凭技术与口碑领跑行业
  • 认知与困境
  • 【学习笔记】线性基
  • x86_64架构__rdtsc指令
  • KTT
  • AT_joisc2021_c フードコート (Foodcourt)
  • SPP question regarding Issues Due To Gaming Spoofers
  • 类型安全ORM的高并发场景解决方案 - 实践
  • L06_mybatis读取MySQL数据库(懵逼版)
  • 提供给第三方接口的验证方法
  • 【2025最新】6款免费DLL修复工具推荐:彻底解决“XXX.dll缺失”问题!
  • 2025 年注浆管生产厂家最新推荐排行榜:聚焦 0.3mm 精度与国企合作案例,助力基建企业精准挑选优质供应商
  • 2025 年试验箱厂家 TOP 企业品牌推荐排行榜,氙灯老化 / 紫外老化 / 冷热冲击 / 恒温恒湿 / 高低温 / 快速温变 / 盐水喷雾 / 高温老化 / 砂尘 / 淋雨试验箱公司推荐!
  • 系统修复
  • 什么是vibe ?
  • 2025年10月试验箱厂家最新推荐排行榜:氙灯老化试验箱,紫外老化试验箱,冷热冲击试验箱,恒温恒湿试验箱公司推荐!
  • AI时代我们需要更多开发者:Shalini Kurapati的技术洞察
  • 新一代虚拟助手AI技术挑战赛启动
  • CSS各种选择器
  • adobe illustrator中鼠标拖动移动幅度大
  • python的字符串方法示例
  • 经典视觉跟踪算法的MATLAB实现