【问题标题】:Error making more than one copy of OpenXML worksheet制作多个 OpenXML 工作表副本时出错
【发布时间】:2014-02-15 16:05:07
【问题描述】:

我有一个修改现有电子表格的程序。该程序的一部分会创建某些工作表的副本。要创建一个副本,程序运行良好,生成的文件也很好,在 Excel 中打开时没有错误。但是,当创建同一个工作表的两个副本时,程序仍然可以正常运行,但是在 Excel 中打开时,出现以下关于不可读内容的错误:

Repaired Records: Worksheet properties from /xl/workbook.xml part (Workbook)

这是用于执行复制的代码:

private void CopySheet(int sNum, int pNum, string type)
{
    var tempSheet = SpreadsheetDocument.Create(new MemoryStream(), SpreadsheetDocumentType.Workbook);
    WorkbookPart tempWBP = tempSheet.AddWorkbookPart();
    var part = Document.XGetWorkSheetPart(sNum);
    var sheetData = part.Worksheet.ChildElements[5].Clone() as SheetData;
    var merge = part.Worksheet.ChildElements[6].Clone() as MergeCells;
    WorksheetPart tempWSP = tempWBP.AddPart<WorksheetPart>(part);

    var copy = Document.WorkbookPart.AddPart<WorksheetPart>(tempWSP);
    //copy.Worksheet.RemoveChild<SheetData>(copy.Worksheet.ChildElements[5] as SheetData);
    //copy.Worksheet.InsertAt<SheetData>(sheetData, 5);
    //copy.Worksheet.RemoveChild<MergeCells>(copy.Worksheet.ChildElements[6] as MergeCells);
    //copy.Worksheet.InsertAt<MergeCells>(merge, 6);
    //copy.Worksheet.SheetProperties.CodeName.Value = "Phase" + pNum + type;

    var sheets = Document.WorkbookPart.Workbook.Sheets;
    var sheet = new Sheet();
    sheet.Id = Document.WorkbookPart.GetIdOfPart(copy);
    sheet.Name = "Phase " + pNum + " " + type;
    sheet.SheetId = (uint)sheets.ChildElements.Count;
    sheets.Append(sheet);
}

此方法利用.AddPart&lt;&gt;() 对不属于文档的任何部件(及其引用的任何内容)执行深层复制这一事实,在临时工作表的帮助下,创建深层副本工作表的所有引用部分。

如上所述,如果该函数只为给定的工作表调用一次,这将非常有效。但是,如果多次调用该文件,则在 Excel 中打开该文件时会出现内容不可读的错误。话虽这么说,文件本身看起来还不错,没有丢失数据或任何东西(这将有助于找出究竟是什么问题),只是错误表明有问题。

被注释掉的行是我必须做的一个“hack”来处理与.AddPart&lt;&gt;()有关的问题,但我不会在这里详细介绍它们,因为我已经发布了关于这个here (但我仍然没有得到答复,所以请务必也回答这个问题!)。话虽如此,这些行似乎与当前的问题无关,因为无论是否有这些代码行都会出现错误。

【问题讨论】:

    标签: c# excel openxml


    【解决方案1】:

    我注意到源文件的工作表无论出于何种原因都没有正确编号,因此它们的工作表 ID 不是连续的(6、1、3)。因此,我的程序是,在使用代码 sheet.SheetID = sheet.ChildElements.Count + 1 创建文件的两个副本时,将值设置为 4、5、6 和 7,这会导致与现有工作表发生冲突。因此,我修改了该部分,以便程序始终获得有效的 ID:

    // ...
    uint id = 1;
    bool valid = false;
    while (!valid)
    {
        uint temp = id;
        foreach (OpenXmlElement e in sheets.ChildElements)
        {
            var s = e as Sheet;
            if (id == s.SheetId.Value)
            {
                id++;
                break;
            }
        }
        if (temp == id)
            valid = true;
    }
    sheet.SheetId = id;
    //...
    

    这样,我的 sheetID 变为 (6, 1, 3, 2, 4, 5, 7),因此没有冲突,也没有更多错误!

    【讨论】:

      【解决方案2】:
          static WorksheetPart GetWorkSheetPart(WorkbookPart workbookPart, string sheetName)
          {
              //Get the relationship id of the sheetname
              string relId = workbookPart.Workbook.Descendants<Sheet>()
              .Where(s => s.Name.Value.Equals(sheetName))
              .First()
              .Id;
              return (WorksheetPart)workbookPart.GetPartById(relId);
          }
      
          static void FixupTableParts(WorksheetPart worksheetPart, int numTableDefParts)
          {
              //Every table needs a unique id and name
              foreach (TableDefinitionPart tableDefPart in worksheetPart.TableDefinitionParts)
              {
                  tableId++;
                  tableDefPart.Table.Id = (uint)tableId;
                  tableDefPart.Table.DisplayName = "CopiedTable" + tableId;
                  tableDefPart.Table.Name = "CopiedTable" + tableId;
                  tableDefPart.Table.Save();
              }
          }
      
          private void CopySheet(SpreadsheetDocument mySpreadsheet, string sheetName, string clonedSheetName)
          {
              WorkbookPart workbookPart = mySpreadsheet.WorkbookPart;
              IEnumerable<Sheet> source = workbookPart.Workbook.Descendants<Sheet>();
              Sheet sheet = Enumerable.First<Sheet>(source, (Func<Sheet, bool>)(s => (string)s.Name == sheetName));
              string sheetWorkbookPartId = (string)sheet.Id;
              WorksheetPart sourceSheetPart = (WorksheetPart)workbookPart.GetPartById(sheetWorkbookPartId);
              SpreadsheetDocument tempSheet = SpreadsheetDocument.Create(new MemoryStream(), mySpreadsheet.DocumentType);
              WorkbookPart tempWorkbookPart = tempSheet.AddWorkbookPart();
              WorksheetPart tempWorksheetPart = tempWorkbookPart.AddPart<WorksheetPart>(sourceSheetPart);
              //Add cloned sheet and all associated parts to workbook
              WorksheetPart clonedSheet = workbookPart.AddPart<WorksheetPart>(tempWorksheetPart);
      
              int numTableDefParts = sourceSheetPart.GetPartsCountOfType<TableDefinitionPart>();
              tableId = numTableDefParts;
              if (numTableDefParts != 0)
                  FixupTableParts(clonedSheet, numTableDefParts);
              CleanView(clonedSheet);
      
              //Add new sheet to main workbook part
              Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();
              Sheet copiedSheet = new Sheet();
              copiedSheet.Name = clonedSheetName;
              copiedSheet.Id = workbookPart.GetIdOfPart(clonedSheet);
              copiedSheet.SheetId = (uint)sheets.ChildElements.Count + 1;
              sheets.Append(copiedSheet);
              workbookPart.Workbook.Save();
          }
      
          static void CleanView(WorksheetPart worksheetPart)
          {
              SheetViews views = worksheetPart.Worksheet.GetFirstChild<SheetViews>();
              if (views != null)
              {
                  views.Remove();
                  worksheetPart.Worksheet.Save();
              }
          }
      

      【讨论】:

      • Excel 在打开“修复的记录:来自 /xl/workbook.xml 部分(工作簿)的工作表属性”和“删除的记录:来自 /xl/worksheets/sheet14.xml 部分的单元格信息”时显示错误,你能帮我解决吗?
      • 每个工作表(标签)都需要有唯一的名称。当 2 个或更多工作表具有相同名称时,也会显示此错误
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-19
      • 2023-04-09
      • 2011-02-22
      • 1970-01-01
      • 2015-02-15
      • 1970-01-01
      相关资源
      最近更新 更多