From 263a46619c1b55b83dc820c27af86d5ad5931574 Mon Sep 17 00:00:00 2001 From: "Dmitry.Mozin" Date: Mon, 16 Oct 2023 11:46:14 +0300 Subject: [PATCH 1/6] [MEDIDEV-509] First iteration. --- Excel.TemplateEngine/ITemplateEngine.cs | 2 +- .../LazyParse/IFormulaEvaluator.cs | 12 +++++++ .../LazyParse/LazyClassParser.cs | 32 +++++++++++++++---- .../ObjectPrinting/LazyParse/LazyRowReader.cs | 28 +++++++++++++--- .../ObjectPrinting/LazyParse/ListParser.cs | 10 +++--- Excel.TemplateEngine/TemplateEngine.cs | 4 +-- 6 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs diff --git a/Excel.TemplateEngine/ITemplateEngine.cs b/Excel.TemplateEngine/ITemplateEngine.cs index f0b4364..7d60fc7 100644 --- a/Excel.TemplateEngine/ITemplateEngine.cs +++ b/Excel.TemplateEngine/ITemplateEngine.cs @@ -16,7 +16,7 @@ public interface ITemplateEngine (TModel model, Dictionary mappingForErrors) Parse([NotNull] ITableParser tableParser) where TModel : new(); - public TModel LazyParse([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null) + public TModel LazyParse([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null, IFormulaEvaluator formulaEvaluator = null) where TModel : new(); } } \ No newline at end of file diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs new file mode 100644 index 0000000..8f8cc28 --- /dev/null +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs @@ -0,0 +1,12 @@ +#nullable enable + +using DocumentFormat.OpenXml.Spreadsheet; + +namespace SkbKontur.Excel.TemplateEngine.ObjectPrinting.LazyParse +{ + public interface IFormulaEvaluator + { + string? TryEvaluate( + Cell cell); + } +} diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs index 898ddbe..fad842b 100644 --- a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs @@ -33,7 +33,11 @@ public LazyClassParser(ILog logger) /// /// Target file offset relative to a template. [NotNull] - public TModel Parse([NotNull] LazyTableReader tableReader, [NotNull] RenderingTemplate template, ObjectSize readerOffset) + public TModel Parse( + [NotNull] LazyTableReader tableReader, + [NotNull] RenderingTemplate template, + ObjectSize readerOffset, + [CanBeNull] IFormulaEvaluator formulaEvaluator = null) where TModel : new() { var model = new TModel(); @@ -52,7 +56,10 @@ public TModel Parse([NotNull] LazyTableReader tableReader, [NotNull] Ren { foreach (var templateCell in templateRow) { - var targetCell = targetRowReader.TryReadCell(templateCell.CellPosition.Add(readerOffset)); + var targetCell = targetRowReader.TryReadCell( + templateCell.CellPosition.Add(readerOffset), + formulaEvaluator); + if (targetCell == null) continue; @@ -71,7 +78,7 @@ public TModel Parse([NotNull] LazyTableReader tableReader, [NotNull] Ren var templateListCells = templateRow.SkipWhile(x => x.CellPosition.CellReference != templateCell.CellPosition.CellReference) .ToArray(); - ParseEnumerable(tableReader, model, templateListCells, enumerableType, readerOffset); + ParseEnumerable(tableReader, model, templateListCells, enumerableType, readerOffset, formulaEvaluator); break; } @@ -90,7 +97,8 @@ private void ParseEnumerable([NotNull] LazyTableReader tableReader, [NotNull] object model, [NotNull] [ItemNotNull] ICell[] templateListCells, [NotNull] Type enumerableType, - [NotNull] ObjectSize readerOffset) + [NotNull] ObjectSize readerOffset, + [CanBeNull] IFormulaEvaluator formulaEvaluator) { var firstEnumerablePath = ExcelTemplatePath.FromRawExpression(templateListCells.First().StringValue) .SplitForEnumerableExpansion() @@ -99,7 +107,12 @@ private void ParseEnumerable([NotNull] LazyTableReader tableReader, var modelType = model.GetType(); var itemType = ObjectPropertiesExtractor.ExtractChildObjectTypeFromPath(modelType, firstEnumerablePath); - var items = ParseList(tableReader, itemType, templateListCells.Select(x => new SimpleCell(x.CellPosition, x.StringValue)), readerOffset); + var items = ParseList( + tableReader, + itemType, + templateListCells.Select(x => new SimpleCell(x.CellPosition, x.StringValue)), + readerOffset, + formulaEvaluator); var withoutArrayAccess = firstEnumerablePath.WithoutArrayAccess(); var enumerableSetter = ObjectChildSetterFactory.GetEnumerableSetter(modelType, withoutArrayAccess, enumerableType, itemType); @@ -107,10 +120,15 @@ private void ParseEnumerable([NotNull] LazyTableReader tableReader, enumerableSetter(model, items); } - private object ParseList([NotNull] LazyTableReader tableReader, [NotNull] Type itemType, [NotNull, ItemNotNull] IEnumerable templateListCells, ObjectSize readerOffset) + private object ParseList( + [NotNull] LazyTableReader tableReader, + [NotNull] Type itemType, + [NotNull, ItemNotNull] IEnumerable templateListCells, + ObjectSize readerOffset, + [CanBeNull] IFormulaEvaluator formulaEvaluator) { return parseList.MakeGenericMethod(itemType) - .Invoke(null, new object[] {tableReader, templateListCells, true, logger, readerOffset}); + .Invoke(null, new object[] {tableReader, templateListCells, true, logger, readerOffset, formulaEvaluator}); } private void ParseSingleValue([NotNull] SimpleCell cell, diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs index 5f59da4..f5343f0 100644 --- a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs @@ -24,14 +24,17 @@ public LazyRowReader([NotNull] Row row, [NotNull] IReadOnlyList sharedSt } [NotNull] - private SimpleCell LoadCurrentCell() + private SimpleCell LoadCurrentCell( + [CanBeNull] IFormulaEvaluator formulaEvaluator) { var cell = (Cell)reader.LoadCurrentElement(); - return ToSimpleCell(cell!); + return ToSimpleCell(cell!, formulaEvaluator); } [CanBeNull] - public SimpleCell TryReadCell([NotNull] ICellPosition cellPosition) + public SimpleCell TryReadCell( + [NotNull] ICellPosition cellPosition, + [CanBeNull] IFormulaEvaluator formulaEvaluator = null) { if (cellPosition.RowIndex != RowIndex) throw new ArgumentException($"Incorrect cell reference. Target cell reference: {cellPosition}. Current row index: {RowIndex}."); @@ -50,7 +53,8 @@ public SimpleCell TryReadCell([NotNull] ICellPosition cellPosition) if (reader.ElementType != typeof(Cell)) continue; - currentCell = LoadCurrentCell(); + currentCell = LoadCurrentCell( + formulaEvaluator); if (cellPosition.ColumnIndex > currentCell!.CellPosition.ColumnIndex) continue; @@ -66,15 +70,29 @@ public SimpleCell TryReadCell([NotNull] ICellPosition cellPosition) } [NotNull] - private SimpleCell ToSimpleCell([NotNull] Cell cell) + private SimpleCell ToSimpleCell( + [NotNull] Cell cell, + [CanBeNull] IFormulaEvaluator formulaEvaluator) { var cellIndex = new CellPosition(cell.CellReference); + var cellValue = cell.CellValue?.InnerText; if (cell.DataType?.Value == CellValues.SharedString && cellValue != null) { var i = int.Parse(cellValue); cellValue = sharedStrings[i]; } + else if( + cell.CellFormula != null && + formulaEvaluator != null && + string.IsNullOrEmpty(cellValue)) + { + var formulaEvaluatedValue = formulaEvaluator.TryEvaluate( + cell); + + if(!string.IsNullOrEmpty(formulaEvaluatedValue)) + cellValue = formulaEvaluatedValue; + } return new SimpleCell(cellIndex, cellValue); } diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/ListParser.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/ListParser.cs index 4fc0faa..5549294 100644 --- a/Excel.TemplateEngine/ObjectPrinting/LazyParse/ListParser.cs +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/ListParser.cs @@ -26,7 +26,8 @@ public static IReadOnlyList Parse([NotNull] LazyTableReader tableR [NotNull, ItemNotNull] IEnumerable templateListCells, bool filterTemplateCells, [NotNull] ILog logger, - [NotNull] ObjectSize readerOffset) + [NotNull] ObjectSize readerOffset, + [CanBeNull] IFormulaEvaluator formulaEvaluator = null) { var itemType = typeof(TItem); @@ -49,7 +50,7 @@ public static IReadOnlyList Parse([NotNull] LazyTableReader tableR while (row != null) { var itemDict = itemPropPaths.ToDictionary(x => x, _ => (object)null); - FillInItemDict(itemTemplate, row, itemType, itemDict, readerOffset, logger); + FillInItemDict(itemTemplate, row, itemType, itemDict, readerOffset, logger, formulaEvaluator); if (IsRowEmpty(itemDict, impotentItemProps)) { @@ -71,12 +72,13 @@ private static void FillInItemDict((ICellPosition CellPosition, ExcelTemplatePat Type itemType, Dictionary itemDict, ObjectSize readerOffset, - ILog logger) + ILog logger, + IFormulaEvaluator formulaEvaluator) { foreach (var prop in itemTemplate) { var cellPosition = new CellPosition(row.RowIndex, prop.CellPosition.ColumnIndex + readerOffset.Width); - var cell = row.TryReadCell(cellPosition); + var cell = row.TryReadCell(cellPosition, formulaEvaluator); if (cell == null || string.IsNullOrWhiteSpace(cell.CellValue)) continue; diff --git a/Excel.TemplateEngine/TemplateEngine.cs b/Excel.TemplateEngine/TemplateEngine.cs index c1fe905..d765477 100644 --- a/Excel.TemplateEngine/TemplateEngine.cs +++ b/Excel.TemplateEngine/TemplateEngine.cs @@ -54,7 +54,7 @@ public void Render([NotNull] ITableBuilder tableBuilder, [NotNull] TMode /// Class to parse. /// LazyTableReader of target xlsx file. /// Target file offset relative to a template. - public TModel LazyParse([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null) + public TModel LazyParse([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null, IFormulaEvaluator formulaEvaluator = null) where TModel : new() { readerOffset ??= new ObjectSize(0, 0); @@ -62,7 +62,7 @@ public TModel LazyParse([NotNull] LazyTableReader lazyTableReader, Objec var renderingTemplate = templateCollection.GetTemplate(rootTemplateName) ?? throw new InvalidOperationException($"Template with name {rootTemplateName} not found in xlsx"); var parser = parserCollection.GetLazyClassParser(); - return parser.Parse(lazyTableReader, renderingTemplate, readerOffset); + return parser.Parse(lazyTableReader, renderingTemplate, readerOffset, formulaEvaluator); } private const string rootTemplateName = "RootTemplate"; From 719b2beb9a6d049d0d8d35186cbb77b8df0ac33c Mon Sep 17 00:00:00 2001 From: "Dmitry.Mozin" Date: Mon, 16 Oct 2023 12:15:36 +0300 Subject: [PATCH 2/6] [MEDIDEV-509] Coding style fix, first iteration. --- .../ObjectPrinting/LazyParse/IFormulaEvaluator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs index 8f8cc28..3e88b09 100644 --- a/Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/IFormulaEvaluator.cs @@ -9,4 +9,4 @@ public interface IFormulaEvaluator string? TryEvaluate( Cell cell); } -} +} \ No newline at end of file From 3e742ec141e661bf209338d784dd4739a47b1aa9 Mon Sep 17 00:00:00 2001 From: "Dmitry.Mozin" Date: Mon, 16 Oct 2023 12:43:53 +0300 Subject: [PATCH 3/6] [MEDIDEV-509] Coding style fix, second iteration. --- .../ObjectPrinting/LazyParse/LazyClassParser.cs | 5 +++-- .../ObjectPrinting/LazyParse/LazyRowReader.cs | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs index fad842b..42506e9 100644 --- a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs @@ -32,11 +32,12 @@ public LazyClassParser(ILog logger) /// Target document LazyTableReader. /// /// Target file offset relative to a template. + /// Target document formula evaluator. [NotNull] public TModel Parse( [NotNull] LazyTableReader tableReader, - [NotNull] RenderingTemplate template, - ObjectSize readerOffset, + [NotNull] RenderingTemplate template, + [NotNull] ObjectSize readerOffset, [CanBeNull] IFormulaEvaluator formulaEvaluator = null) where TModel : new() { diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs index f5343f0..492e2b7 100644 --- a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyRowReader.cs @@ -82,7 +82,7 @@ private SimpleCell ToSimpleCell( var i = int.Parse(cellValue); cellValue = sharedStrings[i]; } - else if( + else if ( cell.CellFormula != null && formulaEvaluator != null && string.IsNullOrEmpty(cellValue)) @@ -90,7 +90,7 @@ private SimpleCell ToSimpleCell( var formulaEvaluatedValue = formulaEvaluator.TryEvaluate( cell); - if(!string.IsNullOrEmpty(formulaEvaluatedValue)) + if (!string.IsNullOrEmpty(formulaEvaluatedValue)) cellValue = formulaEvaluatedValue; } From 1b3fb270a9e23ff7ccabcc493afa7a1a53105bfa Mon Sep 17 00:00:00 2001 From: "Dmitry.Mozin" Date: Mon, 16 Oct 2023 12:59:38 +0300 Subject: [PATCH 4/6] [MEDIDEV-509] Coding style fix, third iteration. --- .../ObjectPrinting/LazyParse/LazyClassParser.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs index 42506e9..942db7d 100644 --- a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs @@ -20,7 +20,7 @@ namespace SkbKontur.Excel.TemplateEngine.ObjectPrinting.LazyParse /// internal class LazyClassParser { - public LazyClassParser(ILog logger) + public LazyClassParser([NotNull] ILog logger) { this.logger = logger; } @@ -124,8 +124,8 @@ private void ParseEnumerable([NotNull] LazyTableReader tableReader, private object ParseList( [NotNull] LazyTableReader tableReader, [NotNull] Type itemType, - [NotNull, ItemNotNull] IEnumerable templateListCells, - ObjectSize readerOffset, + [NotNull, ItemNotNull] IEnumerable templateListCells, + [NotNull] ObjectSize readerOffset, [CanBeNull] IFormulaEvaluator formulaEvaluator) { return parseList.MakeGenericMethod(itemType) From 6ac5ef2bf20e18ef64768f52be11335dbba12e04 Mon Sep 17 00:00:00 2001 From: "Dmitry.Mozin" Date: Mon, 16 Oct 2023 13:38:23 +0300 Subject: [PATCH 5/6] ++ --- .../ObjectPrinting/LazyParse/LazyClassParser.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs index 942db7d..8026a51 100644 --- a/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs +++ b/Excel.TemplateEngine/ObjectPrinting/LazyParse/LazyClassParser.cs @@ -35,7 +35,7 @@ public LazyClassParser([NotNull] ILog logger) /// Target document formula evaluator. [NotNull] public TModel Parse( - [NotNull] LazyTableReader tableReader, + [NotNull] LazyTableReader tableReader, [NotNull] RenderingTemplate template, [NotNull] ObjectSize readerOffset, [CanBeNull] IFormulaEvaluator formulaEvaluator = null) @@ -58,7 +58,7 @@ public TModel Parse( foreach (var templateCell in templateRow) { var targetCell = targetRowReader.TryReadCell( - templateCell.CellPosition.Add(readerOffset), + templateCell.CellPosition.Add(readerOffset), formulaEvaluator); if (targetCell == null) @@ -109,10 +109,10 @@ private void ParseEnumerable([NotNull] LazyTableReader tableReader, var itemType = ObjectPropertiesExtractor.ExtractChildObjectTypeFromPath(modelType, firstEnumerablePath); var items = ParseList( - tableReader, - itemType, - templateListCells.Select(x => new SimpleCell(x.CellPosition, x.StringValue)), - readerOffset, + tableReader, + itemType, + templateListCells.Select(x => new SimpleCell(x.CellPosition, x.StringValue)), + readerOffset, formulaEvaluator); var withoutArrayAccess = firstEnumerablePath.WithoutArrayAccess(); @@ -122,8 +122,8 @@ private void ParseEnumerable([NotNull] LazyTableReader tableReader, } private object ParseList( - [NotNull] LazyTableReader tableReader, - [NotNull] Type itemType, + [NotNull] LazyTableReader tableReader, + [NotNull] Type itemType, [NotNull, ItemNotNull] IEnumerable templateListCells, [NotNull] ObjectSize readerOffset, [CanBeNull] IFormulaEvaluator formulaEvaluator) From dce50909577c157cab65ca108e540840be9a51bc Mon Sep 17 00:00:00 2001 From: "Dmitry.Mozin" Date: Mon, 16 Oct 2023 16:21:19 +0300 Subject: [PATCH 6/6] [MEDIDEV-509] Added documentation --- Excel.TemplateEngine/TemplateEngine.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Excel.TemplateEngine/TemplateEngine.cs b/Excel.TemplateEngine/TemplateEngine.cs index d765477..a1830ca 100644 --- a/Excel.TemplateEngine/TemplateEngine.cs +++ b/Excel.TemplateEngine/TemplateEngine.cs @@ -54,6 +54,7 @@ public void Render([NotNull] ITableBuilder tableBuilder, [NotNull] TMode /// Class to parse. /// LazyTableReader of target xlsx file. /// Target file offset relative to a template. + /// Target file formula evaluator. public TModel LazyParse([NotNull] LazyTableReader lazyTableReader, ObjectSize readerOffset = null, IFormulaEvaluator formulaEvaluator = null) where TModel : new() {