我有一个修改现有电子表格的程序。部分程序会创建某些工作表的副本。要创建一个副本,程序运行完美,生成的文件也很好,在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<>()
执行任何Part(及其引用的任何部分)的深层副本的事实,该部分尚未属于文档,在临时工作表的帮助下创建工作表的所有引用部分的深层副本。
如上所述,如果函数仅针对给定工作表调用一次,则此方法非常有效。但是,如果多次调用它,则在Excel中打开文件时会出现无法读取的内容错误。话虽这么说,文件本身看起来很好,没有丢失数据或任何东西(这将有助于弄清楚到底出了什么问题),只是错误说有错误。
注释掉的行是&#34; hack&#34;我必须处理有关.AddPart<>()
的问题,但我不会在这里详细介绍它们,因为我已经发布了关于here的信息(但我仍然没有#&}# 39;得到答复,所以请务必回答这个问题!)。话虽这么说,这些线似乎与当前的问题无关,因为错误出现时有或没有这些代码行。
答案 0 :(得分:1)
我注意到源文件的表单由于某种原因没有正确编号,因此它们的SheetID不是顺序的(6,1,3)。因此,我的程序是在使用代码表创建文件的两个副本时.SheetID = sheets.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),因此没有冲突,也没有错误!
答案 1 :(得分:0)
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();
}
}