C#测试调用OpenXml填充word文档的表格
使用OpenXml将统计数据输出到word文档的表格中,如果需要生成多页数据的话,需要使用前面文章用到的表格复制功能(参考文献3),同时要计算总页数、当前页数、每页数据等信息并田中到每页的表格内。
以景点统计数据为例,基于DeepSeek生成景点类及22条测试数据,将数据集合中的部分属性输出到word文件的表格中。景点类及word表格模板如下所示:
public class ScenicSpot
{public int Id { get; set; } // 景点IDpublic string Name { get; set; } // 景点名称public string Description { get; set; } // 景点描述public string Location { get; set; } // 地理位置public decimal TicketPrice { get; set; } // 门票价格public double Area { get; set; } // 占地面积(公顷)public int VisitorCapacity { get; set; } // 游客容量public DateTime OpenDate { get; set; } // 开放日期public bool IsWorldHeritage { get; set; } // 是否世界遗产public double Rating { get; set; } // 评分(1-5分)public string Category { get; set; } // 景点类别public int AnnualVisitors { get; set; } // 年游客量(万人次)
}

程序的主要思路是找到word文档中的表格并复制一份到内存,然后计算总页数,接着逐页计算并填充统计数据、页码信息。程序的主要实现逻辑及文档输出效果如下所示。
private static void ProcessDocument(WordprocessingDocument doc, Dictionary<string, string> replacements)
{MainDocumentPart mainPart = doc.MainDocumentPart;if (mainPart == null) return;Body body = mainPart.Document.Body; string tableTitle = "datatable";// 通过表格属性中的标题查找表格Table targetTable = FindTableByTableTitle(body, tableTitle);if (targetTable == null){Console.WriteLine($"未找到标题为 '{tableTitle}' 的表格");return;}int startRowIndex = 2;//每页填充起始行int endRowIndex = 16;//每页填充结束行int pageInfoRowIndex = 17;//当前页、总页数信息所在行int curPageColIndex = 3;//当前页信息所在列int totalPageColIndex = 4;//总页数信息所在列int linePerPage = 15;//每页填充行数//计算总页数int totalPage = (m_lstScenicSpot.Count % linePerPage == 0) ? (m_lstScenicSpot.Count / linePerPage) : (m_lstScenicSpot.Count / linePerPage + 1);int curPage = 1;int lineIndex = 1;// 克隆表格Table clonedTable = (Table)targetTable.CloneNode(true);Table curTable = targetTable;do{// 如果不是首页,则克隆新表格并插入word文档中if(curPage!=1){ InsertPageBreakAfterElement(body, curTable);// 在当前表格后插入分页符curTable =(Table)clonedTable.CloneNode(true);//复制新表格InsertElementAfterLastPageBreak(body, curTable);// 在分页符后插入新表格}//取当前页的数据IEnumerable<ScenicSpot> pageData = m_lstScenicSpot.Skip((curPage - 1) * linePerPage).Take(linePerPage);//逐行插入数据var rows = curTable.Elements<TableRow>();if (rows != null && rows.Count() > 0){for (int rowIndex = startRowIndex; (rowIndex <= endRowIndex) && (rowIndex < (startRowIndex + pageData.Count())); rowIndex++){TableRow row = rows.ElementAt(rowIndex);var cells = row.Elements<TableCell>();ScenicSpot rowData = pageData.ElementAt(rowIndex - startRowIndex);FillTabelCellData(cells.ElementAt(0), lineIndex.ToString());FillTabelCellData(cells.ElementAt(1), rowData.Name);FillTabelCellData(cells.ElementAt(2), rowData.Location);FillTabelCellData(cells.ElementAt(3), rowData.Category);FillTabelCellData(cells.ElementAt(4), rowData.Description);lineIndex++;}}// 插入页码FillTargetTableCellContent(curTable, pageInfoRowIndex, curPageColIndex, $"第 {curPage.ToString()} 页");FillTargetTableCellContent(curTable, pageInfoRowIndex, totalPageColIndex, $"共 {totalPage.ToString()} 页");curPage++;}while(curPage <= totalPage);// 保存文档mainPart.Document.Save();
}private static void FillTabelCellData(TableCell cell,string content)
{cell.RemoveAllChildren<Paragraph>();// 添加新的段落和文本内容到单元格中Paragraph para = new Paragraph(new Run(new Text(content)));cell.AppendChild(para);
}private static void FillTargetTableCellContent(Table table, int rowIndex, int columnIndex, string content)
{TableRow row = table.Elements<TableRow>().ElementAt(rowIndex);// 获取目标单元格TableCell cell = row.Elements<TableCell>().ElementAt(columnIndex);// 清除原有内容cell.RemoveAllChildren<Paragraph>();// 创建新段落和文本Paragraph para = new Paragraph();Run run = new Run();run.Append(new Text(content));para.Append(run);cell.Append(para);
}

参考文献
[1]https://github.com/dotnet/Open-XML-SDK
[2]https://learn.microsoft.com/zh-cn/office/open-xml/open-xml-sdk
[3]https://blog.csdn.net/gc_2299/article/details/151157804
