You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于C# OpenXML合并多Excel工作表,保留透视表等元素

使用OpenXML合并含筛选、透视表的Excel工作表

核心思路

要完整保留筛选排序列、透视表等复杂元素,不能仅复制工作表的表层节点,必须同步复制所有关联的部件(如透视表缓存、样式定义),并处理ID冲突问题。以下是简化的实现方案:

步骤与代码实现

  1. 以其中一个Excel文件为基础目标文档,逐个导入另一个文件的工作表及关联资源
  2. 处理透视表缓存ID、工作表名称等冲突问题
  3. 保存目标文档
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Linq;

public static void MergeExcelWorkbooks(string targetFilePath, string sourceFilePath)
{
    // 打开目标文档(可写)和源文档(只读)
    using var targetDoc = SpreadsheetDocument.Open(targetFilePath, true);
    using var sourceDoc = SpreadsheetDocument.Open(sourceFilePath, false);

    var targetWorkbookPart = targetDoc.WorkbookPart;
    var sourceWorkbookPart = sourceDoc.WorkbookPart;

    foreach (var sourceSheet in sourceWorkbookPart.Workbook.Sheets.OfType<Sheet>())
    {
        // 获取源工作表部件
        var sourceWorksheetPart = (WorksheetPart)sourceWorkbookPart.GetPartById(sourceSheet.Id);
        
        // 将源工作表部件复制到目标文档
        var newWorksheetPart = targetWorkbookPart.AddPart<WorksheetPart>(sourceWorksheetPart);
        
        // 复制透视表及关联缓存部件
        foreach (var sourcePivotPart in sourceWorksheetPart.PivotTableParts)
        {
            var newPivotPart = newWorksheetPart.AddPart<PivotTablePart>(sourcePivotPart);
            
            // 复制透视表缓存定义并更新缓存ID
            var sourceCacheDef = sourcePivotPart.PivotCacheDefinitionPart;
            var newCacheDef = newPivotPart.AddPart<PivotCacheDefinitionPart>(sourceCacheDef);
            newCacheDef.PivotCacheDefinition.CacheId = GetNextCacheId(targetWorkbookPart);
            
            // 复制透视表缓存记录(如果存在)
            var sourceCacheRecords = sourceCacheDef.PivotCacheRecordsPart;
            if (sourceCacheRecords != null)
            {
                newCacheDef.AddPart<PivotCacheRecordsPart>(sourceCacheRecords);
            }
        }
        
        // 生成不重复的工作表名称
        var uniqueSheetName = GetUniqueSheetName(targetWorkbookPart, sourceSheet.Name.Value);
        
        // 向目标工作簿添加新工作表节点
        var newSheet = new Sheet
        {
            Id = targetWorkbookPart.GetIdOfPart(newWorksheetPart),
            SheetId = (uint)(targetWorkbookPart.Workbook.Sheets.Count() + 1),
            Name = uniqueSheetName
        };
        targetWorkbookPart.Workbook.Sheets.Append(newSheet);
    }

    // 保存修改
    targetWorkbookPart.Workbook.Save();
}

// 获取不重复的工作表名称
private static string GetUniqueSheetName(WorkbookPart workbookPart, string originalName)
{
    var existingNames = workbookPart.Workbook.Sheets.OfType<Sheet>().Select(s => s.Name.Value);
    var candidateName = originalName;
    int counter = 1;
    while (existingNames.Contains(candidateName))
    {
        candidateName = $"{originalName}_{counter}";
        counter++;
    }
    return candidateName;
}

// 获取下一个可用的透视表缓存ID
private static uint GetNextCacheId(WorkbookPart workbookPart)
{
    uint maxId = 0;
    foreach (var cacheDefPart in workbookPart.PivotCacheDefinitionParts)
    {
        if (cacheDefPart.PivotCacheDefinition.CacheId > maxId)
        {
            maxId = cacheDefPart.PivotCacheDefinition.CacheId;
        }
    }
    return maxId + 1;
}

注意事项

  • 运行前确保目标文件未被其他程序占用
  • 若源文档包含自定义样式,需额外合并StylesPart节点,避免格式丢失
  • 筛选、排序信息属于工作表节点的子元素,复制工作表部件时会自动保留
  • 如需处理命名范围冲突,可扩展代码合并DefinedNames节点

内容的提问来源于stack exchange,提问作者andrey1567

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 13:32:30