Ответ 1
Проблема вызвана ошибкой реализации ClosedXML.
Его можно легко воспроизвести, используя следующий фрагмент (модифицированная версия примера Pivot Tables) и открытие результирующего файла в Excel:
static void CreateTestPivotTables(string filePath)
{
var wb = new XLWorkbook();
var wsData = wb.Worksheets.Add("Data");
wsData.Cell("A1").Value = "Category";
wsData.Cell("A2").Value = "A";
wsData.Cell("A3").Value = "B";
wsData.Cell("A4").Value = "B";
wsData.Cell("B1").Value = "Number";
wsData.Cell("B2").Value = 100;
wsData.Cell("B3").Value = 150;
wsData.Cell("B4").Value = 75;
var source = wsData.Range("A1:B4");
for (int i = 1; i <= 2; i++)
{
var name = "PT" + i;
var wsPT = wb.Worksheets.Add(name);
var pt = wsPT.PivotTables.AddNew(name, wsPT.Cell("A1"), source);
pt.RowLabels.Add("Category");
pt.Values.Add("Number")
.ShowAsPctFrom("Category").And("A")
.NumberFormat.Format = "0%";
}
wb.SaveAs(filePath);
}
Ошибка находится в XLWorkbook_Save.cs - GeneratePivotTables
метод:
private static void GeneratePivotTables(WorkbookPart workbookPart, WorksheetPart worksheetPart,
XLWorksheet xlWorksheet,
SaveContext context)
{
foreach (var pt in xlWorksheet.PivotTables)
{
var ptCdp = context.RelIdGenerator.GetNext(RelType.Workbook);
var pivotTableCacheDefinitionPart = workbookPart.AddNewPart<PivotTableCacheDefinitionPart>(ptCdp);
GeneratePivotTableCacheDefinitionPartContent(pivotTableCacheDefinitionPart, pt);
var pivotCaches = new PivotCaches();
var pivotCache = new PivotCache {CacheId = 0U, Id = ptCdp};
pivotCaches.AppendChild(pivotCache);
workbookPart.Workbook.AppendChild(pivotCaches);
var pivotTablePart =
worksheetPart.AddNewPart<PivotTablePart>(context.RelIdGenerator.GetNext(RelType.Workbook));
GeneratePivotTablePartContent(pivotTablePart, pt);
pivotTablePart.AddPart(pivotTableCacheDefinitionPart, context.RelIdGenerator.GetNext(RelType.Workbook));
}
}
по строке workbookPart.Workbook.AppendChild(pivotCaches);
, которая добавляет несколько PivotCaches
в workbookPart.Workbook
, в то время как она позволяет содержать 0 или 1.
С учетом сказанного единственный способ исправить это - внутри исходного кода, модифицировав вышеуказанный метод следующим образом:
private static void GeneratePivotTables(WorkbookPart workbookPart, WorksheetPart worksheetPart,
XLWorksheet xlWorksheet,
SaveContext context)
{
var pivotCaches = workbookPart.Workbook.GetFirstChild<PivotCaches>();
foreach (var pt in xlWorksheet.PivotTables)
{
var ptCdp = context.RelIdGenerator.GetNext(RelType.Workbook);
var pivotTableCacheDefinitionPart = workbookPart.AddNewPart<PivotTableCacheDefinitionPart>(ptCdp);
GeneratePivotTableCacheDefinitionPartContent(pivotTableCacheDefinitionPart, pt);
if (pivotCaches == null)
workbookPart.Workbook.AppendChild(pivotCaches = new PivotCaches());
var pivotCache = new PivotCache { CacheId = (uint)pivotCaches.Count(), Id = ptCdp };
pivotCaches.AppendChild(pivotCache);
var pivotTablePart =
worksheetPart.AddNewPart<PivotTablePart>(context.RelIdGenerator.GetNext(RelType.Workbook));
GeneratePivotTablePartContent(pivotTablePart, pt);
pivotTablePart.PivotTableDefinition.CacheId = pivotCache.CacheId;
pivotTablePart.AddPart(pivotTableCacheDefinitionPart, context.RelIdGenerator.GetNext(RelType.Workbook));
}
}
Обновление: Хорошая новость заключается в том, что мой пост вызвал исправление исходного хранилища ClosedXML Франсуа Бота (также запишет petelids, который привел его туда), поэтому вы можете взять код оттуда, пока следующий релиз, который, надеюсь, будет включать его.