Skip to content

Commit

Permalink
Merge pull request #8 from skbkontur/a.dobrynin/SetWorksheetChildNode…
Browse files Browse the repository at this point in the history
…sLocationsAccordingToSchema

Добавление дочерних элементов листа в корректном порядке
  • Loading branch information
aldobrynin authored Aug 11, 2020
2 parents a1bc7af + cdf426e commit 843c50b
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using NUnit.Framework;

using SkbKontur.Excel.TemplateEngine.FileGenerating;
using SkbKontur.Excel.TemplateEngine.FileGenerating.DataTypes;
using SkbKontur.Excel.TemplateEngine.FileGenerating.Primitives;
using SkbKontur.Excel.TemplateEngine.ObjectPrinting.ExcelDocumentPrimitives.Implementations;
using SkbKontur.Excel.TemplateEngine.ObjectPrinting.NavigationPrimitives.Implementations;
Expand All @@ -26,15 +27,7 @@ public void TestPrintingDropDownFromTheOtherWorksheet()
{
targetDocument.CopyVbaInfoFrom(templateDocument);

foreach (var index in Enumerable.Range(1, templateDocument.GetWorksheetCount() - 1))
{
var worksheet = templateDocument.GetWorksheet(index);
var name = templateDocument.GetWorksheetName(index);
var innerTemplateEngine = new SkbKontur.Excel.TemplateEngine.TemplateEngine(new ExcelTable(worksheet), logger);
var targetWorksheet = targetDocument.AddWorksheet(name);
var innerTableBuilder = new TableBuilder(new ExcelTable(targetWorksheet), new TableNavigator(new CellPosition("A1"), logger));
innerTemplateEngine.Render(innerTableBuilder, new {});
}
CopySecondaryWorksheets(templateDocument, targetDocument);

var template = new ExcelTable(templateDocument.GetWorksheet(0));
var templateEngine = new SkbKontur.Excel.TemplateEngine.TemplateEngine(template, logger);
Expand Down Expand Up @@ -247,6 +240,7 @@ public void TestPrintingCommentsWithEnabledDataValidationByOtherSheetData()

var target = new ExcelTable(targetDocument.GetWorksheet(0));
var tableNavigator = new TableNavigator(new CellPosition("A1"), logger);
targetDocument.GetWorksheet(0).SetPrinterSettings(printerSettings);
var tableBuilder = new TableBuilder(target, tableNavigator, new Style(template.GetCell(new CellPosition("A1"))));
templateEngine.Render(tableBuilder, new {});

Expand Down Expand Up @@ -276,5 +270,19 @@ private void CopySecondaryWorksheets(IExcelDocument templateDocument, IExcelDocu
}

private readonly ConsoleLog logger = new ConsoleLog();

private static readonly ExcelPrinterSettings printerSettings = new ExcelPrinterSettings
{
PrintingOrientation = ExcelPrintingOrientation.Landscape,
PageMargins = new ExcelPageMargins
{
Left = 0.25,
Right = 0.25,
Top = 0.75,
Bottom = 0.75,
Header = 0.3,
Footer = 0.3
}
};
}
}
2 changes: 1 addition & 1 deletion Excel.TemplateEngine/Excel.TemplateEngine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<ItemGroup>
<PackageReference Include="morelinq" Version="3.2.0" />
<PackageReference Include="C5" Version="2.5.3" />
<PackageReference Include="DocumentFormat.OpenXml" Version="2.9.1" />
<PackageReference Include="DocumentFormat.OpenXml" Version="2.11.3" />
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
<PackageReference Include="Vostok.Logging.Abstractions" Version="1.0.1" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Linq;

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;

namespace SkbKontur.Excel.TemplateEngine.FileGenerating.Helpers
{
public static class OpenXmlElementHelper
{
// todo (a.dobrynin, 05.08.2020): replace this method with targetWorksheet.AddChild(child) when DocumentFormat.OpenXml 2.12.0 is released
// https://github.com/OfficeDev/Open-XML-SDK/pull/774
/// <summary>
/// Adds node in the correct location according to the schema
/// http://msdn.microsoft.com/en-us/library/office/cc880096(v=office.15).aspx
/// https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.worksheet?view=openxml-2.8.1#definition
/// https://github.com/OfficeDev/Open-XML-SDK/blob/058ec42001ca97850fd82cc16e3b234c155a6e7e/src/DocumentFormat.OpenXml/GeneratedCode/schemas_microsoft_com_office_excel_2006_main.g.cs#L90
/// </summary>
public static T AddChildToCorrectLocation<T>(this OpenXmlCompositeElement parent, T child) where T : OpenXmlElement
{
if (!(parent is Worksheet))
throw new InvalidOperationException("Schema-oriented insertion is supported only for Worksheets");

var precedingElementTypes = openXmlWorksheetNodesOrder.TakeWhile(x => x != typeof(T));
var closestPrecedingSibling = precedingElementTypes.Reverse()
.Select(precedingElementType => parent.Elements().LastOrDefault(x => x.GetType() == precedingElementType))
.FirstOrDefault(existingElement => existingElement != null);

return closestPrecedingSibling != null
? parent.InsertAfter(child, closestPrecedingSibling)
: parent.InsertAt(child, 0);
}

private static readonly Type[] openXmlWorksheetNodesOrder =
{
typeof(SheetProperties),
typeof(SheetDimension),
typeof(SheetViews),
typeof(SheetFormatProperties),
typeof(Columns),
typeof(SheetData),
typeof(SheetCalculationProperties),
typeof(SheetProtection),
typeof(ProtectedRanges),
typeof(Scenarios),
typeof(AutoFilter),
typeof(SortState),
typeof(DataConsolidate),
typeof(CustomSheetViews),
typeof(MergeCells),
typeof(PhoneticProperties),
typeof(ConditionalFormatting),
typeof(DataValidations),
typeof(Hyperlinks),
typeof(PrintOptions),
typeof(PageMargins),
typeof(PageSetup),
typeof(HeaderFooter),
typeof(RowBreaks),
typeof(ColumnBreaks),
typeof(CustomProperties),
typeof(CellWatches),
typeof(IgnoredErrors),
typeof(Drawing),
typeof(LegacyDrawing),
typeof(LegacyDrawingHeaderFooter),
typeof(DrawingHeaderFooter),
typeof(Picture),
typeof(OleObjects),
typeof(Controls),
typeof(WebPublishItems),
typeof(TableParts),
typeof(WorksheetExtensionList),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

using SkbKontur.Excel.TemplateEngine.FileGenerating.Caches;
using SkbKontur.Excel.TemplateEngine.FileGenerating.DataTypes;
using SkbKontur.Excel.TemplateEngine.FileGenerating.Helpers;

using Vostok.Logging.Abstractions;

Expand Down Expand Up @@ -50,25 +51,25 @@ public void SetPrinterSettings(ExcelPrinterSettings excelPrinterSettings)
pageMargins.Footer = excelPrinterSettings.PageMargins.Footer;

if (!worksheet.Elements<PageMargins>().Any())
worksheet.AppendChild(pageMargins);
InsertWorksheetChild(worksheet, pageMargins);
}

var pageSetup = worksheet.Elements<PageSetup>().FirstOrDefault() ?? new PageSetup();
pageSetup.Orientation = excelPrinterSettings.PrintingOrientation == ExcelPrintingOrientation.Landscape ? OrientationValues.Landscape : OrientationValues.Portrait;

if (!worksheet.Elements<PageSetup>().Any())
worksheet.AppendChild(pageSetup);
InsertWorksheetChild(worksheet, pageSetup);
}

public void MergeCells(ExcelCellIndex upperLeft, ExcelCellIndex lowerRight)
{
var mergeCells = worksheet.GetFirstChild<MergeCells>() ?? CreateMergeCellsWorksheetPart();
var mergeCells = worksheet.GetFirstChild<MergeCells>() ?? InsertWorksheetChild(worksheet, new MergeCells());
mergeCells.AppendChild(new MergeCell {Reference = $"{upperLeft.CellReference}:{lowerRight.CellReference}"});
}

public void ResizeColumn(int columnIndex, double width)
{
var columns = worksheet.GetFirstChild<Columns>() ?? CreateColumns();
var columns = worksheet.GetFirstChild<Columns>() ?? InsertWorksheetChild(worksheet, new Columns());
while (columns.ChildElements.Count < columnIndex)
{
columns.AppendChild(new Column
Expand Down Expand Up @@ -142,7 +143,7 @@ public void CopyDataValidationsFrom([NotNull] IExcelWorksheet template)
var dataValidations = templateWorksheet.GetFirstChild<DataValidations>();
if (dataValidations == null)
return;
worksheet.InsertBefore(dataValidations.CloneNode(true), worksheet.GetFirstChild<PageMargins>());
InsertWorksheetChild(worksheet, (DataValidations)dataValidations.CloneNode(true));
}

public void CopyWorksheetExtensionListFrom(IExcelWorksheet template)
Expand Down Expand Up @@ -246,7 +247,7 @@ private void CopyDrawingsPartAndGetId([NotNull] WorksheetPart templateWorksheetP
var drawingsPartId = templateWorksheetPart.DrawingsPart == null ? null : templateWorksheetPart.GetIdOfPart(templateWorksheetPart.DrawingsPart);
SafelyAddPart(targetWorksheet.WorksheetPart, drawingsPart, drawingsPartId);
targetWorksheet.RemoveAllChildren<Drawing>();
targetWorksheet.Append(new Drawing {Id = drawingsPartId});
InsertWorksheetChild(targetWorksheet, new Drawing {Id = drawingsPartId});
}

[SuppressMessage("ReSharper", "PossiblyMistakenUseOfParamsMethod")]
Expand All @@ -259,7 +260,7 @@ private void CopyVmlDrawingPartAndGetId([NotNull] WorksheetPart templateWorkshee
var vmlDrawingPartId = vmlDrawingPart == null ? null : templateWorksheetPart.GetIdOfPart(vmlDrawingPart);
SafelyAddPart(targetWorksheet.WorksheetPart, vmlDrawingPart, vmlDrawingPartId);
targetWorksheet.RemoveAllChildren<LegacyDrawing>();
targetWorksheet.InsertAfter(new LegacyDrawing {Id = vmlDrawingPartId}, worksheet.GetFirstChild<PageMargins>());
InsertWorksheetChild(targetWorksheet, new LegacyDrawing {Id = vmlDrawingPartId});
}

[CanBeNull]
Expand Down Expand Up @@ -346,47 +347,9 @@ public IExcelRow CreateRow(int rowIndex)
return new ExcelRow(newRow, documentStyle, excelSharedStrings);
}

private MergeCells CreateMergeCellsWorksheetPart()
private static T InsertWorksheetChild<T>(Worksheet openXmlWorksheetNodesOrder, T child) where T : OpenXmlElement
{
// Имеет принципиальное значение, куда именно вставлять элемент MergeCells
// см. http://msdn.microsoft.com/en-us/library/office/cc880096(v=office.15).aspx

var mergeCells = new MergeCells();
if (worksheet.Elements<CustomSheetView>().Any())
worksheet.InsertAfter(mergeCells, worksheet.Elements<CustomSheetView>().First());
else if (worksheet.Elements<DataConsolidate>().Any())
worksheet.InsertAfter(mergeCells, worksheet.Elements<DataConsolidate>().First());
else if (worksheet.Elements<SortState>().Any())
worksheet.InsertAfter(mergeCells, worksheet.Elements<SortState>().First());
else if (worksheet.Elements<AutoFilter>().Any())
worksheet.InsertAfter(mergeCells, worksheet.Elements<AutoFilter>().First());
else if (worksheet.Elements<Scenarios>().Any())
worksheet.InsertAfter(mergeCells, worksheet.Elements<Scenarios>().First());
else if (worksheet.Elements<ProtectedRanges>().Any())
worksheet.InsertAfter(mergeCells, worksheet.Elements<ProtectedRanges>().First());
else if (worksheet.Elements<SheetProtection>().Any())
worksheet.InsertAfter(mergeCells, worksheet.Elements<SheetProtection>().First());
else if (worksheet.Elements<SheetCalculationProperties>().Any())
worksheet.InsertAfter(mergeCells, worksheet.Elements<SheetCalculationProperties>().First());
else
worksheet.InsertAfter(mergeCells, worksheet.Elements<SheetData>().First());
return mergeCells;
}

private Columns CreateColumns()
{
var columns = new Columns();
if (worksheet.Elements<SheetFormatProperties>().Any())
worksheet.InsertAfter(columns, worksheet.Elements<SheetFormatProperties>().First());
else if (worksheet.Elements<SheetViews>().Any())
worksheet.InsertAfter(columns, worksheet.Elements<SheetViews>().First());
else if (worksheet.Elements<Dimensions>().Any())
worksheet.InsertAfter(columns, worksheet.Elements<Dimensions>().First());
else if (worksheet.Elements<SheetProperties>().Any())
worksheet.InsertAfter(columns, worksheet.Elements<SheetProperties>().First());
else
worksheet.InsertAt(columns, 0);
return columns;
return openXmlWorksheetNodesOrder.AddChildToCorrectLocation(child);
}

public IExcelDocument ExcelDocument { get; }
Expand All @@ -396,5 +359,6 @@ private Columns CreateColumns()
private readonly ILog logger;
private readonly Worksheet worksheet;
private readonly TreeDictionary<uint, Row> rowsCache;

}
}

0 comments on commit 843c50b

Please sign in to comment.